Модуль:Турнирная сетка

Материал из Наро-Фоминский Футбол
Перейти к навигации Перейти к поиску

Для документации этого модуля может быть создана страница Модуль:Турнирная сетка/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 = "&nbsp;" 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 "&nbsp;")
        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