Edge Rewrite
// HTMLRewriter · presentation

This page was redesigned at the edge.

Cloudflare fetched the original article and streamed it through HTMLRewriter to apply an entirely new visual system without rebuilding the source page.

Jump to content

Module:Build bracket/StateChecks

Permanently protected module
From Wikipedia, the free encyclopedia
local StateChecks = {}

-- =========================
-- 1) MODULE BINDINGS
-- =========================
-- Bound at runtime
local state, config, Helpers

-- Local aliases (filled in bind; with fallbacks)
local isempty, notempty

function StateChecks.bind(_state, _config, _Helpers)
    state, config, Helpers = _state, _config, _Helpers
    isempty  = (Helpers and Helpers.isempty)  or function(v) return v == nil or v == "" end
    notempty = (Helpers and Helpers.notempty) or function(v) return v ~= nil and v ~= "" end
end

-- =========================
-- 2) CONTENT CHECKS
-- =========================
-- True when the entry at (col,row) is empty for rendering purposes.
-- For 'team' → check team text; for 'text' → check text; everything else counts as blank.
function StateChecks.isBlankEntry(col, row)
    local colEntries = state.entries and state.entries[col]
    if not colEntries then return true end

    local e = colEntries[row]
    if not e then return true end

    local ct = e.ctype
    if ct == "team" then
        return isempty(e.team)
    elseif ct == "text" then
        return isempty(e.text)
    end
    -- headers/lines/blanks or anything else are non-content here
    return true
end

-- =========================
-- 3) SEED VISIBILITY
-- =========================
-- Show seeds when forced, when this team has a seed, or when any teammate in the same match has a seed.
function StateChecks.showSeeds(j, i)
    local col = state.entries and state.entries[j]
    if not col then return false end

    local e = col[i]
    if not e or e.ctype ~= "team" then return false end

    if config.forceseeds or notempty(e.seed) then
        return true
    end

    local group = e.group
    local tpm   = state.teamsPerMatch[j] or 2
    if tpm <= 1 then return false end

    -- Teams are laid out every 2 rows per match.
    local step  = 2
    local R     = config.r

    local function neighborHasSeed(idx)
        local n = col[idx]
        return n and n.ctype == "team" and n.group == group and notempty(n.seed)
    end

    -- Check teammates forward/back within the match block
    for k = 1, tpm - 1 do
        local plus  = i + step * k
        local minus = i - step * k
        if plus  <= R and neighborHasSeed(plus)  then return true end
        if minus >= 1 and neighborHasSeed(minus) then return true end
    end

    return false
end

-- =========================
-- 4) ROUND VISIBILITY (HIDE)
-- =========================
-- Mutates state.hide[j][hidx] to false when content is found under a header (keeps legacy semantics).

function StateChecks.teamLegs(j, i)
    local col          = state.entries and state.entries[j]
    local roundDefault = (state.rlegs and state.rlegs[j]) or 1
    if not col then return roundDefault end

    local e = col[i]
    if not e or e.ctype ~= "team" then return roundDefault end

    local legs = roundDefault
    if notempty(e.legs) then
        legs = tonumber(e.legs) or legs
    end

    -- Treat nil/'' and strings containing 'nbsp' as blank
    local function isScoreBlank(v)
        if isempty(v) then return true end
        return type(v) == "string" and v:find("nbsp", 1, true) ~= nil
    end

    if config.autolegs and e.score then
        local l = 1
        while not isScoreBlank(e.score[l]) do
            l = l + 1
        end
        local inferred = l - 1
        if inferred > 0 then
            legs = inferred
        end
    end

    return legs
end

-- =========================
-- 6) ROUND CONTENT CHECK
-- =========================
-- Used for 'byes' detection: true when there is no content until the next header (or end).
function StateChecks.roundIsEmpty(j, i)
    local col = state.entries and state.entries[j]
    if not col then return true end

    local row, R = i + 1, config.r
    while row <= R do
        local e = col[row]
        if e and e.ctype == "header" then break end
        if not StateChecks.isBlankEntry(j, row) then
            return false
        end
        row = row + 1
    end
    return true
end

-- =========================
-- 7) DEFAULT HEADER TEXT
-- =========================
-- Default header text when none provided (keeps legacy strings).
function StateChecks.defaultHeaderText(j, headerindex)
    if headerindex ~= 1 then
        return "Lower round " .. tostring(j)
    end

    local base    = config.base or 0
    local orig_j  = j + base
    local total   = config.c_total or (config.c + base)
    local rem     = total - orig_j

    if rem == 0 then
        return "Final"
    elseif rem == 1 then
        return "Semifinals"
    elseif rem == 2 then
        return "Quarterfinals"
    else
        return "Round " .. tostring(orig_j)
    end
end

-- =========================
-- 8) PATH PRESENCE CHECK
-- =========================
-- True when the path block between j → j+1 at row i has no visible lines at all.
function StateChecks.noPaths(j, i)
    local hasCross = state.hascross and state.hascross[j]
    local cols     = hasCross and 3 or 2

    -- Path cells: any nonzero border means a path
    local pcj = state.pathCell and state.pathCell[j]
    local pci = pcj and pcj[i]
    if pci then
        for k = 1, cols do
            local edges = pci[k] and pci[k][1]
            if edges and (
                (edges[1] and edges[1] ~= 0) or
                (edges[2] and edges[2] ~= 0) or
                (edges[3] and edges[3] ~= 0) or
                (edges[4] and edges[4] ~= 0)
            ) then
                return false
            end
        end
    end

    -- Cross cells: left/right flag at index 1 means a cross path
    if hasCross then
        local ccj = state.crossCell and state.crossCell[j]
        local cci = ccj and ccj[i]
        if cci then
            local left, right = cci.left, cci.right
            if (left and left[1] == 1) or (right and right[1] == 1) then
                return false
            end
        end
    end

    return true
end

return StateChecks