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.

// 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: a400c431cb76cf5a

Jump to content

Module:MasterGunner

From Wikipedia, the free encyclopedia

-- South African Master Gunner module
-- Data: [[Module:MasterGunner/data]]
-- Template: [[Template:MasterGunner]]
-- Initial code by John Dovey (13 April 2023) [[User:BoonDock]]

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

local LIST_PAGE = 'Master Gunners of the South African Army'
local BADGE_FILE = 'SANDF Arty Master Gunner badge embossed.png'
local ERROR_CAT = '' -- avoid redlinked tracking cats; errors use class="error"

local function trim(s)
	if s == nil then
		return ''
	end
	return mw.text.trim(tostring(s))
end

local function isUnknown(record)
	if not record then
		return true
	end
	local surname = trim(record.Surname)
	return surname == '' or surname == 'Unknown'
end

-- Sorted list of data keys by numeric Code
local function sortedKeys(includeUnknown)
	local keys = {}
	for key, record in pairs(data) do
		if includeUnknown or not isUnknown(record) then
			keys[#keys + 1] = key
		end
	end
	local function sortKey(code)
		-- Grandfathered Larkhill awards use 1000+ codes; list them first chronologically
		if code and code >= 1000 then
			return code - 10000
		end
		return code or 0
	end
	table.sort(keys, function(a, b)
		local ca = sortKey(data[a].Code)
		local cb = sortKey(data[b].Code)
		if ca == cb then
			return a < b
		end
		return ca < cb
	end)
	return keys
end

local function adjacentKey(codeNum, direction)
	local keys = sortedKeys(false)
	local idx
	for i, key in ipairs(keys) do
		if data[key].Code == codeNum then
			idx = i
			break
		end
	end
	if not idx then
		return nil
	end
	return keys[idx + direction]
end

function p.GetGunner(gunnercode)
	local record = data[gunnercode]
	if isUnknown(record) then
		return "''Unknown''"
	end
	local rank = trim(record.Rank)
	local name = mw.text.trim(trim(record.FirstName) .. ' ' .. trim(record.Surname))
	local wiki = trim(record.WikiPage)
	local nameHtml
	if wiki == '' then
		nameHtml = name
	else
		nameHtml = string.format('[[%s|%s]]', wiki, name)
	end
	if rank ~= '' then
		return rank .. '<br />' .. nameHtml
	end
	return nameHtml
end

function p.Gunner(frame)
	local args = getArgs(frame)
	local gunnercode = args.code
	if not gunnercode then
		return '<strong class="error">Error: No code specified</strong>' .. ERROR_CAT
	end
	local record = data[gunnercode]
	if not record then
		return string.format('<strong class="error">Error: code %s not found</strong>', gunnercode) .. ERROR_CAT
	end
	if isUnknown(record) then
		return string.format('%s: number %s (unknown / vacant)', gunnercode, tostring(record.Code))
	end
	return string.format(
		'%s: #%s — %s %s (%s)',
		gunnercode,
		tostring(record.Code),
		trim(record.FirstName),
		trim(record.Surname),
		trim(record.Year)
	)
end

function p.GunnerBox(frame)
	local args = getArgs(frame)
	local gunnercode = args.code
	local imagesize = args.imagesize or '150px'

	if not gunnercode then
		return '<strong class="error">Error: No <code>code</code> specified. Use the Gunner number preceded by an A, e.g. <code>code=A48</code>.</strong>' .. ERROR_CAT
	end

	local record = data[gunnercode]
	if not record then
		return string.format('<strong class="error">Error: code %s not found</strong>', gunnercode) .. ERROR_CAT
	end

	local float = args.float or 'none'
	local floatClass = ''
	if float == 'left' then
		floatClass = 'floatleft'
	elseif float == 'right' then
		floatClass = 'floatright'
	end

	local rows = {}
	local function add(line)
		rows[#rows + 1] = line
	end

	add('{| class="wikitable ' .. floatClass .. '" style="text-align:center; width:15em; font-size:90%"')
	add('|-')
	add('! colspan="2" style="background:#8B0000; color:white;" | Master Gunner #' .. tostring(record.Code))
	add('|-')
	add(string.format(
		'| colspan="2" | [[File:%s|border|%s|link=List of badges of the South African Army#Proficiency:_Master_Gunner|Master Gunner badge]]',
		BADGE_FILE,
		imagesize
	))
	add('|-')

	local nameCell = p.GetGunner(gunnercode)
	local post = trim(record.Post)
	local note = trim(record.Note)
	if post ~= '' then
		nameCell = nameCell .. frame:expandTemplate{ title = 'efn', args = { 'Post occupied when award was made: ' .. post } }
	end
	if note ~= '' then
		nameCell = nameCell .. frame:expandTemplate{ title = 'efn', args = { note } }
	end
	add('| colspan="2" | ' .. nameCell)
	add('|-')
	add(string.format('| colspan="2" | [[%s|Year]]: \'\'\'%s\'\'\'', LIST_PAGE, trim(record.Year)))

	local prevKey = adjacentKey(record.Code, -1)
	local nextKey = adjacentKey(record.Code, 1)
	add('|-')
	if prevKey then
		add(string.format('| style="text-align:left; font-size:85%%" | ←&nbsp;#%s<br />%s', tostring(data[prevKey].Code), p.GetGunner(prevKey)))
	else
		add('| style="text-align:left; font-size:85%" | ')
	end
	if nextKey then
		add(string.format('| style="text-align:right; font-size:85%%" | #%s&nbsp;→<br />%s', tostring(data[nextKey].Code), p.GetGunner(nextKey)))
	else
		add('| style="text-align:right; font-size:85%" | ')
	end
	add('|}')

	return table.concat(rows, '\n')
end

function p.GunnerTable(frame)
	local args = getArgs(frame)
	local showUnknown = args.showunknown == 'yes' or args.showUnknown == 'yes'

	local rows = {}
	local function add(line)
		rows[#rows + 1] = line
	end

	add('{| class="wikitable sortable"')
	add('|+ List of Master Gunners')
	add('|-')
	add('! Data key !! Number !! Rank !! Surname !! First names !! Post !! Year !! Notes')

	for _, key in ipairs(sortedKeys(showUnknown)) do
		local record = data[key]
		local unknown = isUnknown(record)
		if unknown then
			add('|- style="background:#f8f8f8; color:#555"')
		else
			add('|-')
		end
		add('| <code>' .. key .. '</code>')
		add('| data-sort-value="' .. tostring(record.Code or 0) .. '" | ' .. tostring(record.Code or ''))
		add('| ' .. trim(record.Rank))
		local surname = trim(record.Surname)
		local wiki = trim(record.WikiPage)
		if wiki ~= '' and not unknown then
			add(string.format('| [[%s|%s]]', wiki, surname))
		else
			add('| ' .. surname)
		end
		add('| ' .. trim(record.FirstName))
		local post = trim(record.Post)
		if post ~= '' then
			post = mw.ustring.gsub(post, ',', '<br />')
		end
		add('| ' .. post)
		add('| ' .. trim(record.Year))
		local note = trim(record.Note)
		if note ~= '' then
			add('| <small>' .. note .. '</small>')
		else
			add('|')
		end
	end
	add('|}')
	return table.concat(rows, '\n')
end

return p