<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3AProgression_rainbow%2Fsandbox</id>
	<title>Module:Progression rainbow/sandbox - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3AProgression_rainbow%2Fsandbox"/>
	<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Progression_rainbow/sandbox&amp;action=history"/>
	<updated>2026-04-20T03:39:54Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://stockhub.co/index.php?title=Module:Progression_rainbow/sandbox&amp;diff=144519&amp;oldid=prev</id>
		<title>imported&gt;WOSlinker: use require(&#039;strict&#039;) instead of require(&#039;Module:No globals&#039;)</title>
		<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Progression_rainbow/sandbox&amp;diff=144519&amp;oldid=prev"/>
		<updated>2022-10-21T10:04:48Z</updated>

		<summary type="html">&lt;p&gt;use require(&amp;#039;strict&amp;#039;) instead of require(&amp;#039;Module:No globals&amp;#039;)&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;--[[&lt;br /&gt;
This implements {{progression rainbow}}&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
require(&amp;#039;strict&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
-- rounding to first decimal, from http://lua-users.org/wiki/SimpleRound&lt;br /&gt;
local function round(num)&lt;br /&gt;
	return math.floor(num * 10 + 0.5) / 10&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function percent(param, total)&lt;br /&gt;
	-- These suck for i18n because the % is forced to the right without spacing,&lt;br /&gt;
	-- both in a required context (CSS) and unrequired (to-be-displayed text).&lt;br /&gt;
	-- I.e., there should be a separate version of this&lt;br /&gt;
	return tostring(round(100 * param / total)) .. &amp;#039;%&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function percent_remaining(sum, total)&lt;br /&gt;
	local remaining = total - sum&lt;br /&gt;
	if remaining &amp;gt; 0 then&lt;br /&gt;
		return percent(remaining, total)&lt;br /&gt;
	else&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function category_count(category, project)&lt;br /&gt;
	return mw.site.stats.pagesInCategory(&lt;br /&gt;
		string.format(&amp;#039;%s %s articles&amp;#039;, category, project),&lt;br /&gt;
		&amp;#039;pages&amp;#039;&lt;br /&gt;
	)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- This is only done once in this module, here for demonstration.&lt;br /&gt;
-- Gist: Make it cleaner to initialize &amp;#039;trivial&amp;#039; variables.&lt;br /&gt;
local function arg_or_default(args, from_arg, default)&lt;br /&gt;
	if args[from_arg] and args[from_arg] ~= &amp;#039;&amp;#039; then&lt;br /&gt;
		return args[from_arg]&lt;br /&gt;
	else&lt;br /&gt;
		return default&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._main(args)&lt;br /&gt;
&lt;br /&gt;
	local classes = {&lt;br /&gt;
		{count = 0, class = &amp;#039;List&amp;#039;, category = &amp;#039;List-Class&amp;#039;},&lt;br /&gt;
		{count = 0, class = &amp;#039;Stub&amp;#039;, category = &amp;#039;Stub-Class&amp;#039;},&lt;br /&gt;
		{count = 0, class = &amp;#039;Start&amp;#039;, category = &amp;#039;Start-Class&amp;#039;},&lt;br /&gt;
		{count = 0, class = &amp;#039;C&amp;#039;, category = &amp;#039;C-Class&amp;#039;},&lt;br /&gt;
		{count = 0, class = &amp;#039;B&amp;#039;, category = &amp;#039;B-Class&amp;#039;},&lt;br /&gt;
		{count = 0, class = &amp;#039;GA&amp;#039;, category = &amp;#039;GA-Class&amp;#039;},&lt;br /&gt;
		{count = 0, class = &amp;#039;A&amp;#039;, category = &amp;#039;A-Class&amp;#039;},&lt;br /&gt;
		{count = 0, class = &amp;#039;FA&amp;#039;, category = &amp;#039;FA-Class&amp;#039;}&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	local project_classes = {&lt;br /&gt;
		{count = 0, class = &amp;#039;FL&amp;#039;, category = &amp;#039;FL-Class&amp;#039;},&lt;br /&gt;
		{count = 0, class = &amp;#039;Unassessed&amp;#039;, category = &amp;#039;Unassessed&amp;#039;}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local project = arg_or_default(args, &amp;quot;project&amp;quot;, nil)&lt;br /&gt;
	&lt;br /&gt;
	local sum_classes = 0&lt;br /&gt;
	if project then&lt;br /&gt;
		for _, class in ipairs(classes) do&lt;br /&gt;
			class.count = category_count(class.category, project)&lt;br /&gt;
			if class.class == &amp;#039;FA&amp;#039; then&lt;br /&gt;
				class.count = class.count + category_count(&lt;br /&gt;
					project_classes[1].category,&lt;br /&gt;
					project&lt;br /&gt;
				)&lt;br /&gt;
			end&lt;br /&gt;
			sum_classes = sum_classes + class.count&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		for i, class in ipairs(classes) do&lt;br /&gt;
			-- &amp;#039;or class.count&amp;#039; to keep us safe from nil arg&lt;br /&gt;
			class.count = tonumber(args[i]) or class.count&lt;br /&gt;
			sum_classes = sum_classes + class.count&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local total&lt;br /&gt;
	if project then&lt;br /&gt;
		-- It makes more sense to do this sum here rather than in the project&lt;br /&gt;
		-- loop above because total is initialized here in the non-project case&lt;br /&gt;
		total = sum_classes + category_count(&lt;br /&gt;
			project_classes[2].category,&lt;br /&gt;
			project&lt;br /&gt;
		)&lt;br /&gt;
	else&lt;br /&gt;
		total = tonumber(args[9]) or 100&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local height = arg_or_default(args, &amp;#039;height&amp;#039;, nil)&lt;br /&gt;
	&lt;br /&gt;
	local root = mw.html.create(&amp;#039;ul&amp;#039;)&lt;br /&gt;
	root:addClass(&amp;#039;progression-rainbow&amp;#039;)&lt;br /&gt;
	if height then&lt;br /&gt;
		root:css(&amp;#039;height&amp;#039;, height)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local current_frame = mw.getCurrentFrame()&lt;br /&gt;
	for _, class in ipairs(classes) do&lt;br /&gt;
		if class.count ~= 0 then&lt;br /&gt;
			local percentage = percent(class.count, total)&lt;br /&gt;
				root:newline() -- sprinkled through to make the HTML easier to read&lt;br /&gt;
				root:tag(&amp;#039;li&amp;#039;)&lt;br /&gt;
					:css(&amp;#039;background&amp;#039;, current_frame:expandTemplate{&lt;br /&gt;
						title = &amp;#039;class/colour&amp;#039;, args = { class.class }&lt;br /&gt;
					})&lt;br /&gt;
					:css(&amp;#039;width&amp;#039;, percentage)&lt;br /&gt;
					:attr(&amp;#039;title&amp;#039;, string.format(&amp;#039;%s %s&amp;#039;, percentage, class.category))&lt;br /&gt;
					:tag(&amp;#039;span&amp;#039;)&lt;br /&gt;
						:addClass(&amp;#039;sr-only&amp;#039;)&lt;br /&gt;
						:wikitext(string.format(&amp;#039;%s %s&amp;#039;, percentage, class.category))&lt;br /&gt;
						:done()&lt;br /&gt;
					:done()&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	root:newline()&lt;br /&gt;
	&lt;br /&gt;
	local remaining = percent_remaining(sum_classes, total)&lt;br /&gt;
	if remaining then&lt;br /&gt;
		root:tag(&amp;#039;li&amp;#039;)&lt;br /&gt;
			:addClass(&amp;#039;remaining&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;width&amp;#039;, remaining)&lt;br /&gt;
			:attr(&amp;#039;title&amp;#039;, string.format(&amp;#039;%s remaining&amp;#039;, remaining))&lt;br /&gt;
			:tag(&amp;#039;span&amp;#039;)&lt;br /&gt;
				:addClass(&amp;#039;sr-only&amp;#039;)&lt;br /&gt;
				:wikitext(string.format(&amp;#039;%s remaining&amp;#039;, remaining))&lt;br /&gt;
				:done()&lt;br /&gt;
			:done()&lt;br /&gt;
		:newline()&lt;br /&gt;
	end&lt;br /&gt;
	root:allDone()&lt;br /&gt;
	return current_frame:extensionTag{&lt;br /&gt;
		name = &amp;#039;templatestyles&amp;#039;, args = { src = &amp;#039;Module:Progression rainbow/styles.css&amp;#039;}&lt;br /&gt;
	} .. current_frame:extensionTag{&lt;br /&gt;
		name = &amp;#039;templatestyles&amp;#039;, args = { src = &amp;#039;Screen reader-only/styles.css&amp;#039;}&lt;br /&gt;
	} .. &amp;#039;\n&amp;#039; .. tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.main(frame)&lt;br /&gt;
	return p._main(require(&amp;#039;Module:Arguments&amp;#039;).getArgs(frame))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>imported&gt;WOSlinker</name></author>
	</entry>
</feed>