Edge Rewrite
// request.cf · coarse context

A page that knows where it met you.

Only coarse request metadata is shown. This demo does not display or persist visitor IP addresses.

Country
US
Cloudflare location
CMH
Connection
HTTP/2
Language
Not provided

Ray ID: a402efe06c8c1e9f

Jump to content

Module:MilAward

Permanently protected module
From Wikipedia, the free encyclopedia

require('strict')
local p = {}
local data = mw.loadData('Module:MilAward/data')
local getArgs = require('Module:Arguments').getArgs

local function countByCountry()
    -- Counts how many award entries exist per country.
    local StatCount = {}
    for code, record in pairs(data) do
        local country = record.Country
        StatCount[country] = (StatCount[country] or 0) + 1
    end
    return StatCount
end

function p.GraphData(frame)
    -- Produces the x= and y= lines for a graph of number of entries per country.
    local StatCount = countByCountry()
    local xValues, yValues = {}, {}
    for country, count in pairs(StatCount) do
        table.insert(xValues, country)
        table.insert(yValues, count)
    end
    local output = " \n| x=" .. table.concat(xValues, ", ") .. " \n| y=" .. table.concat(yValues, ", ") .. "\n"
    return output
end

function p.Stats(frame)
    local StatCount = countByCountry()

    -- Stable alphabetical order so the country table is readable before the reader sorts it.
    local countries = {}
    for country, _ in pairs(StatCount) do
        table.insert(countries, country)
    end
    table.sort(countries)

    local wikiRows = {}
    for _, country in ipairs(countries) do
        table.insert(wikiRows, "|-\n|" .. country .. "||" .. StatCount[country])
    end

    -- Do not append GraphData-style | x= / | y= here: those were leftover from the old
    -- Graph:Chart workflow and rendered as broken text after the wikitable.
    local wikiCode = "{| class=\"wikitable sortable col2right\"\n|-\n! Country !! Count\n" .. table.concat(wikiRows, "\n") .. "\n|}"

    local tablist = p.PrintStats()
    local output = wikiCode .. "\n\n" .. tablist
    return output
end

function p.PrintStats()
    -- Convert key-value pairs into a list of {code, data[code]} pairs
    local pairsList = {}
    for code, values in pairs(data) do
        table.insert(pairsList, {code, values})
    end

    -- Sort the list based on the "Description" field of each pair (guard against a missing field)
    table.sort(pairsList, function(a, b)
        return (a[2].Description or "") < (b[2].Description or "")
    end)

    -- Generate wiki table code for the sorted list
    local tableCode = "{| class=\"wikitable sortable\"\n"
    tableCode = tableCode .. "|-\n"
    tableCode = tableCode .. "! Code !! Old Code !! Description !! Country !! Postnom !! Ribbon !! Org\n"

    for i, pair in ipairs(pairsList) do
        local code, values = pair[1], pair[2]
        local oldcode = values.Code or ""
        local country = values.Country or ""
        local description = values.Description or ""
        local class = values.Class or ""
        local postnom = values.PostNom or ""
        local ribbonimage = values.RibbonImage or ""
        local pagelink = values.PageLink or ""
        local note = values.Note or ""
        local org = values.Org or ""

        tableCode = tableCode .. "|-\n"
        tableCode = tableCode .. "|" .. code .. "\n"
        if code == oldcode then
        	tableCode = tableCode .. "| \n"
        else
        	tableCode = tableCode .. "|" .. oldcode .. "\n"
        end
        tableCode = tableCode .. "|[[" .. pagelink .. "|" .. description
        if string.len(class) > 0 then
        	tableCode = tableCode .. "]] '''(" .. class .. ")'''"
		else
        	tableCode = tableCode .. "]]"
        end
        if string.len(note) > 0 then
            tableCode = tableCode .. mw.getCurrentFrame():expandTemplate{ title = 'Efn', args = {note} } -- Note: Page needs {{notelist}}
        end
        tableCode = tableCode .. "\n"
        tableCode = tableCode .. "|" .. country .. "\n"
        tableCode = tableCode .. "|" .. postnom .. "\n"
        tableCode = tableCode .. "|[[File:" .. ribbonimage .. "|x30px]]\n"
        tableCode = tableCode .. "|" .. org .. "\n"
    end

    tableCode = tableCode .. "|}"
    return tableCode
end

function p.Display(frame)
	-- Take parameters out of the frame and pass them to p._Display(). Return the result.
	local templateArgs = getArgs(frame)
	local code = templateArgs[1] or 'None'
	local size = templateArgs[2] or "40px"
	local namedcode = templateArgs["code"]
	if namedcode then
		code = namedcode
	end
	local namedsize = templateArgs["size"]
	if namedsize then
		size = namedsize
	end
	return p._Display(code, size)
end

function p._Display(code, size)
    -- Debug/inspection helper: dumps the raw data fields for a code. (size is currently unused.)
    local rec = data[code]
    if not rec then
        return '<span style="color:#d33"> (Code not found: <b>' .. tostring(code) .. '</b>)</span> [[Category:MilAward Error]]'
    end
    local output = ""
    output = output .. " '''Found award with code''': " .. rec.Code .. "<br />"
    output = output .. "''Code'': " .. rec.Code .. "<br />"
    output = output .. "''Description'': " .. rec.Description .. "<br />"
    output = output .. "''Ribbon Image'': " .. rec.RibbonImage .. "<br />"
    output = output .. "''Post-Nominal'': " .. rec.PostNom .. "<br />"
    output = output .. "''Page Link'': " .. rec.PageLink .. "<br />"
    output = output .. "''Country'': " .. rec.Country .. "<br />"
    return output
end

local function _Ribbon(code, size)
	local rec = data[code]
	if string.len(size) < 1 then
		size = "x12px" -- Check that there is a value for size and if not, set the value
	end
	local ribbonimage = rec.RibbonImage or ""
	if string.len(ribbonimage) < 1 then -- If there is no ribbonimage defined for the record, then assign a default one.
		ribbonimage = "NOT-AVAILABLE-RIBBON.svg"
	end
    local output = "[[File:" .. ribbonimage .. "|".. size .. "|link=" .. rec.PageLink .. "|" .. rec.Description .. " ''" .. rec.PostNom .. " ''" .. "]]"
    return output
end

function p.Ribbon(frame)
	-- Function extracts the parameters from the frame (passed into the function)
	-- It checks that the first argument is not empty, and returns an error if so
	local templateArgs = getArgs(frame)
	local code = templateArgs[1] or 'None'
	local size = templateArgs[2] or "x12px"

    local namedcode = templateArgs["code"] -- Check for named argument "code" and overwrite the value in the local variable if it has a value
	if namedcode then
		code = namedcode
	end

	local namedsize = templateArgs["size"] -- Check for named argument "size" and overwrite the value in the local variable if it has a value
	if namedsize then
		size = namedsize
	end

	if string.match(code, "%*") then -- The code field has asterisks in it. Raise an error
		local output = '<span style="color:#d33"> Bad Code: <b>[' .. code .. ']</b>. Replace all * with x</span> [[Category:MilAward Error]]'
		return output
	end -- End if

	if not code or '' == code then
		return '<span style="color:#d33"> (Invalid Code: <b>' .. code .. '</b> )</span> [[Category:MilAward Error]]'
	end

	-- Code is case sensitive - do not uppercase it
	if not data[code] then
		return '<span style="color:#d33"> (Code not found: <b>' .. code .. '</b> )</span> [[Category:MilAward Error]]'
	end
	return _Ribbon (code, size)
end


local function _RibbonDesc(code, size, country, norib, nocat, org)
    -- This routine is where the data is structured for output
    local rec = data[code]
    local output = ''
    if norib ~= "yes" then -- They do NOT want the ribbon to display if this is yes
    	output = output .. _Ribbon(code, size) -- Start by getting the ribbon. Call the function designed to do that
    end
    output = output ..  " [[" .. rec.PageLink .. "|" .. rec.Description .. "]] "  -- add the pagelink and description
    if rec.Class and string.len(rec.Class) > 0 then -- Only add the Class if there is something in the field
    	output = output .. " (''" .. rec.Class .. "'') "
    end
    if string.len(rec.PostNom or "") > 0 then -- Only add the postnom if there is something in the field
    	 output = output .. " ('''" .. rec.PostNom .. "''') "
    end

    if string.len(rec.Note or "") > 0 then -- Only add the Note if there is something in the field
    	output = output .. mw.getCurrentFrame():expandTemplate{ title = 'Efn', args = {rec.Note} } -- Note: Page needs {{notelist}}
    end
    if string.len(country) > 0 then -- if a value for country has been specified
        if country:upper() ~= (rec.Country or ""):upper() then -- check that the country specified does NOT equal that on record
            output = output .. " (" .. rec.Country .. ") " -- add the country code to the end of the output
        end
    end
    if string.len(org) > 0 then -- if a value for org has been specified
        if org:upper() == "YES" then -- check that it is YES
            if string.len(rec.Org or "") > 0 then -- Check there is actually something in the org field
                output = output .. " (''" .. rec.Org .. "'') " -- add the Org code to the end of the output
            end
        end
    end

    local nocat_length = string.len(nocat)
    if nocat_length > 1 then -- If ANYTHING has been specified as a value for nocat, then it's true
        -- Caller opted out of recipient categorisation
    else
        -- Need to exclude adding the recipient category if it is not in mainspace.
        local current_title = mw.title.getCurrentTitle()
        if current_title.namespace == 0 then -- mainspace only
            local recipcat = rec.RecipCat or "" -- If there is a recipient category specified, then add it to the output
            local categories = {}
            if string.len(recipcat) > 0 then
                local categoryTitle = mw.title.new('Category:' .. mw.text.trim(recipcat))
                if categoryTitle.exists and not categoryTitle.isRedirect then
                    -- category exists and is not a redirect
                    categories[#categories+1] = " [[Category:" .. recipcat .. "]]"
                end
                -- else: category does not exist or is a redirect - not added
            end
            output = output .. table.concat(categories)
        end
    end

    return output
end

function p.RibbonDesc(frame)
	local templateArgs = getArgs(frame)
    local code = 'Unknown' -- initialise a local variable called code to something rational
    local size = 'x20px' -- initialise a local variable called size to something rational
	if templateArgs[1] then code = templateArgs[1] end -- check that it is not "nil" before assigning the value
    if templateArgs[2] then size = templateArgs[2] end -- Check that it is not "nil" before assigning the value

	local namedcode = templateArgs["code"] -- assign the local variable "namedcode" to the value of the argument called code
	if namedcode then -- if the assignment of value has worked ie there was actually a parameter called code with a value then
		code = namedcode -- assign the value found above to the variable "code" overwriting any other value it may have had
	end

	local namedsize = templateArgs["size"] -- exactly the same as for "code" above
	if namedsize then
		size = namedsize
	end

    local country = templateArgs["country"] or '' -- if the argument "country" has been passed, assign it to a local variable
    local norib = templateArgs["norib"] or ''

	if not code or '' == code then -- if there was no code assigned (field empty) then return an error of invalid code
		local output =  '<span style="color:#d33"> (Invalid Code: <b>' .. code .. '</b>)</span>'
        return output
	end
	if string.match(code, "%*") then -- The code field has asterisks in it. Raise an error
		local output = '<span style="color:#d33"> Bad Code: <b>[' .. code .. ']</b>. Replace all * with x</span> [[Category:MilAward Error]]'
		return output
	end -- End if

	-- Do not convert to uppercase. Codes are case sensitive
	if not data[code] then
		return '<span style="color:#d33"> (Code: <b>' .. code .. '</b> Not found)</span>'
	end

    local nocat = templateArgs["nocat"] or '' -- Assign local value for nocat parameter
    local org = templateArgs["org"] or '' -- Assign local value for org parameter

	return _RibbonDesc (code, size, country, norib, nocat, org)
end

function p.Stack(frame)
    local templateArgs = getArgs(frame)
    local size = templateArgs["size"] or "x12px"

    local RibbonList = {}
    for i = 1, 40 do -- 40 is the max number of params that will be examined.
        local rl = templateArgs[i] or ""
        if rl ~= "" then
            table.insert(RibbonList, rl)
        end
    end
    local row = {}
    for i, rl in ipairs(RibbonList) do
        if data[rl] then -- check whether this is found in the data
            table.insert(row, _Ribbon(rl, size))
        end
    end
    return table.concat(row, " ")
end

function p.DescList(frame)
    local templateArgs = getArgs(frame)
    local size = templateArgs["size"] or 'x20px'
    local namedcountry = templateArgs["country"] or 'yes'
    local output = '\n'

    for i = 1, 40 do -- 40 is the max number of positional params examined, matching p.Stack
        local value = templateArgs[i]
        if value and string.len(value) > 1 and data[value] then
            output = output .. "* " .. _RibbonDesc(value, size, namedcountry, '', '', '') .. "\n"
        end
    end
    return output
end

function p.PostNom(frame)
    local templateArgs = getArgs(frame)
    local size = templateArgs["size"] or '85%'
    local sep = templateArgs["sep"] or ', '
    if sep == "none" then
        sep = " "
    end
    local output = '<span class="noexcerpt nowraplinks" style="font-size:' .. size .. '; font-weight:normal;">'
    local any = false

    for i = 1, 40 do -- positional args only, so this both preserves order and skips size/sep automatically
        local value = templateArgs[i]
        if value and string.len(value) > 1 and data[value] then
            if string.len(data[value].PostNom or "") > 1 then
                output = output .. "[[" .. data[value].PageLink .. "|" ..  data[value].PostNom .. "]]" .. sep
                any = true
            end
        end
    end
    if any then
        local seplen = (string.len(sep) + 1) * -1 -- Take length of sep, add one to it and make it negative (* -1)
        output = output:sub(1, seplen) -- Remove the trailing separator
    end
    output = output .. '</span>'

    return output
end

-- Initial code by John Dovey (13 April 2023) [[User:BoonDock]], 
-- Updated with bug fixes 7 September 2026
-- Updated 10 September 2026: Stats no longer dumps GraphData | x=/| y= after the country wikitable; country rows sorted A–Z
-- - PostNom no longer corrupts its <span> tag when nothing matches 
-- - DescList/PostNom iterate args positionally (like Stack already did) so award order matches what the editor typed, and named params can't collide with codes
-- - PrintStats header is back on one line (was silently misaligning the table)
-- - _Display guards against unknown codes instead of throwing a script error
-- - Leading-comma bug in the GraphData/Stats CSV lines fixed, and the duplicated country-counting loop is now one shared countByCountry() helper
-- - _Ribbon/_RibbonDesc cache data[code] once instead of re-indexing repeatedly, and guard Country/PostNom/Note/Org/RibbonImage against missing fields (same nil-crash class as the Description sort bug)
-- - Mainspace check now uses current_title.namespace == 0 instead of the namespace-name-length heuristic
-- - Dead code removed: unreachable if not size check, stray commented-out lines, unused module-level GlobalTemplateArgs, redundant local wikiCode shadow
-- x -- 
return p