Edge Rewrite
// HTMLRewriter · presentation

This page was redesigned at the edge.

Cloudflare fetched the original article and streamed it through HTMLRewriter to apply an entirely new visual system without rebuilding the source page.

Jump to content

Module:Political groupings

Permanently protected module
From Wikipedia, the free encyclopedia

local p = {}

local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')

local partyFetch = require('Module:Political party')._fetch

local colorCache = {}
local shortCache = {}

local function getSum(text)
    if string.match(text, "[^%d%+]") then
        return nil
    end

	local sum = 0

    for num in text:gmatch("%d+") do
        sum = sum + tonumber(num)
    end

    return sum
end

local function getBaseName(party)
	return mw.ustring.gsub(party, "%s*%b()", "")
end

function p._getColor(party)
	if string.sub(party, 1, 1) == "#" then
		return party
	end
	local cached = colorCache[party]
	if string.lower(getBaseName(party)) == "independent" then
		party = "Independent"
	end
	if cached then
		return cached
	end
	local color = partyFetch({party, "color"}) or "black"
	color = mw.text.decode(mw.text.trim(color))
	colorCache[party] = color
	return color
end

local function getShort(party, displayNames)
	if displayNames and displayNames[party] then
		return displayNames[party]
	end
	local cached = shortCache[party]
	if cached then
		return cached
	end
	local short = partyFetch({party, "shortname"}) or party
	short = mw.text.trim(short)
	shortCache[party] = short
	return short
end

local function makeLink(party, useShort, displayNames)
	local base = getBaseName(party)
	if string.lower(base) == "independent" then
		return "Independent"
	end
	local target = mw.title.new(party, mw.site.namespaces.Main)
	if not target.exists then
		if useShort then
			return getShort(party, displayNames)
		end
		return party
	end
	if useShort then
		return "[[" .. party .. "|" .. getShort(party, displayNames) .. "]]"
	end
	return "[[" .. party .. "|" .. base .. "]]"
end

local function capitalizeFirst(str)
	return mw.language.getContentLanguage():ucfirst(str or "")
end

local function makeColorBox(color)
	local moreStyle = "background-color: " .. color .. "; border: 1px solid darkgray;"
	return [[<span class="legend-color mw-no-invert" style="forced-color-adjust:none;]] .. moreStyle .. [[">&nbsp;&nbsp;&nbsp;</span>]]
end

local function isVacancy(party)
	party = string.lower(party)
	return party == "vacant" or party == "vacancy" or party == "casual vacancy"
end

local function processColor(party)
	if string.sub(party, 1, 5) == "&#35;" then
		return "#" .. string.sub(party, 6)
	end
	if string.sub(party, 1, 6) == "&#x23;" then
		return "#" .. string.sub(party, 7)
	end
	return party
end

function p._buildTable(args, tableMode)
	local parties = {}
	local seats = {}
	local seatCounts = {}

	local groupingsSeen = {}
	local groupings = {}
	local partyGrouping = {}
	local groupCounts = {}

	local partyColors = {}
	local borderColors = {}
	
	local total = 0

	local vacancies = 0
	
	local displayNames = {}

	local lastParty
	local addedParty
	local lastDisplayName
	for _, v in ipairs(args) do
		if not getSum(v) then
			if string.sub(v, 1, 1) == ":" then
				local grouping = string.sub(v, 2)
				if not groupingsSeen[grouping] then
					groupingsSeen[grouping] = true
					table.insert(groupings, grouping)
					groupCounts[grouping] = 0
				end
				partyGrouping[addedParty] = grouping
				groupCounts[grouping] = groupCounts[grouping] + getSum(seats[addedParty])
			elseif lastParty then
				lastDisplayName = v
			else
				lastParty = v
				lastDisplayName = nil
			end
		else
			if isVacancy(lastParty) and not tableMode then
				vacancies = vacancies + v
				total = total + (getSum(v) or 0)
			else
				table.insert(parties, lastParty)
				seats[lastParty] = v
				seatCounts[lastParty] = getSum(v) or 0
				total = total + (getSum(v) or 0)
				displayNames[lastParty] = lastDisplayName
				partyColors[lastParty] = p._getColor(lastParty)
				addedParty = lastParty
			end
			lastParty = nil
		end
	end

	local idx = 1
	while true do
		local partySeats = args["n" .. idx]
		if not partySeats then
			break
		end
		local partyName = args["p" .. idx] or args["c" .. idx]
		if partyName then
			table.insert(parties, partyName)
			seats[partyName] = partySeats
			partySeats = getSum(partySeats) or 0
			partyColors[partyName] = processColor(args["c" .. idx] or p._getColor(partyName))
			seatCounts[partyName] = partySeats
			local border = args["b" .. idx]
			if border then
				borderColors[partyName] = border
			end
			total = total + partySeats
			displayNames[partyName] = nil
		end
		idx = idx + 1
	end

	return {groupings = groupings,
			parties = parties,
			partyGrouping = partyGrouping,
			groupCounts = groupCounts,
			seats = seats,
			seatCounts = seatCounts,
			displayNames = displayNames,
			vacancies = vacancies,
			partyColors = partyColors,
			borderColors = borderColors,
			total = total}
end

function p._getListing(args)

	local tableMode = yesno(args.table)

	local parsed = p._buildTable(args, tableMode)
	local groupings = parsed.groupings
	local parties = parsed.parties
	local partyGrouping = parsed.partyGrouping
	local groupCounts = parsed.groupCounts
	local seats = parsed.seats
	local displayNames = parsed.displayNames
	local vacancies = parsed.vacancies

	local useShort = not yesno(args.full_names)
	
	local hadOthers = false

    local otherName = "other parties"

    if #groupings == 0 then
		otherName = "all parties"
	end
	
	for i, party in ipairs(parties) do
		if not partyGrouping[party] then
			partyGrouping[party] = otherName
			groupCounts[otherName] = (groupCounts[otherName] or 0) + (getSum(seats[party]) or 0)
			hadOthers = true
		end
	end

	if hadOthers then
		table.insert(groupings, otherName)
	end

	local output = {}

	if args.total and tonumber(args.total) ~= parsed.total then
		table.insert(output, mw.text.tag(
    		'strong',
    		{ class = 'error' },
    		string.format('Number of seats (%d) mismatches specified total (%d)\n',
					parsed.total, tonumber(args.total))
		))
	end
	
	if tableMode then
		table.insert(output, "{| class=\"wikitable\"\n")
		table.insert(output, "! colspan=2| Party\n")
		table.insert(output, "! " .. (args["seat_header"] or args["seat-header"] or "Seats") .. "\n")
 	 	for j, party in ipairs(parties) do
			local color = p._getColor(party)
		 	table.insert(output, "|-\n")
			table.insert(output, "|style=\"background-color:" .. color .. "\"|\n")
		 	table.insert(output, "|" .. makeLink(party, useShort, displayNames) .. "||align=center|" .. seats[party] .. "\n")
		end
		table.insert(output, "|-\n")
		table.insert(output, "!colspan=2|Total\n")
		table.insert(output, "!align=center|" .. parsed.total .. "\n")
		table.insert(output, "|}\n")
	else
		for i, group in ipairs(groupings) do
			table.insert(output, ";" .. capitalizeFirst(group) .. " (" .. groupCounts[group] .. ")\n")
			for j, party in ipairs(parties) do
				if partyGrouping[party] == group then
					local span = "nowrap"
					if yesno(args.wrap) then
						span = ""
					end
					table.insert(output, ": " .. "<span class='" .. span .. "'>" .. makeColorBox(p._getColor(party)) .. " " .. makeLink(party, useShort, displayNames) .. " (" .. seats[party] .. ")</span>\n")
				end
			end
		end
		if vacancies > 0 then
			local vacanciesString = "Vacancies"
			if vacancies == 1 then
				vacanciesString = "Vacancy"
			end
			table.insert(output, ";" .. vacanciesString .. " (" .. vacancies .. ")\n")
			local party = "Casual vacancy"
			table.insert(output, ": " .. "<span class='nowrap'>" .. makeColorBox(p._getColor(party)) .. " " .. makeLink(party, useShort) .. " (" .. vacancies .. ")</span>\n")
		end
	end

	return table.concat(output)
end

function p.getListing(frame)
    local args = getArgs(frame, {
        wrappers = 'Template:political groupings'
    })

    return p._getListing(args)
end

return p