--[[
This implements {{progression rainbow}}
]]
require('Module:No globals')
local getArgs = require('Module:Arguments').getArgs
local p = {}
-- rounding to first decimal, from http://lua-users.org/wiki/SimpleRound
local function round(num)
return math.floor(num * 10 + 0.5) / 10
end
local function class_percent(param, total)
-- These suck for i18n because the % is forced to the right without spacing,
-- both in a required context (CSS) and unrequired (to-be-displayed text).
return tostring(round(100 * param / total)) .. '%'
end
local function percent_remaining(sum, total)
local remaining = total - sum
if remaining > 0 then
return tostring(round(100 * remaining / total)) .. '%'
else
return nil
end
end
local function category_count(category, project)
return mw.site.stats.pagesInCategory(
-- specious use of string.format
string.format('%s %s articles', category, project),
'pages'
)
end
-- This is only done once in this module, here for demonstration.
-- Gist: Make it cleaner to initialize 'trivial' variables.
local function arg_or_default(args, from_arg, default)
if args[from_arg] and args[from_arg] ~= '' then
return args[from_arg]
else
return default
end
end
function p.main(frame)
local args = getArgs(frame)
return p._main(args, frame)
end
function p._main(args, frame)
-- frame needs to be passed to p._main for extensionTag and expandTemplate
local classes = {
{count = 0, class = 'List', category = 'List-Class'},
{count = 0, class = 'Stub', category = 'Stub-Class'},
{count = 0, class = 'Start', category = 'Start-Class'},
{count = 0, class = 'C', category = 'C-Class'},
{count = 0, class = 'B', category = 'B-Class'},
{count = 0, class = 'GA', category = 'GA-Class'},
{count = 0, class = 'A', category = 'A-Class'},
{count = 0, class = 'FA', category = 'FA-Class'}
}
local project_classes = {
{count = 0, class = 'FL', category = 'FL-Class'},
{count = 0, class = 'Unassessed', category = 'Unassessed'}
}
local project = arg_or_default(args, "project", nil)
local sum_classes = 0
if project then
for _, class in ipairs(classes) do
class.count = category_count(class.category, project)
if class.class == 'FA' then
class.count = class.count + category_count(
project_classes[1].category,
project
)
end
sum_classes = sum_classes + class.count
end
else
-- Parameter 9 and others is the total non-project, so exclude
-- I can't get this to work cleanly with (i)pairs
for i = 1,8 do
-- 'or 0' to keep us safe from a non-numeric value.
classes[i].count = tonumber(args[i]) or 0
sum_classes = sum_classes + classes[i].count
end
end
local total
if project then
-- It makes more sense to do this sum here rather than in the project
-- loop above, because total is initialized here in the non-project case
total = sum_classes + category_count(
project_classes[2].category,
project
)
else
total = tonumber(args[9]) or 100
end
local root = mw.html.create('table')
root:addClass('progression-rainbow')
:attr('role', 'presentation')
for _, class in pairs(classes) do
if class.count ~= 0 then
local percentage = class_percent(class.count, total)
root:newline() -- sprinkled through to make the HTML easier to read
-- I don't understand why we don't need to create a 'tr'. When
-- added deliberately, we get a <tr class='empty'></tr> hanging
-- out.
:tag('td')
:css('background', frame:expandTemplate{
title = 'class/colour', args = { class.class }}
)
:css('width', percentage)
:tag('span')
-- wikitext accessibly-hidden by CSS
:wikitext(string.format('%s %s', percentage, class.category))
:done()
:done()
end
end
root:newline()
local remaining = percent_remaining(sum_classes, total)
if remaining then
root:tag('td')
:addClass('remaining')
:css('width', remaining)
:tag('span')
:wikitext(string.format('%s remaining', remaining))
:done()
:done()
:newline()
end
return frame:extensionTag{
name = 'templatestyles',
args = { src = 'Progression rainbow/styles.css'}
} .. '\n' .. tostring(root)
end
return p