Module:Sports rbr table

From MicrasWiki
Jump to navigationJump to search

Usage

Position tables

{{#invoke:Sports rbr table|table
| sortable = <!-- y or n or omit -->
| team1 = 
| pos1  = <!-- 1 / 2 / 3 / 4 / ... -->
| team2 = 
| pos2  = <!-- 1 / 2 / 3 / 4 / ... -->
<!-- ... -->
| color_1 = 1st
| text_1  = 1st place
| source = 
}}

WDL tables

{{#invoke:Sports rbr table|table
| sortable = <!-- y or n or omit -->
| team1 = 
| res1  = <!-- W / D / L ... -->
| team2 = 
| res2  = <!-- W / D / L ... -->
<!-- ... -->
| color_W = green2
| color_D = yellow2
| color_L = red2
| source = 
}}

Style

The XXX in style=XXX is to be replaced by one of the following available styles:

  • matchup – for tables showing matchups and head-to-head results

Parameters

General parameters
Parameter Description
title A top caption for the table, omit for no title.
sortable Is the table sortable? Set to y for a sortable table, and omit for unsortable.
color_X The background color for position X. Here, X can be a single number (e.g., 1 for position 1), or a non-numeric value corresponding to a position used in the table (e.g., R for relegated or W for withdrew ...) See the color section below for more information on color syntax.
color_-3 The background color for position 1, 2, and 3. See the color section below for more information on color syntax.
color_15- The background color for position 15, 16, .... See the color section below for more information on color syntax.
text_Y Legend text for color_Y. Adding any legend text will trigger the inclusion of a legend at the bottom of the table.
source Source for the information in the table.
notes Any additional notes at add to the foot of the table.
update
start_date
Date of the last round of matches included in the table. If the table is complete, use |update=complete. If the matches will occur at a future date, use |update=future and |start_date= for the date of the first round of matches.
legendpos Position for the legend. Supported values include tr (top right), br (bottom right), tl (top left), bl (bottom left), t (top), and b (bottom).
legendorder The order for the entries in the legend (e.g., |legendorder=W/D/L).
toptext Text to include at the top of the table. This is useful when |legendpos=tr and you wish to have the legend float next to text at the top.
header Text for the team column header. The default is Team ╲ Round.
labelalign Alignment for the column labels. The default is left.
firstround The number of the first round. The default is 1.
rnd1 Text to use for the label for round 1. The default is 1.
splitN A line can be added between section of the table (if desired) by adding |splitN=yes with N the position below which the bar should be shown.
Compact syntax
Parameter Description
team1 The wikilinked name of the first team. For additional teams, use team2, team3, ... For a temporary place holder, use |team1=- or |team1=&nbsp; or |team1=&ensp; or |team1=TBA.
pos1 The forward slash (/) delimited list of round-by-round positions for the first team. For example, |pos1=1/2/3/8/3/2/1 for seven rounds with the position changing from 1 to 2 to 3 to 8 to 3 to 2 to 1.
pos1_rnd3_note A footnote to append the 3rd position in the pos1 positions.
res1 The forward slash (/) delimited list of match results for the first team. For example, |res1=W/D/D/W/L for five rounds with the round-by-round results of win, draw, draw, win, loss. Note, this parameter cannot be used if |pos1= is being used.
res1_rnd3_note A footnote to append the 3rd result in the res1 match results.
Sports table syntax
Parameter Description
team1 this can be abbreviation for the first team. The remainder of the documentation in this section assumes the abbreviation is ABC. For additional teams, use team2, team3, ...
name_ABC The wikilinked name of team ABC
pos_ABC The forward slash (/) delimited list of round-by-round positions for team ABC. For example, |pos_ABC=1/2/3/8/3/2/1 for seven rounds with the position changing from 1 to 2 to 3 to 8 to 3 to 2 to 1.
res_ABC The forward slash (/) delimited list of match results for team ABC. For example, |res_ABC=W/D/D/W/L for five rounds with the round-by-round results of win, draw, draw, win, loss. Note, this parameter cannot be used if |pos_ABC= is being used.

Color

The module has several preset background colors that have acceptable contrast with black foreground text. It is recommended to use one of these colors, which match colors used by Module:Sports table.

Name Hex value
green1 BBF3BB
green2 CCF9CC
green3 DDFCDD
green4 EEFFEE
blue1 BBF3FF
blue2 CCF9FF
blue3 DDFCFF
blue4 EEFFFF
Name Hex value
yellow1 FFFFBB
yellow2 FFFFCC
yellow3 FFFFDD
yellow4 FFFFEE
red1 FFBBBB
red2 FFCCCC
red3 FFDDDD
red4 FFEEEE
Name Hex value
black1 BBBBBB
black2 CCCCCC
black3 DDDDDD
black4 EEEEEE
1st FFD700
2nd C0C0C0
3rd CC9966

In some rare cases, it may be necessary to override the background color for a particular cell. This can be accomplished using |posX_rndY_color= or |resX_rndY_color= where X is the row number, and Y is the round number.

Examples

Example 1: Compact positions syntax

First place
Promoted
Championship League
Relegated
Example 1
Team ╲ Round12345
A Team12222
B Team21444
C Team34161
D Team43613
E Team56387
F Team65835
G Team78558
H Team87776
Source: Some source
{{#invoke:Sports rbr table|table
| title = Example 1
| sortable = y
| team1 = A Team
| pos1  = 1/2/2/2/2
| team2 = B Team
| pos2  = 2/1/4/4/4
| team3 = C Team
| pos3  = 3/4/1/6/1
| team4 = D Team
| pos4  = 4/3/6/1/3
| team5 = E Team
| pos5  = 5/6/3/8/7
| team6 = F Team
| pos6  = 6/5/8/3/5
| team7 = G Team
| pos7  = 7/8/5/5/8
| team8 = H Team
| pos8  = 8/7/7/7/6
| color_1 = 1st
| text_1 = First place
| color_2 = green1
| text_2 = Promoted
| color_3-4 = blue2
| text_3-4 = Championship League
| color_7- = red1
| text_7- = Relegated
| source = Some source
}}

Example 2: Sports table positions syntax

First place
Promoted
Championship League
Relegated
Example 2
Team ╲ Round12345
A Team12222
B Team21444
C Team34161
D Team43613
E Team56387
F Team65835
G Team78558
H Team87776
Source: Some source
{{#invoke:Sports rbr table|table
| title = Example 2
| sortable = y
| team1 = AAA | team2 = BBB | team3 = CCC | team4 = DDD
| team5 = EEE | team6 = FFF | team7 = GGG | team8 = HHH
| name_AAA = A Team
| pos_AAA  = 1/2/2/2/2
| name_BBB = B Team
| pos_BBB  = 2/1/4/4/4
| name_CCC = C Team
| pos_CCC  = 3/4/1/6/1
| name_DDD = D Team
| pos_DDD  = 4/3/6/1/3
| name_EEE = E Team
| pos_EEE  = 5/6/3/8/7
| name_FFF = F Team
| pos_FFF  = 6/5/8/3/5
| name_GGG = G Team
| pos_GGG  = 7/8/5/5/8
| name_HHH = H Team
| pos_HHH  = 8/7/7/7/6
| color_1 = 1st
| text_1 = First place
| color_2 = green1
| text_2 = Promoted
| color_3-4 = blue2
| text_3-4 = Championship League
| color_7- = red1
| text_7- = Relegated
| source = Some source
}}

Example 3: Team combined table

Example 3
Round123456789101112131415161718192021
GroundHAAHAHAHHAAHHAHAAHHAA
ResultWLLWWDWLLLLWWWWLDLLDL
Position41014867789101111876667999
Source: Some source
{{#invoke:sports rbr table|table
|title=Example 3
|header=Round
|label1= Ground
| res1= H/ A/ A/ H/ A/ H/ A/ H/ H/ A/ A/ H/ H/ A/ H/ A/ A/ H/ H/ A/ A
|label2= Result
| res2= W/ L/ L/ W/ W/ D/ W/ L/ L/ L/ L/ W/ W/ W/ W/ L/ D/ L/ L/ D/ L
|label3= Position
| pos3= 4/10/14/ 8/ 6/ 7/ 7/ 8/ 9/10/11/11/ 8/ 7/ 6/ 6/ 6/ 7/ 9/ 9/ 9
| color_W = green2| color_D = yellow2| color_L = red2
| color_1=green1| color_2=green2| color_3-4=green3
| color_5-7=blue1| color_18-=red1
| source = Some source
}}

Example 4: Team combined table with a legend

Example 4
Round123456789101112131415161718192021
GroundHAAHAHAHHAAHHAHAAHHAA
ResultWLLWWDWLLLLWWWWLDLLDL
Position41014867789101111876667999
Source: Some source
A = Away; H = Home; W = Win; D = Draw; L = Loss
{{#invoke:sports rbr table|table|legendpos=b
|title=Example 4
|header=Round
|label1= Ground
| res1= H/ A/ A/ H/ A/ H/ A/ H/ H/ A/ A/ H/ H/ A/ H/ A/ A/ H/ H/ A/ A
|label2= Result
| res2= W/ L/ L/ W/ W/ D/ W/ L/ L/ L/ L/ W/ W/ W/ W/ L/ D/ L/ L/ D/ L
|label3= Position
| pos3= 4/10/14/ 8/ 6/ 7/ 7/ 8/ 9/10/11/11/ 8/ 7/ 6/ 6/ 6/ 7/ 9/ 9/ 9
<!-- -->
| color_W = green2|text_W=Win
| color_D = yellow2|text_D=Draw
| color_L = red2|text_L=Loss
| text_H = Home|text_A = Away
| color_1=green1| color_2=green2| color_3-4=green3
| color_5-7=blue1| color_18-=red1
| source = Some source
}}

-- This module implements {{Sports rbr table}}
local p = {}

-- Internationalisation
local labels = {
	teamround = 'Team ╲ Round',
	source = 'Source:',
	notes = 'Notes:',
	matches = 'match(es)',
	updatedto = 'Updated to <matches> played on <date>.',
	firstplayed = 'First <matches> will be played on <date>.',
	futuredate = '?',
	complete = 'complete',
	future = 'future'
}

local modname = 'Module:Sports rbr table'
local templatestyles = 'Module:Sports rbr table/styles.css'

local args = nil

local preview, tracking = '', ''
local hasnotes = false

local colorlist = {}
local textlist = {}

local color_map = {
		green1='#BBF3BB', green2='#CCF9CC', green3='#DDFCDD', green4='#EEFFEE',
		blue1='#BBF3FF', blue2='#CCF9FF', blue3='#DDFCFF', blue4='#EEFFFF',
		yellow1='#FFFFBB', yellow2='#FFFFCC', yellow3='#FFFFDD', yellow4='#FFFFEE',
		red1='#FFBBBB', red2='#FFCCCC', red3='#FFDDDD', red4='#FFEEEE',
		black1='#BBBBBB', black2='#CCCCCC', black3='#DDDDDD', black4='#EEEEEE',
		['1st']='#FFD700', ['2nd']='#C0C0C0', ['3rd']='#CC9966'
	}

local legend_symbols = {O='W/O'}

local legend_order_default = {'A', 'H', 'N', 'B', 'W', 'D', 'L', 'Ab', 'P', 'O'}

local function isnotempty(s)
	return s and s:match( '^%s*(.-)%s*$' ) ~= ''
end

local function zeropad(n)
	if n>=0 and n < 10 then
		return '00' .. n
	end
	if n>=0 and n < 100 then
		return '0' .. n
	end
	return '' .. n
end

local function pad_key(k)
	-- Zero pad, fix ranges and dashes
	if k then
		k = k .. ' '
		k = mw.ustring.gsub(k, '–', '-')
		k = mw.ustring.gsub(k, '_([%d][^%d])', '_0%1')
		k = mw.ustring.gsub(k, '%-([%d][^%d])', '-0%1')
		k = mw.ustring.gsub(k, '_([%d][%d][^%d])', '_0%1')
		k = mw.ustring.gsub(k, '%-([%d][%d][^%d])', '-0%1')
		k = mw.ustring.gsub(k, '([^%d])%-([%d])', '%1000-%2')
		k = mw.ustring.gsub(k, '([%d])%-%s*$', '%1-999')
		k = mw.ustring.gsub(k, '^%s*(.-)%s*$', '%1')
	end

	return k
end

local function matches_date(text, m, d)
	return mw.ustring.gsub(mw.ustring.gsub(text .. '', '<matches>', m), '<date>', d)
end

local function escapetag(text)
	return mw.ustring.gsub(text, '</', '<FORWARDSLASH')
end

local function unescapetag(text)
	return mw.ustring.gsub(text, '<FORWARDSLASH', '</')
end

local function get_color(p)
	if p then
		p = mw.ustring.gsub(p, '</?[Aa][Bb][Bb][Rr][^<>]*>', '')
		p = mw.ustring.gsub(p, '<[Ss][Uu][Pp]>[^<>]*</[Ss][Uu][Pp]>', '')
		p = mw.ustring.gsub(p, '</?[Ss][^<>]*>', '')
		p = mw.ustring.gsub(p, '†%s*$', '')
		p = mw.ustring.gsub(p, '=%s*$', '')
		p = mw.ustring.gsub(p, '%[%[[^%[%]|]*|([^%[%]|]*)%]%]', '%1')
		if p:match('^%a%a*$') then
			if args['text_' .. p] == nil then
				tracking = tracking .. ' '
			end
		end
	end
	local c = colorlist[p] or colorlist[zeropad(tonumber(p) or -1)]
	if c then
		return color_map[c] or c
	end
	p = tonumber(p or '0') or 0
	if p <= 0 then
		return nil
	end
	-- ranges in order of specificity
	local offset1, offset2 = 999, 999
	for k,v in pairs( colorlist ) do
		local r1 = tostring(k):match( '^%s*([%d]+)%-[%d]+%s*$' )
		local r2 = tostring(k):match( '^%s*[%d]+%-([%d]+)%s*$' )
		if r1 and r2 then
			r1 = tonumber(r1)
			r2 = tonumber(r2)
			if (r1 <= p) and (r2 >= p) then
				if (c == nil) or ((p - r1) <= offset1 and (r2 - p) <= offset2) then
					c = color_map[v] or v
					offset1 = p - r1
					offset2 = r2 - p
				end
			end
		end
	end
	return c
end

local function check_arg(k, st)
	k = tostring(k) or ''
	if k == 'firstround' or k == 'sortable' or k == 'updated' or k == 'update'
		or k =='source' or k =='notes' or k == 'legendpos' or k == 'date' 
		or k == 'header' or k == 'title' or k == 'start_date' or k == 'labelnowrap'
		or k == 'labelalign' or k == 'toptext' or st.addtl_args(k) then
	elseif k == 'legendorder' then
		tracking = tracking .. ' '
	elseif tostring(k):match( '^%s*text_?(.-)%s*$' ) then
	elseif tostring(k):match( '^%s*colou?r_?(.-)%s*$' ) then
	elseif tostring(k):match( '^%s*team[%d]+%s*$' ) then
	elseif tostring(k):match( '^%s*label[%d]+%s*$' ) then
		if args['header'] then
		else
			tracking = tracking .. ' '
		end
	elseif tostring(k):match( '^%s*opp[%d]+%s*$' ) then
	elseif tostring(k):match( '^%s*pos[%d]+%s*$' ) then
	elseif tostring(k):match( '^%s*grnd[%d]+%s*$' ) then
	elseif tostring(k):match( '^%s*res[%d]+%s*$' ) then
	elseif tostring(k):match( '^%s*posc[%d]+%s*$' ) then
	elseif tostring(k):match( '^%s*grndc[%d]+%s*$' ) then
	elseif tostring(k):match( '^%s*resc[%d]+%s*$' ) then
	elseif tostring(k):match( '^%s*split[%d]+%s*$' ) then
	elseif k == 'rnd1' then
		tracking = tracking .. ' '
	elseif tostring(k):match( '^%s*rnd[%d]+%s*$' ) then
	elseif tostring(k):match( '^%s*opp_' ) then
	elseif tostring(k):match( '^%s*pos_' ) then
	elseif tostring(k):match( '^%s*grnd_' ) then
	elseif tostring(k):match( '^%s*res_' ) then
	elseif tostring(k):match( '^%s*posc_' ) then
	elseif tostring(k):match( '^%s*grndc_' ) then
	elseif tostring(k):match( '^%s*resc_' ) then
	elseif tostring(k):match( '^%s*name_' ) then
	elseif tostring(k):match( '^%s*note_' ) then
	elseif tostring(k):match( '^%s*pos[%d]+_rnd[%d]+_colou?r%s*$' ) then
		tracking = tracking .. ' '
	elseif tostring(k):match( '^%s*res[%d]+_rnd[%d]+_colou?r%s*$' ) then
		tracking = tracking .. ' '
	elseif tostring(k):match( '^%s*pos[%d]+_rnd[%d]+_note%s*$' ) then
	elseif tostring(k):match( '^%s*res[%d]+_rnd[%d]+_note%s*$' ) then
	else
		local vlen = mw.ustring.len(k)
		k = mw.ustring.sub(k, 1, (vlen < 25) and vlen or 25) 
		k = mw.ustring.gsub(k, '[^%w\-_ ]', '?')
		preview = preview .. 'Unknown: "' .. k .. '"<br>'
		tracking = tracking .. ' '
	end
end

function p.table(frame)
	local getArgs = require('Module:Arguments').getArgs
	local yesno = require('Module:Yesno')
	args = getArgs(frame, {wrappers = {'Template:Sports rbr table'}})
	
	local style_def = args['style']
	local p_style = require(modname)
	if style_def ~= nil then p_style = require(modname .. '/' .. style_def) end
	
	args = p_style.defaults(args,yesno,color_map)
	
	local rounds = tonumber(args['rounds'] or '0') or 0
	local firstround = tonumber(args['firstround'] or 1) or 1
	local sortable = yesno(args['sortable'] or 'no')
	local updated = args['updated'] or args['update']
	local source = args['source']
	local notes = args['notes']
	local delimiter = args['delimiter'] or '/'
	local addlegend = nil
	local legendpos = (args['legendpos'] or 'tr'):lower()
	local header, footer, prenotes  = '', '', ''
	
	-- Lowercase two labels --
	labels['complete'] = string.lower(labels['complete'])
	labels['future'] = string.lower(labels['future'])

	-- Adjust rounds
	rounds = rounds - (firstround - 1)
	
	-- Tracking
	if updated and updated:match(' %d%d%d%d$') then
		local YY = mw.ustring.gsub(updated, '^.*(%d%d)$', '%1')
		local pn = frame:getParent():getTitle() or ''
		if pn:match('^User:') or pn:match('^User talk:') or pn:match('^Draft:') or pn:match('^Talk:') then
		else
			if pn:match('%d%d' .. YY) or pn:match('[–%-]' .. YY) then
			else
				tracking = tracking .. ' '
			end
		end
    end
	-- Require a source
	if source == nil then
		source = frame:expandTemplate{ title = 'citation needed', args = { reason='No source parameter defined', date=args['date'] or os.date('%B %Y') } }
	elseif source and source:match('[^%[]#') then 
		if source:match('eason#') or source:match('%d%d#') then
			tracking = tracking .. ' '
		elseif source:match('^[Hh][Tt][Tt][Pp]') then
			tracking = tracking .. ' '
		end
	end
	
	-- Process team, pos, and color args
	local team_list = {}
	local maxrounds = 0
	local rowlength = {}
	for k, v in pairs( args ) do
		check_arg(k, p_style)
		-- Preprocess ranges
		if tostring(k):match( '^%s*text_?(.-)%s*$' ) then
			k = pad_key(k)
		end
		if tostring(k):match( '^%s*colou?r_?(.-)%s*$' ) then
			k = pad_key(k)
		end

		-- Create the list of teams and count rounds
		local i = tonumber(
				tostring(k):match( '^%s*team([%d]+)%s*$' ) or
				tostring(k):match( '^%s*label([%d]+)%s*$' ) or '0'
				)
		if ( i > 0 and isnotempty(v) ) then
			table.insert(team_list, i)
			local p = p_style.get_argvalues_for_maxround(args,i)
			if args['name_' .. v] then
				local t = args['team' .. i] or args['label' .. i] or ''
				p = p_style.get_argvalues_for_maxround(args,t,'_')
			end
			local pos = mw.text.split(escapetag(p), '%s*' .. delimiter .. '%s*')
			table.insert(rowlength, #pos)
			maxrounds = (#pos > maxrounds) and #pos or maxrounds
			-- maxrounds = p_style.get_maxrounds(args,team_list,i,v,rowlength,maxrounds,delimiter)
		end
		-- Create the list of colors
		local s = tostring(k):match( '^%s*colou?r_?(.-)%s*$' )
		if ( s and isnotempty(v) ) then
			colorlist[s] = v:lower()
		end
		-- Check if we are adding a legend
		s = tostring(k):match( '^%s*text_?(.-)%s*$' )
		if ( s and isnotempty(v) ) then
			textlist[s] = v
			addlegend = 1
		end
	end
	
	maxrounds = p_style.get_rounds_or_maxrounds(rounds,maxrounds,args,team_list)
	
	table.sort(rowlength)
	for k=2,#rowlength do
		if rowlength[k] ~= rowlength[k-1] then
			tracking = tracking .. ' '
		end
	end

	-- sort the teams
	table.sort(team_list)

	local fs = 95
	if ((maxrounds - firstround) > 37 ) then
		fs = fs - 2*(maxrounds - firstround - 37)
		fs = (fs < 80) and 80 or fs
	end

	-- Build the table
	local root = mw.html.create('table')
	root:addClass('wikitable')
	root:addClass(sortable and 'sortable' or nil)
	root:addClass('sportsrbrtable')
	root:css('font-size', fs .. '%')

	if args['title'] then
		root:tag('caption'):wikitext(args['title'])
	end

	local navbar = ''
	if args['template_name'] then
		navbar = '<br />' .. frame:expandTemplate{ title = 'navbar', args = { mini=1, style='', brackets=1, args['template_name']}}
		-- remove the next part if https://en.wikipedia.org/w/index.php?oldid=832717047#Sortable_link_disables_navbar_links?
		-- is ever fixed
		if sortable then
			navbar = mw.ustring.gsub(navbar, '<%/?abbr[^<>]*>', ' ')
		end
	end
	
	-- Heading row
	local row = p_style.header(root,args,labels,maxrounds,navbar,team_list,firstround)

	-- Team positions
	local prefixes = {'pos', 'res', 'grnd'}
	for k=1,#team_list do
		local i = team_list[k]
		local t = args['team' .. i] or args['label' .. i] or ''
		local o = args['opp' .. i] or ''
		local n = args['note' .. i] or ''
		local efnname = 'note' .. i
		local suf = i
		if args['name_' .. t] then
			o = args['opp_' .. t] or ''
			n = args['note_' .. t] or ''
			efnname = 'note' .. t
			suf = '_' .. t
			t = args['name_' .. t]
		end

		if n ~= '' then
			if args['note_' .. n] then 
				n = frame:expandTemplate{ title = 'efn', args = { name='note' .. n, ''} }
			else
				n = frame:expandTemplate{ title = 'efn', args = { name=efnname, n} }
			end
			hasnotes = true
		end
		
		local resfound = (args['grnd' .. i] and 1 or 0) + (args['pos' .. i] and 1 or 0) + (args['res' .. i] and 1 or 0)
		if args['name_' .. t] then
			resfound = (args['grnd_' .. t] and 1 or 0) + (args['pos_' .. t] and 1 or 0) + (args['res_' .. t] and 1 or 0)
		end
		if (resfound > 1) then
			tracking = tracking .. ' '
		end
		local rowsdisp = 0
		for subrow,lbl in ipairs(prefixes) do
			local p = args[lbl .. suf] or ''
			local pc = args[lbl .. 'c' .. suf] or ''
			if p ~= '' or (rowsdisp == 0 and subrow == 3) then
				rowsdisp = rowsdisp + 1
				row = root:tag('tr')
				row:tag('th')
					:addClass(args['team' .. i] and 'sportsrbrtable-team' or 'sportsrbrtable-lbl')
					:css('text-align', args['labelalign'])
					:css('white-space', args['labelnowrap'] and 'nowrap' or nil)
					:attr('scope', 'row')
					:wikitext(mw.ustring.gsub(t,'^%s*%-%s*$', '&nbsp;') .. n)
				if t:match('<%s*[Cc][Ee][Nn][Tt][Ee][Rr]%s*>') then
					tracking = tracking .. ' '
				end
				local opp = mw.text.split(escapetag(o), '%s*' .. delimiter .. '%s*')
				local pos = mw.text.split(escapetag(p), '%s*' .. delimiter .. '%s*')
				local clr = mw.text.split(escapetag(pc), '%s*' .. delimiter .. '%s*')
				for r=1,maxrounds do
					local s = args['team' .. i .. '_rnd' .. r .. '_' .. 'color'] or
						args['team' .. i .. '_rnd' .. r .. '_' .. 'colour'] or
						args[lbl .. i .. '_rnd' .. r .. '_' .. 'color'] or
						args[lbl .. i .. '_rnd' .. r .. '_' .. 'colour'] or nil
					local n = args['team' .. i .. '_rnd' .. r .. '_' .. 'note'] or
						args[lbl .. i .. '_rnd' .. r .. '_' .. 'note'] or nil
					if s then s = color_map[s] or s end
					local opprt, posrt = unescapetag(opp[r] or ''), unescapetag(pos[r] or '')
					local posrc = isnotempty(clr[r]) and clr[r] or posrt

					if posrt:match('^%s*<[Uu]>[%d–]+[A-Za-z][A-Za-z0-9]*') then
						posrc = posrc:match('^%s*<[Uu]>[%d–]+([A-Za-z][A-Za-z0-9]*)')
						posrt = mw.ustring.gsub(posrt, '^%s*(<[Uu]>[%d–]+)[A-Za-z][A-Za-z0-9]*', '%1')
					elseif posrt:match('^%s*[%d–]+[A-Za-z][A-Za-z0-9]*') then
						posrc = posrc:match('^%s*[%d–]+([A-Za-z][A-Za-z0-9]*)')
						posrt = mw.ustring.gsub(posrt, '^%s*([%d–]+)[A-Za-z][A-Za-z0-9]*', '%1')
					end
			
					local ds
					if args['sortable'] and (opprt or posrt):match('^%s*[%d]+[^%d%s]') then
						ds = mw.ustring.gsub(opprt or posrt, '^%s*([%d]+)[^%d%s].*$', '%1')
					end

					if n then
						if args['note_' .. n] then
							n = frame:expandTemplate{ title = 'efn', args = { name='note' .. n, args['note_' .. n]} }
						else
							n = frame:expandTemplate{ title = 'efn', args = { name='note' .. i .. '_rnd_' .. r, n} }
						end
						hasnotes = true
					end
		
					row:tag('td')
						:attr('data-sort-value', ds)
						:css('background-color', s or get_color(p_style.rowbg(posrc, opprt)))
						:wikitext(p_style.rowtext(frame,args,legend_symbols,posrt,opprt) .. (n or ''))
				end
				if args['split' .. i] and k ~= #team_list then
					row = root:tag('tr')
						:css('background-color', '#BBBBBB')
						:css('line-height', '3pt')
					row:tag('td')
						:attr('colspan', maxrounds + 1)
				end
			end
		end
	end

	-- build the legend
	if addlegend then
		-- Sort the keys for the legend
		local legendkeys = {}
		for k,v in pairs( textlist ) do
			table.insert(legendkeys, k)
		end
		table.sort(legendkeys)

		if args['legendorder'] then
			legendkeys = mw.text.split(args['legendorder'] .. delimiter ..
				table.concat(legend_order_default, delimiter) .. delimiter ..
				table.concat(legendkeys, delimiter), '%s*' .. delimiter .. '%s*')
		else
			legendkeys = mw.text.split(
				table.concat(legend_order_default, delimiter) .. delimiter ..
				table.concat(legendkeys, delimiter), '%s*' .. delimiter .. '%s*')
		end
		local lroot
		if (legendpos == 't' or legendpos == 'b') then
			lroot = mw.html.create('')
			local firsttag = true
			for k,v in pairs( legendkeys ) do
				if v and textlist[v] then
					if firsttag == false then lroot:wikitext('; ') end
					local c = colorlist[v] or ''
					local l = lroot:tag('span')
						:css('margin', '0')
						:css('white-space', 'nowrap')
						:tag('span')
							:addClass('legend-text')
							:css('border', 'none')
							:css('padding', '1px .3em')
							:css('background-color', color_map[c] or c)
							:css('font-size', '95%')
							:css('border', '1px solid #BBB')
							:css('line-height', '1.25')
							:css('text-align', 'center')
							:wikitext(p_style.legendtext(legend_symbols,v))
							:done()
						:wikitext(' = ' .. textlist[v])
					textlist[v] = nil
					firsttag = false
				end
			end
		else
			lroot = mw.html.create('table')
			if legendpos == 'tl' or legendpos == 'bl' then
				lroot:addClass('wikitable')
				lroot:css('font-size', '88%')
			else
				lroot:addClass('infobox')
				lroot:addClass('bordered')
				-- lroot:css('width', 'auto')
			end
			for k,v in pairs( legendkeys ) do
				if v and textlist[v] then
					local c = colorlist[v] or ''
					local row = (legendpos == 'tl' or legendpos == 'bl') and lroot or lroot:tag('tr')
					local l = row:tag('th'):css('background-color', color_map[c] or c)
					if legend_symbols[v] then
						l:css('font-weight', 'normal')
							:css('padding', '1px 3px')
							:wikitext(legend_symbols[v])
					else
						l:css('width', '10px')
					end
					row:tag('td')
						:css('padding', '1px 3px')
						:wikitext(textlist[v])
					textlist[v] = nil
				end
			end
		end
		if (legendpos == 'bl' or legendpos == 'br') then
			footer = footer .. tostring(lroot)
		elseif (legendpos == 'b') then
			prenotes = prenotes .. tostring(lroot)
		elseif (legendpos == 't') then
			args['toptext'] = (args['toptext'] or '')
				.. frame:expandTemplate{ title = 'refbegin' }
				.. tostring(lroot)
				.. frame:expandTemplate{ title = 'refend' }

		else
			header = header .. tostring(lroot)
		end
	end

	-- simplify updated == complete case
	local lupdated = updated and string.lower(updated) or ''
	if lupdated == labels['complete'] or lupdated == 'complete' then
		lupdated = ''
	end

	-- add note list
	if hasnotes then
		footer = footer .. frame:expandTemplate{ title = 'notelist' }
	end
	
	-- build the footer	
	if prenotes ~= '' or notes or source or lupdated ~= '' then
		footer = footer .. frame:expandTemplate{ title = 'refbegin' }
		if lupdated ~= '' then
			local mtext = args['matches_text'] or labels['matches']
			if lupdated == labels['future'] or lupdated == 'future' then
				footer = footer .. matches_date(labels['firstplayed'] .. ' ',
					mtext, args['start_date'] or labels['futuredate'])
			else
				footer = footer .. matches_date(labels['updatedto'] .. ' ',
					mtext, updated)
			end
		end
		if source then
			footer = footer .. labels['source'] .. ' ' .. source
		end
		if prenotes ~= '' then
			if lupdated ~= '' or source then
				footer = footer .. '<br>'
			end
			footer = footer .. prenotes
		end
		if notes then
			if prenotes ~= '' or lupdated ~= '' or source then
				footer = footer .. '<br>'
			end
			footer = footer .. labels['notes'] .. ' ' .. notes
		end
		footer = footer .. frame:expandTemplate{ title = 'refend' }
	end
	-- add clear right for the legend if necessary
	footer = footer .. ((addlegend and (legendpos == 'bl' or legendpos == 'br'))
		and '<div style="clear:right"></div>' or '')
	if tracking ~= '' then
		if frame:preprocess( "{{REVISIONID}}" ) == "" then
			tracking = preview
		end
	end
	return frame:extensionTag{ name = 'templatestyles', args = { src = templatestyles} }
		.. header .. (args['toptext'] or '') .. '<div style="overflow:hidden">'
		.. '<div class="noresize overflowbugx" style="overflow:auto">'
		.. tostring(root) .. '</div></div>' .. footer .. tracking
end

function p.get_argvalues_for_maxround(args, x, del)
	del = del or ''
	return args['pos' .. del .. x] or args['res' .. del .. x] or ''
end

function p.get_rounds_or_maxrounds(rounds, maxrounds)
	return (rounds > maxrounds) and rounds or maxrounds
end

function p.addtl_args(k)
	-- just return 'true', no additional args
	return true
end

function p.defaults(args)
	-- set nothing
	return args
end

function p.header(root,args,labels,maxrounds,navbar,team_list,firstround)
	local row = root:tag('tr')
	row:tag('th')
		:attr('rowspan', args['sortable'] and 2 or nil)
		:wikitext((args['header'] or labels['teamround']) .. navbar)
	for r=1,maxrounds do
		row:tag('th')
			:addClass(args['sortable'] and 'sportsrbrtable-rnd-sort' or 'sportsrbrtable-rnd')
			:attr('scope', 'col')
			:wikitext(args['rnd' .. (r + (firstround - 1))]
				or (r + (firstround - 1)))
	end
	if args['sortable'] then
		row = root:tag('tr')
		for r=1,maxrounds do
			row:tag('th')
				:addClass('sportsrbrtable-rnd-toggle')
		end
	end
	return row
end

function p.rowtext(frame,args,legend_symbols,posrt,postrc,opprt,opprc)
	return legend_symbols[posrt] or posrt
end

function p.rowbg(posrc)
	return posrc
end

function p.legendtext(legend_symbols,v)
	return legend_symbols[v] or (v:match('^[^%d][^%d]?$') and v) or '&nbsp;'
end

return p