Module:Sports table: Difference between revisions

From IxWiki
Jump to navigation Jump to search
wp>Frietjes
use stack templates
 
m 1 revision imported
 
(No difference)

Latest revision as of 18:02, 10 August 2020

This Lua-based module is meant to build group and league tables for sports as well. Note that this module is used extensively, so test potential changes rigorously in the sandbox and please ensure consensus exists before implementing major changes. The rest of this documentation explains how the set-up of the module. Refer to individual style pages for detailed usage instructution

Usage

The basic command is {{#invoke:Sports table|main|style=XXX}}

Style

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

General styles

  • WDL – For tables with a win-draw-loss system
  • WL – For tables with a win-loss system
  • WL PK – For tables with a win-loss system that gives different weights to wins and losses from a penalty kick shootout
  • WL OT – For tables with a win-loss system that gives different weights to overtime wins
  • WL OTL tiebreak – For tables with a win-loss-OT loss system and a separate tiebreak column
  • WL goal points – For tables with a win-loss system that gives additional points for goals
  • WDLHA – For tables with separate home and away win-draw-loss accounting
  • WLHA – For tables with separate home and away win-loss accounting
  • WDL OT – For tables with a win-loss system which allow draws or overtime wins in certain situations
  • PP – For simple tables which only show games played and number of points
  • Round robin
  • Custom – For tables in which the number of columns and all column headers are specified as inputs, for greater customization

Sport or league specific styles

More styles

The module uses Lua to create the tables. Most functionality is obtained from the main module, but specific column formatting comes from the style sub-modules. The existing styles can handle a lot of different options. In case you need additional options it could be useful to create a new style. Note that some tweaking of an existing style could give you the functionality you need, rather than creating a completely new style. In case you do create a new style, you might want to refer to the Lua reference manual.

Other options

Other options can be used, for example: {{#invoke:Sports table|main|style=WL OT |sortable_table = yes |source=ICC |update=July 28, 2018

sortable_table

"yes" makes the table columns sortable

source

Adds a link which should point to a web resource with the information for verifying or updating the table

update

Gives the date when the table info was last updated. This is to be set manually - it's not automatically changed when someone changes the table.

float

Set to left or right to float the table to the left or right on the page

title_source

To append a reference to the title and suppress the need for a source at the foot of the table


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

require('Module:No globals')

local p = {}

-- Main function
function p.main(frame)
	-- Declare locals
	local getArgs = require('Module:Arguments').getArgs
	local Args = getArgs(frame, {parentFirst = true})
	local ii_start, ii_end, N_rows_res = 0
	local text_field_result
	local notes_exist = false
	local t = {}
	local t_footer = {}
	local t_return = {}
	local team_list = {}
	local jj, jjj
	
	-- 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
	
	-- 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 ''

	-- 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 modules
	local yesno = require('Module:Yesno')
	-- Load style and (sub) modules
	local style_def = Args['style'] or 'WDL'
	-- Historically 'football' exists as style, this is now forwarded to WDL
	if style_def == 'football' then style_def = 'WDL' end
	local p_style = require('Module:Sports table/'..style_def)
	local p_sub = require('Module:Sports table/sub')
	
	-- Random value used for uniqueness
	math.randomseed( os.clock() * 10^8 )
	local rand_val = math.random()
	
	-- Declare colour scheme
	local result_col = {}
	result_col = {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',
		orange1='#FEDCBA', orange2='#FEEAD5',
		white1='inherit',['']='inherit'
	}
	
	-- Show all stats in table or just matches played and points
	local full_table = true
	local pld_pts_val = string.lower(Args['only_pld_pts'] or 'no')
	local show_class_rules = yesno(Args['show_class_rules'] or 'yes') and true or false
	-- True if par doesn't exist, false otherwise
	if yesno(pld_pts_val) then
		full_table = false
	elseif pld_pts_val=='no_hide_class_rules' then
		full_table = true
		show_class_rules = false
	end
	
	-- Declare results column header
	local results_header = {}
	results_header = {Q='Qualification', QR='Qualification or relegation',
		P='Promotion', PQR='Promotion, qualification or relegation',
		PR='Promotion or relegation', PQ='Promotion or qualification', 
		R='Relegation'}
	local results_defined = false -- Check whether this would be needed
	-- Possible prefix for result fields
	local respre = (Args['result_prefix'] or '') .. '_'
	respre = (respre == '_') and '' or respre
	-- Now define line for column header (either option or custom)
	local local_res_header = results_header[Args[respre..'res_col_header']] or Args[respre..'res_col_header']  or ''
	-- Check whether it includes a note
	local res_head_note = Args['note_header_res']
	local res_head_note_text = ''
	if full_table and res_head_note then
		notes_exist = true
		res_head_note_text = frame:expandTemplate{ title = 'efn', args = { group='lower-alpha',  res_head_note} }
	end
	local results_header_txt = '! scope="col" |'..local_res_header..res_head_note_text..'\n'
	
	-- Get status option
	local t_status = p_style.status(Args)
	
	-- 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
	
	-- Read in number of consecutive teams (ignore entries after skipping a spot)
	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
	
	-- Show position
	local position_col = yesno(Args['show_positions'] or 'yes') and true or false
	
	-- Show groups or note
	local group_col = yesno(Args['show_groups'] or 'no') and true or false

	-- Show match_table or not
	local match_table = yesno(Args['show_matches'] or 'no') and true or false
	local p_matches = match_table and 
		(style_def == 'Chess' and require('Module:Sports results/'..style_def) or require('Module:Sports results'))
	
	-- Custom position column label or note
	local pos_label = Args['postitle'] or '<abbr title="Position">Pos</abbr>'
	if position_col == false then pos_label = nil end
	
	-- Show status or not
	local show_status = yesno(Args['show_status'] or 'yes') and true or false

	-- Get VTE button text (but only for non-empty text)
	local VTE_text = ''
	if (template_name ~= '') then
		VTE_text = frame:expandTemplate{ title = 'navbar', args = { mini=1, style='float:right', brackets=1, 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 yesno(Args['sortable_table'] or 'no') then
			VTE_text = mw.ustring.gsub(VTE_text, '<%/?abbr[^<>]*>', ' ')
		end
	end
	
	-- Add source to title if specified and possible
	local title_source = false
	if Args['title'] and Args['title_source'] then
		Args['title'] = Args['title'] .. Args['title_source']
		title_source = true
	elseif Args['table_header'] and Args['table_header_source'] then
		Args['table_header'] = Args['table_header'] .. Args['table_header_source']
		title_source = true
	end

	-- Write column headers
	t_return = p_style.header(t,Args,p_sub,pos_label,group_col,VTE_text,full_table,results_header_txt)
	if match_table then
		-- Add empty column header
		t_return.count = t_return.count+1
		table.insert(t_return.tab_text,'! scope="row" class="unsortable" style="background-color:white;border-top:white;border-bottom:white;line-width:3pt;"| \n')
		
		-- Add rest of header
		t_return = p_matches.header(t_return,Args,p_sub,N_teams,team_list,tonumber(Args['legs']) or 1)
	end
	t = t_return.tab_text
	local N_cols = t_return.count
	
	-- Determine what entries go into table
	-- Find out which team to show (if any)
	local ii_show = team_list[Args['showteam'] or nil] -- nil if non-existant
	-- Start and end positions to show
	local n_to_show = tonumber(Args['show_limit']) or N_teams
	-- Check for "legal value", if not legal (or non declared), then show all
	local check_n = ((n_to_show>=(N_teams-top_pos+1)) or (n_to_show<=1) or (n_to_show~=math.floor(n_to_show)))
	-- Also check whether there is a valid ii_show
	if check_n or (not ii_show) then
		ii_start = top_pos
		ii_end = N_teams
	else
		-- It's a proper integer between top_pos+1 and N_teams-1
		-- If it is in the middle show the same number above and below
		-- If it is in the top or bottom, show the exact number
		-- How many to show on the side
		local n_show_side = math.floor(n_to_show/2)
		if (ii_show-top_pos+1)<=n_show_side then
			-- Top team
			ii_start = top_pos
			ii_end = top_pos+n_to_show-1
		elseif ii_show>=(N_teams+1-n_show_side) then
			-- Bottom team
			ii_start = N_teams+1-n_to_show
			ii_end = N_teams
		else
			-- Normal case
			ii_start = ii_show-n_show_side
			ii_end = ii_show+n_show_side
		end
	end
	
	-- For results column
	local new_res_ii = ii_start
	-- Pre-check for existence of column
	for ii = ii_start, ii_end do
		if Args[respre..'result'..ii] and Args[respre..'text_' .. Args[respre..'result'..ii]] then results_defined = true end
	end
	-- Remove results header if it is unused
	if full_table and not results_defined then
		-- First get it as one string, then use string replace to replace that header by empty string
		local t_str = tostring(table.concat(t))
		t_str = mw.ustring.gsub( t_str, results_header_txt, '' )
		N_cols = N_cols-1 -- There is actually one column less
		t = {}
		table.insert(t, t_str)
	end
	
	-- Write rows
	local team_name, team_code_ii, team_code_jj, pos_num, group_txt, note_local
	local note_string, note_local, note_local_num, note_id
	local note_id_list = {}
	local hth_id_list = {}
	for ii = ii_start, ii_end do
		-- First get code
		team_code_ii = team_list[ii]
		-- Now read values
		pos_num = Args['pos_'..team_code_ii]			or ii
		group_txt = Args['group_'..team_code_ii]		or ' '
		team_name = Args['name_'..team_code_ii]		 	or team_code_ii
		note_local = Args['note_'..team_code_ii] 		or nil
		
		-- Does it need a promotion/qualification/relegation tag
		local result_local = Args[respre..'result'..ii] or nil
		local bg_col = nil
		-- Get local background colour
		if result_local then
			bg_col = result_col[Args[respre..'col_'..result_local]] or Args[respre..'col_'..result_local] or 'inherit'
			bg_col = 'background-color:'..bg_col..';' 	-- Full style tag
		end
		if not bg_col then bg_col = 'background-color:transparent;' end -- Becomes default if undefined
		
		-- Bold this line or not
		local ii_fw = ii == ii_show and 'font-weight: bold;' or 'font-weight: normal;'
		
		-- Check whether there is a note or not, if so get text ready for it
		if note_local and full_table then
			-- Set global check for notes to true
			notes_exist = true
			-- There are now 3 options for notes
			-- 1) It is a full note
			-- 2) It is a referal to another note (i.e. it's just a team code; e.g. note_AAA=Text, note_BBB=AAA) in which the note for BBB should link to the same footnote as AAA, with
			-- 2a) The other linked note exist in the part of the table shown
			-- 2b) The part of the note does not exist in the part of the table shown
			if not Args['note_'..note_local] then
				-- Option 1
				-- Now define the identifier for this
				note_id = '"table_note_'..team_code_ii..rand_val..'"' -- Add random end for unique ID if more tables are present on article (which might otherwise share an ID)
				note_id_list[team_code_ii] = note_id
				
				-- Call refn template
				note_string = frame:expandTemplate{ title = 'efn', args = { group='lower-alpha',  name=note_id, note_local} }
			else 
				-- Option 2
				-- It is option 2a in either one if either the main note is inside the sub-table
				--                                  or another ref to that note is inside the sub-table
				-- Basically when it either has been defined, or the main link will be in the table
				note_local_num = team_list[note_local]
				if note_id_list[note_local] or ((note_local_num >= ii_start) and (note_local_num <= ii_end)) then
					-- Option 2a
					note_id = '"table_note_'..note_local..rand_val..'"'
					note_string = frame:extensionTag{ name = 'ref', args = { group = 'lower-alpha', name = note_id} }
				else
					-- Option 2b
					-- Now define the identifier for this
					note_id = '"table_note_'..note_local..rand_val..'"' -- Add random end for unique ID
					note_id_list[note_local] = note_id
					
					-- Call refn template
					note_string = frame:expandTemplate{ title = 'efn', args = { group='lower-alpha',  name=note_id, Args['note_'..note_local]} }
				end
			end
		else
			note_string = '';
		end
		
		-- Insert status when needed
		local status_string = ''
		local status_local = show_status and Args[respre .. 'status_'..team_code_ii] or nil
		local status_let_first = true
		local curr_letter
		-- Only if it is defined
		if status_local then
			-- Take it letter by letter
			for jjj = 1,mw.ustring.len(status_local) do
				curr_letter = mw.ustring.upper(mw.ustring.sub(status_local,jjj,jjj))
				-- See whether it exist
				if t_status.code[curr_letter] then
					-- Depending on whether it is the first letter of not
					if status_let_first then
						status_string = curr_letter
						t_status.called[curr_letter] = true
						status_let_first = false
					else
						status_string = status_string..', '..curr_letter
						t_status.called[curr_letter] = true
					end
				end
		end
		-- Only add brackets/dash and bolding if it exist
			if not status_let_first then 
				if t_status.position == 'before' then
					status_string = '<span style="font-weight:bold">'..string.lower(status_string)..' &ndash;</span> ' 
				else
					status_string = ' <span style="font-weight:bold">('..status_string..')</span>' 
				end
			end
		end
		
		-- Now build the rows
		table.insert(t,'|- \n')																			-- New row
		if position_col then
			table.insert(t,'| style="text-align: center;'..ii_fw..bg_col..'"| '..pos_num..'\n')	-- Position number
		end
		if full_table and group_col then
			table.insert(t,'| style="'..ii_fw..bg_col..'" |'..group_txt..'\n') 							-- Group number/name
		end
		-- Build the team string order based on status position
		local team_string
		if t_status.position == 'before' then
			team_string = status_string..team_name..note_string
		else
			team_string = team_name..note_string..status_string
		end
		table.insert(t,'! scope="row" style="text-align: left; white-space:nowrap;'..ii_fw..bg_col..'"| '..team_string..'\n')-- Team (with possible note)
		-- Call to subfunction
		t_return = p_style.row(frame,t,Args,p_sub,notes_exist,hth_id_list,full_table,rand_val,team_list,team_code_ii,ii_start,ii_end,ii_fw,bg_col,N_teams,ii,ii_show)
		t = t_return.t
		notes_exist = t_return.notes_exist
		hth_id_list = t_return.hth_id_list
		
		-- Now check what needs to be added inside the results column
		if full_table then
			local res_jjj
			if ii == new_res_ii then
				-- First check how many rows you need for this
				N_rows_res = 1
				jjj = ii+1
				result_local = Args[respre..'result'..ii] or ''
				local cont_loop = true
				while (jjj<=ii_end) and cont_loop do
					if Args['split'..tostring(jjj-1)] then
						cont_loop = false
						new_res_ii = jjj
					else
						res_jjj = Args[respre..'result'..jjj] or ''
						if result_local == res_jjj then 
							N_rows_res = N_rows_res+1 
						else
							cont_loop = false
							new_res_ii = jjj
						end
					end
					jjj = jjj+1
				end
				-- Now create this field (reuse ii_fw and bg_col)
				-- Bold (if in range) or not
				if ii_show and (ii_show>=ii) and (ii_show<=(ii+N_rows_res-1)) then
					ii_fw = 'font-weight: bold;'
				else
					ii_fw = 'font-weight: normal;'
				end
				-- Get background colour
				bg_col = nil
				if Args[respre..'result'..ii] then
					bg_col = result_col[Args[respre..'col_'..result_local]] or Args[respre..'col_'..result_local] or 'inherit'
					bg_col = 'background-color:'..bg_col..';' 	-- Full style tag
				end
				if not bg_col then bg_col = 'background-color:transparent;' end -- Becomes default if undefined
				-- Check for notes
				local note_res_string, note_ref, note_text = '', '', ''
				if Args['note_res_'..result_local] then
					notes_exist = true
					local note_res_local = Args['note_res_'..result_local]
					
					-- Split the note_res_local into a table if all the entries are valid
					local multiref = 1
					local note_res_local_table = mw.text.split(note_res_local, '%s*,%s*')
					if (#note_res_local_table > 1) then
						for k, note_res_loc in ipairs(note_res_local_table) do
							multiref = multiref * (Args['note_res_' .. note_res_loc] and 1 or 0)
						end
					else
						multiref = 0
					end

					-- Split failed, so make a single entry table with hth_local inside
					if multiref < 1 then
						note_res_local_table = { note_res_local }
					end

					for k,note_res_local in ipairs(note_res_local_table) do
						if not Args['note_res_'..note_res_local] then
							-- It does not point to another result note
							note_ref = respre..'res_'..result_local
							note_id = '"table_note_res_'..result_local..rand_val..'"' -- Identifier
							note_text = note_res_local
						else
							-- It does point to another result note
							note_ref = respre..'res_'..note_res_local
							note_id = '"table_note_res_'..note_res_local..rand_val..'"' -- Identifier
							note_text = Args['note_res_'..note_res_local]
						end
						-- Check whether it is already printed
						if not note_id_list[note_ref] then
							-- Print it
							note_id_list[note_ref] = note_id
							note_res_string = note_res_string .. frame:expandTemplate{ title = 'efn', args = { group='lower-alpha',  name=note_id, note_text} }
						else
							-- Refer to it
							note_res_string = note_res_string .. frame:extensionTag{ name = 'ref', args = { group = 'lower-alpha', name = note_id} }
						end
					end
				end
				-- Get text
				local text_result = Args[respre..'text_'..result_local] or ''
				if text_result:match('fbmulticomp') then
					ii_fw = 'padding:0;' .. ii_fw
					if text_result:match('fbmulticompefn') then
						notes_exist = true
					end
				end
				text_field_result = '| style="'..ii_fw..bg_col..'" rowspan="'..tostring(N_rows_res)..'" |'..text_result..note_res_string..'\n'
				-- See whether it is needed (only when blank for all entries)
				if results_defined then table.insert(t,text_field_result) end
			end
		end
	
		-- Insert match row if needed
		if match_table then
			local legs = tonumber(Args['legs']) or 1
			-- Add empty cell
			table.insert(t,'| style="background-color:white;border-top:white;border-bottom:white;"| \n')
			
			-- Now include note to match results if needed 
			for jj=top_pos,N_teams do
				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
								note_id = '"table_note_'..team_code_ii..'_'..team_code_jj..rand_val..'"' -- Add random end for unique ID if more tables are present on article (which might otherwise share an ID)
								note_id_list[team_code_ii..'_'..team_code_jj] = note_id
								
								note_string = frame:expandTemplate{ title = 'efn', args = { group='lower-alpha', name=note_id,  match_note} }
							else 
								-- Check for existence elsewhere
								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 = 'lower-alpha', name = note_id} }
								else
									-- Now define the identifier for this
									note_id = '"table_note_'..match_note..rand_val..'"' -- Add random end for unique ID
									note_id_list[match_note] = note_id
									-- Call refn template
									note_string = frame:expandTemplate{ title = 'efn', args = { group='lower-alpha', 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
			
			-- Add rest of match row
			t = p_matches.row(t,Args,N_teams,team_list,ii,ii_show,legs)
		end
	
		-- Now, if needed, insert a split (solid line to indicate split in standings, but only when it is not at the last shown position)
		if Args['split'..ii] and (ii<ii_end) then
			-- Base size on N_cols (it needs 2*N_cols |)
			table.insert(t,'|- style="background-color:'..result_col['black1']..'; line-height:3pt;"\n')
			table.insert(t,string.rep('|',2*N_cols)..'\n')
		end
	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 (title_source == true and '')
		or frame:expandTemplate{ title = 'citation needed', args = { reason='No source parameter defined', date=os.date('%B %Y') } }
	local class_rules = Args['class_rules']	or nil
	
	-- Create footer text
	-- Date updating
	local matches_text = Args['matches_text'] or 'match(es)'
	if string.lower(update)=='complete' then
		-- Do nothing
	elseif update=='' then
		-- Empty parameter
		table.insert(t_footer,'Updated to '..matches_text..' played on unknown. ')
	elseif string.lower(update)=='future' then
		-- Future start date
		table.insert(t_footer,'First '..matches_text..' will be played on '..start_date..'. ')
	else
		table.insert(t_footer,'Updated to '..matches_text..' played on '..update..'. ')
	end
	
	-- Stack footer or not
	local footer_break = yesno(Args['stack_footer'] or 'no') and true or false
	
	-- Variable for linebreak
	local stack_string = '<br>'
	
	if footer_break and (not (string.lower(update)=='complete')) then table.insert(t_footer,stack_string) end
	
	if source ~= '' then
		table.insert(t_footer,'Source: '..source)
	end
	if class_rules and full_table and show_class_rules then
		table.insert(t_footer,'<br>Rules for classification: '..class_rules)
	end
	
	-- Now for the named status
	local status_exist = false
	local status_string = ''
	local curr_letter
	for jjj = 1,mw.ustring.len(t_status.letters) do
		curr_letter = mw.ustring.upper(mw.ustring.sub(t_status.letters,jjj,jjj))
		if t_status.called[curr_letter] then
			if (footer_break and status_exist) then
				status_string = status_string..stack_string
			end
			if t_status.position == 'before' then
				status_string = status_string..'<span style="font-weight:bold">'..string.lower(curr_letter)..' &ndash;</span> '..t_status.code[curr_letter]..'; '
			else
				status_string = status_string..'<span style="font-weight:bold">('..curr_letter..')</span> '..t_status.code[curr_letter]..'; '
			end
			status_exist = true
		end
	end
	-- Now end it with a point instead (if it contains entries the '; ' needs to be removed)
	if status_exist then
		status_string = '<br>'..mw.ustring.sub(status_string,1,mw.ustring.len(status_string)-2)..'.'
		table.insert(t_footer,status_string)
	end

	-- Add notes (if applicable)
	if notes_exist then
		table.insert(t_footer,'<br>Notes:')
		-- As reflist size text
		t_footer = '<div class="reflist">'..table.concat(t_footer)..'</div>'
		t_footer = t_footer..frame:expandTemplate{ title = 'notelist', args = { group='lower-alpha'} }
	else
		-- As reflist size text
		t_footer = '<div class="reflist">'..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
	
	-- Generate tracking
	if not Args['notracking'] then
		local getTracking = require('Module:Sports table/argcheck').check
		local warning_categories, tracking_categories = getTracking(Args, frame:getParent().args)
		if #warning_categories > 0 then
			if frame:preprocess( "{{REVISIONID}}" ) == "" then
				for k=1,#warning_categories do
					warning_categories[k] = mw.ustring.gsub(warning_categories[k], '^%[%[Category:Pages using sports table with (.*)|(.*)%]%]$', '<div style="color:red">Warning: %1 = %2</div>')
				end
			end
		end
		for k=1,#warning_categories do
				table.insert(t, warning_categories[k])
		end
		for k=1,#tracking_categories do
				table.insert(t, tracking_categories[k])
		end
		
		if(Args['showteam'] == nil) then
			local getWarnings = require('Module:Sports table/totalscheck').check
			local total_warnings = getWarnings(Args, team_list, ii_start, ii_end)
			if #total_warnings > 0 then
				if frame:preprocess( "{{REVISIONID}}" ) == "" then
					for k=1,#total_warnings do
						table.insert(t, '<div style="color:green">Possible problem: ' .. total_warnings[k] .. '</div>')
					end
				end
			end
		end
	else
		table.insert(t, '[[Category:Pages using sports table with notracking]]')
	end
	
	if Args['float'] then
		return frame:expandTemplate{ title = 'stack begin', args = {clear = 'true', margin = '1', float = Args['float']} }
			.. '\n' .. table.concat(t) .. frame:expandTemplate{ title = 'stack end'}
	end

	return table.concat(t)
end
 
return p