Module:RoundN: Difference between revisions

Content deleted Content added
mNo edit summary
per edit request on talk page - fix the node_function{orphan} bug
 
(29 intermediate revisions by 12 users not shown)
Line 4:
'Semi-finals',
'Final',
'Third Placeplace'
},
-- The text and background colors are paired and when you set one, you should set the other (accessibility)
textColor = {head = '#202122', '#202122', '#202122', '#202122', '#202122'},
bgColor = {head = '#f2f2f2', 'gold', 'silver', '#C96', '#f9f9f9'},
reuseStr = {},
saveStr = function(self, name, ...)
Line 14 ⟶ 17:
end
}
 
--Provides a convenient naming shortcut up to {{#invoke:RoundN|N512}} = {{invoke:RoundN|main|columns = 9}}
for columns = 1, 9 do
local N = math.pow(2, columns)
p['N' .. N] = function(frame)
return p.main(frame.args, columns)
end
p['n' .. N] = p['N' .. N]--to make case insensitive
end
 
--saves memory and avoids errors when using a nil as a table by providing a temporary table; if using nil as false; use 'table(k)' to look up table[k]
p.nilAsTab = {
Line 143 ⟶ 156:
end
 
local function newRow(bodyRow)
--Provides a convenient naming shortcut up to {{#invoke:RoundN|N512}} = {{invoke:RoundN|main|columns = 9}}
for columns = 1, 9 do
local N = math.pow(2, columns)
p['N' .. N] = function(frame)
return p.main(frame.args, columns)
end
p['n' .. N] = p['N' .. N]--to make case insensitive
end
 
function newRow(bodyRow)
local first = p.flex_tree.merge and mw.clone(p.flex_tree.cell) or p.flex_tree.cell
tab.r = tab:tag'tr'
Line 165 ⟶ 169:
end
 
local function drawHead(text, row3rd)
local td = (row3rd and rowNum[row3rd]:tag'td':attr{rowspan = 2}
or head.row:tag'td')
Line 173 ⟶ 177:
['text-align'] = 'center',
border = '1px solid #aaa',
['background-color'] = '#f2f2f2'p.bgColor.head,
color = p.textColor.head
}
end
end
 
local function spacer(width)
tab.r:tag'td'
:attr{width = width}
Line 184 ⟶ 189:
end
 
local function dpBox(v, r)
p.dpBoxBase = p.dpBoxBase or mw.html.create'td':attr{rowspan = 2, colspan = p.colspan}
if not v then
p.dpBoxEmpty = p.previewnumbers and mw.clone(p.dpBoxBase) or p.dpBoxEmpty or mw.clone(p.dpBoxBase):wikitext(p.flex_tree.wt)
rowNum[r]:node(p.dpBoxEmpty)
else
Line 213 ⟶ 218:
end,
spin = function(self, v)
table.insert(self, v)
return self
end,
Line 247 ⟶ 252:
}
 
local function boldWin(s1, s2)
return setmetatable(
p.bold and s1 ~= s2 and (math[({'min', 'max'})[p.bold]](s1, s2) == s1 and {true} or {[2] = true}) or callableEmpty,
Line 254 ⟶ 259:
end
 
local function maxSpan(span, start, rows)
return math.min(span, math.max(0, rows - start + 1))
end
Line 260 ⟶ 265:
--in case of templates like RDseed need padding value
p.teamBoxPadding = function()
return '.6ex'
end
p:saveStr('tbpad',.teamBoxPadTab = {padding = '0 ', .. p.teamBoxPadding())}
p.teamBoxNormal = {border = '1px solid #aaa', ['background-color'] = p.bgColor[4], color = p.textColor[4]}
function teamBox(v, r, f)
local function teamBox(v, r, f)
if p.flex_tree.merge and not v and f.phase == 2 then
for i = -2, 0 do
Line 275 ⟶ 281:
if not p.bold then
--backwards compatability (wikitemplates bold each arg individually)
local hasBold, b = tostring(v):gsub("([^']*)'''([^']*)", '%1%%s<b>%2</b>')
if b == 1 then
v = hasBold:format('<b>')
end
end
local cell
if f[1] then
cell = f.sumBox and f.sumBox[1] and
{padding = f.sumBox[1]}
or {['border-left'] = f.borderLeft}
cell['text-align'] = v and f[1]
else
cell = p.teamBoxPadTab
end
local text = v or f[1] and '' or '&nbsp;'
if f.bold then
text = mw.ustring.gsub(text, '(%(%[%[[^%[%]]*%]%]%))', '<span style="font-weight:normal">%1</span>')
end
tab.r = rowNum[r]:tag'td'
:css{(p.teamBoxCSS)
:css(cell)
border = '1px solid #aaa',
background = ({'gold', 'silver', '#C96', '#f9f9f9'})[f.color and f.phase or 4],
[f[1] and 'text-align' or 'padding'] = f[1] or p.reuseStr.tbpad,
}
:css{
padding = f.sumBox and f.sumBox[1],
['border-left'] = f.borderLeft,
}
:attr{rowspan = 2}
:node(mw.html.create(f.bold and 'b'):wikitext(v or '&nbsp;'text))
end
end
Line 317 ⟶ 329:
local mType, mNum = string.match(k, '^(%l+)match(%d*)$')
mType, mNum = ({skip = skipMatch, manualbold = unBold})[mType], tonumber(mNum)
if mType then
if mNum then
mType[mNum] = args:clean(k) == 'yes' or args[k] == 'true'
Line 340 ⟶ 352:
for _, v in ipairs({--more args to boolean
'widescore',
'template',
'color',
'color_repechage',
'3rdplace',
'omit_blanks',
Line 355 ⟶ 367:
end
end
p.namespace = mw.title.getCurrentTitle().namespace
p.previewnumbers = p.namespace ~= 0 and p.previewnumbers
p.scoreWasher:init(args['score-clean'])
p.scoreWasher.demo = args.demoWash and tonumber(args:clean('demoWash', {pattern = '%D'}), 10)
Line 362 ⟶ 376:
p.scoreBoxes = (tonumber(args:clean('score-boxes', {pattern = '%D'})) or 1) + sumBox
p.scoreSumBox = p.scoreBoxes > 0 and p.scoreSumBox or nil
local boxStyle = p.scoreBoxes > 1 and
(p.scoreSumBox and
setmetatable(
{{}, [p.scoreBoxes] = {'0 1ex'}},
{__call = function(t, i) if t[i] then return nil end return 0 end}
)
or setmetatable(
{},
{__call = function() return 0 end}
)
)
or setmetatable({}, {__call = function() return nil end})
p.colspan = p.scoreBoxes > 0 and (p.scoreBoxes + 1) or nil
local nodeArgs = {
Line 404 ⟶ 430:
end
tab
:cssText(table.concat{args.scroll_height and 'padding' or 'margin', ':', fontSize and (math.ceil(fontSize * 10) / 10) or '.9', 'em 2em 1em 1em;border:0;', fontSize and '' or 'font-size:90%;border-collapse:separate;', args.style})
:attr{cellpadding = 0, cellspacing = 0}
if not p.no_column_head then--headings row
Line 411 ⟶ 437:
:css{['white-space'] = args.scroll_height and 'nowrap'}
newRow()
else
tab.r = tab:tag'tr'
tab.r:tag'td'
Line 430 ⟶ 456:
setmetatable(scoreWidth, _scoreWidth)
end
 
if p.template then
p.template = mw.title.new(args.name)
p.templateFixedName = (p.template.namespace == 0 and 'Template:' or '') .. p.template.fullText
end
p.template = p.template and mw.title.new(args:clean('name', {pattern = ''}))
local head_br = {
count = 0,
Line 462 ⟶ 484:
or p.RD[#p.RD + k - p.tCols - 1]
or ('Round of ' .. math.pow(2, p.tCols - k + 1))
drawHead(head.wt)
k == 1 and p.template and mw.getCurrentFrame():expandTemplate{
title = 'tnavbar-header',
args = {head.wt, p.templateFixedName}
} or head.wt
)
end
end
Line 503 ⟶ 520:
rowNum[1]:node(c < p.cols and
mw.clone(bumpBase):attr{rowspan = bump}
or p.no_column_head and p.template and
mw.html.create'td':wikitext(mw.getCurrentFrame():expandTemplate{
title = 'tnavbar-header',
args = {'', p.templateFixedName}
})
)
end
Line 513 ⟶ 525:
col.top = m.num
p.span = p.tCols > c and bump * 2 or p.branch_upwards or math.max((bump - 1) / 2, 2)
col.color_repechage = p['color_repechage'] and ((c == p.tCols) or ((c == p.tCols-1) and skipMatch[math.pow(2, p.tCols) - 1]))
col.show3rd = p['3rdplace'] and c == p.tCols and rowNum.third
local colorFinal, bumpMid = p.color and c == p.tCols, p.span > 0 and mw.clone(bumpBase):attr{rowspan = p.span} or nil
Line 562 ⟶ 575:
col.show3rd = (m.num - col.top) * 2
if col.show3rd == 2 then
if p.textThird:match('omit_label') then
p.textThird = nil
Line 569 ⟶ 581:
rowNum[rows + 1]:tag'td':attr{
rowspan = m.r + 9 - rows - (text and 0 or 2),
colspan = (p.cols - 1) * 4(3 + p.scoreBoxes)
}
end
Line 586 ⟶ 598:
end
end
dpBox(nodeFunc.pattern and nodeFunc.nonFunc or args[step], m.r, skipMatch[m.num])
if p.previewnumbers then
rowNum[m.r].nodes[#rowNum[m.r].nodes]
p.namespace = p.namespace or mw.title.getCurrentTitle().namespace
if p.namespace ~= 0 then :tag'div'
tab.r:tag'div'
:css{
float = 'left',
Line 599 ⟶ 610:
:wikitext(m.num)
:attr{title = 'Number only visible outside article space (e.g. template) when |numberpreview=yes'}
end
end
end
Line 615 ⟶ 625:
clean = {}
}
local notSummed = not p.scoreSumBox or #m.nonEmpty ==< 12
for s, i in ipairs(m.nonEmpty) do
m.bold.clean[s] = {p.scoreWasher:main(args[i[1]]), p.scoreWasher:main(args[i[2]])}
m.bold.box[s] = notSummed and boldWin(m.bold.clean[s][1], m.bold.clean[s][2]) or setmetatable({}, p.nilAsTab)callableEmpty
end
if notp.scoreSumBox notSummedand m.nonEmpty[2] then
local i = {-step, -step - 1}
table.insert(m.nonEmpty, i)
Line 626 ⟶ 636:
m.bold.box[p.scoreBoxes] = boldWin(args[i[1]], args[i[2]])
end
m.boldgetmetatable(boxStyle).win__index = m.boldp.boxscoreSumBoxes and {[#m.nonEmpty] or setmetatable({},= boxStyle[p.nilAsTab)scoreBoxes]}
m.bold.win = m.bold.box[#m.nonEmpty] or callableEmpty
else
m.bold = infiniteEmpty
Line 633 ⟶ 644:
else
if m.showBox[m.phase] then
if col.color_repechage then
local base = {color = colorFinal, phase = m.phase + (col.show3rd or 0)}
col.color_repechage = 2
teamBox(args[step + nodeArgs.team[m.phase]], m.r, setmetatable(base, {__index = {bold = m.bold.win(m.phase)}}))
if p.colspan thenend
if #mp.nonEmpty == 0bold then
if m.bold.win(m.phase) and (colorFinal or col.color_repechage) then
for s = 1, p.scoreBoxes do
color_index = 1 + (col.show3rd or 0) + (col.color_repechage or 0)
teamBox('', m.r, base)
elseif m.bold.box[#m.nonEmpty] then
end
color_index = 2 + (col.show3rd or 0) + (col.color_repechage or 0)
else
color_index = 4
end
p.teamBoxCSS = (colorFinal or col.color_repechage) and
{border = p.teamBoxNormal.border, ['background-color'] = p.bgColor[color_index], color = p.textColor[color_index]}
or p.teamBoxNormal
else
p.teamBoxCSS = (colorFinal or col.color_repechage) and
{border = p.teamBoxNormal.border, ['background-color'] = p.bgColor[m.phase + (col.show3rd or 0) + (col.color_repechage or 0)], color = p.textColor[m.phase + (col.show3rd or 0) + (col.color_repechage or 0)]}
or p.teamBoxNormal
end
local f = {phase = m.phase, bold = m.bold.win(m.phase)}
teamBox(args[step + nodeArgs.team[m.phase]], m.r, f)
f[1] = 'center'
if p.colspan then
if m.nonEmpty[1] then
local loneSum
if #m.nonEmpty < p.scoreBoxes then
loneSum = #m.nonEmpty == 1 and boxStyle[p.scoreBoxes]
tab.r:attr{colspan = 1 + p.scoreBoxes - #m.nonEmpty}
end
local thinLeft = p.scoreSumBox and {[1] = {}, [#m.nonEmpty] = {'0 1ex'}} or {}
for s, i in ipairs(m.nonEmpty) do
f.borderLeft = boxStyle(s)
teamBox(args[i[m.phase]], m.r, setmetatable(base, {__index = {'center', borderLeft = not thinLeft[s] and 0 or nil, sumBox = thinLeft[s], bold = m.bold.box[s](m.phase)}}))
f.sumBox = loneSum or boxStyle[s]
f.bold = m.bold.box[s](m.phase)
teamBox(args[i[m.phase]], m.r, f)
end
else
for s = 1, p.scoreBoxes do
f.borderLeft = boxStyle(s)
teamBox(nil, m.r, f)
end
end
Line 653 ⟶ 689:
if m.phase == 2 then
col.show3rd = col.show3rd ~= 2 and col.show3rd or nil
if p.scoreWasher.demo and p.scoreWasher.demo == m.num and mw.title.getCurrentTitle()p.namespace ~= 0 then
table.insert(m.bold.clean, 1, {args[step + nodeArgs.team[1]], args[step + nodeArgs.team[2]]})
return table.concat{
Line 695 ⟶ 731:
end
col.n = 0
col.t2 = nil
for r = bumps + 1, rows, p.unit * 2 do
tab.r = rowNum[r]:tag'td'
Line 703 ⟶ 740:
col.n = col.n + 2
col.t2 = skipMatch[col.tot + col.n / 2 + 1] and 3 or ((skipMatch[col.top + col.n] and 1 or 0) + (skipMatch[col.top + col.n + 1] and 2 or 0))
if col.t == 0 then --draws the ']' when a PAIR of matches needs lines
tab.r
:attr{rowspan = maxSpan(p.unit * 2, r, rows)}
Line 710 ⟶ 747:
['border-left'] = 0
})
else --draws the lines when only top OR bottom match need lines
else
tab.r
:attr{rowspan = maxSpan(p.unit, r, rows)}
:cssText(col.t == 2 and
p:saveStr('topRight', 'border-width:', tab.line[2], ' 0 0;border-style:solid')
or col.t == 1 and (nodeFunc.bridge.lay[c](col.n - 2) and
Line 796 ⟶ 833:
function p.seed(frame)
local parent = frame:getParent() or frame
local function arg(k, alt)
return parent.args[k] or frame.args[k] or alt
end
Line 804 ⟶ 841:
return mw.html.create'div'
:css{
margin = ('-1px %s -1px -%s0.7ex'):format(padding, padding),
float = 'left',
['background-color'] = '#f2f2f2'p.bgColor.head,
border = '1px solid #aaa',
color = p.textColor.head,
['text-align'] = 'center',
width = width