Module:Sports series: Difference between revisions

Content deleted Content added
improve matching logic
improve link rewriting
 
(14 intermediate revisions by 3 users not shown)
Line 78:
 
-- Function to determine the winner based on scores within parentheses (first) or regular format (second)
local function determineWinner(cleanAggregate, team1, team2, boldWinner, colorWinner, aggregate, isFBRStyle, legs, leg1Score, leg2Score, disableAwayGoals, skipAutoWinner, aggFormat)
local team1Winner, team2Winner = false, false
local score1, score2
Line 114:
end
if aggregate then
if aggregate:find("aggFormat == 'bold' or aggFormat == 'both'") then
aggregate = aggregate:gsub("'''<b>", .. aggregate .. "</b>")
aggregate = "<strong>" .. aggregate .. "</strong>"
end
manualColorDraw = aggregate:find("aggFormat == 'italic'") andor notaggFormat == (aggregate:gsub("'both'", ""):match("^%s*$"))
aggregate = aggregate:gsub("''", "")
end
 
Line 140 ⟶ 138:
 
-- Regular winner determination logic if manual bolding or coloring is not conclusive
if not team1Winner and not team2Winner and not isDraw and not skipAutoWinner and (boldWinner or colorWinner or isFBRStyle) then
local parenthetical = cleanAggregate:match('%((%d+%-+%d+)%)')
local outsideParenthetical = cleanAggregate:match('^(%d+%-+%d+)')
Line 152 ⟶ 150:
score1 = tonumber(score1)
score2 = tonumber(score2)
 
if score1 > score2 then
team1Winner = true
Line 166 ⟶ 164:
if team1AwayGoals and team2AwayGoals then
team1AwayGoals, team2AwayGoals = tonumber(team1AwayGoals), tonumber(team2AwayGoals)
 
if team1AwayGoals > team2AwayGoals then
team1Winner = true
Line 174 ⟶ 172:
end
end
 
if (colorWinner or isFBRStyle) and legs == 0 then
isDraw = not team1Winner and not team2Winner
Line 182 ⟶ 180:
 
return team1, team2, team1Winner, team2Winner, manualBold, manualColor, isDraw, aggregate
end
 
-- Function to process score bold/italic formatting
function processScore(s)
if not s or s == "" then
return "", false
end
 
local scoreFormat = false
 
-- Check for 5+ apostrophes (both bold and italic)
if s:match("'''''+") then
scoreFormat = "both"
s = s:gsub("''+", "")
return s, scoreFormat
end
 
-- Check for 3+ apostrophes (bold)
if s:match("'''+") then
scoreFormat = "bold"
s = s:gsub("''+", "")
return s, scoreFormat
end
 
-- Check for 2 apostrophes (italic)
if s:match("''") then
scoreFormat = "italic"
s = s:gsub("''+", "")
return s, scoreFormat
end
 
-- If no matches found, return original string and false
return s, scoreFormat
end
 
-- Function to check if any parameter in a given row is non-nil and non-empty
local function anyParameterPresent(startIndex, step, args)
-- Check regular parameters
for index = startIndex, startIndex + step - 1 do
if args[index] and args[index]:match("^%s*(.-)%s*$") ~= "" then
Line 191 ⟶ 223:
end
end
return false
end
 
-- Check aggregate note
-- Function to add a legend to below the table when isFBRStyle is true
local rowIndex = math.floor((startIndex - 1) / step) + 1
local function createFBRLegend()
local aggNote = args['note_agg_' .. rowIndex]
return mw.html.create('div')
if aggNote and aggNote:match("^%s*(.-)%s*$") ~= "" then
:css('font-size', '90%')
:css('margin-bottom',return '0.5em')true
end
:wikitext("Legend: Blue = home team win; Yellow = draw; Red = away team win.")
 
-- Check leg notes
local numLegs = step - (noFlagIcons and 3 or 5) -- Calculate number of legs
for leg = 1, numLegs do
local legNote = args['note_leg' .. leg .. '_' .. rowIndex]
if legNote and legNote:match("^%s*(.-)%s*$") ~= "" then
return true
end
end
 
return false
end
 
Line 216 ⟶ 257:
 
-- Check for walkover-related strings (never shown in small text)
if str:lower():match("walkover") or str:lower():match("w%.o%.") or str:lower():match("w/o") or str:lower():match("bye") then
return false
end
Line 236 ⟶ 277:
-- Remove opening and closing HTML tags
str = str:gsub("</?%w+[^>]*>", "")
 
-- Remove apostrophes
str = str:gsub("''+", "")
 
-- Remove all whitespace
Line 246 ⟶ 290:
return true
end
end
 
-- Function to rewrite anchor links in a string
local function rewriteAnchorLinks(str, baselink, currentPageTitle)
if not str or str == "" then
return str
end
-- Add the base link to anchor links when the module is transcluded on another page
if baselink ~= '' then
str = mw.ustring.gsub(str, '(%[%[)(#[^%[%]]*%|)', '%1' .. baselink .. '%2')
end
-- Remove redundant page references when viewing anchors on the current page
if currentPageTitle and currentPageTitle ~= "" then
local escapedTitle = currentPageTitle:gsub("([%(%)%.%%%+%-%*%?%[%^%$])", "%%%1")
local titlePattern = '%[%[' .. escapedTitle .. '(#[^%[%]]*%|)'
str = mw.ustring.gsub(str, titlePattern, '[[%1')
end
return str
end
 
-- Function to format the dashes and winning notes for aggregate/leg score parameters, and divide the score from references/notes/superscripts
local function format_and_extract_score(s, doWrapaddSpan)
if not s then return '', '' end -- Return empty strings if input is nil
 
-- Handle walkovers
if s:match("^%s*[Ww]%s*[/.]%s*[Oo]%s*%.?%s*$") then
return "[[Walkover|w/o]]", ""
end
 
local function format_dash(pattern)
Line 264 ⟶ 334:
format_dash('%s*(%[%[[^%[%]]*%|[%d%.]+)%s*&[MmNn][Dd][Aa][Ss][Hh];%s*([%d%.]+)')
format_dash('%s*(%[[^%[%]%s]*%s+[%d%.]+)%s*&[MmNn][Dd][Aa][Ss][Hh];%s*([%d%.]+)')
 
-- Format winning notes in brackets
if doWrap and not (s:match("%(.*%(")) then
s = mw.ustring.gsub(s, '(%(%d+%s*–%s*%d+)%s+[Pp]%.?[EeSs]?%.?[NnOo]?%.?%)', '%1 [[Penalty shoot-out (association football)|p]])')
s = mw.ustring.gsub(s, '%([Aa]%.?[Ee]%.?[Tt]%.?%)', '([[Overtime (sports)#Association football|a.e.t.]])')
else
s = mw.ustring.gsub(s, '(%(%d+%s*–%s*%d+)%s+[Pp]%.?[EeSs]?%.?[NnOo]?%.?%)', '<span class="nowrap">%1 [[Penalty shoot-out (association football)|p]])</span>')
s = mw.ustring.gsub(s, '%([Aa]%.?[Ee]%.?[Tt]%.?%)', '<span class="nowrap">([[Overtime (sports)#Association football|a.e.t.]])</span>')
end
s = mw.ustring.gsub(s, '%([Aa]%.?[Gg]?%.?[Rr]?%.?%)', '([[Away goals rule|a]])')
 
-- Extract end text
-- Pattern to match superscript
local supStart = s:find('<sup')
-- Pattern to match the unique placeholder
local placeholderStart = s:find('\127%\'"`UNIQ')
 
Line 287 ⟶ 345:
pos = s:find('%(', pos)
if not pos then break end
 
-- Check if there are unclosed [[ before this position
local beforeParen = s:sub(1, pos - 1)
local openLinks = 0select(2, beforeParen:gsub('%[%[', '')) - select(2, beforeParen:gsub('%]%]', ''))
for linkStart in beforeParen:gmatch('%[%[') do
openLinks = openLinks + 1
end
for linkEnd in beforeParen:gmatch('%]%]') do
openLinks = openLinks - 1
end
 
-- If there are no unclosed links, this is a valid parenthesis
if openLinks == 0 then
return pos
end
 
pos = pos + 1
end
Line 308 ⟶ 358:
end
 
-- Find the first parenthesis outside of wikilinks
local parenStart = find_paren_outside_wikilinks(s)
 
-- Store all start positions in a table
local startPositions = {}
if supStart then table.insert(startPositions, supStart) end
Line 317 ⟶ 365:
if parenStart then table.insert(startPositions, parenStart) end
 
local startPosscoreMatch, endText
if #startPositions > 0 then
local startPos = math.min(unpack(startPositions))
-- Find the minimum start position
-- Find the last non-whitespace character before startPos
end
local scoreEnd = s:sub(1, startPos - 1):match(".*%S") or ""
 
scoreEnd = #scoreEnd
if startPos then
-- Find the preceding whitespace
local wsStart = s:find("%s*$", 1, startPos)
 
-- Extract the score and endText
local scoreMatch = s:sub(1, wsStart and wsStart - 1 or startPos - 1scoreEnd)
local endText = s:sub(wsStartscoreEnd or+ startPos1)
 
return scoreMatch, endText
else
-- If no match found, return the entire score
returnscoreMatch s,= ""s
endText = ""
end
 
-- Format winning notes in brackets (only if endText is not empty)
if endText ~= "" then
if addSpan then
endText = mw.ustring.gsub(endText, '(%(%d+%s*–%s*%d+)%s*[Pp]%.?[EeSs]?%.?[NnOo]?%.?%)', '<span class="nowrap">%1 [[Penalty shoot-out (association football)|p]])</span>')
endText = mw.ustring.gsub(endText, '%([Aa]%.?[Ee]%.?[Tt]%.?%)', '<span class="nowrap">([[Overtime (sports)#Association football|a.e.t.]])</span>')
else
endText = mw.ustring.gsub(endText, '(%(%d+%s*–%s*%d+)%s*[Pp]%.?[EeSs]?%.?[NnOo]?%.?%)', '%1 [[Penalty shoot-out (association football)|p]])')
endText = mw.ustring.gsub(endText, '%([Aa]%.?[Ee]%.?[Tt]%.?%)', '([[Overtime (sports)#Association football|a.e.t.]])')
end
endText = mw.ustring.gsub(endText, '%([Aa]%.?[Gg]?%.?[Rr]?%.?%)', '([[Away goals rule|a]])')
end
 
return scoreMatch, endText
end
 
Line 341 ⟶ 401:
local function cleanTeam(str, defaultName)
if str and str ~= "" then
str = str:gsub('<sup.->.-</sup>', '')
str = str:gsub("</?%w+[^>]*>", "")
str = str:gsub('\127%\'"`UNIQ.-QINU`"%\'\127', '')
Line 373 ⟶ 433:
link = "[[#" .. team1 .. " v " .. team2 .. "|" .. linkScore .. "]]"
end
return link .. score:sub(#linkScore + 1)
end
Line 378 ⟶ 439:
 
return score
end
 
-- Function to process notes for aggregate and leg scores
local function processNote(frame, notes, noteKey, noteText, endText, rowIndex, rand_val, noteGroup, baselink, currentPageTitle)
if not noteText then return endText, notes end
if noteText:match("^%s*<sup") or noteText:match("^\127%\'%\"`UNIQ") then
return noteText .. endText, notes
end
 
local function createInlineNote(name)
return frame:extensionTag{
name = 'ref',
args = {
name = name,
group = noteGroup
}
}
end
 
-- Check if noteText is a reference to another note
local referenced_note = noteText:match("^(agg_%d+)$") or noteText:match("^(leg%d+_%d+)$")
if referenced_note then
local referenced_note_id = '"table_note_' .. referenced_note .. '_' .. rand_val .. '"'
return endText .. createInlineNote(referenced_note_id), notes
end
 
-- Process anchor links in noteText before storing
if noteText:find("%[%[") then
noteText = rewriteAnchorLinks(noteText, baselink, currentPageTitle)
end
 
local note_id = '"table_note_' .. noteKey .. '_' .. rowIndex .. '_' .. rand_val .. '"'
if not notes[note_id] then
notes[note_id] = noteText
end
 
return endText .. createInlineNote(note_id), notes
end
 
-- Function to generate the footer if necessary
local function createFooter(frame, notes, noteGroup, isFBRStyle, displayNotes, externalNotes, legs)
local needFooter = (isFBRStyle and legs == 0) or displayNotes or (next(notes) ~= nil)
 
if not needFooter then
return '' -- Return an empty string if no footer is needed
end
 
local divContent = mw.html.create('div')
:addClass('sports-series-notes')
 
if isFBRStyle and legs == 0 then
divContent:wikitext("Legend: Blue = home team win; Yellow = draw; Red = away team win.")
end
 
if (next(notes) ~= nil and not externalNotes) or displayNotes then
divContent:wikitext((isFBRStyle and legs == 0) and "<br>Notes:" or "Notes:")
end
 
local footer = tostring(divContent)
 
if next(notes) ~= nil or displayNotes then
local noteDefinitions = {}
for noteId, noteText in pairs(notes) do
if type(noteId) == 'string' and noteId:match('^"table_note') then
table.insert(noteDefinitions, frame:extensionTag{
name = 'ref',
args = {
name = noteId,
group = noteGroup
},
content = noteText
})
end
end
 
if externalNotes then
local hiddenRefs = mw.html.create('span')
:addClass('sports-series-hidden')
:wikitext(table.concat(noteDefinitions))
if isFBRStyle and legs == 0 then
footer = footer .. tostring(hiddenRefs)
else
footer = tostring(hiddenRefs)
end
else
local reflistArgs = {
refs = table.concat(noteDefinitions),
group = noteGroup
}
footer = footer .. frame:expandTemplate{
title = 'reflist',
args = reflistArgs
}
end
end
 
return footer
end
 
-- Main function that processes input and returns the wikitable
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {trim = true})
local yesno = require('Module:Yesno')
 
-- Check for section transclusion
Line 393 ⟶ 552:
end
 
local root = mw.html.create()
-- Helper function for boolean checks
local functiontemplatestyles isTrue(value)= frame:extensionTag{
name = 'templatestyles',
if not value then return false end
args = { src = 'Screen reader-only/styles.css' }
local lowerValue = value:lower()
} .. frame:extensionTag{
return lowerValue == 'y' or lowerValue == 'yes' or lowerValue == '1' or lowerValue == 'true'
name = 'templatestyles',
end
args = { src = 'Module:Sports series/styles.css' }
 
}
-- Helper function for negative boolean checks
root:wikitext(templatestyles)
local function isFalse(value)
if not value then return false end
local lowerValue = value:lower()
return lowerValue == 'n' or lowerValue == 'no' or lowerValue == '0' or lowerValue == 'false' or lowerValue == 'null' or lowerValue == 'none'
end
 
local rootflagYesno = mwyesno(args.html.create(flag)
local noFlagIconsshowFlags = flagYesno ~= false
local fillBlanksnoFlagIcons = isTrue(args.fill_blanks)not showFlags
local generateLinksfillBlanks = isTrueyesno(args.generate_linksfill_blanks)
local generateLinks = yesno(args.generate_links)
local solidCell = isTrueyesno(args.solid_cell) or args.solid_cell == 'grey' or args.solid_cell == 'gray'
local baselink = frame:getParent():getTitle()
iflocal currentPageTitle = mw.title.getCurrentTitle().text == baselink then baselink = '' endfullText
if currentPageTitle == baselink then baselink = '' end
local notes = {}
local noteGroup = args.note_group or 'lower-alpha'
local noteListValue = yesno(args.note_list)
local displayNotes = noteListValue == true
local externalNotes = noteListValue == false
math.randomseed(os.clock() * 10^8) -- Initialize random number generator
local rand_val = math.random()
 
-- Process the font size parameter
Line 426 ⟶ 590:
 
-- Process flag parameter to determine flag template and variant
local flagTemplate = args.flag or 'fbaicon' -- Default to {{fbaicon}}
local noFlagIcons = isFalse(args.flag)
local flagSize = args.flag_size
if flagSize and not flagSize:match('px$')showFlags then
if args.flag and args.flag ~= '' and not flagYesno then
flagSize = flagSize .. 'px'
flagTemplate = args.flag:gsub('^Template:', '')
end
if not templateExists(flagTemplate) then
flagTemplate = 'flag icon'
end
end
 
if flagSize and not flagSize:match('px$') then
-- Check if flagTemplate exists and adjust if necessary
flagSize = flagSize .. 'px'
if not noFlagIcons and flagTemplate ~= 'fbaicon' then
if not templateExists(flagTemplate) then
flagTemplate = 'flagicon'
end
end
Line 449 ⟶ 614:
end
 
local legs = 2
local legs = (isFalse(args.legs) or args.legs == '1') and 0 or tonumber(args.legs) or 2
if args.legs and legs < 0 then
if yesno(args.legs) == false or args.legs == '1' 2then
legs = 0
else
legs = tonumber(args.legs) and math.max(tonumber(args.legs), 2) or 2
end
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 = notargs.bold_winner isFalse== nil or yesno(args.bold_winner, true)
local colorWinner = isTrueyesno(args.color_winner)
local matchesStyle = args.matches_style
local isFBRStyle = matchesStyle and matchesStyle:upper() == "FBR"
local isHA = isTrueyesno(args.h_a) or (isFBRStyle and legs == 0)
local disableAwayGoals = isFalseyesno(args.away_goals) == false
local disableSmallText = isFalseyesno(args.small_text) == false
local noWrapnoWrapValue = isTrueyesno(args.nowrap)
local disableNoWrapnoWrap = isFalse(args.nowrap)noWrapValue == true
local doWrapdisableNoWrap = notnoWrapValue noWrap== and not disableNoWrapfalse
local aggFormat
 
local tableClass = 'wikitable sports-series'
local tableStyledoCollapsed = 'text-align: center;'yesno(args.collapsed)
if isTrue(args.collapsed)doCollapsed then
tableClass = tableClass .. 'wikitable mw-collapsible mw-collapsed'
tableStyle = tableStyle .. ' width: 100%;'
end
if isTrueyesno(args.center_table) and not doCollapsed then
tableStyletableClass = tableStyletableClass .. ' margincenter-left: auto; margin-right: auto; border: none;table'
end
if noWrap then
tableStyle = tableStyle .. ' white-space: nowrap;'
end
if fontSize then
tableStyle = tableStyle .. table:css(' font-size: ' .., fontSize .. '%;')
end
 
Line 489 ⟶ 655:
table:attr('id', args.id) -- Optional id parameter to allow anchor to table
end
if noWrap then
 
table:attr('data-nowrap', 'y')
-- Add FBR legend if isFBRStyle is true
ifelseif isFBRStylenot and legs == 0disableNoWrap then
roottable:nodeattr(createFBRLegend()'data-nowrap', 'n')
isHA = true
end
 
Line 506 ⟶ 671:
-- Add a title row above column headings if the "title" parameter is passed
if args.title then
local titleRow = table:tag('tr'):addClass('title-row')
titleRow:tag('th')
:attr('colspan', colCount)
Line 515 ⟶ 680:
-- Create the header row with team and score columns
local header = table:tag('tr')
if doWrap then
header:css('white-space', 'nowrap')
end
local defaultTeam1 = isHA and 'Home team' or 'Team 1'
local defaultTeam2 = isHA and 'Away team' or 'Team 2'
header:tag('th'):attr('scope', 'col'):css('width', teamWidth):wikitext(args['team1'] or defaultTeam1)
header:tag('th')
header:tag('th'):attr('scope', 'col'):css('width', scoreWidth):wikitext(args['aggregate'] or legs == 0 and 'Score' or '[[Aggregate score|<abbr title="Aggregate score">Agg.</abbr>]]<span class="sr-only"> Tooltip Aggregate score</span>')
:attr('scope', 'col')
header:tag('th'):attr('scope', 'col'):css('width', teamWidth):wikitext(args['team2'] or defaultTeam2)
: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 == 0 and 'Score' or '[[Aggregate score|<abbr title="Aggregate score">Agg.</abbr>]]<span class="sr-only" style="border: 0; clip: rect(0, 0, 0, 0); clip-path: polygon(0px 0px, 0px 0px, 0px 0px); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; white-space: nowrap;">Tooltip Aggregate score</span>')
header:tag('th')
:attr('scope', 'col')
:css('text-align', 'left')
:css('width', teamWidth)
:wikitext(args['team2'] or defaultTeam2)
 
-- Add columns for each leg if applicable
Line 543 ⟶ 694:
if not legHeading then
if args.leg_prefix then
legHeading = isTrueyesno(args.leg_prefix) and ('Leg ' .. leg) or (args.leg_prefix .. ' ' .. leg)
elseif args.leg_suffix and not isTrueyesno(args.leg_suffix) then
legHeading = ordinal(leg) .. ' ' .. args.leg_suffix
else
Line 551 ⟶ 702:
end
 
header:tag('th'):attr('scope', 'col'):css('width', scoreWidth):wikitext(legHeading)
:attr('scope', 'col')
:css('width', scoreWidth)
:wikitext(legHeading)
end
end
Line 562 ⟶ 710:
while anyParameterPresent(i, step, args) do
local rowIndex = math.floor((i - 1) / step) + 1
local aggNote = args['note_agg_' .. rowIndex]
local headingParam = args['heading' .. rowIndex]
 
Line 584 ⟶ 733:
-- Add a heading above a given row in the table
if headingParam and not showCountry then
local headingRow = table:tag('tr'):addClass('heading-row')
headingRow:tag('td')
:attr('colspan', colCount)
:css('background', 'whitesmoke')
:wikitext('<strong>' .. headingParam .. '</strong>')
end
Line 606 ⟶ 754:
-- Clean the aggregate score
local cleanAggregate = cleanScore(aggregateScore)
aggregateScore, aggFormat = processScore(aggregateScore)
-- Format and rewrite anchor links for aggregate score
-- Format anchor links for aggregate score
aggregateScore, aggregateEndText = format_and_extract_score(aggregateScore, doWrap)
local aggParen = cleanAggregate:match("%(.*%(")
local aggSpan = (disableNoWrap or (not noWrap and not disableNoWrap and aggParen))
aggregateScore, aggregateEndText = format_and_extract_score(aggregateScore, aggSpan)
-- Apply link rewriting to note text before creating the note
aggregateEndText, notes = processNote(frame, notes, 'agg', aggNote, aggregateEndText, rowIndex, rand_val, noteGroup, baselink, currentPageTitle)
if generateLinks and legs == 0 then
-- Skip link generation for "Bye" entries
aggregateScore = cleanAndGenerateLinks(team1, team2, aggregateScore, false)
local isBye = aggregateScore:match("^%s*[Bb][Yy][Ee]%s*$") or aggregateScore:match("|[Bb][Yy][Ee]%]%]")
if not isBye then
aggregateScore = cleanAndGenerateLinks(team1, team2, aggregateScore, false)
end
end
 
local skipAutoWinner = legs == 0 and aggregateScore ~= '' and checkSmallText(aggregateScore)
 
-- Determine the winning team on aggregate
team1, team2, team1Winner, team2Winner, manualBold, manualColor, isDraw, aggregateScore = determineWinner(cleanAggregate, team1, team2, boldWinner, colorWinner, aggregateScore, isFBRStyle, legs, leg1Score, leg2Score, disableAwayGoals, skipAutoWinner, aggFormat)
local skipDetermineWinner = legs == 0 and aggregateScore ~= '' and checkSmallText(aggregateScore)
 
if not skipDetermineWinner then
team1, team2, team1Winner, team2Winner, manualBold, manualColor, isDraw, aggregateScore = determineWinner(cleanAggregate, team1, team2, boldWinner, colorWinner, aggregateScore, isFBRStyle, legs, leg1Score, leg2Score, disableAwayGoals)
end
 
-- Add background-color for winning team if set by user
local team1Style = 'text-align: right;'
local team2Style = 'text-align: left;'
if team1Winner and (colorWinner or manualColor) then
team1Style = team1Style .. ' background-color: #CCFFCC;'
end
if team2Winner and (colorWinner or manualColor) then
team2Style = team2Style .. ' background-color: #CCFFCC;'
end
-- Function to create flag template parameters
local function getFlagParams(icon, variant)
Line 643 ⟶ 788:
 
-- When set by user, adds blank flag placeholder next to team names
if fillBlanks and not noFlagIconsshowFlags then
local flagDimensions = flagSize or "25x17px"
local placeholderFlag = string.format('<span class="flagicon">[[File:Flag placeholder.svg|%s|link=]]</span>', flagDimensions)
if not team1Icon or team1Icon == "" then
team1Text = team1Text .. '&nbsp;<span' class="flagicon">[[File:Flag placeholder.svg|25x17px|link=]]</span>'. placeholderFlag
end
if not team2Icon or team2Icon == "" then
team2Text = '<spanplaceholderFlag class="flagicon">[[File:Flag placeholder.svg|25x17px|link=]]</span>. '&nbsp;' .. team2Text
end
end
 
local aggregateContent
if not disableSmallText and skipDetermineWinnerskipAutoWinner then
aggregateContent = '<span styleclass="fontsports-size:85%;series-small">' .. aggregateScore .. '</span>' .. aggregateEndText
else
aggregateContent = aggregateScore .. aggregateEndText
Line 660 ⟶ 807:
 
-- Create aggregate score cell with conditional styling
local aggregateStyleaggregateClass = ''
if doWrap and not (cleanAggregate:match("%(.*%(")) then
aggregateStyle = 'white-space: nowrap;'
end
if isFBRStyle and legs == 0 then
if team1Winner then
aggregateStyleaggregateClass = aggregateStyle .. 'backgroundfbr-color: #BBF3FF;home-win'
elseif team2Winner then
aggregateStyleaggregateClass = aggregateStyle .. 'backgroundfbr-color: #FFBBBB;away-win'
elseif isDraw then
aggregateStyleaggregateClass = aggregateStyle .. 'background-color: #FFFFBB;draw'
end
elseif isDraw then
aggregateStyleaggregateClass = aggregateStyle .. 'background-color: #FFFFBB;draw'
end
if not disableNoWrap and (not noWrap and aggParen) then
aggregateClass = (aggregateClass ~= '' and aggregateClass .. ' ' or '') .. 'allow-wrap'
end
 
-- Create rows for aggregate score and team names, bolded if set by user
row:tag('td'):cssTextaddClass(team1Styleteam1Winner and (colorWinner or manualColor) and 'winner' or nil):wikitext((team1Winner and (boldWinner or manualBold) and team1Text ~= '') and ('<strong>' .. team1Text .. '</strong>') or team1Text)
row:tag('td'):cssTextaddClass(aggregateStyleaggregateClass ~= '' and aggregateStyleaggregateClass or nil):wikitext(aggregateContent)
row:tag('td'):cssTextaddClass(team2Styleteam2Winner and (colorWinner or manualColor) and 'winner' or nil):wikitext((team2Winner and (boldWinner or manualBold) and team2Text ~= '') and ('<strong>' .. team2Text .. '</strong>') or team2Text)
 
-- Add columns for each leg score if applicable
Line 686 ⟶ 833:
local legIndex = i + 4 + leg + (noFlagIcons and -2 or 0)
local legScore = args[legIndex]
local legNote = args['note_leg' .. leg .. '_' .. rowIndex]
if legScore ~= "nil" then
if legScore == "null" then
if solidCell then
row:tag('td'):cssaddClass('background', '#BBBBBBsolid-cell')
else
legScore = '—'
Line 695 ⟶ 843:
end
 
if legScore ~= "null" or not solidCell then
-- Format and rewrite anchor links for leg scores
local cleanLeg = cleanScore(legScore)
legScore,local legEndText = format_and_extract_score(legScore, doWrap)legFormat
iflegScore, generateLinkslegFormat then= processScore(legScore)
local legParen = cleanLeg:match("%(.*%(")
local legSpan = (disableNoWrap or (not noWrap and not disableNoWrap and legParen))
legScore, legEndText = format_and_extract_score(legScore, legSpan)
-- Apply link rewriting to note text before creating the note
legEndText, notes = processNote(frame, notes, 'leg' .. leg, legNote, legEndText, rowIndex, rand_val, noteGroup, baselink, currentPageTitle)
if generateLinks and not aggregateContent:lower():find("bye") then
if leg == 1 then
legScore = cleanAndGenerateLinks(team1, team2, legScore, false)
Line 706 ⟶ 860:
end
end
if legFormat == 'bold' or legFormat == 'both' then legScore = '<b>' .. legScore .. '</b>' end
if legFormat == 'italic' or legFormat == 'both' then legScore = '<i>' .. legScore .. '</i>' end
local legContent
if not disableSmallText and legScore ~= '' and checkSmallText(legScore) then
legContent = '<span styleclass="fontsports-size:85%;series-small">' .. legScore .. '</span>' .. legEndText
else
legContent = legScore .. legEndText
end
local legStylelegClass = ''
if doWrapnot disableNoWrap and (not (cleanLeg:match("%(.*%(")noWrap and legParen) then
legStylelegClass = 'whiteallow-space: nowrap;wrap'
end
-- Write cells for legs
row:tag('td'):cssTextaddClass(legStylelegClass ~= '' and legStylelegClass or nil):wikitext(legContent)
end
end
Line 726 ⟶ 882:
i = i + step
end
 
-- Generate footer text
local footerText = createFooter(frame, notes, noteGroup, isFBRStyle, displayNotes, externalNotes, legs)
root:wikitext(footerText)
 
local tableCode = tostring(root)
 
-- Rewrite anchor links for the entire table (except for notes which were handled separately)
tableCode = rewriteAnchorLinks(tableCode, baselink, currentPageTitle)
if baselink ~= '' then
tableCode = mw.ustring.gsub(tableCode, '(%[%[)(#[^%[%]]*%|)', '%1' .. baselink .. '%2')
end
 
-- Return the completed table with rewritten links
return tableCode
end