Module:Series overview

Revision as of 11:19, 7 June 2020 by Neuleinster (talk | contribs) (Created page with "-- This module implements {{Series overview}}. require('Module:No globals') local yesno = require('Module:Yesno') local HTMLcolor = mw.loadData( 'Module:Color contrast/colors...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Usage

The purpose of this template is to easily add a series overview table (as per WP:TVOVERVIEW) for television series' that require it, in either a simple format (i.e. just episodes and dates) or with extra information (e.g. networks, ratings, etc).

Syntax and examples

Basic example

Code
{{Series overview
| color1     = #74E387
| link1      = #Season 1
| episodes1  = 26
| start1     = {{Start date|2012|9|8}}
| end1       = {{End date|2013|6|15}}

| color2     = #004000
| link2      = #Season 2
| episodes2  = 26
| start2     = {{Start date|2013|9|13}}
| end2       = {{End date|2014|6|21}}

| color3     = #000000
| link3      = #Season 3
| episodes3  = 26
| start3     = {{Start date|2014|9|19}}
| end3       = {{End date|2015|6|26}}
}}
SeasonEpisodesOriginally aired
First airedLast aired
126September 8, 2012 (2012-09-08)June 15, 2013 (2013-06-15)
226September 13, 2013 (2013-09-13)June 21, 2014 (2014-06-21)
326September 19, 2014 (2014-09-19)June 26, 2015 (2015-06-26)

Alternate link text with caption and raw link text

Code
{{Series overview
| caption    = Series overview

| color1     = #74E387
| link1      = #Season 1
| linkT1     = Chapter One
| episodes1  = 26
| start1     = {{Start date|2012|9|8}}
| end1       = {{End date|2013|6|15}}

| color2     = #004000
| link2      = #Season 2
| linkT2     = Chapter Two
| episodes2  = 26
| start2     = {{Start date|2013|9|13}}
| end2       = {{End date|2014|6|21}}

| color3     = #000000
| link3      = #Season 3
| linkT3     = Chapter Three
| linkR3     = {{dummy ref|1}}
| episodes3  = 26
| start3     = {{Start date|2014|9|19}}
| end3       = {{End date|2015|6|26}}
}}
Series overview
SeasonEpisodesOriginally aired
First airedLast aired
Chapter One26September 8, 2012 (2012-09-08)June 15, 2013 (2013-06-15)
Chapter Two26September 13, 2013 (2013-09-13)June 21, 2014 (2014-06-21)
Chapter Three[1]26September 19, 2014 (2014-09-19)June 26, 2015 (2015-06-26)

Series/Season & "dd mmm yyyy" dates

The top-left cell displays either Series or Season, determined if the |df= parameter of the first {{Start date}} template is set. If it is included (|df=y), the cell will display Series, otherwise the cell will display Season. This can be overridden by setting either |seriesT= or |seasonT= to custom text.

Code
{{Series overview
| color1     = #74E387
| link1      = #Season 1
| episodes1  = 26
| start1     = {{Start date|2012|9|8|df=y}}
| end1       = {{End date|2013|6|15|df=y}}

| color2     = #004000
| link2      = #Season 2
| episodes2  = 26
| start2     = {{Start date|2013|9|13|df=y}}
| end2       = {{End date|2014|6|21|df=y}}

| color3     = #000000
| link3      = #Season 3
| episodes3  = 26
| start3     = {{Start date|2014|9|19|df=y}}
| end3       = {{End date|2015|6|26|df=y}}
}}
SeriesEpisodesOriginally aired
First airedLast aired
1268 September 2012 (2012-09-08)15 June 2013 (2013-06-15)
22613 September 2013 (2013-09-13)21 June 2014 (2014-06-21)
32619 September 2014 (2014-09-19)26 June 2015 (2015-06-26)

Split season

Code
{{Series overview
| color1     = #74E387
| link1      = #Season 1
| episodes1  = 26
| start1     = {{Start date|2012|9|8}}
| end1       = {{End date|2013|6|15}}

| color2     = #004000
| link2      = #Season 2
| episodes2  = 26
| start2     = {{Start date|2013|9|13}}
| end2       = {{End date|2014|6|21}}

| link3      = #Season 3
| episodes3  = 38
| color3A    = #000000
| episodes3A = 13
| start3A    = {{Start date|2014|9|19}}
| end3A      = {{End date|2014|12|24}}
| color3B    = #00004A
| episodes3B = 12
| start3B    = {{Start date|2015|2|15}}
| end3B      = {{End date|2015|6|26}}
| color3C    = #00008A
| episodes3C = 13
| start3C    = {{Start date|2015|11|4}}
| end3C      = {{End date|2016|1|31}}
}}
SeasonEpisodesOriginally aired
First airedLast aired
126September 8, 2012 (2012-09-08)June 15, 2013 (2013-06-15)
226September 13, 2013 (2013-09-13)June 21, 2014 (2014-06-21)
33813September 19, 2014 (2014-09-19)December 24, 2014 (2014-12-24)
12February 15, 2015 (2015-02-15)June 26, 2015 (2015-06-26)
13November 4, 2015 (2015-11-04)January 31, 2016 (2016-01-31)

And with the |episodes parameter set to "hide".

SeasonEpisodesOriginally aired
First airedLast aired
126September 8, 2012 (2012-09-08)June 15, 2013 (2013-06-15)
226September 13, 2013 (2013-09-13)June 21, 2014 (2014-06-21)
313September 19, 2014 (2014-09-19)December 24, 2014 (2014-12-24)
12February 15, 2015 (2015-02-15)June 26, 2015 (2015-06-26)
13November 4, 2015 (2015-11-04)January 31, 2016 (2016-01-31)

Specials

Code
{{Series overview
| color1     = #74E387
| link1      = #Season 1
| episodes1  = 26
| start1     = {{Start date|2012|9|8}}
| end1       = {{End date|2013|6|15}}

| color2     = #004000
| link2      = #Season 2
| episodes2  = 26
| start2     = {{Start date|2013|9|13}}
| end2       = {{End date|2014|6|21}}

| color3     = #000000
| link3      = #Season 3
| episodes3  = 26
| start3     = {{Start date|2014|9|19}}
| end3       = {{End date|2015|6|26}}

| color3S    = #00004A
| link3S     = #Special
| linkT3S    = S
| episodes3S = 1
| start3S    = {{Start date|2015|10|21}}
}}
SeasonEpisodesOriginally aired
First airedLast aired
126September 8, 2012 (2012-09-08)June 15, 2013 (2013-06-15)
226September 13, 2013 (2013-09-13)June 21, 2014 (2014-06-21)
326September 19, 2014 (2014-09-19)June 26, 2015 (2015-06-26)
S1October 21, 2015 (2015-10-21)

And with the |episodes parameter removed and the link text changed.

SeasonEpisodesOriginally aired
First airedLast aired
126September 8, 2012 (2012-09-08)June 15, 2013 (2013-06-15)
226September 13, 2013 (2013-09-13)June 21, 2014 (2014-06-21)
326September 19, 2014 (2014-09-19)June 26, 2015 (2015-06-26)
SpecialOctober 21, 2015 (2015-10-21)

Special first, followed by season one

Code
{{Series overview
| color0S    = #00004A
| link0S     = #Special
| linkT0S    = S
| episodes0S = 1
| start0S    = {{Start date|2011|10|21}}

| color1     = #74E387
| link1      = #Season 1
| episodes1  = 26
| start1     = {{Start date|2012|9|8}}
| end1       = {{End date|2013|6|15}}

| color2     = #004000
| link2      = #Season 2
| episodes2  = 26
| start2     = {{Start date|2013|9|13}}
| end2       = {{End date|2014|6|21}}

| color3     = #000000
| link3      = #Season 3
| episodes3  = 26
| start3     = {{Start date|2014|9|19}}
| end3       = {{End date|2015|6|26}}
}}
SeasonEpisodesOriginally aired
First airedLast aired
S1October 21, 2011 (2011-10-21)
126September 8, 2012 (2012-09-08)June 15, 2013 (2013-06-15)
226September 13, 2013 (2013-09-13)June 21, 2014 (2014-06-21)
326September 19, 2014 (2014-09-19)June 26, 2015 (2015-06-26)

Extra information and country-based header

Code
{{Series overview
| infoA      = Rank
| infoB      = Rating
| infoC      = Average viewership<br />(in millions)
| country    = U.S.

| color1     = #74E387
| link1      = #Season 1
| episodes1  = 26
| start1     = {{Start date|2012|9|8}}
| end1       = {{End date|2013|6|15}}
| infoA1     = 55
| infoB1     = 11.8
| infoC1     = 3.2

| color2     = #004000
| link2      = #Season 2
| episodes2  = 26
| start2     = {{Start date|2013|9|13}}
| end2       = {{End date|2014|6|21}}
| infoA2     = 65
| infoB2     = 9.2

| color3     = #000000
| link3      = #Season 3
| episodes3  = 26
| start3     = {{Start date|2014|9|19}}
| end3       = {{End date|2015|6|26}}
| infoA3     = 63
}}
SeasonEpisodesOriginally aired (U.S.)RankRatingAverage viewership
(in millions)
First airedLast aired
126September 8, 2012 (2012-09-08)June 15, 2013 (2013-06-15)5511.83.2
226September 13, 2013 (2013-09-13)June 21, 2014 (2014-06-21)659.2TBA
326September 19, 2014 (2014-09-19)June 26, 2015 (2015-06-26)63TBATBA

Multiple networks

Code
{{Series overview
| color1     = #74E387
| link1      = #Season 1
| episodes1  = 26
| start1     = {{Start date|2012|9|8}}
| end1       = {{End date|2013|6|15}}
| network1   = [[The WB]]

| color2     = #004000
| link2      = #Season 2
| episodes2  = 26
| start2     = {{Start date|2013|9|13}}
| end2       = {{End date|2014|6|21}}

| color3     = #000000
| link3      = #Season 3
| episodes3  = 26
| start3     = {{Start date|2014|9|19}}
| end3       = {{End date|2015|6|26}}
| network3   = [[The CW]]
}}
SeasonEpisodesOriginally aired
First airedLast airedNetwork
126September 8, 2012 (2012-09-08)June 15, 2013 (2013-06-15)The WB
226September 13, 2013 (2013-09-13)June 21, 2014 (2014-06-21)
326September 19, 2014 (2014-09-19)June 26, 2015 (2015-06-26)The CW

Auxiliary columns

Code
{{Series overview
| auxA       = Title
| auxB       = Stories

| color1     = #74E387
| link1      = #Season 1
| auxA1      = ''First''
| auxB1      = 13
| episodes1  = 26
| start1     = {{Start date|2012|9|8}}
| end1       = {{End date|2013|6|15}}

| color2     = #004000
| link2      = #Season 2
| auxA2      = ''Second''
| auxB2      = 14
| episodes2  = 26
| start2     = {{Start date|2013|9|13}}
| end2       = {{End date|2014|6|21}}

| color3     = #000000
| link3      = #Season 3
| auxA3      = ''Third''
| auxB3      = 15
| episodes3  = 26
| start3     = {{Start date|2014|9|19}}
| end3       = {{End date|2015|6|26}}
}}
SeasonTitleStoriesEpisodesOriginally aired
First airedLast aired
1First1326September 8, 2012 (2012-09-08)June 15, 2013 (2013-06-15)
2Second1426September 13, 2013 (2013-09-13)June 21, 2014 (2014-06-21)
3Third1526September 19, 2014 (2014-09-19)June 26, 2015 (2015-06-26)

Released

Code
{{Series overview
| released   = y

| color1     = #74E387
| link1      = #Season 1
| episodes1  = 26
| start1     = {{Start date|2012|9|8}}
| end1       = start

| color2     = #004000
| link2      = #Season 2
| episodes2  = 26
| start2     = {{Start date|2013|9|13}}
| end2       = {{End date|2014|6|21}}

| color3     = #000000
| link3      = #Season 3
| episodes3  = 26
| start3     = {{Start date|2014|9|19}}
| end3       = start
}}
SeasonEpisodesOriginally released
First releasedLast released
126September 8, 2012 (2012-09-08)
226September 13, 2013 (2013-09-13)June 21, 2014 (2014-06-21)
326September 19, 2014 (2014-09-19)

End dates omitted with the |allreleased parameter set.

SeasonEpisodesOriginally released
126September 8, 2012 (2012-09-08)
226September 13, 2013 (2013-09-13)
326September 19, 2014 (2014-09-19)

Multi-series franchise

Code
{{Series overview
| width       = 75%
| infoA       = [[Showrunner]]
| infoB       = Status
| multiseries = 
{{Series overview
| series      = ''Series A''
| infoA       = y
| infoB       = y

| color1      = #74E387
| link1       = #Season 1
| episodes1   = 26
| start1      = {{Start date|2012|9|8}}
| end1        = {{End date|2013|6|15}}
| infoA1      = John Smith
| infoB1      = Released

| color2      = #004000
| link2       = #Season 2
| episodes2   = 26
| start2      = {{Start date|2013|9|13}}
| end2        = {{End date|2014|6|21}}

| color3      = #000000
| link3       = #Season 3
| episodes3   = 26
| start3      = {{Start date|2014|9|19}}
| end3        = {{End date|2015|6|26}}
}}
{{Series overview
| series      = ''Series B''
| infoA       = y
| infoB       = y

| color1      = #7487E3
| link1       = #Season 1
| episodes1   = 26
| start1      = {{Start date|2015|9|21}}
| end1        = {{End date|2016|6|11}}
| infoA1      = Jane Doe
| infoB1      = Released

| color2      = #000040
| link2       = #Season 2
| episodes2   = 26
| start2      = {{Start date|2016|9|17}}
| end2        = {{End date|2017|6|30}}
| infoB2      = Airing
}}
}}
SeriesSeasonEpisodesOriginally airedShowrunnerStatus
First airedLast aired
Series A126September 8, 2012 (2012-09-08)June 15, 2013 (2013-06-15)John SmithReleased
226September 13, 2013 (2013-09-13)June 21, 2014 (2014-06-21)
326September 19, 2014 (2014-09-19)June 26, 2015 (2015-06-26)
Series B126September 21, 2015 (2015-09-21)June 11, 2016 (2016-06-11)Jane DoeReleased
226September 17, 2016 (2016-09-17)June 30, 2017 (2017-06-30)Airing

Parameters

Template parameters
Parameter Description Type Status
Caption caption An appropriate caption for the table, normally something like "Series overview". Required for proper accessibility. When a caption is not required on the page where the table is located, but is on a page where the table is transcluded, the caption may be wrapped in <includeonly> and </includeonly>. Text Required
Header titles Season/Series seasonT Set to change custom text in the cell where Series/Season is typically displayed.
Format: Series
Alternate: seriesT
Text Optional
Info sub-headers info{A-Z} The sub-headers of the extra information (e.g. Viewers (in millions)) for the series in question. 26 columns are available for extra information (labelled infoA ... infoZ). When used in multi-series franchise overviews, set the value to the column titles in the initial declaration of the template, and set to "y" in each of the separate series overviews to still include the info cells.
Format: Viewers (in millions)
Text Optional
Auxiliary aux{A-Z} The titles of the auxiliary columns. 26 columns are available for auxiliary columns (labelled auxA ... auxZ).
Format: Title
Text Optional
Country country Add a country to the "Originally aired/released" header cell.
Format: U.S.
Text Optional
Network network The network that multiple seasons have aired under, if a series has aired on two or more networks. Only use as a header title in multi-series franchises, in the initial declaration of the template, not the season-specific networks and set to "y" in this case. Text Optional
Transclusion display *_transclude Gives the option to toggle the display of certain columns (network and info columns are the only ones supported so far) when tranclcuding the overview. This parameter takes one of two values: 1) "onlyinclude", so the column is only included in the table when transcluded (i.e. not shown on the origin page), or 2) "noinclude", so the column is only included in the table on the origin page (i.e. not shown on the transcluding page). For the template to determine what the original article is, the original article title must be included as the first unnamed parameter (e.g. as {{Series overview|PAGE NAME}} or {{Series overview|1=PAGE NAME}}). Text Optional
Franchises Multiple series multiseries The individual series overviews that make up a multi-series franchise table. Use in the first series overview that declares the headers. The parameter value should be the separate series overviews. Set to "y" when "dontclose" is declared. Series overviews Optional
Series series The linked, italicized title of the series when used in a multi-series franchise. Use in each separate series overview. Link Required when multiseries is set
Don't Close dontclose Set this parameter to "y" to be able to close the initial wikicode declaration of the multi-series franchise header overview, but to be able to continue displaying the separate series and rows after the header but outside of the initial declaration. Particularly useful for when the individual rows have to be transcluded outside of the article and thus must be outside of a template. To close the initial declaration, </table> must be used. Text Optional
Season specifics Color color* The color of the season table for the season in question.
Format: black / #000000
Color Required
Link link* The link to the season in question.
Transclusion format: <includeonly>List of iZombie episodes</includeonly>#Season 1 (2015)
Non-transclusion format: #Season 1 (2015)
Text Required
Link Text linkT* Alternate text to display in the season link rather than the season number.
Format: Special
Text Optional
Raw Link Text linkR* Additional text to display next to the season link, outside of the link itself. Good for references or notes.
Format: {{efn}}
Text Optional
Auxiliary aux{A-Z}* Auxiliary columns for season titles, etc. This column spans rows when succeeding auxiliary parameters are not set.
Format: Coven
Text Optional
Episodes episodes* The number of episodes in the season in question.
Set to "hide" for split seasons to hide the total episode count and use only the split episode counts. This is particular useful for when the episodes don't combine together; for example, a pilot episode then a full season. Setting to "hide" for regular seasons has no effect.
Format: 22
Exclusion: {{N/A|TBA}}
Number / Text Optional
Start date start* The start date of the season in question. This parameter is required for the row of the overview to appear; without a date but with the inclusion of any other parameter, the row will not display. To display a row without a start date, use {{N/A|TBA}}.
Format: {{Start date|2015|3|17}}
Exclusion: {{N/A|TBA}}
Date Required
End date end* The end date of the season in question. If equal to start (i.e. the season was aired/released on the same day), the date spans over two columns. Not included if the "allreleased" parameter is set.
Format: {{End date|2015|6|9}}
Exclusion: {{N/A|TBA}}
Date/Text Optional
Network network* The network that multiple seasons have aired under, if a series has aired on two or more networks. The span of the network column is calculated automatically.
Format: ABC
Text Optional
Info info{A-Z}* The values of the extra information (e.g. Ratings) for the season in question.
Note: Information cell parameters will be automatically set to {{N/A|TBA}} if set for a previous season (e.g. info1A) but not included for the current season (e.g. info2A) in regular series overviews. Information cells will automatically span over empty rows in multi-series franchise series overviews if set for a previous season but not included for the current season; they cannot, however, span between separate series-specific overviews, meaning information may be repeated (e.g. a "Released" status for multiple series that have been released).
Format: 28
Text Optional
Release Released released Determines whether the television series in question was released online or aired. Changes "Originally/First/Last aired" to "Originally/First/Last released".
Format: y
Text Optional
All Released allreleased Determines whether the television series has all episodes in every season released on the same day (e.g. Orange Is the New Black).
Format: y
Text Optional

* indicates any number that is a positive integer, starting from one for regular/split seasons, and zero for specials.


-- This module implements {{Series overview}}.

require('Module:No globals')
local yesno = require('Module:Yesno')
local HTMLcolor = mw.loadData( 'Module:Color contrast/colors' )

--------------------------------------------------------------------------------
-- SeriesOverview class
-- The main class.
--------------------------------------------------------------------------------

local SeriesOverview = {}

function SeriesOverview.cellspan(SeasonEntries, SeasonEntries_ordered, key, cell, multipart)
	local spanlength = 1
	
	local firstEntry = SeasonEntries[SeasonEntries_ordered[cell]]
	if key == 'network' and firstEntry.networkA and not firstEntry.networkB then spanlength = 2 end
	
	for i = cell+1, #SeasonEntries_ordered do
		local entry = SeasonEntries[SeasonEntries_ordered[i]]
		-- Split season, then regular season
		if entry.startA then
			if not entry[key..'A'] then spanlength = spanlength + 1
			else break end
			if not entry[key..'B'] then spanlength = spanlength + 1
			else break end
		else
			if not entry[key] and (key == 'network' or (string.sub(key,0,3) == 'aux' and (not entry.special or entry.episodes)) or (string.sub(key,0,4) == 'info') and multipart) then
				spanlength = spanlength + 1
			else break end
		end
	end
	return spanlength
end

-- Sorting function
function SeriesOverview.series_sort(op1, op2)
	local n1,s1 = string.match(op1,"(%d+)(%a*)")
	local n2,s2 = string.match(op2,"(%d+)(%a*)")
	local n1N,n2N = tonumber(n1),tonumber(n2)

	if n1N == n2N then
		return s1 < s2
	else
		return n1N < n2N
	end
end

-- Function to add either text or {{N/a}} to cell
function SeriesOverview.season_cell(text, frame)
	local cell
	
	if string.find(text or '', 'table-na', 0, true) ~= nil then
		local findpipe = string.find(text, ' | ', 0, true)
		if findpipe ~= nil then
			cell = SeriesOverview.series_attributes( frame:expandTemplate{title='N/A',args={string.sub(text,findpipe+3)}} )
		else
			cell = SeriesOverview.series_attributes( frame:expandTemplate{title='N/A'} )
		end
	else
		cell = mw.html.create('td'):wikitext(text)
	end
	
	return cell
end

-- Allow usages of {{N/A}} cells
function SeriesOverview.series_attributes(infoParam)
	local entries = {}
	local infoCell = mw.html.create('td')
	local attrMatch = '([%a-]*)="([^"]*)"'
	
	while true do
		local a,b = string.match(infoParam,attrMatch)
		if a == nil or b == nil then break end
		infoCell:attr(a,b)
		infoParam = string.gsub(infoParam,attrMatch,'',1)
	end

	infoParam = string.gsub(infoParam,'%s*|%s*','',1)
	infoCell:wikitext(infoParam)
	
	return infoCell
end

function SeriesOverview.new(frame, args)
	args = args or {}
	
	local initialArticle = args['1'] or ''
	local categories = ''
	local title = mw.title.getCurrentTitle()
	local allReleased = yesno(args.allreleased)

	-- Create series overview table
	local root = mw.html.create((args.multiseries or not args.series) and 'table' or '')
	local cellPadding = '0 8px'
	local basePadding = '0.2em 0.4em'

	root
		:addClass('wikitable')
		:addClass('plainrowheaders')
		:css('text-align', 'center')
	
	-- Sortable
	if args.sortable then
		root:addClass('sortable');
	end
	
	-- Width
	if args.width then
		root:css('width', args.width)
	end

	-- Caption
	if args.caption then
		root:tag('caption'):wikitext(args.caption)
	end

	-- Extract seasons info and place into a 3D array
	local SeasonEntries = {}
	for k,v in pairs(args) do
		local str, num, str2 = string.match(k, '([^%d]*)(%d*)(%a*)')
		if num ~= '' then 
			-- Special
			local special = false
			if string.sub(str2,1,1) == 'S' then
				special = true
				num = num .. str2
				str2 = ''
			end
			-- Add to entries, create if necessary
			if not SeasonEntries[num] then
				SeasonEntries[num] = {}
			end
			SeasonEntries[num][str .. str2] = v
			if special then
				SeasonEntries[num]['special'] = 'y'
			end
		end
	end

	-- Order table by season number
	local SeasonEntries_ordered = {}
	for k in pairs(SeasonEntries) do
		table.insert(SeasonEntries_ordered, k)
	end
	table.sort(SeasonEntries_ordered,SeriesOverview.series_sort)
	
	local firstRow = args.multiseries and {} or SeasonEntries[SeasonEntries_ordered[1]]
	
	-- Colspan calculation for information cells (0 = no info set)
	local numAuxCells = 0
	local numInfoCells = 0
	for i = string.byte('A'), string.byte('Z') do
		local param = 'info' .. string.char(i)
		if args[param] then numInfoCells = numInfoCells + 1 end
	end
	
	-- Top info cell
	-- @ = string.char(64), A = string.char(65)
	local topInfoCell = numInfoCells > 0 and string.char(numInfoCells + (string.byte('A') - 1)) or '@'
	
	-- Networks are included if the very first entry sets the first network
	local setNetwork = (args.multiseries and args.network) or firstRow.network or firstRow.networkA
	local networkTransclude = args.network_transclude
	if (networkTransclude == 'onlyinclude' and title.fullText == initialArticle) or (networkTransclude == 'noinclude' and title.fullText ~= initialArticle) then
		setNetwork = false
	end

	-- Headers
	do
		if args.multiseries or not args.series then
			local headerRow = root:tag('tr')
			headerRow
				:css('text-align', 'center')
			
			local releasedBlurb = args.released and 'released' or 'aired'
			
			-- Base series/season content on the format of the first date; Series = D M Y, Season = M D, Y
			local matchDMY = false
			local thisStart = firstRow.start or firstRow.startA
			if thisStart then
				if string.match(thisStart:gsub("&nbsp;"," "), '(%d+)%s(%a+)%s(%d+)') then
					matchDMY = true
				end
			end
			
			-- Multiple series header
			if args.multiseries then
				headerRow:tag('th')
					:attr('scope', 'col')
					:css('padding', cellPadding)
					:attr('rowspan', allReleased and 1 or 2)
					:wikitext('Series')
			end
			
			-- Season header
			headerRow:tag('th')
				:attr('scope', 'col')
				:attr('rowspan', allReleased and 1 or 2)
				:attr('colspan', 2)
				:css('min-width', '50px')
				:css('padding', cellPadding)
				:wikitext(args.seriesT or args.seasonT or (matchDMY and 'Series') or 'Season')
			
			-- Aux headers
			for i = string.byte('A'), string.byte('Z') do
				local param = 'aux' .. string.char(i)
				if args[param] then
					numAuxCells = numAuxCells + 1
					headerRow:tag('th')
						:attr('scope', 'col')
						:css('padding', cellPadding)
						:attr('rowspan', allReleased and 1 or 2)
						:wikitext(args[param])
				end
			end

			-- Episodes header
			headerRow:tag('th')
				:attr('scope', 'col')
				:attr('rowspan', allReleased and 1 or 2)
				:attr('colspan', 2)
				:css('padding', cellPadding)
				:wikitext('Episodes')

			-- Originally aired header
			local OriginallyColspan = (not allReleased and setNetwork) and 3 or 2
			local countryBlurb = ''
			if args.country then
				countryBlurb = ' (' .. args.country .. ')'
			end
			headerRow:tag('th')
				:attr('scope', 'col')
				:attr('colspan', OriginallyColspan)
				:wikitext('Originally ' .. releasedBlurb .. countryBlurb)
			
			-- Network subheader for released series
			if setNetwork and allReleased then
				headerRow:tag('th')
					:attr('scope', 'col')
					:attr('rowspan', allReleased and 1 or 2)
					:css('padding', cellPadding)
					:wikitext('Network')
			end
			
			-- Information headers
			if topInfoCell ~= '@' then
				for i = string.byte('A'), string.byte(topInfoCell) do
					local param = 'info' .. string.char(i)
					local infoTransclude = args[param .. '_transclude']
					if (infoTransclude == 'onlyinclude' and title.fullText == initialArticle) or (infoTransclude == 'noinclude' and title.fullText ~= initialArticle) then else
						headerRow:tag('th')
							:attr('scope', 'col')
							:attr('rowspan', allReleased and 1 or 2)
							:css('padding', cellPadding)
							:wikitext(args[param])
					end
				end
			end
			
			-- Subheader row
			local subheaderRow = mw.html.create('tr')

			if not allReleased then
				-- First aired subheader
				subheaderRow:tag('th')
					:attr('scope', 'col')
					:wikitext('First ' .. releasedBlurb)

				-- Last aired subheader
				subheaderRow:tag('th')
					:attr('scope', 'col')
					:wikitext('Last ' .. releasedBlurb)
				
				-- Network subheader for aired series
				if setNetwork then
					subheaderRow:tag('th')
						:attr('scope', 'col')
						:css('padding', cellPadding)
						:wikitext('Network')
				end
			end
		
			-- Check for scenarios with an empty subheaderRow
			if not allReleased or numInfoCells > 0 then
				root:node(subheaderRow)
			end
		end
	end

	-- Season rows
	do
		if args.multiseries then
			-- Multi series individual entries
			if args.multiseries ~= "y" then
				root:node(args.multiseries)
			end
		else
			-- One row entries, only categorized in the mainspace
			if title.namespace == 0 and #SeasonEntries == 1 then
				categories = categories .. '[[Category:Articles using Template:Series overview with only one row]]'
			end
		
			-- Determine number of rows in the whole overview
			local SeasonEntriesRows = 0
			for X = 1, #SeasonEntries_ordered do
				local season, entry = SeasonEntries_ordered[X], SeasonEntries[SeasonEntries_ordered[X]]
				local splits = 0
				for i = string.byte('A'), string.byte('Z') do
					local param = 'start' .. string.char(i)
					if entry[param] then splits = splits + 1 end
				end
				if splits == 0 then splits = 1 end
				SeasonEntriesRows = SeasonEntriesRows + splits
			end
			
			for X = 1, #SeasonEntries_ordered do
				local season, entry = SeasonEntries_ordered[X], SeasonEntries[SeasonEntries_ordered[X]]
				
				-- Determine number of splits in a season
				local splits = 0
				for i = string.byte('A'), string.byte('Z') do
					local param = 'start' .. string.char(i)
					if entry[param] then splits = splits + 1 end
				end
				local splitSeason = (splits > 1)
				
				-- Season rows for each season
				for k0 = string.byte('A')-1, string.byte('Z') do
					local k = string.char(k0)
					if k0 == string.byte('A')-1 then k = '' end
					
					-- New season row
					-- local seasonRow = (entry['color' .. k] or entry['episodes' .. k] or entry['start' .. k] or entry['end' .. k]) and root:tag('tr') or mw.html.create('tr')
					local seasonRow = entry['start' .. k] and root:tag('tr') or mw.html.create('tr')
					
					-- Series name for group overviews
					if X == 1 and (k == '' or k == 'A') and args.series then
						seasonRow:tag('th')
							:attr('scope', 'row')
							:attr('rowspan', SeasonEntriesRows)
							:wikitext(args.series)
					end
					
					-- Coloured cell
					if entry['color' .. k] ~= nil and HTMLcolor[entry['color' .. k]] == nil then 
						entry['color' .. k] = '#'..(mw.ustring.match(entry['color' .. k], '^[%s#]*([a-fA-F0-9]*)[%s]*$') or '')
					end
					if splitSeason and entry.color then
						if k == 'A' then
							seasonRow:tag('td')
								:attr('rowspan', entry.color and splits or 1)
								:css('background', entry.color)
								:css('width','10px')
						end
					else
						seasonRow:tag('td')
							:css('background',entry['color' .. k])
							:css('width','10px')
					end
					
					-- Season number link, included only in the first row
					if k == '' or k == 'A' then
						seasonRow:tag('th')
							:attr('scope', 'row')
							:attr('rowspan', splitSeason and splits or nil)
							:attr('colspan', entry.special and not entry.episodes and 3+numAuxCells or 1)
							:css('text-align', 'center')
							:wikitext((entry.link and '[[' .. entry.link .. '|' .. (entry.linkT or season) .. ']]' or (entry.linkT or season)) .. (entry.linkR or ''))
					end
					
					-- Aux cells
					for i = string.byte('A'), string.byte('Z') do
						local param = 'aux' .. string.char(i)
						if entry[param .. k] then
							local thisCell = SeriesOverview.season_cell(entry[param .. k], frame)
								:attr('scope', 'col')
								:attr('rowspan', SeriesOverview.cellspan(SeasonEntries, SeasonEntries_ordered, param, X, (args.series and true or false)))
								:css('padding', cellPadding)
							seasonRow:node(thisCell)
						end
					end
					
					-- Episodes counts
					if ((splitSeason and k == 'A' and entry.episodes ~= 'hide') or not splitSeason) then
						if entry.episodes then
							local thisCell = SeriesOverview.season_cell(entry.episodes, frame)
								:attr('colspan', splitSeason and 1 or 2)
								:attr('rowspan', splitSeason and splits or nil)
							seasonRow:node(thisCell)
						elseif not entry.special then
							local infoCell = SeriesOverview.series_attributes( frame:expandTemplate{title='N/A',args={'TBA'}} )
							infoCell
								:attr('colspan', splitSeason and 1 or 2)
								:attr('rowspan', splitSeason and splits or nil)
							seasonRow:node(infoCell)
						end
					end
					if splitSeason then
						if entry['episodes' .. k] then
							local thisCell = SeriesOverview.season_cell(entry['episodes' .. k], frame)
								:attr('colspan', (entry.episodes ~= 'hide') and 1 or 2)
							seasonRow:node(thisCell)
						else
							local infoCell = SeriesOverview.series_attributes( frame:expandTemplate{title='N/A',args={'TBA'}} )
								:attr('colspan', (entry.episodes ~= 'hide') and 1 or 2)
							seasonRow:node(infoCell)
						end
					end
				
					-- Start date
					if entry['start' .. k] then
						local thisCell = SeriesOverview.season_cell(entry['start' .. k], frame)
							:attr('colspan',((not entry.special and entry['end' .. k] == 'start') or (entry.special and not entry['end' .. k]) or allReleased) and 2 or 1)
							:css('padding',basePadding)
						seasonRow:node(thisCell)
					else
						local infoCell = SeriesOverview.series_attributes( frame:expandTemplate{title='N/A',args={'TBA'}} )
						infoCell:css('padding',basePadding)
						seasonRow:node(infoCell)
					end
					
					-- End date
					if not allReleased and entry['end' .. k] ~= 'start' and ((entry.special and entry['end' .. k]) or not entry.special) then
						if entry['end' .. k] then
							local thisCell = SeriesOverview.season_cell(entry['end' .. k], frame)
								:css('padding',cellPadding)
							seasonRow:node(thisCell)
						else
							local infoCell = SeriesOverview.series_attributes( frame:expandTemplate{title='N/A',args={'TBA'}} )
							infoCell:css('padding',cellPadding)
							seasonRow:node(infoCell)
						end
					end
					
					-- Network
					if entry['network' .. k] and setNetwork then
						local thisCell = SeriesOverview.season_cell(entry['network' .. k], frame)
							:attr('rowspan', SeriesOverview.cellspan(SeasonEntries, SeasonEntries_ordered, 'network', X, (args.series and true or false)))
						seasonRow:node(thisCell)
					end
					
					-- Information
					for i = string.byte('A'), string.byte(topInfoCell) do
						local param0 = 'info' .. string.char(i)
						local param = 'info' .. string.char(i) .. k
						
						local infoTransclude = args[param .. '_transclude']
						if (infoTransclude == 'onlyinclude' and title.fullText == initialArticle) or (infoTransclude == 'noinclude' and title.fullText ~= initialArticle) then else
							local infoParam = entry[param]
							
							if infoParam and splitSeason and k == '' and not entry[param .. 'A'] then
								entry[param .. 'A'] = entry[param]
								entry[param .. 'span'] = 'y'
							end
							
							local rowspan = (entry[param0 .. 'span'] and splits) or
											(args.series and SeriesOverview.cellspan(SeasonEntries, SeasonEntries_ordered, param0, X, (args.series and true or false)))
											or nil
							
							if k == 'A' or (k ~= 'A' and not entry[param0 .. 'span']) then
								-- Cells with {{N/A|...}} already expanded
								if infoParam then
									if string.sub(infoParam,1,5) == 'style' then
										local infoCell = SeriesOverview.series_attributes(infoParam)
										infoCell:attr('rowspan', rowspan)
										seasonRow:node(infoCell)
									else
										-- Unstyled content info cell
										local thisCell = SeriesOverview.season_cell(infoParam, frame)
											:attr('rowspan', rowspan)
										seasonRow:node(thisCell)
									end
								else
									if not args.series then
										local infoCell = SeriesOverview.series_attributes( frame:expandTemplate{title='N/A',args={'TBA'}} )
										infoCell:attr('rowspan', rowspan)
										seasonRow:node(infoCell)
									end
								end
							elseif not entry[param0 .. 'span'] then
								if not args.series then
									local infoCell = SeriesOverview.series_attributes( frame:expandTemplate{title='N/A',args={'TBA'}} )
									infoCell:attr('rowspan', rowspan)
									seasonRow:node(infoCell)
								end
							end
						end
					end
				
				end -- End k0 string.byte
			end -- End 'for' SeasonEntries_ordered
		end -- End 'if' multiseries
	end -- End 'do' season rows

	return (args.dontclose and mw.ustring.gsub(tostring(root), "</table>", "") or tostring(root)) .. categories
end

--------------------------------------------------------------------------------
-- Exports
--------------------------------------------------------------------------------

local p = {}

function p.main(frame)
	local args = require('Module:Arguments').getArgs(frame, {
		wrappers = 'Template:Series overview'
	})
	return SeriesOverview.new(frame, args)
end

return p