-- Module to build tables for aggregated match results in sports-- See documentation for details
local p =
-- Function to parse and expand a template with given parameterslocal function expandTemplate(frame, templateName, params) return frame:expandTemplateend
-- Function to check the existence of template passed via |flag=local function templateExists(templateName) local title = mw.title.new('Template:' .. templateName) return title and title.existsend
-- Function to process country codes and variants OR youth team flag templates and age level, dividing parameters by the "+" signlocal function processIcon(iconString) if not iconString or iconString:match("^%s*$") then return nil, nil -- Return nil for both iconCode and variant if the input is empty or only whitespace elseif iconString:find('+') then local parts = mw.text.split(iconString, '+', true) local iconCode = parts[1] local variant = parts[2] return iconCode, variant else return iconString, nil -- Return the input string as iconCode if no "+" is present endend
-- Function to determine the correct ordinal suffix for a given number for the headinglocal function ordinal(n) local last_digit = n % 10 local last_two_digits = n % 100 if last_digit
2 and last_two_digits ~= 12 then return n .. 'nd' elseif last_digit
-- Function to clean and process the aggregate score for comparisonlocal function cleanScore(score) -- Return an empty string if score is nil or empty to avoid errors if not score or score:match("^%s*$") then return end
-- Function to replace wiki links with their display text or link text local function replaceLink(match) local pipePos = match:find("|") if pipePos then return match:sub(pipePos + 1, -3) -- Return text after the '|' else return match:sub(3, -3) -- Return text without the brackets end end
-- Replace wiki links score = score:gsub("%[%[.-%]%]", replaceLink)
-- Remove MediaWiki's unique placeholder sequences for references score = score:gsub('"`UNIQ.-QINU`"', )
-- Remove superscript tags and their contents score = score:gsub('
-- Convert dashes to a standard format score = score:gsub('[–—―‒−]', '-')
-- Strip all characters except numbers, dashes and parentheses return score:gsub('[^0-9%-]+', )end
-- Function to determine the winner based on scores within parentheses (first) or regular format (second)local function determineWinner(cleanAggregate, matchType, team1, team2, boldWinner, colorWinner, aggregate, isFBRStyle, legs, leg1Score, leg2Score, disableAwayGoals) local team1Winner, team2Winner = false, false local score1, score2 local manualBold = false local manualColor = false local isDraw = false
-- Handling for manual bolding if team1 and type(team1)
'string' then manualBold2 = team2:find("") and not (team2:gsub("", ""):match("^%s*$")) team2 = team2:gsub("", "") end
if manualBold1 then team1Winner = true manualBold = true end if manualBold2 then team2Winner = true manualBold = true end
-- Handling for manual coloring of team or aggregate cells if team1 and type(team1)
'string' then manualColor2 = team2:find("") and not (team2:gsub("", ""):match("^%s*$")) team2 = team2:gsub("", "") end if aggregate then if aggregate:find("") then aggregate = aggregate:gsub("", "") aggregate = "" .. aggregate .. "" end manualColorDraw = aggregate:find("") and not (aggregate:gsub("", ""):match("^%s*$")) aggregate = aggregate:gsub("", "") end
if manualColor1 then if not team1Winner then team1Winner = true end manualColor = true end if manualColor2 then if not team2Winner then team2Winner = true end manualColor = true end if manualColorDraw then isDraw = true manualColor = true end
-- Regular winner determination logic if manual bolding or coloring is not conclusive if not team1Winner and not team2Winner and not isDraw and (boldWinner or colorWinner or isFBRStyle) then local parenthetical = cleanAggregate:match('%((%d+%-+%d+)%)') local outsideParenthetical = cleanAggregate:match('^(%d+%-+%d+)') if parenthetical then -- Prioritize checking score inside parenthetical score1, score2 = parenthetical:match('(%d+)%-+(%d+)') elseif outsideParenthetical then score1, score2 = outsideParenthetical:match('(%d+)%-+(%d+)') end
if score1 and score2 then score1 = tonumber(score1) score2 = tonumber(score2) if score1 > score2 then team1Winner = true elseif score1 < score2 then team2Winner = true elseif score1
2 and not disableAwayGoals then -- Apply away goals rule local cleanLeg1 = cleanScore(leg1Score):gsub('[]', ) local cleanLeg2 = cleanScore(leg2Score):gsub('[]', ) local _, team2AwayGoals = cleanLeg1:match('(%d+)%-+(%d+)') local team1AwayGoals = cleanLeg2:match('(%d+)%-+(%d+)')
if team1AwayGoals and team2AwayGoals then team1AwayGoals, team2AwayGoals = tonumber(team1AwayGoals), tonumber(team2AwayGoals) if team1AwayGoals > team2AwayGoals then team1Winner = true elseif team2AwayGoals > team1AwayGoals then team2Winner = true end end end if (colorWinner or isFBRStyle) and legs
return team1, team2, team1Winner, team2Winner, manualBold, manualColor, isDraw, aggregateend
-- Function to check if any parameter in a given row is non-nil and non-emptylocal function anyParameterPresent(startIndex, step, args) for index = startIndex, startIndex + step - 1 do if args[index] and args[index]:match("^%s*(.-)%s*$") ~= "" then return true end end return falseend
-- Function to add a legend to below the table when |matches_style=FBRlocal function createFBRLegend return mw.html.create('div') :css('font-size', '90%') :css('margin-bottom', '0.5em') :wikitext("Legend: Blue = home team win; Yellow = draw; Red = away team win.")end
-- Main function that processes input and returns the wikitablefunction p.main(frame) local args = require'Module:Arguments'.getArgs(frame,)
-- Check for section transclusion local tsection = frame:getParent.args['transcludesection'] or frame:getParent.args['section'] or local bsection = args['section'] or if tsection ~= and bsection ~= then if tsection ~= bsection then return -- Return an empty string if sections don't match end end
local root = mw.html.create local matchType = (args.type
'MNT') and 'NT' or (args.type or 'club') -- Set default match type to 'club' local isWNT = args.type
'y' or args.fill_blanks
'1' or args.fill_blanks
-- Process the font size parameter local size if args.font_size then -- Remove trailing '%' if present and convert to number size = tonumber((args.font_size:gsub('%s*%%$', ))) if size then size = math.max(size, 85) -- Ensure size is at least 85 end end
-- Process flag parameter to determine flag template and variant if args.flag and args.flag:find('+') then flagTemplate, flagParam1 = processIcon(args.flag) -- Process flag icons with variants else if args.flag then flagTemplate = args.flag elseif isWNT then flagTemplate = 'fbw' -- Default to for WNT matches elseif matchType
if args.flag and (flagTemplate
'no' or flagTemplate
'false' or flagTemplate
'none' or flagTemplate
'NT' then flagTemplate = isWNT and 'fbw' or 'fb' -- Set flagTemplate to "fbw"/"fb", as disabling flags is not allowed for NT flagParam1 = false end end
-- Check if flagTemplate exists and adjust if necessary if matchType
local legs = (args.legs
'n' or args.legs
'false' or args.legs
'none' or args.legs
'one') and 0 or tonumber(args.legs) or 2 if legs and legs < 0 then legs = 2 end local teamWidth = (tonumber(args['team_width']) and args['team_width'] .. 'px') or '250px' local scoreWidth = (tonumber(args['score_width']) and args['score_width'] .. 'px') or '80px' local boldWinner = not (args.bold_winner
'no' or args.bold_winner
'false' or args.bold_winner
'y' or args.color_winner
'1' or args.color_winner
"FBR" local isHA = args.h_a
'yes' or args.h_a
'true' local disableAwayGoals = args.away_goals
'no' or args.away_goals
'false' or args.away_goals
local tableClass = 'wikitable' local tableStyle = 'text-align: center;' if args.collapsed and (args.collapsed
'yes' or args.collapsed
'true') then tableClass = 'wikitable mw-collapsible mw-collapsed' tableStyle = 'width: 100%; text-align: center;' end if args.nowrap and (args.nowrap
'yes' or args.nowrap
'true') then tableStyle = tableStyle .. ' white-space: nowrap;' end if size then tableStyle = tableStyle .. ' font-size: ' .. size .. '%;' end
-- Create the table element local table = root:tag('table') :addClass(tableClass) :cssText(tableStyle) if args.id then table:attr('id', args.id) -- Optional id parameter to allow anchor to table end
-- Add FBR legend if isFBRStyle is true if isFBRStyle and legs
-- Add a caption to table if the "caption" parameter is passed if args.caption then table:tag('caption'):wikitext(args.caption) end
-- Count number of columns local colCount = 3 + legs
-- Add a title row above column headings if the "title" parameter is passed if args.title then local titleRow = table:tag('tr') titleRow:tag('th') :attr('colspan', colCount) :attr('scope', 'colgroup') :css('text-align', 'center') :wikitext(args.title) end
-- Create the header row with team and score columns local header = table:tag('tr') local defaultTeam1 = isHA and 'Home' or 'Team 1' local defaultTeam2 = isHA and 'Away' or 'Team 2' header:tag('th') :attr('scope', 'col') :css('text-align', 'right') :css('width', teamWidth) :wikitext(args['team1'] or defaultTeam1) header:tag('th') :attr('scope', 'col') :css('width', scoreWidth) :wikitext(args['aggregate'] or legs
-- Add columns for each leg if applicable if legs > 0 then for leg = 1, legs do local legHeading
-- Check if "legN" parameter is present if args['leg' .. leg] then legHeading = args['leg' .. leg] else -- Check if "leg_prefix" parameter is present if args.leg_prefix then -- Check if leg_prefix is y, yes, 1, or true if args.leg_prefix
'yes' or args.leg_prefix
'true' then legHeading = 'Leg ' .. leg else legHeading = args.leg_prefix .. ' ' .. leg end -- Check if "leg_suffix" parameter is present and does not equal y, yes, 1, or true elseif args.leg_suffix and args.leg_suffix ~= 'y' and args.leg_suffix ~= 'yes' and args.leg_suffix ~= '1' and args.leg_suffix ~= 'true' then legHeading = ordinal(leg) .. ' ' .. args.leg_suffix else legHeading = ordinal(leg) .. ' leg' end end
header:tag('th') :attr('scope', 'col') :css('width', scoreWidth) :wikitext(legHeading) end end
local step = (matchType
local row = table:tag('tr') local team1, aggregateScore, team2 local team1Winner, team2Winner, manualBold, manualColor, isDraw = false, false, false, false, false local leg1Score, leg2Score = false, false local team1Asterick, team2Asterick = false, false
-- Process rows for national team matches if matchType
-- Clean the aggregate score local cleanAggregate = cleanScore(aggregateScore) -- Name the 1st/2nd leg scores for two-legged ties for possibly determining the winner on away goals if legs
2 then if noFlagIcons then leg1Score = args[i+3] leg2Score = args[i+4] else leg1Score = args[i+5] leg2Score = args[i+6] end end -- Determine the winning team on aggregate team1, team2, team1Winner, team2Winner, manualBold, manualColor, isDraw, aggregateScore = determineWinner(cleanAggregate, matchType, team1, team2, boldWinner, colorWinner, aggregateScore, isFBRStyle, legs, leg1Score, leg2Score, disableAwayGoals) -- Add background-color for winning team if set by user local team1Style = team1Winner and ((colorWinner or manualColor) and 'background-color: #CCFFCC;' or ) .. 'text-align: right;' or 'text-align: right;' local team2Style = team2Winner and ((colorWinner or manualColor) and 'background-color: #CCFFCC;' or ) .. 'text-align: left;' or 'text-align: left;' -- Generate text, and flags (if not disabled), to display for each team local team1Text = noFlagIcons and (team1 or ) or ((team1Icon ~= "" and team1Icon ~= nil) and ((team1 or ) .. ' ' .. expandTemplate(frame, flagTemplate,)) or (team1 or )) local team2Text = noFlagIcons and (team2 or ) or ((team2Icon ~= "" and team2Icon ~= nil) and (expandTemplate(frame, flagTemplate,) .. ' ' .. (team2 or )) or (team2 or )) -- When set by user, adds blank flags when country code parameter is left blank if fillBlanks then if not noFlagIcons then if not team1Icon or team1Icon
-- Add columns for each leg score if applicable if legs > 0 then for leg = 1, legs do local legIndex = i + 4 + leg + (matchType
i = i + step end
return tostring(root)end
return p