Module:Sports results

Moduledocumentatie​[bekijk] [bewerk] [ververs] [geschiedenis]

-- Module to build results cross-tables for standings in Sports
-- See documentation for details

require('Module:No globals')

local p = {}

-- Main function
function p.main(frame)
        -- Get the args, stripping out blank values
        local getArgs = require('Module:Arguments').getArgs
        local Args = getArgs(frame, {parentFirst = true})

        -- Exit early if we are using section transclusion for a different section
        if (Args['transcludesection'] and Args['section'])
                and Args['transcludesection'] ~= Args['section'] then
                return ''
        end

        -- Declare locals
        local t = {}
        local t_footer = {}
        local t_return = {}
        local team_list = {}
        local notes_exist = false
        local ii, ii_fw, bg_col, team_name, team_code_ii, ii_start, ii_end
        -- Optional custom team header
        local team_header = Args['team_header'] or 'Thuis \\ Uit'
        -- Number of legs
        local legs = tonumber(Args['legs']) or 1
        local multirowlegs = (Args['multirowlegs'] or 'no') ~= 'no'

        -- Edit links if requested
        local baselink = frame:getParent():getTitle()
        if mw.title.getCurrentTitle().text == baselink then  baselink = '' end
        local template_name = Args['template_name']
                or (baselink ~= '' and (':' .. baselink))
                or ''
        local edit_links = template_name == '' and ''
                or require('Module:Navbar')._navbar({
                        template_name,
                        mini=1,
                        style='float:right',
                        brackets=1
                })

        -- Get the custom start point for the table (most will start by default at 1)
        local top_pos = tonumber(Args['highest_pos']) or 1
        -- Get the custom end point for the table (unrestricted if bottom_pos is < top_pos)
        local bottom_pos = tonumber(Args['lowest_pos']) or 0
        local N_teams = top_pos - 1 -- Default to 0 at start, but higher number needed to skip certain entries

        -- Load some other modules
        local p_sub = require('Module:Sports table/sub')

        -- Alternative syntax for team list
        if Args['team_order'] and Args['team_order'] ~= '' then
                local tlist = mw.text.split(Args['team_order'], '%s*[;,]%s*')
                for k, tname in ipairs(tlist) do
                        if tname ~= '' then
                                Args['team' .. k] = tname
                        end
                end
        end

        if Args['team_header_note'] then
                notes_exist=true
                local note_string = frame:expandTemplate{ title = 'refn',
                                                             args = { group='kleine-letter', Args['team_header_note']} }
                team_header = team_header .. note_string
        end

        -- Read in number of consecutive teams (ignore entries after skipping a spot)
        ii_start = N_teams
        while Args['team'..N_teams+1] ~= nil and (bottom_pos < top_pos or N_teams < bottom_pos) do
                N_teams = N_teams+1
                -- Sneakily add it twice to the team_list parameter, once for the actual
                -- ranking, the second for position lookup in sub-tables
                -- This is possible because Lua allows both numbers and strings as indices.
                team_list[N_teams] = Args['team'..N_teams] -- i^th entry is team X
                team_list[Args['team'..N_teams]] = N_teams -- team X entry is position i
        end
        ii_end = N_teams
        -- Get team to show
        local ii_show = team_list[Args['showteam']] -- nil if non-existant

        -- Set the font size
        local font_size=Args['font_size'] or '100%'

        -- Create header
        -- Open table
        table.insert(t,'{|class="wikitable plainrowheaders" style="text-align:center;font-size:'..font_size..';"\n')
        -- Table title
        if Args['title'] then
                table.insert(t,'|+ ' .. Args['title'] .. '\n')
        end
        -- First column
        t_return.count = 0                      -- Dummy parameter, using subfunction call seems best at this point because both module are intertwined
        t_return.tab_text = t           -- Actual text
        t_return = p_sub.colhead(t_return,'auto', edit_links .. ' ' .. team_header)
        -- Other columns passed to subfunction
        t_return = p.header(t_return,Args,p_sub,N_teams,team_list,legs,multirowlegs)
        t = t_return.tab_text

        -- Random value used for uniqueness
        math.randomseed( os.clock() * 10^8 )
        local rand_val = math.random()

        local note_string, note_id
        local note_id_list = {}

        -- Now create individual rows
        ii_start = tonumber(Args['highest_row']) and (tonumber(Args['highest_row']) > top_pos) and tonumber(Args['highest_row']) or top_pos
        ii_end = tonumber(Args['lowest_row']) and (tonumber(Args['lowest_row']) < N_teams) and tonumber(Args['lowest_row']) or N_teams
        for ii=ii_start,ii_end do
                -- Get team info
                team_code_ii = team_list[ii]
                team_name = Args['name_'..team_code_ii] or team_code_ii
                local ii_style = 'text-align:' .. (Args['team_align'] or 'right') .. ';'
                        .. (ii and ii == ii_show and 'font-weight:bold;' or '')
                        .. (Args['team_nowrap'] and 'white-space:nowrap;' or '')
                local team_note = Args['note_'..team_code_ii]
                if team_note then
                        notes_exist = true
                        -- Only when it exist
                        -- First check for existence of reference for note
                        if not Args['note_'..team_note] then
                                -- It's the entry
                                -- Add random end for unique ID if more tables are present on article (which might otherwise share an ID)
                                note_id = '"table_note_'..team_code_ii..rand_val..'"'
                                note_id_list[team_code_ii] = note_id
                                note_string = frame:expandTemplate{ title = 'refn',
                                        args = { group='kleine-letter', name=note_id,  team_note} }
                        else
                                -- Check for existence elsewhere
                                local note_local_num = team_list[team_note] or ii_end + 1
                                if note_id_list[team_note] or ((note_local_num >= ii_start) and (note_local_num <= ii_end)) then
                                        -- It exists
                                        note_id = '"table_note_'..team_note..rand_val..'"' -- Identifier
                                        note_string = frame:extensionTag{ name = 'ref',
                                                args = { group = 'kleine-letter', name = note_id} }
                                else
                                        -- Now define the identifier for this
                                        -- Add random end for unique ID
                                        note_id = '"table_note_'..team_note..rand_val..'"'
                                        note_id_list[team_note] = note_id
                                        -- Call refn template
                                        note_string = frame:expandTemplate{ title = 'refn',
                                                args = { group='kleine-letter', name=note_id, Args['note_'..team_note]} }
                                end
                        end
                        -- Now append this to the team_name string
                        team_name = team_name..note_string
                end
                -- Team names
                table.insert(t,'|- \n')  -- New row
                table.insert(t,'! scope="row"'.. (multirowlegs and ' rowspan=' .. legs or '')
                        .. 'style="'.. ii_style ..'"| '..team_name..'\n')  -- Position number

                -- Now include note to match results if needed
                for jj=top_pos,N_teams do
                        local team_code_jj = team_list[jj]
                        if ii == jj then
                                -- Nothing
                        else
                                for l=1,legs do
                                        local m = (legs == 1) and 'match_' or 'match' .. l .. '_'
                                        local match_note = Args[m ..team_code_ii..'_'..team_code_jj..'_note']
                                        if match_note then
                                                notes_exist = true
                                                -- Only when it exist
                                                -- First check for existence of reference for note
                                                if not (Args['note_'..match_note] or Args[m ..match_note..'_note']) then
                                                        -- It's the entry
                                                        -- Add random end for unique ID if more tables are present on article (which might otherwise share an ID)
                                                        note_id = '"table_note_'..team_code_ii..'_'..team_code_jj..rand_val..'"'
                                                        note_id_list[team_code_ii..'_'..team_code_jj] = note_id
                                                        note_string = frame:expandTemplate{ title = 'refn',
                                                             args = { group='kleine-letter', name=note_id,  match_note} }
                                                else
                                                        -- Check for existence elsewhere
                                                        local note_local_num = team_list[match_note] or ii_end + 1
                                                        if note_id_list[match_note] or ((note_local_num >= ii_start) and (note_local_num <= ii_end)) then
                                                             -- It exists
                                                             note_id = '"table_note_'..match_note..rand_val..'"' -- Identifier
                                                             note_string = frame:extensionTag{ name = 'ref',
                                                             args = { group = 'kleine-letter', name = note_id} }
                                                        else
                                                             -- Now define the identifier for this
                                                             -- Add random end for unique ID
                                                             note_id = '"table_note_'..match_note..rand_val..'"'
                                                             note_id_list[match_note] = note_id
                                                             -- Call refn template
                                                             note_string = frame:expandTemplate{ title = 'refn',
                                                             args = { group='kleine-letter', name=note_id, Args['note_'..match_note]} }
                                                        end
                                                end
                                                -- Now append this to the match result string
                                                Args[m..team_code_ii..'_'..team_code_jj] = (Args[m..team_code_ii..'_'..team_code_jj] or '–')..note_string
                                        end
                                end
                        end
                end
                -- Then individual results
                t = p.row(t,Args,N_teams,team_list,ii,ii_show,legs,multirowlegs)
        end

        -- Close table
        table.insert(t, '|}\n')

        -- Get info for footer
        local update = Args['update']
                or 'unknown'
        local start_date = Args['start_date']
                or 'unknown'
        local source = Args['source'] or Args['bron']
                or '<sup class="noprint nopopups">[[Wikipedia:Bronvermelding#Bron gevraagd|<span title="Geen source/bron parameter gedefinieerd">[bron?]</span>]]</sup>'

        -- Create footer text
        -- Date updating
        if string.lower(update)=='complete' then
                -- Do nothing
        elseif update=='' then
                -- Empty parameter
                table.insert(t_footer,'Bijgewerkt tot wedstrijden gespeeld op onbekend. ')
        elseif string.lower(update)=='future' then
                -- Future start date
                table.insert(t_footer,'De eerste wedstrijden word(t/en) gespeeld op '..start_date..'. ')
        else
                table.insert(t_footer,'Bijgewerkt tot wedstrijden gespeeld op '..update..'. ')
        end
        table.insert(t_footer,'Bron: '..source)
        if (Args['matches_style'] or '') == 'FBR' then
                table.insert(t_footer, Args['team_header']
                        and '<br />Kleuren: groen - winst ploeg in linkerkolom; blauw - gelijkspel; rood - winst ploeg in toprij.'
                        or '<br />Kleuren: groen - winst thuisploeg; blauw - gelijkspel; rood - verlies thuisploeg.')
        elseif (Args['matches_style'] or '') == 'BSR' then
                table.insert(t_footer, Args['team_header']
                        and '<br />Kleuren: groen - winst ploeg in linkerkolom; rood - winst ploeg in toprij.'
                        or '<br /><br />Kleuren: groen - winst thuisploeg; rood - verlies thuisploeg.')
        end
        if Args['a_note'] then
                table.insert(t_footer, '<br />Voor toekomstige wedstrijden, duidt een "a" aan, dat er een artikel bestaat over de rivaliteit tussen twee ploegen.')
        end
        if Args['ot_note'] then
                table.insert(t_footer, '<br />Uitslagen met een lichtere achtergrondkleur zijn in de verlenging beslist.')
        end

        local templatestyles = frame:extensionTag{
                name = 'templatestyles', args = { src = 'Module:Sports results/styles.css' }
        }

        -- Add notes (if applicable)
        if notes_exist then
                table.insert(t_footer,'<br>Noten:')
                t_footer = templatestyles .. '<div class="sports-results-notes">'..table.concat(t_footer)..'</div>'
                t_footer = t_footer..frame:expandTemplate{ title = 'references', args = { group='kleine-letter'} }
        else
                t_footer = templatestyles .. '<div class="sports-results-notes">'..table.concat(t_footer)..'</div>'
        end

        -- Add footer to main text table
        table.insert(t,t_footer)

        -- Rewrite anchor links
        for k=1,#t do
                if t[k]:match('%[%[#[^%[%]]*%|') then
                        t[k] = mw.ustring.gsub(t[k], '(%[%[)(#[^%[%]]*%|)', '%1' .. baselink .. '%2')
                end
        end

        return '<div style="overflow:hidden">'
                .. '<div class="noresize overflowbugx" style="overflow:auto">\n'
                .. table.concat(t) .. '</div></div>'
end

-- Other functions
local function get_short_name(s, t, n, ss)
        -- return short name if defined
        if s and s ~= '' then
                return s
        end
        -- deflag if necessary
        if ss and n then
                if ss == 'noflag' then
                        n = mw.ustring.gsub(n, '%[%[[Ff][Ii][Ll][Ee]:[^%[%]]*%]%]', '')
                elseif ss == 'flag' then
                        n = mw.ustring.gsub(n, '(<span class="flagicon">%s*%[%[[Ff][Ii][Ll][Ee]:[^%[%]]*link=)[^%|%[%]]*(%]%][^<>]*</span>)%s*%[%[([^%[%]%|]*)%|[^%[%]]*%]%]', '%1%3%2')
                        n = mw.ustring.gsub(n, '.*(<span class="flagicon">%s*%[%[[Ff][Ii][Ll][Ee]:[^%[%]]*%]%][^<>]*</span>).*', '%1')
                        n = mw.ustring.gsub(n, '&nbsp;(</span>)', '%1')
                end
        end

        -- replace link text in name with team abbr if possible
        if n and t and n:match('(%[%[[^%[%]]*%]%])') then
                n = mw.ustring.gsub(n, '(%[%[[^%|%]]*%|)[^%|%]]*(%]%])', '%1' .. t .. '%2')
                n = mw.ustring.gsub(n, '(%[%[[^%|%]]*)(%]%])', '%1|' .. t .. '%2')
                n = mw.ustring.gsub(n, '(%[%[[^%|%]]*%|)([A-Z][A-Z][A-Z])(%]%])&nbsp;<span[^<>]*>%([A-Z][A-Z][A-Z]%)</span>', '%1%2%3')
                return n
        end
        -- nothing worked, so just return the unlinked team abbr
        return t or ''
end

local function get_score_background(s, c)
        local s1, s2
        -- Define the colouring
        local wc, lc, tc
        if c == 'level2' then
        wc, lc, tc = '#CCF9CC', '#FFCCCC', '#CCF9FF' -- groen2, red2, blue2
        elseif c == 'level3' then
        wc, lc, tc = '#DDFCDD', '#FFDDDD', '#DDFCFF' -- groen3, red3, blue3
        elseif c == 'level4' then
        wc, lc, tc = '#EEFFEE', '#FFEEEE', '#EEFFFF' -- groen4, red4, blue4
        else
        wc, lc, tc = '#BBF3BB', '#FFBBBB', '#BBF3FF' -- groen1, red1, blue1
        end

        -- check for override
        if s:match('^%s*<span%s%s*style%s*=["\'%s]*background[%-colr]*%s*:([^\'";<>]*).-$') then
                local c = mw.ustring.gsub(s,'^%s*<span%s%s*style%s*=["\'%s]*background[%-colr]*%s*:([^\'";<>]*).-$', '%1')
                return c
        end

        -- delink if necessary
        if s:match('^%s*%[%[[^%[%]]*%|([^%[%]]*)%]%]') then
                s = s:match('^%s*%[%[[^%[%]]*%|([^%[%]]*)%]%]')
        end
        if s:match('^%s*%[[^%[%]%s]*%s([^%[%]]*)%]') then
                s = s:match('^%s*%[[^%[%]%s]*%s([^%[%]]*)%]')
        end
        if s:match('<span[^<>]*>(.-)</span>') then
                s = s:match('<span[^<>]*>(.-)</span>')
        end

        -- get the scores
        s1 = tonumber(mw.ustring.gsub( s or '',
                '^%s*([%d%.][%d%.]*)%s*–%s*([%d%.][%d%.]*).*', '%1' ) or '') or ''
        s2 = tonumber(mw.ustring.gsub( s or '',
                '^%s*([%d%.][%d%.]*)%s*–%s*([%d%.][%d%.]*).*', '%2' ) or '') or ''

        -- return colouring if possible
        if s1 ~= '' and s2 ~= '' then
                return (s1 > s2) and wc or ((s2 > s1) and lc or tc)
        else
                return 'transparent'
        end
end

local function format_score(s)
        s = mw.ustring.gsub(s or '', '^%s*([%d%.]+)%s*[–−—%-]%s*([%d%.]+)', '%1–%2')
        s = mw.ustring.gsub(s, '^%s*([%d%.]+)%s*&[MmNn][Dd][Aa][Ss][Hh];%s*([%d%.]+)', '%1–%2')
        s = mw.ustring.gsub(s, '^%s*(%[%[[^%[%]]*%|[%d%.]+)%s*%-%s*([%d%.]+)', '%1–%2')
        s = mw.ustring.gsub(s, '^%s*(%[[^%[%]%s]*%s+[%d%.]+)%s*%-%s*([%d%.]+)', '%1–%2')
        s = mw.ustring.gsub(s, '^%s*(%[%[[^%[%]]*%|[%d%.]+)%s*&[MmNn][Dd][Aa][Ss][Hh];%s*([%d%.]+)', '%1–%2')
        s = mw.ustring.gsub(s, '^%s*(%[[^%[%]%s]*%s+[%d%.]+)%s*&[MmNn][Dd][Aa][Ss][Hh];%s*([%d%.]+)', '%1–%2')
        return s
end

function p.header(tt,Args,p_sub,N_teams,team_list,legs,multirowlegs)
        local ii, team_code_ii, short_name
        legs = legs or 1

        -- Set match column width
        local col_width = Args['match_col_width'] or '28'

        -- Get some default values in case it doesn't start at 1
        local top_pos = tonumber(Args['highest_pos']) or 1

        for l=1,legs do
                if multirowlegs and l > 1 then
                        break
                end
                for ii=top_pos,N_teams do
                        team_code_ii = team_list[ii]
                        short_name = get_short_name(Args['short_'..team_code_ii],
                                team_code_ii, Args['name_'..team_code_ii], Args['short_style'] or '')
                        local bl = legs > 1 and ii == top_pos and ' style="border-left:2px solid #aaa;"' or ''
                        tt = p_sub.colhead(tt,col_width .. bl,short_name)
                end
        end
        return tt
end

function p.row(tt,Args,N_teams,team_list,ii,ii_show,legs,multirowlegs)
        -- Note ii is the row number being shown
        local jj, fw, bg, result, result_extra, team_code_ii, team_code_jj
        legs = legs or 1

        -- Set score cell style
        local matches_style = Args['matches_style'] or ''

        team_code_ii = team_list[ii]

        -- Get some default values in case it doesn't start at 1
        local top_pos = tonumber(Args['highest_pos']) or 1
        for l=1,legs do
                if multirowlegs and l > 1 then
                        table.insert(tt,'|- \n')  -- New row
                end
                for jj=top_pos,N_teams do
                        team_code_jj = team_list[jj]
                        local m = (legs == 1) and 'match_' or 'match' .. l .. '_'
                        result = Args[m..team_code_ii..'_'..team_code_jj] or ''
                        result_extra = Args['result_'..team_code_ii..'_'..team_code_jj] or ''
                        local bl = legs > 1 and jj == top_pos and 'border-left:2px solid #aaa;' or ''

                        if ii == jj or result == 'null' then
                                -- Solid cell
                                fw = 'font-weight:' .. (ii==ii_show and 'bold' or 'normal') .. ';'
                                bg = 'background:transparent;'

                                -- Grey background color for solid cell
                                if Args['solid_cell'] == 'grey' then
                                        table.insert(tt,'| style="'..fw..bl..'background:#bbb;" |\n')
                                else
                                        table.insert(tt,'| style="'..fw..bl..bg..'" | &mdash;\n')
                                end
                        else
                                -- Content cell
                                -- Set bolding and background
                                fw = 'font-weight:' .. ((ii==ii_show or jj == ii_show) and 'bold' or 'normal') .. ';'
                                bg = 'background:transparent;'

                                -- Reformat dashes
                                if result ~= '' then
                                        result = format_score(result)
                                end
                                -- Background coloring if enabled
                                if matches_style == 'FBR' and result ~= '' then
                                        if result_extra == 'OT' then
                                                bg = 'background:' .. get_score_background(result,'level2') .. ';'
                                        elseif result_extra == 'PK' then
                                                bg = 'background:' .. get_score_background(result,'level3') .. ';'
                                        else
                                                bg = 'background:' .. get_score_background(result,'') .. ';'
                                        end
                                elseif matches_style == 'BSR' and result ~= '' then
                                        if result_extra == 'OT' then
                                                bg = 'background:' .. get_score_background(result,'level3') .. ';'
                                        elseif result_extra == 'OTL' then
                                                bg = 'background:' .. get_score_background('0–1','level3') .. ';'
                                        elseif result_extra == 'OTW' then
                                                bg = 'background:' .. get_score_background('1–0','level3') .. ';'
                                        elseif result_extra == 'L' then
                                                bg = 'background:' .. get_score_background('0–1','') .. ';'
                                        elseif result_extra == 'W' then
                                                bg = 'background:' .. get_score_background('1–0','') .. ';'
                                        else
                                                bg = 'background:' .. get_score_background(result,'') .. ';'
                                        end
                                end
                                table.insert(tt,'| style="white-space:nowrap;'..fw..bl..bg..'" |'..result..'\n')
                        end
                end
        end

        return tt
end

return p