Jump to content

Module:Progression rainbow

Permanently protected module
From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Izno (talk | contribs) at 16:36, 31 October 2020 (clean up a var name, use a local in one of the functions). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

--[[
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)
	return tostring(round(100 * param / total)) .. '%'
end

local function percent_remaining(sum, total)
	local remaining = sum - total
	if remaining ~= 0 then -- find this a bit specious
		return tostring(round(-100 * remaining / total)) .. '%'
	else
		return nil
	end
end

local function category_count(category, project)
	return mw.site.stats.pagesInCategory(
		category .. ' ' .. project .. ' articles',
		'pages'
	)
end

function p.main(frame)
	local args = getArgs(frame)
	return p._main(args, frame)
end

function p._main(args, frame)
-- Is there a way to avoid passing a reference to the parent frame?
-- extensionTag must be available in p._main, which on the frame object.

	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'}
	}

	-- generally, I think if there were more 'project' orthogonal attributes
	-- there would be a case for object-orientation here
	-- I'm not sure what that would look like
	local project
	-- is there a more idiomatic way to initialize project?
	if args['project'] and args['project'] ~= '' then
		project = args['project']
	else
		project = nil
	end
	
	local sum_classes = 0
	if project then
		for i, class in pairs(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
		-- I'm not sure if it's clear in this for loop that I want to get
		-- parameters 1 to 8, which I could also do instead as 'for 1,8...'' ]]
		-- unfortunately can't do for i, class in ipairs(args) because of
		-- parameter 9, which is the total non-project
		for i, class in pairs(classes) do
			if args[i] then
				class['count'] = tonumber(args[i])
				sum_classes = sum_classes + class['count']
			end
		end
	end

	local total
	if project then
		-- I think it makes more sense to do this sum here rather than in the
		-- project loop above, because I initialized total here in the non-
		-- project case
		total = sum_classes + category_count(
			project_classes[2]['category'],
			project
		)
	else
		total = args[9] or 100
	end
	
	local root = mw.html.create('table')
	root:addClass('progression-rainbow')
		:attr('role', 'presentation')

	for i, 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
				:tag('td')
				:css('background', frame:expandTemplate{
					title = 'class/colour', args = { class['class'] }}
				)
				:css('width', percentage)
				:tag('span')
				-- wikitext accessibly-hidden by CSS
				:wikitext(percentage .. " " .. class['category'])
				-- what is the more friendly way for i18n?
				: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')
		-- and same question here for i18n
		:wikitext(remaining .. " remaining")
		:done()
		:done()
		:newline()
	end
	-- Not sure if p._main should be stringified instead of returning an object.
	return frame:extensionTag{
		name = 'templatestyles',
		args = { src = 'Progression rainbow/styles.css'}
	} .. '\n' .. tostring(root)
	-- not sure how to add \n before root is initialized, because root must be
	-- an HTML element, and \n is not
end

return p