Difference between revisions of "Module:TeamBracket-Tennis"
Jump to navigation
Jump to search
blackwiki>Nakon m (Protected Module:TeamBracket-Compact-Tennis: High-risk Lua module ([Edit=Allow only template editors and admins] (indefinite) [Move=Allow only template editors and admins] (indefinite))) |
blackwiki>Frietjes (starting a modified version of Module:TeamBracket for tennis, most likely has bugs) |
||
| Line 1: | Line 1: | ||
| − | |||
| − | |||
-- | -- | ||
| − | + | -- This module will implement {{8TeamBracket-Tennis5}} | |
| + | -- | ||
| + | |||
local p = {} | local p = {} | ||
local args | local args | ||
| Line 8: | Line 8: | ||
local sets | local sets | ||
local padding | local padding | ||
| + | local showSeeds | ||
local function getArgs(frame) | local function getArgs(frame) | ||
local parent = frame:getParent(); | local parent = frame:getParent(); | ||
local args = parent.args; | local args = parent.args; | ||
| − | for k,v in pairs(frame.args) do | + | for k,v in pairs(frame.args) do |
args[k] = v | args[k] = v | ||
end | end | ||
| − | return | + | return args; |
| + | end | ||
| + | |||
| + | function getSeeds() | ||
| + | local seeds = {1, 2} | ||
| + | local count = 2 | ||
| + | local before = false | ||
| + | for r = 2, rounds do | ||
| + | local max = math.pow(2, r) | ||
| + | for i = 1, count do | ||
| + | local pos = i * 2 | ||
| + | if before then pos = pos - 1 end | ||
| + | table.insert(seeds, pos, max - seeds[i * 2 - 1] + 1) | ||
| + | before = not before | ||
| + | end | ||
| + | count = count * 2 | ||
| + | end | ||
| + | return seeds | ||
end | end | ||
| Line 24: | Line 42: | ||
function addBlank(row, width) | function addBlank(row, width) | ||
local cell = row:tag('td') | local cell = row:tag('td') | ||
| − | |||
| − | |||
| − | |||
if width then | if width then | ||
cell:css('width', width) | cell:css('width', width) | ||
| Line 35: | Line 50: | ||
function addPath(rows, index, round, top, left) | function addPath(rows, index, round, top, left) | ||
local prop = top and 'border-bottom-width' or 'border-top-width' | local prop = top and 'border-bottom-width' or 'border-top-width' | ||
| − | |||
if left and round == 1 then | if left and round == 1 then | ||
| + | addBlank(rows[index]):css('height', '7px') | ||
| + | addBlank(rows[index + 1]):css('height', '7px') | ||
| + | return nil | ||
| + | else | ||
| + | local cell = addBlank(rows[index]) | ||
| + | :attr('rowspan', '2') | ||
| + | :css('border-width', '0') | ||
| + | :css('border-style', 'solid') | ||
| + | :css('border-color', 'black') | ||
| + | if left or round < rounds and not left then | ||
| + | cell:css(prop, '2px') | ||
| + | end | ||
| + | return cell | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function addCompactPath(rows, index, round, top, left) | ||
| + | local prop = top and 'border-bottom-width' or 'border-top-width' | ||
| + | if left and round == 1 then | ||
| + | addBlank(rows[index]) | ||
return nil | return nil | ||
else | else | ||
| + | local cell = addBlank(rows[index]) | ||
| + | :css('border-width', '0') | ||
| + | :css('border-style', 'solid') | ||
| + | :css('border-color', 'black') | ||
if left or round < rounds and not left then | if left or round < rounds and not left then | ||
cell:css(prop, '2px') | cell:css(prop, '2px') | ||
| Line 58: | Line 96: | ||
function getTeamArg(round, type, team) | function getTeamArg(round, type, team) | ||
| − | local argname = | + | local argname = getTeamArgName(round, type, team) |
local value = args[argname] | local value = args[argname] | ||
if not value or string.len(value) == 0 then | if not value or string.len(value) == 0 then | ||
| Line 66: | Line 104: | ||
end | end | ||
| − | function | + | function getTeamArgName(round, type, team) |
| − | + | return string.format('RD%d-%s' .. padding, round, type, team) | |
| − | |||
end | end | ||
| Line 87: | Line 124: | ||
end | end | ||
end | end | ||
| − | + | ||
| − | function renderTeam(row, round, team, | + | function renderTeam(row, round, team, top, compact) |
| + | local seedCell | ||
local seedArg = getTeamArg(round, 'seed', team) | local seedArg = getTeamArg(round, 'seed', team) | ||
| − | local seedCell = | + | -- seed value for the paired team |
| − | + | local pairSeedArg = getTeamArg(round, 'seed', | |
| − | + | team % 2 == 0 and team - 1 or team + 1) | |
| − | + | -- show seed if seed is defined for either or both | |
| − | + | local showSeed = seedArg and string.len(seedArg) > 0 | |
| − | + | or pairSeedArg and string.len(pairSeedArg) > 0 | |
| − | + | if showSeed and showSeeds then | |
| − | + | seedCell = row:tag('td') | |
| + | :css('text-align', 'center') | ||
| + | :css('background-color', '#f2f2f2') | ||
| + | :css('border-color', '#aaa') | ||
| + | :css('border-style', 'solid') | ||
| + | :css('border-top-width', '1px') | ||
| + | :css('border-left-width', '1px') | ||
| + | :css('border-right-width', '1px') | ||
| + | :css('border-bottom-width', '0') | ||
| + | :wikitext(seedArg) | ||
| + | :newline() | ||
| + | end | ||
local teamArg = getTeamArg(round, 'team', team) | local teamArg = getTeamArg(round, 'team', team) | ||
| Line 103: | Line 152: | ||
teamArg = ' ' | teamArg = ' ' | ||
end | end | ||
| − | local teamCell = | + | local teamCell = row:tag('td') |
:css('background-color', '#f9f9f9') | :css('background-color', '#f9f9f9') | ||
| − | :css('border-width', '1px') | + | :css('border-color', '#aaa') |
| − | :css('border- | + | :css('border-style', 'solid') |
| + | :css('border-top-width', '1px') | ||
| + | :css('border-left-width', '1px') | ||
| + | :css('border-right-width', '0') | ||
| + | :css('border-bottom-width', '0') | ||
:css('padding', '0 2px') | :css('padding', '0 2px') | ||
:wikitext(teamArg) | :wikitext(teamArg) | ||
| + | :newline() | ||
| + | if not showSeed and showSeeds then | ||
| + | teamCell:attr('colspan', '2') | ||
| + | end | ||
| + | |||
| + | local scoreCell = row:tag('td') | ||
| + | :css('text-align', 'center') | ||
| + | :css('border-color', '#aaa') | ||
| + | :css('border-style', 'solid') | ||
| + | :css('border-top-width', '1px') | ||
| + | :css('border-left-width', '1px') | ||
| + | :css('border-right-width', '1px') | ||
| + | :css('border-bottom-width', '0') | ||
| + | :css('background-color', '#f9f9f9') | ||
| + | :wikitext(getTeamArg(round, 'score', team)) | ||
:newline() | :newline() | ||
| − | + | if not compact then | |
| − | + | if seedCell then | |
| − | :css(' | + | seedCell:attr('rowspan', '2') |
| − | :css('border-width', '1px') | + | :css('border-bottom-width', '1px') |
| − | :css(' | + | end |
| − | :css('border-bottom-width', | + | scoreCell:attr('rowspan', '2') |
| − | : | + | :css('border-bottom-width', '1px') |
| − | : | + | teamCell:attr('rowspan', '2') |
| + | :css('border-right-width', '1px') | ||
| + | :css('border-bottom-width', '1px') | ||
| + | else | ||
| + | if not top then | ||
| + | if seedCell then | ||
| + | seedCell:css('border-bottom-width', '1px') | ||
| + | end | ||
| + | teamCell:css('border-bottom-width', '1px') | ||
| + | scoreCell:css('border-bottom-width', '1px') | ||
| + | end | ||
end | end | ||
end | end | ||
| − | function renderRound(rows, count, r) | + | function renderRound(rows, count, r) |
local teams = math.pow(2, rounds - r + 1) | local teams = math.pow(2, rounds - r + 1) | ||
local step = count / teams | local step = count / teams | ||
| − | local | + | local topTeam = true -- is top row in match-up |
| − | local | + | local topPair = true -- is top match-up in pair of match-ups |
local team = 1 | local team = 1 | ||
for i = 1, count, step do | for i = 1, count, step do | ||
| − | if | + | local offset, height, blank |
| − | + | -- leave room for groups for teams other than first and last | |
| − | + | if team == 1 or team == teams then | |
| + | offset = topTeam and i or i + 2 | ||
| + | height = step - 2 | ||
| + | else | ||
| + | offset = topTeam and i + 1 or i + 2 | ||
| + | height = step - 3 | ||
| + | end | ||
| + | if height > 0 then | ||
| + | blank = addBlank(rows[offset]) | ||
| + | :attr('colspan', tonumber(showSeeds and '4' or '3') + sets) | ||
| + | :attr('rowspan', height) | ||
| + | :css('border-color', 'black') | ||
| + | :css('border-style', 'solid') | ||
| + | :css('border-width', '0') | ||
| + | end | ||
-- add bracket | -- add bracket | ||
| − | local j = | + | local j = topTeam and i + step - 2 or i |
| − | + | -- add left path | |
| − | renderTeam(rows[j], r, team, | + | addPath(rows, j, r, topTeam, true) |
| − | local | + | renderTeam(rows[j], r, team, topTeam, false) |
| − | if | + | local rightPath = addPath(rows, j, r, topTeam, false) |
| − | right:css('border-right-width', '2px') | + | if not topTeam then topPair = not topPair end |
| + | if not topPair and r < rounds then | ||
| + | if blank then blank:css('border-right-width', '2px') end | ||
| + | rightPath:css('border-right-width', '2px') | ||
end | end | ||
| − | -- | + | team = team + 1 |
| − | + | topTeam = not topTeam | |
| − | blank = addBlank(rows[offset + | + | end |
| + | end | ||
| + | |||
| + | function renderCompactRound(rows, count, r) | ||
| + | local teams = math.pow(2, rounds - r + 1) | ||
| + | local step = count / teams | ||
| + | local topTeam = true -- is top row in match-up | ||
| + | local topPair = true -- is top match-up in pair of match-ups | ||
| + | local team = 1 | ||
| + | |||
| + | for i = 1, count, step do | ||
| + | local offset, height, blank | ||
| + | -- empty space above or below | ||
| + | local offset = topTeam and i or i + 1 | ||
| + | local height = step - 1 | ||
| + | |||
| + | if height > 0 then | ||
| + | blank = addBlank(rows[offset]) | ||
| + | :attr('colspan', tonumber(showSeeds and '4' or '3') + sets) | ||
:css('border-color', 'black') | :css('border-color', 'black') | ||
| − | :attr(' | + | :css('border-style', 'solid') |
| − | + | :css('border-width', '0') | |
| − | + | :attr('rowspan', height) | |
| − | + | end | |
| + | -- add bracket | ||
| + | local j = topTeam and i + step - 1 or i | ||
| + | -- add left path | ||
| + | addCompactPath(rows, j, r, topTeam, true) | ||
| + | renderTeam(rows[j], r, team, topTeam, true) | ||
| + | local rightPath = addCompactPath(rows, j, r, topTeam, false) | ||
| + | if not topTeam then topPair = not topPair end | ||
| + | if not topPair and r < rounds then | ||
| + | if blank then blank:css('border-right-width', '2px') end | ||
| + | rightPath:css('border-right-width', '2px') | ||
end | end | ||
| − | |||
team = team + 1 | team = team + 1 | ||
| − | + | topTeam = not topTeam | |
end | end | ||
| − | end | + | end |
| + | |||
| + | function renderGroups(rows, count, round) | ||
| + | local roundFromLast = rounds - round + 1 | ||
| + | local groups = math.pow(2, roundFromLast - 2) | ||
| + | local step = count / groups | ||
| + | local group = 1 | ||
| + | for i = step / 2, count, step do | ||
| + | local name = 'RD' .. round .. '-group' .. group | ||
| + | addBlank(rows[i]):css('height', '7px') | ||
| + | addBlank(rows[i + 1]):css('height', '7px') | ||
| + | addBlank(rows[i]) | ||
| + | :attr('rowspan', '2') | ||
| + | :attr('colspan', ((showSeeds and 4 or 3) + sets) * round - 1) | ||
| + | :css('text-align', 'center') | ||
| + | :css('border-color', 'black') | ||
| + | :css('border-style', 'solid') | ||
| + | :css('border-width', '0 2px 0 0') | ||
| + | :wikitext(args[name]) | ||
| + | :newline() | ||
| + | group = group + 1 | ||
| + | end | ||
| + | end | ||
| − | function renderTree(tbl) | + | function renderTree(tbl, compact) |
| − | local count = math.pow(2, rounds) | + | -- create 3 or 1 rows for every team |
| + | local count = math.pow(2, rounds) * ((compact and 0 or 2) + sets) | ||
local rows = {} | local rows = {} | ||
for i = 1, count do | for i = 1, count do | ||
rows[i] = addTableRow(tbl) | rows[i] = addTableRow(tbl) | ||
end | end | ||
| + | if not compact then | ||
| + | -- fill rows with groups | ||
| + | for r = 1, rounds - 1 do | ||
| + | renderGroups(rows, count, r) | ||
| + | end | ||
| + | end | ||
| + | -- fill rows with bracket | ||
for r = 1, rounds do | for r = 1, rounds do | ||
| − | renderRound(rows, count, r) | + | if compact then |
| + | renderCompactRound(rows, count, r) | ||
| + | else | ||
| + | renderRound(rows, count, r) | ||
| + | end | ||
end | end | ||
end | end | ||
| − | function renderHeading(tbl) | + | function renderHeading(tbl, compact) |
local titleRow = addTableRow(tbl) | local titleRow = addTableRow(tbl) | ||
local widthRow = addTableRow(tbl) | local widthRow = addTableRow(tbl) | ||
| Line 172: | Line 328: | ||
addBlank(titleRow) | addBlank(titleRow) | ||
addBlank(widthRow, r > 1 and '5px' or nil) | addBlank(widthRow, r > 1 and '5px' or nil) | ||
| − | + | titleRow:tag('td') | |
| − | + | :attr('colspan', tonumber(showSeeds and '2' or '1') + sets) | |
| − | :attr('colspan', 2 + sets) | ||
:css('text-align', 'center') | :css('text-align', 'center') | ||
| − | :css('border | + | :css('border', '1px solid #aaa') |
:css('background-color', '#f2f2f2') | :css('background-color', '#f2f2f2') | ||
:wikitext(getRoundName(r)) | :wikitext(getRoundName(r)) | ||
| − | + | :newline() | |
| − | addBlank(widthRow, getWidth('seed', '25px')) | + | local seedCell |
| − | + | if showSeeds then | |
| − | addBlank(widthRow, getWidth('team', '150px')) | + | seedCell = addBlank(widthRow, getWidth('seed', '25px')) |
| − | + | end | |
| + | local teamCell = addBlank(widthRow, getWidth('team', '150px')) | ||
| + | local scoreCells | ||
for s = 1, sets do | for s = 1, sets do | ||
| − | addBlank(widthRow, getWidth('score', '12px') | + | scoreCell[s] = addBlank(widthRow, getWidth('score', '12px')) |
| − | |||
end | end | ||
| − | |||
addBlank(titleRow) | addBlank(titleRow) | ||
addBlank(widthRow, r < rounds and '5px' or nil) | addBlank(widthRow, r < rounds and '5px' or nil) | ||
| − | :css('height', '7px') | + | |
| + | if compact then | ||
| + | teamCell:css('height', '7px') | ||
| + | else | ||
| + | if seedCell then | ||
| + | seedCell:wikitext(' ') | ||
| + | end | ||
| + | teamCell:wikitext(' ') | ||
| + | for s = 1, sets do | ||
| + | scoreCell[s]:wikitext(' ') | ||
| + | end | ||
| + | end | ||
end | end | ||
end | end | ||
| Line 197: | Line 363: | ||
function p.teamBracket(frame) | function p.teamBracket(frame) | ||
args = getArgs(frame) | args = getArgs(frame) | ||
| − | rounds = tonumber(args.rounds) or | + | rounds = tonumber(args.rounds) or 2 |
| − | sets = tonumber(args.sets) or 5 | + | sets = tonumber(args.sets or 5) or 5 |
local teams = math.pow(2, rounds) | local teams = math.pow(2, rounds) | ||
padding = '%0' .. (teams < 10 and 1 or 2) .. 'd' | padding = '%0' .. (teams < 10 and 1 or 2) .. 'd' | ||
| + | showSeeds = true | ||
| + | if args['seeds'] and args['seeds'] == 'no' then | ||
| + | showSeeds = false | ||
| + | end | ||
| + | |||
| + | -- set default seeds for round 1 | ||
| + | local seeds = getSeeds() | ||
| + | local argname | ||
| + | for i = 1, table.getn(seeds) do | ||
| + | argname = getTeamArgName(1, 'seed', i) | ||
| + | if not args[argname] then | ||
| + | args[argname] = seeds[i] | ||
| + | end | ||
| + | end | ||
local tbl = mw.html.create('table') | local tbl = mw.html.create('table') | ||
| Line 206: | Line 386: | ||
:css('font-size', '90%') | :css('font-size', '90%') | ||
:css('margin', '1em 2em 1em 1em') | :css('margin', '1em 2em 1em 1em') | ||
| − | :css('border-collapse', ' | + | :css('border-collapse', 'separate') |
:css('border-spacing', '0') | :css('border-spacing', '0') | ||
| − | :attr('cellpadding', '0') | + | |
| − | + | local compact = false | |
| − | renderHeading(tbl) | + | if args['compact'] and args['compact'] == 'yes' then |
| − | renderTree(tbl) | + | compact = true |
| + | end | ||
| + | |||
| + | if compact then | ||
| + | tbl:css('font-size', '90%'):attr('cellpadding', '0') | ||
| + | end | ||
| + | |||
| + | renderHeading(tbl, compact) | ||
| + | renderTree(tbl, compact) | ||
return tostring(tbl) | return tostring(tbl) | ||
end | end | ||
| − | + | ||
return p | return p | ||
Revision as of 14:48, 13 April 2017
| 40px | This Lua module is used on 19,000+ pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages. Consider discussing changes at Wikipedia talk:High-risk templates before implementing them.
Transclusion count updated automatically (see documentation). |
| 40x40px | This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
This template implements a variant of Module:TeamBracket for tennis tournaments. It is a generic visual representation of the tournament bracket. For common usage, use the templates in Category:Tennis tournament bracket templates.
Usage
{{#invoke: TeamBracket-Tennis | teamBracket
| rounds =
| sets =
| seeds = <!-- yes / no / or blank -->
| compact = <!-- yes / no / or blank -->
| nowrap = <!-- yes / no / or blank -->
| seed-width =
| team-width =
| score-width =
| RD1 =
| RD1-seed1 =
| RD1-team1 =
| RD1-score1-1 =
| RD1-score1-2 =
| RD1-score1-3 =
}}
Parameter list
The parameters are as follows:
seed-width –the width of the cells for seeds.team-width –the width of the cells for team names.score-width –the width of the cells for scores.compact –set toyesfor compact formatseeds –set tonoto omit seed cells, andyesto always show seed cellsnowrap –set toyesto prevent lines from wrappingbyes –set to1,2, ... to specify the maximum round number with byesheadings –set tonoto omit the column headings
RDn –The name of round n.RDn-seedm –The seed of team m in round n.RDn-teamm –The name of team m in round n.RDn-scorem-s –The score of set s for team m in round n.RDn-groupm –Label for the mth group in round n.
Examples
{{#invoke: TeamBracket-Tennis | teamBracket
| rounds = 2
| sets = 3
| RD1-seed1 = '''1'''
| RD1-seed2 = 4
| RD1-team1 = '''John'''
| RD1-team2 = Declan
| RD1-score1-1 = '''6'''
| RD1-score2-1 = 0
| RD1-score1-2 = 3
| RD1-score2-2 = '''6'''
| RD1-score1-3 = '''7'''
| RD1-score2-3 = 6
| RD1-seed3 = 2
| RD1-seed4 = 3
| RD1-team3 = Barry
| RD1-team4 = Steve
| RD2-seed1 = 1
| RD2-team1 = John
}}
Lua error at line 344: attempt to index global 'scoreCell' (a nil value).
Templates using this module
- {{2TeamBracket-Tennis3}}
- {{2TeamBracket-Tennis5}}
- {{2TeamBracket-Tennis7}}
- {{2TeamBracket-Tennis9}}
- {{2TeamBracket-Compact-Tennis3}}
- {{2TeamBracket-Compact-Tennis5}}
- {{4TeamBracket-Tennis3}}
- {{4TeamBracket-Tennis5}}
- {{4TeamBracket-Tennis35}}
- {{4TeamBracket-Tennis3-with third}}
- {{4TeamBracket-Tennis35-with third}}
- {{4TeamBracket-Tennis5-with 3rd}}
- {{4TeamBracket-Tennis7-with 3rd}}
- {{4TeamBracket-Compact-Tennis3}}
- {{4TeamBracket-Compact-Tennis7}}
- {{8TeamBracket-Tennis3}}
- {{8TeamBracket-Tennis5}}
- {{8TeamBracket-Tennis35}}
- {{8TeamBracket-Tennis353}}
- {{8TeamBracket-Tennis355}}
- {{8TeamBracket-Tennis3-with third}}
- {{8TeamBracket-Tennis5-with third}}
- {{8TeamBracket-Tennis35-with third}}
- {{8TeamBracket-Compact-Tennis7}}
- {{16TeamBracket-Tennis3}}
- {{16TeamBracket-Tennis5}}
- {{16TeamBracket-Tennis5777}}
- {{16TeamBracket-Compact-Tennis3}}
- {{16TeamBracket-Compact-Tennis5}}
- {{16TeamBracket-Compact-Tennis35}}
- {{16TeamBracket-Compact-Tennis7}}
- {{16TeamBracket-Compact-Tennis3355}}
- {{16TeamBracket-Compact-Tennis3555}}
- {{16TeamBracket-Compact-Tennis3-with 3rd}}
- {{16TeamBracket-Compact-Tennis7-with 3rd}}
- {{32TeamBracket-Tennis3}}
- {{32TeamBracket-Tennis5}}
--
-- This module will implement {{8TeamBracket-Tennis5}}
--
local p = {}
local args
local rounds
local sets
local padding
local showSeeds
local function getArgs(frame)
local parent = frame:getParent();
local args = parent.args;
for k,v in pairs(frame.args) do
args[k] = v
end
return args;
end
function getSeeds()
local seeds = {1, 2}
local count = 2
local before = false
for r = 2, rounds do
local max = math.pow(2, r)
for i = 1, count do
local pos = i * 2
if before then pos = pos - 1 end
table.insert(seeds, pos, max - seeds[i * 2 - 1] + 1)
before = not before
end
count = count * 2
end
return seeds
end
function addTableRow(tbl)
return tbl:tag('tr')
end
function addBlank(row, width)
local cell = row:tag('td')
if width then
cell:css('width', width)
end
return cell
end
function addPath(rows, index, round, top, left)
local prop = top and 'border-bottom-width' or 'border-top-width'
if left and round == 1 then
addBlank(rows[index]):css('height', '7px')
addBlank(rows[index + 1]):css('height', '7px')
return nil
else
local cell = addBlank(rows[index])
:attr('rowspan', '2')
:css('border-width', '0')
:css('border-style', 'solid')
:css('border-color', 'black')
if left or round < rounds and not left then
cell:css(prop, '2px')
end
return cell
end
end
function addCompactPath(rows, index, round, top, left)
local prop = top and 'border-bottom-width' or 'border-top-width'
if left and round == 1 then
addBlank(rows[index])
return nil
else
local cell = addBlank(rows[index])
:css('border-width', '0')
:css('border-style', 'solid')
:css('border-color', 'black')
if left or round < rounds and not left then
cell:css(prop, '2px')
end
return cell
end
end
function getWidth(param, default)
local arg = args[param .. '-width']
if not arg or string.len(arg) == 0 then
arg = default
end
if tonumber(arg) ~= nil then
arg = arg .. 'px'
end
return arg
end
function getTeamArg(round, type, team)
local argname = getTeamArgName(round, type, team)
local value = args[argname]
if not value or string.len(value) == 0 then
return ''
end
return string.gsub(value, " *<[Bb][Rr] */?> * *", "<br/>")
end
function getTeamArgName(round, type, team)
return string.format('RD%d-%s' .. padding, round, type, team)
end
function getRoundName(round)
local name = args['RD' .. round]
if name and string.len(name) > 0 then
return name
end
local roundFromLast = rounds - round + 1
if roundFromLast == 1 then
return "Finals"
elseif roundFromLast == 2 then
return "Semifinals"
elseif roundFromLast == 3 then
return "Quarterfinals"
else
return "Round of " .. math.pow(2, roundFromLast)
end
end
function renderTeam(row, round, team, top, compact)
local seedCell
local seedArg = getTeamArg(round, 'seed', team)
-- seed value for the paired team
local pairSeedArg = getTeamArg(round, 'seed',
team % 2 == 0 and team - 1 or team + 1)
-- show seed if seed is defined for either or both
local showSeed = seedArg and string.len(seedArg) > 0
or pairSeedArg and string.len(pairSeedArg) > 0
if showSeed and showSeeds then
seedCell = row:tag('td')
:css('text-align', 'center')
:css('background-color', '#f2f2f2')
:css('border-color', '#aaa')
:css('border-style', 'solid')
:css('border-top-width', '1px')
:css('border-left-width', '1px')
:css('border-right-width', '1px')
:css('border-bottom-width', '0')
:wikitext(seedArg)
:newline()
end
local teamArg = getTeamArg(round, 'team', team)
if not teamArg or string.len(teamArg) == 0 then
teamArg = ' '
end
local teamCell = row:tag('td')
:css('background-color', '#f9f9f9')
:css('border-color', '#aaa')
:css('border-style', 'solid')
:css('border-top-width', '1px')
:css('border-left-width', '1px')
:css('border-right-width', '0')
:css('border-bottom-width', '0')
:css('padding', '0 2px')
:wikitext(teamArg)
:newline()
if not showSeed and showSeeds then
teamCell:attr('colspan', '2')
end
local scoreCell = row:tag('td')
:css('text-align', 'center')
:css('border-color', '#aaa')
:css('border-style', 'solid')
:css('border-top-width', '1px')
:css('border-left-width', '1px')
:css('border-right-width', '1px')
:css('border-bottom-width', '0')
:css('background-color', '#f9f9f9')
:wikitext(getTeamArg(round, 'score', team))
:newline()
if not compact then
if seedCell then
seedCell:attr('rowspan', '2')
:css('border-bottom-width', '1px')
end
scoreCell:attr('rowspan', '2')
:css('border-bottom-width', '1px')
teamCell:attr('rowspan', '2')
:css('border-right-width', '1px')
:css('border-bottom-width', '1px')
else
if not top then
if seedCell then
seedCell:css('border-bottom-width', '1px')
end
teamCell:css('border-bottom-width', '1px')
scoreCell:css('border-bottom-width', '1px')
end
end
end
function renderRound(rows, count, r)
local teams = math.pow(2, rounds - r + 1)
local step = count / teams
local topTeam = true -- is top row in match-up
local topPair = true -- is top match-up in pair of match-ups
local team = 1
for i = 1, count, step do
local offset, height, blank
-- leave room for groups for teams other than first and last
if team == 1 or team == teams then
offset = topTeam and i or i + 2
height = step - 2
else
offset = topTeam and i + 1 or i + 2
height = step - 3
end
if height > 0 then
blank = addBlank(rows[offset])
:attr('colspan', tonumber(showSeeds and '4' or '3') + sets)
:attr('rowspan', height)
:css('border-color', 'black')
:css('border-style', 'solid')
:css('border-width', '0')
end
-- add bracket
local j = topTeam and i + step - 2 or i
-- add left path
addPath(rows, j, r, topTeam, true)
renderTeam(rows[j], r, team, topTeam, false)
local rightPath = addPath(rows, j, r, topTeam, false)
if not topTeam then topPair = not topPair end
if not topPair and r < rounds then
if blank then blank:css('border-right-width', '2px') end
rightPath:css('border-right-width', '2px')
end
team = team + 1
topTeam = not topTeam
end
end
function renderCompactRound(rows, count, r)
local teams = math.pow(2, rounds - r + 1)
local step = count / teams
local topTeam = true -- is top row in match-up
local topPair = true -- is top match-up in pair of match-ups
local team = 1
for i = 1, count, step do
local offset, height, blank
-- empty space above or below
local offset = topTeam and i or i + 1
local height = step - 1
if height > 0 then
blank = addBlank(rows[offset])
:attr('colspan', tonumber(showSeeds and '4' or '3') + sets)
:css('border-color', 'black')
:css('border-style', 'solid')
:css('border-width', '0')
:attr('rowspan', height)
end
-- add bracket
local j = topTeam and i + step - 1 or i
-- add left path
addCompactPath(rows, j, r, topTeam, true)
renderTeam(rows[j], r, team, topTeam, true)
local rightPath = addCompactPath(rows, j, r, topTeam, false)
if not topTeam then topPair = not topPair end
if not topPair and r < rounds then
if blank then blank:css('border-right-width', '2px') end
rightPath:css('border-right-width', '2px')
end
team = team + 1
topTeam = not topTeam
end
end
function renderGroups(rows, count, round)
local roundFromLast = rounds - round + 1
local groups = math.pow(2, roundFromLast - 2)
local step = count / groups
local group = 1
for i = step / 2, count, step do
local name = 'RD' .. round .. '-group' .. group
addBlank(rows[i]):css('height', '7px')
addBlank(rows[i + 1]):css('height', '7px')
addBlank(rows[i])
:attr('rowspan', '2')
:attr('colspan', ((showSeeds and 4 or 3) + sets) * round - 1)
:css('text-align', 'center')
:css('border-color', 'black')
:css('border-style', 'solid')
:css('border-width', '0 2px 0 0')
:wikitext(args[name])
:newline()
group = group + 1
end
end
function renderTree(tbl, compact)
-- create 3 or 1 rows for every team
local count = math.pow(2, rounds) * ((compact and 0 or 2) + sets)
local rows = {}
for i = 1, count do
rows[i] = addTableRow(tbl)
end
if not compact then
-- fill rows with groups
for r = 1, rounds - 1 do
renderGroups(rows, count, r)
end
end
-- fill rows with bracket
for r = 1, rounds do
if compact then
renderCompactRound(rows, count, r)
else
renderRound(rows, count, r)
end
end
end
function renderHeading(tbl, compact)
local titleRow = addTableRow(tbl)
local widthRow = addTableRow(tbl)
for r = 1, rounds do
addBlank(titleRow)
addBlank(widthRow, r > 1 and '5px' or nil)
titleRow:tag('td')
:attr('colspan', tonumber(showSeeds and '2' or '1') + sets)
:css('text-align', 'center')
:css('border', '1px solid #aaa')
:css('background-color', '#f2f2f2')
:wikitext(getRoundName(r))
:newline()
local seedCell
if showSeeds then
seedCell = addBlank(widthRow, getWidth('seed', '25px'))
end
local teamCell = addBlank(widthRow, getWidth('team', '150px'))
local scoreCells
for s = 1, sets do
scoreCell[s] = addBlank(widthRow, getWidth('score', '12px'))
end
addBlank(titleRow)
addBlank(widthRow, r < rounds and '5px' or nil)
if compact then
teamCell:css('height', '7px')
else
if seedCell then
seedCell:wikitext(' ')
end
teamCell:wikitext(' ')
for s = 1, sets do
scoreCell[s]:wikitext(' ')
end
end
end
end
function p.teamBracket(frame)
args = getArgs(frame)
rounds = tonumber(args.rounds) or 2
sets = tonumber(args.sets or 5) or 5
local teams = math.pow(2, rounds)
padding = '%0' .. (teams < 10 and 1 or 2) .. 'd'
showSeeds = true
if args['seeds'] and args['seeds'] == 'no' then
showSeeds = false
end
-- set default seeds for round 1
local seeds = getSeeds()
local argname
for i = 1, table.getn(seeds) do
argname = getTeamArgName(1, 'seed', i)
if not args[argname] then
args[argname] = seeds[i]
end
end
local tbl = mw.html.create('table')
:css('border-style', 'none')
:css('font-size', '90%')
:css('margin', '1em 2em 1em 1em')
:css('border-collapse', 'separate')
:css('border-spacing', '0')
local compact = false
if args['compact'] and args['compact'] == 'yes' then
compact = true
end
if compact then
tbl:css('font-size', '90%'):attr('cellpadding', '0')
end
renderHeading(tbl, compact)
renderTree(tbl, compact)
return tostring(tbl)
end
return p