Module:Medals table country
Appearance
![]() | This module is rated as ready for general use. It has reached a mature form and is thought to be relatively bug-free and ready for use wherever appropriate. It is ready to mention on help pages and other Wikipedia resources as an option for new users to learn. To reduce server load and bad output, it should be improved by sandbox testing rather than repeated trial-and-error editing. |
implements:
Usage
local p = {}
-- Load the flagicon data module used to map years to host country flags
local flagicon_data = require("Module:Medals table country/data")
function p.render(frame)
-- Get arguments passed from the parent template
local args = frame:getParent().args
local country = args["country"] or "Country"
local maxRows = 50
-- Control flags
local show_dual_ranks = args["show_dual_ranks"] == "yes"
local show_games_flag = args["show_games_flag"] == "yes"
-- Determine if the table is for Summer or Winter Olympics
local season = (args["season"] or "summer"):lower()
local is_winter = (season == "winter")
local season_name = is_winter and "Winter" or "Summer"
-- Dynamically require ranking data based on season
local ranking_data
if is_winter then
ranking_data = require("Module:Medals table country/data/Winter Olympics ranking")
else
ranking_data = require("Module:Medals table country/data/Summer Olympics ranking")
end
-- Helper to find rank by country
local function find_rank(list, name)
for _, entry in ipairs(list) do
if entry.country == name then
return entry.rank
end
end
return nil
end
-- Fetch or derive total rank values
local alltime_gold_rank_raw = args["alltime_gold_rank"]
if not alltime_gold_rank_raw or alltime_gold_rank_raw == "" then
local gold_rank = find_rank(ranking_data.gold_ranking, country)
alltime_gold_rank_raw = gold_rank and tostring(gold_rank) or ""
end
local alltime_medal_rank_raw = args["alltime_medal_rank"]
if not alltime_medal_rank_raw or alltime_medal_rank_raw == "" then
local alltime_medal_rank = find_rank(ranking_data.total_ranking, country)
alltime_medal_rank_raw = alltime_medal_rank and tostring(alltime_medal_rank) or ""
end
-------------------------------------------------------------------
-- Step 1: Collect raw input rows from arguments into a raw_rows list
-------------------------------------------------------------------
local raw_rows = {}
-- Helper: extract leading numeric value for calculations while preserving full text for display
local function extract_number_and_text(val)
val = tostring(val or "")
local num = val:match("^%s*(%d+)")
return tonumber(num) or 0, val
end
for i = 1, maxRows do
local games = args["row"..i.."_games"]
if games and games ~= "" then
if games == "note" then
local participation_text = args["row"..i.."_participation"] or ""
table.insert(raw_rows, {
is_note = true,
note_text = participation_text,
})
else
local athletes_val = args["row"..i.."_athletes"]
local participation = args["row"..i.."_participation"]
local is_host = args["row"..i.."_host"] == "yes"
-- Special override: if athletes = "no", participation forced to "did not participate"
if athletes_val == "no" then
participation = "''did not participate''"
end
-- Parse medals
local gold_num, gold_text = extract_number_and_text(args["row"..i.."_gold"])
local silver_num, silver_text = extract_number_and_text(args["row"..i.."_silver"])
local bronze_num, bronze_text = extract_number_and_text(args["row"..i.."_bronze"])
local rank_raw = args["row"..i.."_rank"] or ""
local medal_rank_raw = args["row"..i.."_medal_rank"] or ""
-- Add row to list
table.insert(raw_rows, {
games = games,
athletes_val = athletes_val,
participation = participation,
gold = gold_num,
silver = silver_num,
bronze = bronze_num,
gold_display = gold_text,
silver_display = silver_text,
bronze_display = bronze_text,
rank_raw = rank_raw,
medal_rank_raw = medal_rank_raw,
is_host = is_host,
})
end
end
end
-------------------------------------------------------------------
-- Step 2: Process rows and merge participation rows with rowspan
-------------------------------------------------------------------
local rows = {}
local i = 1
while i <= #raw_rows do
local row = raw_rows[i]
if row.is_note then
table.insert(rows, row)
i = i + 1
-- Merge rows that have identical participation notes
elseif row.participation and row.participation ~= "" then
local rowspan = 1
local is_host_in_merged = row.is_host
for j = i + 1, #raw_rows do
if raw_rows[j].participation == row.participation then
rowspan = rowspan + 1
if raw_rows[j].is_host then
is_host_in_merged = true
end
else
break
end
end
local merged_games = {}
for k = i, i + rowspan - 1 do
table.insert(merged_games, raw_rows[k].games)
end
table.insert(rows, {
participation = row.participation,
rowspan = rowspan,
games_list = merged_games,
merged = true,
is_host = is_host_in_merged,
})
i = i + rowspan
else
-- Regular row: build structured row with medals and rankings
local year = row.games and row.games:match("(%d%d%d%d)") or ""
local athletes_num = tonumber(row.athletes_val) or 0
local athletes_cell = string.format("[[%s at the %s %s Olympics|%d]]", country, year, season_name, athletes_num)
-- Medal totals
local total = row.gold + row.silver + row.bronze
-- Helper: build medal table rank links
local function make_rank_link(rank_raw)
local rank_num = tonumber(rank_raw)
local medal_table_title = string.format("%s %s Olympics medal table", year, season_name)
if rank_num then
return string.format("[[%s|%d]]", medal_table_title, rank_num), rank_num
elseif rank_raw == "" then
return string.format("[[%s|–]]", medal_table_title), nil
elseif rank_raw ~= "" then
return rank_raw, nil
else
return "", nil
end
end
-- Rank links
local gold_rank_link, gold_rank_num = make_rank_link(row.rank_raw)
local medal_rank_link, medal_rank_num = make_rank_link(row.medal_rank_raw)
-- Background color for top 3 ranks
local function rank_color(rank)
if rank == 1 then return "#F7F6A8"
elseif rank == 2 then return "#dce5e5"
elseif rank == 3 then return "#ffdab9"
else return ""
end
end
local bgcolor_gold_ranking = rank_color(gold_rank_num)
local bgcolor_medal_ranking = rank_color(medal_rank_num)
-- Add full row to output list
table.insert(rows, {
games = row.games,
athletes = athletes_cell,
athletes_num = athletes_num,
gold = row.gold,
silver = row.silver,
bronze = row.bronze,
gold_display = row.gold_display,
silver_display = row.silver_display,
bronze_display = row.bronze_display,
total = total,
gold_rank = gold_rank_link,
total_rank = medal_rank_link,
bgcolor_gold_ranking = bgcolor_gold_ranking,
bgcolor_medal_ranking = bgcolor_medal_ranking,
is_host = row.is_host,
merged = false,
})
i = i + 1
end
end
-------------------------------------------------------------------
-- Step 3: Compute max athletes, medals and totals
-------------------------------------------------------------------
local max_athletes, max_gold, max_silver, max_bronze, max_total = 0, 0, 0, 0, 0
local total_gold, total_silver, total_bronze = 0, 0, 0
for _, row in ipairs(rows) do
if not row.merged and row.gold and row.silver and row.bronze then
total_gold = total_gold + row.gold
total_silver = total_silver + row.silver
total_bronze = total_bronze + row.bronze
if row.athletes_num and row.athletes_num > max_athletes then max_athletes = row.athletes_num end
if row.gold > max_gold then max_gold = row.gold end
if row.silver > max_silver then max_silver = row.silver end
if row.bronze > max_bronze then max_bronze = row.bronze end
if row.total > max_total then max_total = row.total end
end
end
-- Final totals and all-time rank links (already set above from args or module)
local total_medals = total_gold + total_silver + total_bronze
local alltime_gold_rank = alltime_gold_rank_raw ~= "" and
string.format("[[All-time Olympic Games medal table#Complete ranked medals (excluding precursors)|%s]]", alltime_gold_rank_raw) or ""
local alltime_medal_rank = alltime_medal_rank_raw ~= "" and
string.format("[[All-time Olympic Games medal table#Complete ranked medals (excluding precursors)|%s]]", alltime_medal_rank_raw) or ""
local alltime_gold_rank_link = alltime_gold_rank_raw ~= "" and
string.format("[[All-time Olympic Games medal table#Complete ranked medals (excluding precursors)|%s]]", alltime_gold_rank_raw) or ""
local alltime_medal_rank_link = alltime_medal_rank_raw ~= "" and
string.format("[[All-time Olympic Games medal table#Complete ranked medals (excluding precursors)|%s]]", alltime_medal_rank_raw) or ""
-------------------------------------------------------------------
-- Step 4: Build the wikitable header
-------------------------------------------------------------------
local sticky_header = frame:expandTemplate{ title = "sticky-header" }
local wikitext = '{| class="wikitable sticky-header" style="text-align:center; font-size:90%;"\n'
wikitext = wikitext .. "|-\n! Games !! Athletes"
wikitext = wikitext .. ' !! style="background:gold; width:3.7em; font-weight:bold;"| Gold'
wikitext = wikitext .. ' !! style="background:silver; width:3em; font-weight:bold;"| Silver'
wikitext = wikitext .. ' !! style="background:#c96; width:3.7em; font-weight:bold;"| Bronze'
wikitext = wikitext .. ' !! style="width:3.7em; font-weight:bold;"| Total'
-- Column headers for rank (1 or 2 columns depending on config)
if show_dual_ranks then
wikitext = wikitext .. ' !! style="width:4em; font-weight:bold;"| [[Olympic medal table|<small>{{abbr|Gold Medals|Ranking Gold Medals Table}}</small>]]'
wikitext = wikitext .. ' !! style="width:4em; font-weight:bold;"| [[Olympic medal table|<small>{{abbr|Total Medals|Ranking Total Medals Table}}</small>]]\n'
else
wikitext = wikitext .. ' !! style="width:3em; font-weight:bold;"| Rank\n'
end
-- Helper: bold value if it’s the max
local function bold_if_max(val, max)
return val > 0 and val == max and ("'''" .. val .. "'''") or tostring(val)
end
-- Helper: process flag icon with optional flagicon
local function format_game_with_flag(game)
local expanded_game = frame:preprocess(game)
local year = expanded_game:match("(%d%d%d%d)")
if show_games_flag and year then
local flag_name = flagicon_data[season] and flagicon_data[season][year]
if flag_name then
return string.format("{{flagicon|%s}} %s", flag_name, expanded_game)
end
end
return expanded_game
end
-------------------------------------------------------------------
-- Step 5: Render each table row
-------------------------------------------------------------------
for _, row in ipairs(rows) do
if row.is_note then
local colspan_val = show_dual_ranks and 8 or 7
wikitext = wikitext .. string.format(
"|-\n| colspan=%d style=\"text-align:center;\" | %s\n",
colspan_val,
row.note_text
)
elseif row.merged then
-- Participation row with rowspan
local colspan_val = show_dual_ranks and 7 or 6
wikitext = wikitext .. string.format(
"|-\n| align=left %s | %s || colspan=%d rowspan=%d %s | %s\n",
row.is_host and 'style="border-top:3px solid purple; border-left:3px solid purple; border-bottom:3px solid purple;"' or "",
format_game_with_flag(row.games_list[1]),
colspan_val,
row.rowspan,
row.is_host and 'style="border-top:3px solid purple; border-bottom:3px solid purple; border-right:3px solid purple;"' or "",
row.participation
)
for i = 2, row.rowspan do
wikitext = wikitext .. string.format(
"|-\n| align=left %s | %s\n",
row.is_host and 'style="border-top:3px solid purple; border-bottom:3px solid purple;"' or "",
format_game_with_flag(row.games_list[i])
)
end
else
-- Regular medal row
local line = "|-\n"
local game_display = format_game_with_flag(row.games)
if row.is_host then
local middle_border = 'border-top: 3px solid purple; border-bottom: 3px solid purple;'
local right_border = middle_border .. ' border-right: 3px solid purple;'
line = line .. string.format('| align=left style="border-left: 3px solid purple; %s" | %s', middle_border, game_display)
local athletes_display = (row.athletes_num == max_athletes) and ("'''" .. row.athletes .. "'''") or row.athletes
line = line .. string.format(' || style="%s" | %s', middle_border, athletes_display)
line = line .. string.format(' || style="%s" | %s', middle_border, bold_if_max(row.gold, max_gold))
line = line .. string.format(' || style="%s" | %s', middle_border, bold_if_max(row.silver, max_silver))
line = line .. string.format(' || style="%s" | %s', middle_border, bold_if_max(row.bronze, max_bronze))
line = line .. string.format(' || style="%s" | %s', middle_border, bold_if_max(row.total, max_total))
if show_dual_ranks then
line = line .. string.format(' || style="%s%s" | %s', row.bgcolor_gold_ranking ~= "" and 'background-color:' .. row.bgcolor_gold_ranking .. '; ' or "", middle_border, row.gold_rank)
line = line .. string.format(' || style="%s%s" | %s', row.bgcolor_medal_ranking ~= "" and 'background-color:' .. row.bgcolor_medal_ranking .. '; ' or "", right_border, row.total_rank)
else
line = line .. string.format(' || style="%s%s" | %s', row.bgcolor_gold_ranking ~= "" and 'background-color:' .. row.bgcolor_gold_ranking .. '; ' or "", right_border, row.gold_rank)
end
else
-- Regular non-hosted row
line = line .. "| align=left | " .. game_display
line = line .. " || " .. row.athletes
line = line .. " || " .. (row.gold == max_gold and ("'''" .. row.gold_display .. "'''") or row.gold_display)
line = line .. " || " .. (row.silver == max_silver and ("'''" .. row.silver_display .. "'''") or row.silver_display)
line = line .. " || " .. (row.bronze == max_bronze and ("'''" .. row.bronze_display .. "'''") or row.bronze_display)
line = line .. " || " .. bold_if_max(row.total, max_total)
if show_dual_ranks then
line = line .. (row.bgcolor_gold_ranking ~= "" and (' || style="background-color:' .. row.bgcolor_gold_ranking .. '" | ' .. row.gold_rank) or (" || " .. row.gold_rank))
line = line .. (row.bgcolor_medal_ranking ~= "" and (' || style="background-color:' .. row.bgcolor_medal_ranking .. '" | ' .. row.total_rank) or (" || " .. row.total_rank))
else
line = line .. (row.bgcolor_gold_ranking ~= "" and (' || style="background-color:' .. row.bgcolor_gold_ranking .. '" | ' .. row.gold_rank) or (" || " .. row.gold_rank))
end
end
wikitext = wikitext .. line .. "\n"
end
end
-------------------------------------------------------------------
-- Step 6: Add total row at bottom of table
-------------------------------------------------------------------
wikitext = wikitext .. "|-\n! colspan=2 | Total"
wikitext = wikitext .. string.format(" !! %d !! %d !! %d !! %d", total_gold, total_silver, total_bronze, total_medals)
if show_dual_ranks then
wikitext = wikitext .. " !! " .. alltime_gold_rank_link .. " !! " .. alltime_medal_rank_link .. "\n"
else
wikitext = wikitext .. " !! " .. alltime_gold_rank_link .. "\n"
end
wikitext = wikitext .. "|}"
-------------------------------------------------------------------
-- Final output
-------------------------------------------------------------------
local full_wikitext = sticky_header .. "\n" .. wikitext
return frame:preprocess(full_wikitext)
end
return p