Модуль:Турнирная сетка
Перейти к навигации
Перейти к поиску
Для документации этого модуля может быть создана страница Модуль:Турнирная сетка/doc
local p = {}
-- Функция для генерации блока одной игры
local function buildMatch(args, roundPrefix, matchNum)
local prefix = roundPrefix .. "-" .. matchNum
local date = args[prefix .. "-date"] or ""
local team1 = args[prefix .. "-team1"] or ""
local team2 = args[prefix .. "-team2"] or ""
local score1 = args[prefix .. "-score1"] or ""
local score2 = args[prefix .. "-score2"] or ""
local score1_2 = args[prefix .. "-score1-2"] -- Для второго матча (если 2 игры)
local score2_2 = args[prefix .. "-score2-2"] -- Для второго матча (если 2 игры)
-- Если команды не указаны, возвращаем пустой блок-заполнитель,
-- чтобы сохранить правильное расстояние в сетке
if team1 == "" and team2 == "" and date == "" then
return mw.html.create('div')
:addClass('bracket-match-empty')
:cssText('min-height: 65px; margin: 8px 0;')
end
local matchDiv = mw.html.create('div')
:addClass('bracket-match')
:cssText('border: 1px solid #aaa; border-radius: 4px; margin: 8px 0; background: #fff; overflow: hidden; font-size: 14px;')
if date ~= "" then
matchDiv:wikitext('<div style="background: #f0f0f0; padding: 2px 8px; font-size: 12px; color: #555; border-bottom: 1px solid #ddd;">' .. date .. '</div>')
end
-- Внутренняя функция для создания строки команды
local function createTeamRow(team, score, score2, isLast)
local style = 'display: flex; justify-content: space-between; padding: 5px 8px;'
if not isLast then
style = style .. ' border-bottom: 1px solid #eee;'
end
local row = mw.html.create('div'):cssText(style)
if team == "" then team = " " end
row:wikitext('<span style="flex-grow: 1;">' .. team .. '</span>')
local scoreSpan = mw.html.create('span'):cssText('font-weight: bold; margin-left: 10px; min-width: 15px; text-align: right;')
scoreSpan:wikitext(score ~= "" and score or " ")
row:node(scoreSpan)
-- Если есть второй матч (доп. параметр), выводим его рядом
if score2 then
local score2Span = mw.html.create('span'):cssText('color: #888; font-size: 12px; margin-left: 5px; min-width: 15px; text-align: right;')
score2Span:wikitext(score2)
row:node(score2Span)
end
return row
end
matchDiv:node(createTeamRow(team1, score1, score1_2, false))
matchDiv:node(createTeamRow(team2, score2, score2_2, true))
return matchDiv
end
function p.bracket(frame)
local args = frame:getParent().args
-- Количество раундов (5 = от 1/16 до финала, 4 = от 1/8 и т.д.)
local rounds = tonumber(args.rounds) or 5
-- Названия раундов
local rdNames = {
[1] = args["RD1-name"] or "1/16 финала",
[2] = args["RD2-name"] or "1/8 финала",
[3] = args["RD3-name"] or "1/4 финала",
[4] = args["RD4-name"] or "Полуфинал",
[5] = args["RD5-name"] or "Финал"
}
local finalName = args["Final-name"] or "Финал"
local thirdName = args["3rd-name"] or "Матч за 3-е место"
local isThird = args["3rd"]
local container = mw.html.create('div'):addClass('bracket-container')
container:cssText('display: flex; flex-direction: row; justify-content: center; align-items: stretch; width: 100%; font-family: sans-serif; overflow-x: auto;')
-- ЛЕВАЯ СТОРОНА
local leftSide = mw.html.create('div'):addClass('bracket-left')
leftSide:cssText('display: flex; flex-direction: row;')
for r = 1, rounds - 1 do
local roundDiv = mw.html.create('div'):addClass('bracket-round')
roundDiv:cssText('display: flex; flex-direction: column; width: 170px; min-width: 150px; margin: 0 5px;')
local headerDiv = mw.html.create('div'):cssText('text-align: center; font-weight: bold; margin-bottom: 15px; font-size: 15px; border-bottom: 2px solid #333; padding-bottom: 5px;')
headerDiv:wikitext(rdNames[r])
roundDiv:node(headerDiv)
local matchesContainer = mw.html.create('div'):cssText('display: flex; flex-direction: column; justify-content: space-around; flex-grow: 1;')
-- Количество матчей на одной стороне в данном раунде
local matchesInRound = 2^(rounds - r - 1)
for m = 1, matchesInRound do
matchesContainer:node(buildMatch(args, "RD" .. r, m))
end
roundDiv:node(matchesContainer)
leftSide:node(roundDiv)
end
-- ЦЕНТР (Финал и игра за 3-е место)
local center = mw.html.create('div'):addClass('bracket-center')
center:cssText('display: flex; flex-direction: column; justify-content: center; width: 190px; min-width: 170px; margin: 0 10px;')
-- Финал
local finalRound = mw.html.create('div')
local finalHeader = mw.html.create('div'):cssText('text-align: center; font-weight: bold; margin-bottom: 15px; font-size: 16px; border-bottom: 2px solid #333; padding-bottom: 5px;')
finalHeader:wikitext(finalName)
finalRound:node(finalHeader)
finalRound:node(buildMatch(args, "Final", 1))
-- Матч за 3-е место
if isThird then
local thirdRound = mw.html.create('div')
local thirdHeader = mw.html.create('div'):cssText('text-align: center; font-weight: bold; margin-bottom: 15px; font-size: 15px; border-bottom: 2px solid #aaa; padding-bottom: 5px; margin-top: 20px;')
thirdHeader:wikitext(thirdName)
thirdRound:node(thirdHeader)
thirdRound:node(buildMatch(args, "3rd", 1))
end
center:node(finalRound)
center:node(thirdRound)
-- ПРАВАЯ СТОРОНА
local rightSide = mw.html.create('div'):addClass('bracket-right')
rightSide:cssText('display: flex; flex-direction: row-reverse;')
for r = 1, rounds - 1 do
local roundDiv = mw.html.create('div'):addClass('bracket-round')
roundDiv:cssText('display: flex; flex-direction: column; width: 170px; min-width: 150px; margin: 0 5px;')
local headerDiv = mw.html.create('div'):cssText('text-align: center; font-weight: bold; margin-bottom: 15px; font-size: 15px; border-bottom: 2px solid #333; padding-bottom: 5px;')
headerDiv:wikitext(rdNames[r])
roundDiv:node(headerDiv)
local matchesContainer = mw.html.create('div'):cssText('display: flex; flex-direction: column; justify-content: space-around; flex-grow: 1;')
local matchesInRound = 2^(rounds - r - 1)
for m = 1, matchesInRound do
-- ИСПРАВЛЕНИЕ: Правая сторона нумеруется подряд после левой
local matchNum = matchesInRound + m
matchesContainer:node(buildMatch(args, "RD" .. r, matchNum))
end
roundDiv:node(matchesContainer)
rightSide:node(roundDiv)
end
container:node(leftSide)
container:node(center)
container:node(rightSide)
return tostring(container)
end
return p