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.

// request.cf · coarse context

A page that knows where it met you.

Only coarse request metadata is shown. This demo does not display or persist visitor IP addresses.

Country
US
Cloudflare location
CMH
Connection
HTTP/2
Language
Not provided

Ray ID: a44f30520b61f43c

Jump to content

Module:Sports stat rank

From Wikipedia, the free encyclopedia

-- Module to build tables ranking top player in a particular stat in Sports
-- See documentation for details

require('strict')

local p = {}

-- Main function
function p.main(frame)
    -- Declare locals
    local getArgs = require('Module:Arguments').getArgs
	local Args = getArgs(frame, {parentFirst = true})
	assert(Args['order_cat'], 'Error: Please define order_cat')
	local cat_order = mw.text.split(Args['order_cat'], '%s*[;,]%s*')
	local stat_list = {['Totals'] = {}}
	local t = {}

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

	-- Load modules
	local yesno = require('Module:Yesno')

	local function defaultTrue(val)
		return (yesno(val) == nil) and true or yesno(val)
	end
	local function defaultFalse(val)
		return yesno(val) or false
	end

	-- Set show flags
	local show_totals = defaultTrue(Args['show_totals'])
	local show_num = defaultTrue(Args['show_num'])
	local show_pos = defaultFalse(Args['show_pos'])
	local show_nat = defaultFalse(Args['show_nat'])
	local show_team = defaultFalse(Args['show_team'])
	local show_cat = defaultTrue(Args['show_cat'])

	-- Set threshold checks
	local function checkThresholdRank(next_rank)
		local threshold_rank = tonumber(Args['threshold_rank'])
		if threshold_rank then
			return next_rank <= threshold_rank
		else
			return true	-- Check passes if no threshold rank is specified
		end
	end
	local function checkThresholdStat(next_stat)
		local threshold_stat = tonumber(Args['threshold_stat'])
		if threshold_stat then
			return next_stat >= threshold_stat
		else
			return true	-- Check passes if no threshold rank is specified
		end
	end

    -- Form list of players, stored under stat_list[playertotal][pname]
    for arg, value in pairs(Args) do		
        -- Get player abbreviation
        local pname = string.match(arg, '^name_(.+)')
		if yesno(pname, true) then
	        local pstat = {total = 0}
	        
	        -- Get player stats by category
	        for _, cname in pairs(cat_order) do
	            local stat = tonumber(Args[cname..'_'..pname]) or 0	-- Stat might not be set
	            pstat[cname] = stat
	            pstat.total = pstat.total + stat
	            
	            -- Add stat to appropriate totals category
	            stat_list['Totals'][cname] = (stat_list['Totals'][cname] or 0) + stat
	            stat_list['Totals'].total = (stat_list['Totals'].total or 0) + stat
	        end

			-- Apply stat adjustment to account for matches that count towards multiple competitions
			local adj = tonumber(Args['adj_'..pname]) or 0
			pstat.total = pstat.total - adj
			stat_list['Totals'].total = stat_list['Totals'].total - adj
			
	        -- Add player to stats list
			if not stat_list[pstat.total] then stat_list[pstat.total] = {} end -- Initialise dict for particular stat total
	        stat_list[pstat.total][pname] = pstat
			-- Add player number sort value
			stat_list[pstat.total][pname].num = tonumber(Args['num_'..pname])
			-- Add player name sort value
			local name_stripped_brackets = mw.ustring.gsub(Args['name_'..pname], '[%[%]]', '')
        	local name_clean = mw.ustring.gsub(name_stripped_brackets, '.-|', '') -- strip original page name
			stat_list[pstat.total][pname].sortname = Args['data_sort_value_name_'..pname] or name_clean
		end
    end
    
    -- Sort stat_list, by descending total goals
    local total_array = {}
    for total in pairs(stat_list) do
        table.insert(total_array, total)
    end
    table.sort(total_array, function(a, b)
        -- 'Totals' is placed at the bottom
        if a == 'Totals' then return false end
        if b == 'Totals' then return true end
        
        -- Sort by stat, descending
        return tonumber(a) > tonumber(b)
    end)

	-- Sort sub stat_list for each goals total, by player number or name
    for k, v in pairs(stat_list) do
        if k ~= 'Totals' then -- Skip 'Total' entry
			local player_array = {}
			for pname in pairs(v) do
	        	table.insert(player_array, pname)
	    	end
            table.sort(player_array, function(pnamea, pnameb)
				if Args['sort_by'] == 'NUM' then
					-- Sort by player number, ascending, with no assigned player number placed lower
					if v[pnamea].num and v[pnameb].num then return v[pnamea].num < v[pnameb].num end
					if not v[pnamea].num then return false end
					if not v[pnameb].num then return true end
				end
				-- Sort by player name otherwise, ascending
	            return v[pnamea].sortname < v[pnameb].sortname
            end)
			v.player_array = player_array
        end
    end
    
    -- Create table header
	local style = 'style='..(Args['header_style'] or '')
    table.insert(t, '{| class="wikitable sortable" style="text-align:center"\n')
    table.insert(t, '!width=15 '..style..'|Rank\n')
	if show_num then table.insert(t, '!width=15 '..style..'|<abbr title="Squad number">No.</abbr>\n') end
    if show_pos then table.insert(t, '!width=15 '..style..'|<abbr title="Player position">Pos</abbr>\n') end
    if show_nat then table.insert(t, '!width=15 '..style..'|<abbr title="Nationality">Nat</abbr>\n') end
    table.insert(t, '! '..style..'"|Player\n')
    if show_team then table.insert(t, '! '..style..'|Team\n') end
    if show_cat then
        -- Add category columns
        for _, cname in pairs(cat_order) do
            table.insert(t, '!width=25 data-sort-order="desc" '..style..'|'..(Args['cat_'..cname] or '')..'\n')
        end
    end
    -- Add totals column, named as defined with stat_name, or 'Total' by default
    table.insert(t, '!data-sort-order="desc" '..style..'|'..(Args['stat_name'] or 'Total')..'\n')
    
    -- Create data rows
    local rank = 1 -- Track current ranking
    for _, total in pairs(total_array) do
        local is_totals = total == 'Totals'
        
        if not is_totals then
            -- Player row formatting
			if not (checkThresholdRank(rank) and checkThresholdStat(total)) then
				break	-- Stop creating table rows if threshold checks fail.
			end
			
			local num_players = #stat_list[total].player_array
			local first_player = true -- Track if it is the first player with that stat total, to manage new rows and total cell placement
            
            table.insert(t, '|-\n')
            table.insert(t, '! rowspan="'..num_players..'"|'..rank..'\n')
            for _, pname in pairs(stat_list[total].player_array) do
				local pstat = stat_list[total][pname]
				if not first_player then table.insert(t, '|-\n') end

				if show_num then table.insert(t, '|'..(Args['num_'..pname] or '')..'\n') end
                if show_pos then table.insert(t, '|'..(Args['pos_'..pname] or '')..'\n') end
                if show_nat then table.insert(t, '|'..(Args['nat_'..pname] or '')..'\n') end
				table.insert(t, '| style="text-align:left;" data-sort-value="'..(pstat.sortname or '')..'" |'..(Args['name_'..pname] or '')..'\n')
                if show_team then table.insert(t, '| style="text-align:left;" |'..(Args['team_'..pname] or '')..'\n') end
                if show_cat then
                    -- Add category columns
                    for _, cname in ipairs(cat_order) do
                        table.insert(t, '|'..((pstat[cname] ~= 0) and pstat[cname] or ''))
						if yesno(Args['note_'..cname..'_'..pname], true) then
            				table.insert(t, frame:expandTemplate{title='efn', args={group='lower-alpha', Args['note_'..cname..'_'..pname]}})
						end
						table.insert(t, '\n')
                    end
                end
				if first_player then table.insert(t, '| rowspan="'..num_players..'"|<b>'..total..'</b>\n') end
				first_player = false
            end

			rank = rank + num_players
        elseif show_totals then
            -- Totals row formatting
            local totals_name_colspan = 2 + (show_num and 1 or 0) + (show_pos and 1 or 0) + (show_nat and 1 or 0) + (show_team and 1 or 0) -- Rank and player columns are mandatory
            
            table.insert(t, '|-style="background-color:#d8edf3; font-weight:bold;"\n')
            table.insert(t, '| colspan="'..totals_name_colspan..'" | Totals\n')
            if show_cat then
                -- Add category columns
                for _, cname in ipairs(cat_order) do
                    table.insert(t, '| '..stat_list['Totals'][cname]..'\n')
                end
            end
            table.insert(t, '|'..stat_list['Totals'].total..'\n')
        end
    end
	
	-- Close table
	table.insert(t, '|}')

	-- Create footer
	local note_list = {}
    if yesno(Args['updated'], true) then
        table.insert(note_list, 'Updated to match(es) played on '..Args['updated']..'.')
    end
	
    if yesno(Args['source'], true) then
        table.insert(note_list, 'Source: '..Args['source'])
	end

	local t_footer = '<div class="sports-stat-rank-notes">'..table.concat(note_list, ' ')..'</div>'..frame:expandTemplate{title='notelist', args={group='lower-alpha'}}

	return templatestyles..'\n'..table.concat(t)..t_footer
end

return p