Difference between revisions of "Module:Episode list"

From blackwiki
Jump to navigation Jump to search
blackwiki>Gonnym
(synced changes from sandbox with fixes)
blackwiki>Gonnym
(Undid revision 880421187 by Gonnym (talk))
Line 1: Line 1:
 
local p = {}
 
local p = {}
  
-- This module requires the use of the following modules:
+
local getArgs
local colorContrastModule = require('Module:Color contrast')
+
local yesno = require('Module:Yesno')
local htmlColor = mw.loadData('Module:Color contrast/colors')
+
local mm = require('Module:Math')
local delinkModule = require('Module:Delink')
+
local contrast_ratio = require('Module:Color contrast')._ratio
local langModule = require("Module:Lang");
+
local HTMLcolor = mw.loadData( 'Module:Color contrast/colors' )
local mathModule = require('Module:Math')
 
local yesNoModule = require('Module:Yesno')
 
local tableEmptyCellModule = require('Module:Table empty cell')
 
  
-- mw.html object for the generated row.
+
function p.sublist(frame)
local row
+
return main(frame,true)
 
 
-- Variable that will decide the colspan= of the Short Summary cell.
 
local nonNilParams = 0
 
 
 
-- Variable that will keep track if a TBA value was entered.
 
local cellValueTBA = false
 
 
-- Variable that handles the assigned tracking categories.
 
local trackingCategories = ""
 
 
 
-- List of tracking categories.
 
local trackingCategoryList = {
 
["air_dates"] = "[[Category:Episode lists with unformatted air dates]]",
 
["alt_air_dates"] = "[[Category:Episode lists with incorrectly formatted alternate air dates]]",
 
["faulty_line_colors"] = "[[Category:Episode lists with faulty line colors]]",
 
["non_complaint_line_colors"] = "[[Category:Episode lists with non-compliant line colors]]",
 
["default_line_colors"] = "[[Category:Episode list using the default LineColor]]",
 
["row_deviations"] = "[[Category:Episode lists with row deviations]]",
 
["invalid_top_colors"] = "[[Category:Episode lists with invalid top colors]]",
 
["tba_values"] = "[[Category:Episode lists with TBA values]]"
 
}
 
 
 
-- List of parameter names in this order.
 
local cellNameList = {
 
'Aux1',
 
'DirectedBy',
 
'WrittenBy',
 
'Aux2',
 
'Aux3',
 
'OriginalAirDate',
 
'AltDate',
 
'ProdCode',
 
'Viewers',
 
'Aux4'
 
}
 
 
 
-- List of title parameter names in this order.
 
-- List used for multi title lists.
 
local titleList = {
 
'Title',
 
'RTitle',
 
'AltTitle',
 
'RAltTitle',
 
'NativeTitle',
 
'TranslitTitle',
 
}
 
 
 
-- List of parameter names in this order.
 
-- List used for Doctor Who serials with rowspans.
 
local serialSpanList = {
 
'Aux1',
 
'OriginalAirDate',
 
'Viewers',
 
'Aux4'
 
}
 
 
 
-- Local function which is used to retrieve the episode number or production code number,
 
-- without any additional text.
 
local function idTrim(val, search)
 
local valFind = string.find(val, search)
 
 
if (valFind == nil) then
 
return val
 
else
 
return string.sub(val, 0, valFind-1)
 
end
 
 
end
 
end
  
-- Local function which is used to validate that a parameter has an actual value.
+
function p.list(frame)
local function hasValue(param)
+
return main(frame,false)
if (param ~= nil and param ~= "") then
 
return true
 
else
 
return false
 
end
 
 
end
 
end
  
-- Local function which is used to create a table data cell.
+
function idtrim(val,search)
local function createTableData(text, rowSpan, textAlign)
+
local valfind = string.find(val, search)
if (rowSpan ~= nil and tonumber(rowSpan) > 1) then
+
if valfind == nil then
row:tag('td')
+
return val
:attr('rowspan', rowSpan)
 
:wikitext(text)
 
 
else
 
else
row:tag('td')
+
return string.sub(val, 0, valfind-1)
:css('text-align', textAlign)
 
:wikitext(text)
 
 
end
 
end
 
end
 
end
  
-- Local function which is used to add a tracking category to the page.
+
function main(frame, sublist)
local function addTrackingCategory(category)
+
if not getArgs then
trackingCategories = trackingCategories .. category
+
getArgs = require('Module:Arguments').getArgs
end
 
 
 
-- Local function which is used to create a Short Summary row.
 
local function createShortSummaryRow(args, lineColor)
 
-- fix for lists in the Short Summary
 
local shortSummaryText = args.ShortSummary
 
 
if (shortSummaryText:match('^[*:;#]') or shortSummaryText:match('^{|')) then
 
shortSummaryText = '<span></span>\n' .. shortSummaryText
 
 
end
 
end
 +
local args
  
if (shortSummaryText:match('\n[*:;#]')) then
+
-- Most parameters should still display when blank, so don't remove blanks
shortSummaryText = shortSummaryText .. '\n<span></span>'
+
if sublist then
end
+
args = getArgs(frame, {removeBlanks = false, wrappers = 'Template:Episode list/sublist'})
 
 
local shortSummaryCell = mw.html.create('td')
 
:addClass('description')
 
:css('border-bottom', 'solid 3px ' .. lineColor)
 
:attr('colspan', nonNilParams)
 
:newline()
 
:wikitext(shortSummaryText)
 
 
 
return mw.html.create('tr')
 
:addClass('expand-child')
 
:node(shortSummaryCell)
 
end
 
 
 
-- Local function which is used to add tracking categories for Top Color issues.
 
local function addTopColorTrackingCategories(args)
 
if (hasValue(args.TopColor)) then
 
addTrackingCategory(trackingCategoryList["row_deviations"])
 
 
 
-- Track top colors that have a color contrast rating below AAA with
 
-- respect to text color, link color, or visited link color. See
 
-- [[WP:COLOR]] for more about color contrast requirements.
 
local textContrastRatio = colorContrastModule._ratio{args.TopColor, 'black', ['error'] = 0}
 
local linkContrastRatio = colorContrastModule._ratio{args.TopColor, '#0B0080', ['error'] = 0}
 
local visitedLinkContrastRatio = colorContrastModule._ratio{args.TopColor, '#0645AD', ['error'] = 0}
 
 
if (textContrastRatio < 7 or linkContrastRatio < 7 or visitedLinkContrastRatio < 7) then
 
addTrackingCategory(trackingCategoryList["invalid_top_colors"])
 
end
 
end
 
end
 
 
 
-- Local function which is used to add tracking categories for Line Color issues.
 
local function addLineColorTrackingCategories(args)
 
if (hasValue(args.LineColor)) then
 
local blackContrastRatio = colorContrastModule{args.LineColor, 'black', ['error'] = 0}
 
local whiteContrastRatio = colorContrastModule{'white', args.LineColor, ['error'] = 0}
 
 
if (colorContrastModule._lum({args.LineColor}) == '') then
 
addTrackingCategory(trackingCategoryList["faulty_line_colors"])
 
elseif (blackContrastRatio < 7 and whiteContrastRatio < 7) then
 
addTrackingCategory(trackingCategoryList["non_complaint_line_colors"])
 
end
 
 
else
 
else
addTrackingCategory(trackingCategoryList["default_line_colors"])
+
args = getArgs(frame, {removeBlanks = false, wrappers = 'Template:Episode list'})
 
end
 
end
end
 
 
-- Local function which is used to remove wiki-links from repated information in rowspans.
 
-- Used for Doctor Who serials, where the director and writer are the same for each part of serial.
 
local function removeWikilinks(args, v)
 
return delinkModule._delink{args[v]}
 
end
 
 
-- Local function which is used to set the text of an empty cell
 
-- with either "TBD" or "N/A".
 
-- Set to N/A if viewers haven't been available for four weeks, else set it as TBD.
 
local function setTBDStatus(args)
 
local month, day, year = args.OriginalAirDate:gsub("&nbsp;", " "):match("(%a+) (%d+), (%d+)")
 
 
 
if (month == nil) then
+
local title = mw.title.getCurrentTitle()
day, month, year = args.OriginalAirDate:gsub("&nbsp;", " "):match("(%d+) (%a+) (%d+)")
+
local page_title = mw.title.getCurrentTitle().text
end
+
local initiallist_title = args['1'] or ''
 +
local cellValueTBA = false
 +
 +
-- Is this list on the same page as the page directly calling the template?
 +
local on_initial_page
 
 
if (day == nil) then
+
-- Only sublist had anything about hiding, so only it needs to even check
return tableEmptyCellModule._main({alt_text = "TBD"})
+
if sublist then
else
+
on_initial_page = mw.uri.anchorEncode(page_title) == mw.uri.anchorEncode(initiallist_title)
-- List of months.
+
-- avoid processing ghost references
local monthList = {
+
if not on_initial_page then
['January'] = 1,
+
args.ShortSummary = nil
['February'] = 2,
 
['March'] = 3,
 
['April'] = 4,
 
['May'] = 5,
 
['June'] = 6,
 
['July'] = 7,
 
['August'] = 8,
 
['September'] = 9,
 
['October'] = 10,
 
['November'] = 11,
 
['December'] = 12
 
}
 
 
 
local seconds = os.time() - os.time({year = year, month = monthList[month], day = day, hour = 0, min = 0, sec = 0})
 
 
if (seconds >= 60 * 60 * 24 * 7 * 4) then
 
return tableEmptyCellModule._main({alt_text = "N/A"})
 
else
 
return tableEmptyCellModule._main({alt_text = "TBD"})
 
 
end
 
end
end
 
end
 
 
-- Local function which is used to create an empty cell.
 
local function createEmptyCell(args, v)
 
if (v == 'Viewers' and hasValue(args.OriginalAirDate)) then
 
args[v] = setTBDStatus(args)
 
 
else
 
else
args[v] = tableEmptyCellModule._main({})
+
-- Normal lists can ALWAYS show the summary
end
+
on_initial_page = true
end
 
 
 
-- Air dates that don't use {{Start date}}
 
local function checkUsageOfDateTemplates(args, v, onInitialPage, title)
 
if (v == 'OriginalAirDate'
 
and args[v] ~= ''
 
and string.match(args[v], '%d%d%d%d') ~= nil
 
and string.match(args[v], '2C2C2C') == nil
 
and string.find(args[v], 'dtstart') == nil
 
and onInitialPage
 
and title.namespace == 0)
 
then
 
addTrackingCategory(trackingCategoryList["air_dates"])
 
end
 
 
-- Alternate air dates that do use {{Start date}}
 
if (v == 'AltDate' and args[v] ~= '' and string.find(args[v], 'dtstart') ~= nil and onInitialPage and title.namespace == 0) then
 
addTrackingCategory(trackingCategoryList["alt_air_dates"])
 
end
 
end
 
 
 
-- Local function which is used to create a Production Code cell.
 
local function createProductionCodeCell(args, v)
 
if (hasValue(args.ProdCode) and string.find(args.ProdCode, 'TBA') == nil) then
 
row:tag('td')
 
:attr('id', 'pc' .. idTrim(idTrim(args.ProdCode, ' ----'), '<'))
 
:css('text-align', 'center')
 
:wikitext(args.ProdCode)
 
elseif (args.ProdCode == '') then
 
createEmptyCell(args, v)
 
createTableData(args.ProdCode, 1, "center")
 
else
 
-- ProductionCode parameter not used; Do nothing.
 
 
end
 
end
 
 
nonNilParams = nonNilParams + 1
+
-- Declare all the possible <td>/<th> tags here, and the return string
end
+
local EpisodeNumber,EpisodeNumber2,Title,Aux1,DirectedBy,WrittenBy,
 
+
DirectedBy,Aux2,Aux3,OriginalAirDate,AltDate,ProdCode,
--[[
+
Viewers,Aux4,return_table
Local function which is used to extract data
 
from the numbered serial parameters (Title1, Aux1, etc.), and then convert them to
 
use the non-numbered prameter names (Title, Aux).
 
 
 
The function returns the args as non-numbered prameter names.
 
]]--
 
local function extractDataFromNumberedSerialArgs(args, i)
 
for _, v in ipairs(serialSpanList) do
 
local parameter = v
 
local numberedParameter = v .. "_" .. i
 
args[parameter] = args[numberedParameter]
 
end
 
 
 
return args
+
-- Need just this parameter removed if blank, no others
end
+
if args.ShortSummary then
 
+
if not args.ShortSummary:find('%S') then
--[[
+
args.ShortSummary = nil
Local function which is used to create column cells.
 
 
 
EpisodeNumber, EpisodeNumber2 and Title are created in different functions
 
as they require some various if checks.
 
 
 
See:
 
-- createEpisodeNumberCell()
 
-- createEpisodeNumberCell2()
 
-- createTitleCell()
 
]]--
 
local function createCells(args, isSerial, currentRow, onInitialPage, title)
 
for _, v in ipairs(cellNameList) do
 
if (v == 'ProdCode') then
 
createProductionCodeCell(args, v)
 
elseif (args[v]) then
 
-- Set empty cells to TBA/TBD
 
if (args[v] == '') then
 
createEmptyCell(args, v)
 
end
 
 
-- If serial titles need to be centered and not left, then this should be removed.
 
local textAlign = "center"
 
if (v == 'Aux1' and isSerial) then
 
textAlign = "left"
 
end
 
 
-- Remove wikilinks from links in serial rowspans rows after the first.
 
if (currentRow > 1) then
 
args[v] = removeWikilinks(args, v)
 
end
 
 
createTableData(args[v], 1, textAlign)
 
nonNilParams = nonNilParams + 1
 
checkUsageOfDateTemplates(args, v, onInitialPage, title)
 
end
 
 
if (args[v] == "TBA") then
 
cellValueTBA = true
 
 
end
 
end
 
end
 
end
end
 
  
--[[
+
-- Default color to light blue
Local function which is used to create the Title cell text.
+
local line_color = args.LineColor or 'CCCCFF'
 
 
The title text will be handled in the following way:
 
Line 1: <Title><RTitle> (with no space between)
 
Line 2: <AltTitle><RAltTitle> (with no space between) OR
 
Line 2: Transcription: <TranslitTitle> (<Language>: <NativeTitle>)<RAltTitle> (with space between first two parameters)
 
 
 
If <Title> or <RTitle> are empty,
+
-- Add # to color if necessary, and set to default color if invalid
then the values of line 2 will be placed on line 1 instead.
+
if HTMLcolor[line_color] == nil then
 
+
line_color = '#'..(mw.ustring.match(line_color, '^[%s#]*([a-fA-F0-9]*)[%s]*$') or '')
--]]
+
if line_color == '#' then
local function createTitleText(args)
+
line_color = '#CCCCFF'
local titleString = ''
 
local isCellPresent = false
 
local useSecondLine = false
 
local lineBreakUsed = false
 
 
 
-- Surround the Title with quotes; No quotes if empty.
 
if (args.Title ~= nil) then
 
if (args.Title == "") then
 
isCellPresent = true
 
else
 
titleString = '"' .. args.Title .. '"'
 
useSecondLine = true
 
isCellPresent = true
 
end
 
end
 
 
 
if (args.RTitle ~= nil) then
 
if (args.RTitle == "") then
 
isCellPresent = true
 
else
 
titleString = titleString .. args.RTitle
 
useSecondLine = true
 
isCellPresent = true
 
 
end
 
end
 
end
 
end
 
-- Surround the AltTitle/TranslitTitle with quotes; No quotes if empty.
 
if (args.AltTitle or args.TranslitTitle) then
 
 
isCellPresent = true
 
 
if (useSecondLine) then
 
titleString = titleString .. "<br />"
 
lineBreakUsed = true
 
end
 
 
 
if (hasValue(args.AltTitle)) then
+
-- List of parameter names to test
titleString = titleString .. '"' .. args.AltTitle .. '"'
+
-- Keep this order as is
elseif (hasValue(args.TranslitTitle)) then
+
local cell_names = {
if (hasValue(args.NativeTitleLangCode)) then
+
'EpisodeNumber2',
titleString = titleString .. 'Transcription: "' .. langModule._transl({args.NativeTitleLangCode, args.TranslitTitle, italic = 'no'})  .. '"'
+
'Title',
else
+
'Aux1',
titleString = titleString .. 'Transcription: "' .. args.TranslitTitle .. '"'
+
'DirectedBy',
end
+
'WrittenBy',
end
+
'Aux2',
end
+
'Aux3',
 
+
'OriginalAirDate',
if (args.NativeTitle ~= nil) then
+
'AltDate',
if (args.NativeTitle == "") then
+
'ProdCode',
isCellPresent = true
+
'Viewers',
else
+
'Aux4'
isCellPresent = true
+
}
 
 
if (useSecondLine and lineBreakUsed == false) then
 
titleString = titleString .. "<br />"
 
end
 
 
 
if (hasValue(args.NativeTitleLangCode)) then
 
local languageCode = "Lang-" .. args.NativeTitleLangCode
 
titleString = titleString .. " (" .. langModule._lang_xx_inherit({code = args.NativeTitleLangCode, args.NativeTitle}) .. ")"
 
else
 
titleString = titleString .. " (" .. args.NativeTitle .. ")"
 
end
 
end
 
end
 
 
 
if (args.RAltTitle ~= nil) then
 
if (args.RAltTitle == "") then
 
isCellPresent = true
 
else
 
isCellPresent = true
 
 
if (useSecondLine and lineBreakUsed == false) then
 
titleString = titleString .. "<br />"
 
end
 
 
titleString = titleString .. args.RAltTitle
 
end
 
end
 
 
 
return titleString, isCellPresent
 
end
 
 
 
--[[
 
Local function which is used to extract data
 
from the numbered title parameters (Title1, RTitle2, etc.), and then convert them to
 
use the non-numbered prameter names (Title, RTitle).
 
 
 
The function returns two results:
 
-- The args parameter table.
 
-- A boolean indicating if the title group has data.
 
]]--
 
local function extractDataFromNumberedTitleArgs(args, i)
 
local nextGroupValid = false
 
 
 
for _, v in ipairs(titleList) do
+
-- Is there a way to call a variable by its name stored as a string? Doubt it
local parameter = v
+
-- This list matches strings with the table cell variables
local numberedParameter = v .. "_" .. i
+
local td_tags = {
args[parameter] = args[numberedParameter]
+
['EpisodeNumber2'] = EpisodeNumber2,
+
['Title'] = Title,
if (nextGroupValid == false and hasValue(args[numberedParameter])) then
+
['Aux1'] = Aux1,
nextGroupValid = true
+
['DirectedBy'] = DirectedBy,
end
+
['WrittenBy'] = WrittenBy,
end
+
['DirectedBy'] = DirectedBy,
 +
['Aux2'] = Aux2,
 +
['Aux3'] = Aux3,
 +
['OriginalAirDate'] = OriginalAirDate,
 +
['AltDate'] = AltDate,
 +
['ProdCode'] = ProdCode,
 +
['Viewers'] = Viewers,
 +
['Aux4'] = Aux4,
 +
}
 
 
return args, nextGroupValid
+
local table_row = mw.html.create('tr')
end
+
:addClass('vevent')
 
+
:css('text-align','center')
-- Local function which is used to process the multi title list.
 
local function processMultiTitleList(args, numberOfTitleGroups)
 
local nativeTitleLangCode = args.NativeTitleLangCode
 
local titleText = ""
 
local isCellPresent = false
 
local isFirstTitleGroup = true -- Making sure that the title cell is created at least once and isn't created again if other #N titles are empty.
 
 
 
for i = 1, numberOfTitleGroups do
+
local row_color = yesno(args.RowColor, false)
local args, nextGroupValid = extractDataFromNumberedTitleArgs(args, i)
+
if args.RowColor and string.lower(args.RowColor) == 'on' then
if (nextGroupValid) then
+
row_color = true
if (isFirstTitleGroup == false) then
 
titleText = titleText .. "<hr />"
 
end
 
 
 
local titleTextRow
 
titleTextRow = createTitleText(args)
 
titleText = titleText .. titleTextRow
 
isFirstTitleGroup = false
 
else
 
if (isFirstTitleGroup) then
 
titleText, isCellPresent = createTitleText(args)
 
end
 
 
 
-- Valid titles have to be in succession (#1, #2, #3 and not #1, #4 #5), so exit for loop if next group is empty.
 
return titleText, isCellPresent
 
end
 
 
end
 
end
 
return titleText
 
end
 
  
-- Local function which is used to create a Title cell.
+
local top_color
local function createTitleCell(args, numberOfTitleGroups, multiTitleListEnabled, isSerial)
+
local epn = mm._cleanNumber(args.EpisodeNumber) or 1
local titleText
+
if args.TopColor then
local isCellPresent
+
top_color = '#'..args.TopColor
+
elseif row_color and on_initial_page and mm._mod(epn,2) == 0 then
if (multiTitleListEnabled) then
+
top_color = '#E9E9E9'
titleText, isCellPresent = processMultiTitleList(args, numberOfTitleGroups)
+
elseif on_initial_page and args.ShortSummary then
 +
top_color = '#F2F2F2'
 
else
 
else
titleText, isCellPresent = createTitleText(args)
+
top_color = 'inherit'
end
 
 
 
if (isCellPresent == false) then
 
return nil
 
end
 
 
 
local textAlign = "left"
 
 
 
-- If Title is blank, then set Raw Title to TBA
 
if (hasValue(titleText) == false) then
 
titleText = tableEmptyCellModule._main({})
 
textAlign = "center"
 
 
end
 
end
 +
 +
table_row:css('background',top_color)
 +
 +
-- This will decide the colspan= of the summary cell
 +
-- Start as 1 because EpisodeNumber is always created
 +
local nonnil_params = 1
 
 
local cellType = 'td'
+
-- Created separately because it is the only <th> tag
 
 
if (nonNilParams == 0) then
+
if args.EpisodeNumber then
cellType = "th"
+
if (args.EpisodeNumber == '') then args.EpisodeNumber = frame:expandTemplate{title='TableTBA'}; end
 +
EpisodeNumber = mw.html.create('th')
 +
:attr('scope','row')
 +
:attr('id','ep'..idtrim(idtrim(args.EpisodeNumber,' ----'),'<'))
 +
:css('text-align','center')
 +
:wikitext(args.EpisodeNumber)
 +
table_row:css('background',top_color)
 +
table_row:node(EpisodeNumber)
 
end
 
end
 
+
if (isSerial) then
+
-- The wikitext in the Title cell is a little more involved than the others
row:tag(cellType)
+
local function add_title()
:addClass('summary')
+
local title_string = ''
:attr('rowspan', numberOfTitleGroups)
 
:css('text-align', textAlign)
 
:wikitext(titleText)
 
else
 
row:tag(cellType)
 
:addClass('summary')
 
:css('text-align', textAlign)
 
:wikitext(titleText)
 
end
 
 
 
nonNilParams = nonNilParams + 1
 
end
 
 
 
-- Local function which is used to create a table row header for either the  
 
-- EpisodeNumber or EpisodeNumber2 column cells.
 
local function createTableRowEpisodeNumberHeader(episodeNumber, numberOfTitleGroups, episodeText)
 
row:tag('th')
 
:attr('scope', 'row')
 
:attr('rowspan', numberOfTitleGroups)
 
:attr('id', 'ep' .. idTrim(idTrim(episodeNumber, ' ----'), '<'))
 
:css('text-align', 'center')
 
:wikitext(episodeText)
 
end
 
 
 
--[[
 
Local function which is used to extract the text from the EpisodeNumber or EpisodeNumber2
 
parameters and format them into a correct MoS compliant version.
 
 
 
Styles supported:
 
-- A number range of two numbers, indicating the start and end of the range,
 
seperated by an en-dash (–) with no spaces in between.
 
Example: "1 - 2" -> "1–2"; "1-2-3" -> "1–3".
 
-- An alphanumeric or letter range, similar to the above.
 
Example: "A - B" -> "A–B"; "A-B-C" -> "A–C".
 
Example: "A1 - B1" -> "A1–B1"; "A1-B1-C1" -> "A1–C1".
 
-- A number range of two numbers, indicating the start and end of the range,
 
seperated by a visual <hr /> (divider line).
 
-- An alphanumeric or letter range, similar to the above.
 
]]--
 
local function getEpisodeText(episodeNumber)
 
if (episodeNumber == '') then
 
return tableEmptyCellModule._main({})
 
else
 
 
 
local episodeNumber1
+
-- Surround the Title with quotes; no quotes if empty
local episodeNumber2
+
if args.Title and args.Title:find('%S') then
 +
title_string = title_string..'"'..args.Title..'"'
 +
end
 
 
-- Used for double episodes that need a visual "–"" or "<hr />"" added.
+
if args.RTitle then
local divider
+
title_string = title_string..args.RTitle
 
 
episodeNumber = episodeNumber:gsub('%s*<br%s*/?%s*>%s*', '<hr />')
 
 
 
if (episodeNumber:match('^(%w+)%s*<hr */%s*>%s*(%w+)$')) then
 
episodeNumber1, episodeNumber2 = episodeNumber:match('^(%w+)%s*<hr */%s*>%s*(%w+)$')
 
divider = "<hr />"
 
elseif (episodeNumber:match('^(%w+)%s*<hr */%s*>.-<hr */%s*>%s*(%w+)$')) then -- 3 or more elements
 
episodeNumber1, episodeNumber2 = episodeNumber:match('^(%w+)%s*<hr */%s*>.-<hr */%s*>%s*(%w+)$')
 
divider = "<hr />"
 
elseif (mw.ustring.match(episodeNumber, '^(%w+)%s*[%s%-–,/&]%s*(%w+)$')) then
 
episodeNumber1, episodeNumber2 = mw.ustring.match(episodeNumber, '^(%w+)%s*[%s%-–,/&]%s*(%w+)$')
 
divider = "–"
 
else
 
episodeNumber1, episodeNumber2 = mw.ustring.match(episodeNumber, '^(%w+)%s*[%s%-–,/&].-[%s%-–,/&]%s*(%w+)$') -- 3 or more elements
 
divider = "–"
 
end
 
 
 
if (not episodeNumber2) then
 
return string.match(episodeNumber, '%w+')
 
else
 
return episodeNumber1 .. divider .. episodeNumber2
 
 
end
 
end
end
 
end
 
 
-- Local function which is used to create an EpisodeNumber2 cell.
 
local function createEpisodeNumberCell2(args, numberOfTitleGroups)
 
if (args.EpisodeNumber2) then
 
local episodeText = getEpisodeText(args.EpisodeNumber2)
 
 
 
if (nonNilParams == 0) then
+
-- Surround the AltTitle with quotes; no quotes if empty
createTableRowEpisodeNumberHeader(args.EpisodeNumber2, numberOfTitleGroups, episodeText)
+
if args.AltTitle and args.AltTitle:find('%S') then
else
+
title_string = title_string..'<br>"'..args.AltTitle..'"'
createTableData(episodeText, numberOfTitleGroups, "center")
 
 
end
 
end
 
nonNilParams = nonNilParams + 1
 
 
end
 
end
 
 
-- Local function which is used to create an EpisodeNumber cell.
 
local function createEpisodeNumberCell(args, numberOfTitleGroups)
 
if (args.EpisodeNumber) then
 
local episodeText = getEpisodeText(args.EpisodeNumber)
 
createTableRowEpisodeNumberHeader(args.EpisodeNumber, numberOfTitleGroups, episodeText)
 
nonNilParams = nonNilParams + 1
 
end
 
end
 
 
-- Local function which is used to create a single row of cells.
 
-- This is the standard function called.
 
local function createSingleRowCells(args, numberOfTitleGroups, multiTitleListEnabled, onInitialPage, title)
 
createEpisodeNumberCell(args, 1)
 
createEpisodeNumberCell2(args, 1)
 
createTitleCell(args, numberOfTitleGroups, multiTitleListEnabled, false)
 
createCells(args, false, 1, onInitialPage, title)
 
end
 
 
-- Local function which is used to create a multiple row of cells.
 
-- This function is called when part of the row is rowspaned.
 
-- Current use is for Doctor Who serials.
 
local function createMultiRowCells(args, numberOfTitleGroups, onInitialPage, title, topColor)
 
createEpisodeNumberCell(args, numberOfTitleGroups)
 
createEpisodeNumberCell2(args, numberOfTitleGroups)
 
createTitleCell(args, numberOfTitleGroups, false, true)
 
 
 
for i = 1, numberOfTitleGroups do
+
if args.RAltTitle then
args = extractDataFromNumberedSerialArgs(args, i)
+
title_string = title_string..args.RAltTitle
createCells(args, true, i, onInitialPage, title)
 
if (i ~= numberOfTitleGroups) then
 
row = row:done() -- Use done() to close the 'tr' tag in rowspaned rows.
 
:tag('tr')
 
:css('background', topColor)
 
 
end
 
end
 +
return title_string
 
end
 
end
end
+
 +
local categories = ''
  
-- Local function which is used to retrieve the NumParts value.
+
for _,v in ipairs(cell_names) do
local function getNumberOfTitleGroups(args)
+
-- Title is in the middle, so it's probably better to just switch back and again instead of doing 2 nodes
if (hasValue(args.NumParts)) then
+
-- and then title, and then the rest in a loop
return args.NumParts, true
+
if v == 'Title' then
else
+
-- If Title is blank, then set Raw Title to TBA
return 1, false
+
if args.Title == '' and (args.RTitle == '' or not args.RTitle) then args.RTitle = frame:expandTemplate{title='TableTBA'}; end
end
+
nonnil_params = nonnil_params + 1
end
+
local title_text = add_title()
 
+
td_tags[v] = mw.html.create('td')
-- Local function which is used to retrieve the Top Color value.
+
td_tags[v]:wikitext(title_text)
local function getTopColor(args, rowColorEnabled, onInitialPage)
+
:addClass('summary')
local episodeNumber = mathModule._cleanNumber(args.EpisodeNumber) or 1
+
:css('text-align','left')
if (args.TopColor) then
+
table_row:node(td_tags[v])
if (string.find(args.TopColor, "#")) then
+
elseif args[v] then
return args.TopColor
+
-- Air dates that don't use {{Start date}}
else
+
if v == 'OriginalAirDate' and args[v] ~= '' and string.match(args[v], '%d%d%d%d') ~= nil and string.match(args[v], '2C2C2C') == nil and string.find(args[v],'dtstart') == nil and on_initial_page and title.namespace == 0 then
return '#' .. args.TopColor
+
categories = categories..'[[Category:Episode lists with unformatted air dates]]'
 +
end
 +
-- Alternate air dates that do use {{Start date}}
 +
if v == 'AltDate' and args[v] ~= '' and string.find(args[v],'dtstart') ~= nil and on_initial_page and title.namespace == 0 then
 +
categories = categories..'[[Category:Episode lists with incorrectly formatted alternate air dates]]'
 +
end
 +
-- Set empty cells to TBA/TBD
 +
if args[v] == '' then
 +
-- Set to N/A if viewers haven't been available for four weeks, else set it as TBD
 +
if v == 'Viewers' and args.OriginalAirDate and args.OriginalAirDate ~= '' then
 +
local month, day, year = args.OriginalAirDate:gsub("&nbsp;"," "):match("(%a+) (%d+), (%d+)")
 +
if month == nil then
 +
day, month, year = args.OriginalAirDate:gsub("&nbsp;"," "):match("(%d+) (%a+) (%d+)")
 +
end
 +
if day == nil then
 +
args[v] = frame:expandTemplate{title='TableTBA',args={'TBD'}};
 +
else
 +
local MONTHS = {January=1, February=2, March=3, April=4, May=5, June=6, July=7, August=8, September=9, October=10, November=11, December=12}
 +
local seconds = os.time()-os.time({year=year,month=MONTHS[month],day=day,hour=0,min=0,sec=0})
 +
if seconds >= 60*60*24*7*4 then args[v] = frame:expandTemplate{title='TableTBA',args={'N/A'}};
 +
else args[v] = frame:expandTemplate{title='TableTBA',args={'TBD'}}; end
 +
end
 +
else args[v] = frame:expandTemplate{title='TableTBA'}; end
 +
end
 +
nonnil_params = nonnil_params + 1
 +
td_tags[v] = mw.html.create('td')
 +
td_tags[v]:wikitext(args[v])
 +
table_row:node(td_tags[v])
 
end
 
end
elseif (rowColorEnabled and onInitialPage and mathModule._mod(episodeNumber, 2) == 0) then
+
if args[v] == "TBA" then cellValueTBA = true end
return '#E9E9E9'
 
elseif (onInitialPage and args.ShortSummary) then
 
return '#F2F2F2'
 
else
 
return 'inherit'
 
end
 
end
 
 
 
-- Local function which is used to retrieve the Row Color value.
 
local function isRowColorEnabled(args)
 
local rowColorEnabled = yesNoModule(args.RowColor, false)
 
 
 
if (args.RowColor and string.lower(args.RowColor) == 'on') then
 
rowColorEnabled = true
 
 
end
 
end
 
return rowColorEnabled
 
end
 
  
-- Local function which is used to retrieve the Line Color value.
+
-- Production code also has an additional attribute, so add it separately here
local function getLineColor(args)
+
if td_tags.ProdCode and args.ProdCode and (string.find(args.ProdCode,'TBA') == nil) then
-- Default color to light blue
+
td_tags.ProdCode:attr('id','pc'..idtrim(idtrim(args.ProdCode,' ----'),'<'))
local lineColor = args.LineColor or 'CCCCFF'
 
 
-- Add # to color if necessary, and set to default color if invalid
 
if (htmlColor[lineColor] == nil) then
 
lineColor = '#' .. (mw.ustring.match(lineColor, '^[%s#]*([a-fA-F0-9]*)[%s]*$') or '')
 
if (lineColor == '#') then
 
lineColor = '#CCCCFF'
 
end
 
 
end
 
end
 
 
return lineColor
+
-- add these categories only in the mainspace and only if they are on the page where the template is used
end
+
if on_initial_page and title.namespace == 0 then
 
+
if args.LineColor and args.LineColor ~= '' then
-- Local function which is used to check if the table is located on the page
+
local black_cr = contrast_ratio{args.LineColor, 'black', ['error'] = 0}
-- currently viewed, or on a transcluded page instead.
+
local white_cr = contrast_ratio{'white', args.LineColor, ['error'] = 0}
-- If it is on a transcluded page, the episode summary should not be shown.
+
if frame:expandTemplate{title='ColorToLum',args={args.LineColor}} == '' then
local function isOnInitialPage(args, sublist, pageTitle, initiallistTitle)
+
categories = categories..'[[Category:Episode lists with faulty line colors]]'
-- This should be the only check needed, however, it was previously implemented with two templates
+
elseif black_cr < 7 and white_cr < 7 then
-- with one of them not requiring an article name, so for backward compatability, the whole sequence is kept.
+
categories = categories..'[[Category:Episode lists with non-compliant line colors]]'
local onInitialPage
+
end
 
-- Only sublist had anything about hiding, so only it needs to even check
 
if (sublist) then
 
onInitialPage = mw.uri.anchorEncode(pageTitle) == mw.uri.anchorEncode(initiallistTitle)
 
-- avoid processing ghost references
 
if (not onInitialPage) then
 
args.ShortSummary = nil
 
end
 
else
 
if (initiallistTitle == "") then
 
onInitialPage = true
 
 
else
 
else
onInitialPage = mw.uri.anchorEncode(pageTitle) == mw.uri.anchorEncode(initiallistTitle)
+
categories = categories..'[[Category:Episode list using the default LineColor]]'
 
end
 
end
end
+
+
if args.TopColor and args.TopColor ~= '' then
return onInitialPage
+
categories = categories..'[[Category:Episode lists with row deviations]]'
end
 
  
-- Local function which does the actual main process.
+
-- Track top colors that have a color contrast rating below AAA with
local function _main(args, sublist)
+
-- respect to text color, link color, or visited link color. See
local title = mw.title.getCurrentTitle()
+
-- [[WP:COLOR]] for more about color contrast requirements.
local pageTitle = title.text
+
local text_cr = contrast_ratio{args.TopColor, 'black', ['error'] = 0}
local initiallistTitle = args['1'] or ''
+
local link_cr = contrast_ratio{args.TopColor, '#0B0080', ['error'] = 0}
+
local visited_link_cr = contrast_ratio{args.TopColor, '#0645AD', ['error'] = 0}
-- Is this list on the same page as the page directly calling the template?
+
if text_cr < 7 or link_cr < 7 or visited_link_cr < 7 then
local onInitialPage = isOnInitialPage(args, sublist, pageTitle, initiallistTitle)
+
categories = categories..'[[Category:Episode lists with invalid top colors]]'
 
+
end
-- Need just this parameter removed if blank, no others
+
end
if (hasValue(args.ShortSummary) == false) then
 
args.ShortSummary = nil
 
 
end
 
end
 
local lineColor = getLineColor(args)
 
local rowColorEnabled = isRowColorEnabled(args)
 
local topColor = getTopColor(args, rowColorEnabled, onInitialPage)
 
 
local root = mw.html.create() -- Create the root mw.html object to return
 
row = root:tag('tr') -- Create the table row and store it globally
 
:addClass('vevent')
 
:css('text-align', 'center')
 
:css('background', topColor)
 
 
local numberOfTitleGroups, multiTitleListEnabled = getNumberOfTitleGroups(args)
 
 
 
if (hasValue(args.Serial)) then
+
if cellValueTBA == true and title.namespace == 0 then categories = categories .. "[[Category:Episode lists with TBA values]]" end
createMultiRowCells(args, numberOfTitleGroups, onInitialPage, title, topColor)
 
else
 
createSingleRowCells(args, numberOfTitleGroups, multiTitleListEnabled, onInitialPage, title)
 
end
 
 
 
-- add these categories only in the mainspace and only if they are on the page where the template is used
 
if (onInitialPage and title.namespace) == 0 then
 
addLineColorTrackingCategories(args)
 
addTopColorTrackingCategories(args)
 
end
 
 
 
if (cellValueTBA == true and title.namespace == 0) then
 
addTrackingCategory(trackingCategoryList["tba_values"])
 
end
 
 
 
-- Do not show the summary if this is being transcluded on the initial list page
 
-- Do not show the summary if this is being transcluded on the initial list page
 
-- Do include it on all other lists
 
-- Do include it on all other lists
if (onInitialPage and args.ShortSummary) then
+
if on_initial_page and args.ShortSummary then
local bottomWrapper = createShortSummaryRow(args, lineColor)
+
local bottom_wrapper = mw.html.create('tr')
return tostring(root) .. tostring(bottomWrapper) .. trackingCategories
+
:addClass('expand-child')
 +
-- fix for lists in the Short Summary
 +
local ss = args.ShortSummary
 +
if ss:match('^[*:;#]') or ss:match('^{|') then
 +
ss = '<span></span>\n' .. ss
 +
end
 +
if ss:match('\n[*:;#]') then
 +
ss = ss .. '\n<span></span>'
 +
end
 +
local ShortSummary = mw.html.create('td')
 +
:addClass('description')
 +
:css('border-bottom','solid 3px '..line_color)
 +
:attr('colspan',nonnil_params)
 +
:newline()
 +
:wikitext(ss)
 +
bottom_wrapper:node(ShortSummary)
 +
return tostring(table_row)..tostring(bottom_wrapper)..categories
 
else
 
else
return tostring(root) .. trackingCategories
+
return tostring(table_row)..categories
 
end
 
end
end
 
 
-- Local function which handles both module entry points.
 
local function main(frame, sublist)
 
local getArgs = require('Module:Arguments').getArgs;
 
local args
 
 
-- Most parameters should still display when blank, so don't remove blanks
 
if (sublist) then
 
args = getArgs(frame, {removeBlanks = false, wrappers = 'Template:Episode list/sublist'})
 
else
 
args = getArgs(frame, {removeBlanks = false, wrappers = 'Template:Episode list'})
 
end
 
 
-- args['1'] = mw.getCurrentFrame():getParent():getTitle()
 
return _main(args, sublist, frame)
 
end
 
 
--[[
 
Public function which is used to create an Episode row
 
for an Episode Table used for lists of episodes where each table is on a different page,
 
usually placed on individual season articles.
 
 
For tables which are all on the same page see p.list().
 
 
Parameters:
 
-- |1= — required; The title of the article where the Episode Table is located at.
 
-- |EpisodeNumber= — suggested; The overall episode number in the series.
 
-- |EpisodeNumber2= — suggested; The episode number in the season.
 
-- |Title= — suggested; The English title of the episode.
 
-- |RTitle= — optional; Unformatted parameter that can be used to add a reference after "Title",
 
or can be used as a "raw title" to replace "Title" completely.
 
-- |AltTitle= — optional; An alternative title, such as the title of a foreign show's episode in its native language,
 
or a title that was originally changed.
 
-- |TranslitTitle= — optional; The title of the episode transliteration (Romanization) to Latin characters.
 
-- |RAltTitle= — optional; Unformatted parameter that can be used to add a reference after "AltTitle",
 
or can be used as a "raw title" to replace "AltTitle" completely.
 
-- |NativeTitle= — optional; The title of the episode in the native language.
 
-- |NativeTitleLangCode — optional; The language code of the native title language.
 
-- |Aux1= — optional; General purpose parameter. The meaning is specified by the column header.
 
This parameter is also used for Serial episode titles, such as those used in Doctor Who.
 
-- |DirectedBy= — optional; Name of the episode's director. May contain links.
 
-- |WrittenBy= — optional; Primary writer(s) of the episode. May include links.
 
-- |Aux2= — optional; General purpose parameter. The meaning is specified by the column header.
 
-- |Aux3= — optional; General purpose parameter. The meaning is specified by the column header.
 
-- |OriginalAirDate= — optional; This is the date the episode first aired on TV, or is scheduled to air.
 
-- |AltDate= — optional; The next notable air date, such as the first air date of an anime in English.
 
-- |ProdCode= — optional; The production code in the series. When defined, this parameter also creates a link anchor,
 
prefixed by "pc"; for example, List of episodes#pc01.
 
-- |Viewers= — optional; Number of viewers who watched the episode. Should include a reference.
 
-- |Aux4= — optional; General purpose parameter. The meaning is specified by the column header.
 
-- |ShortSummary= — optional; A short 100–200 word plot summary of the episode.
 
-- |LineColor= — optional; Colors the separator line between episode entries. If not defined the color defaults to "#CCCCFF"
 
and the article is placed in Category:Episode list using the default LineColor.
 
Use of "#", or anything but a valid hex code will result in an invalid syntax.
 
-- |TopColor= — discouraged; Colors the main row of information (that is, not the ShortSummary row).
 
Articles using this parameter are placed in Category:Episode lists with row deviations.
 
-- |RowColor= — optional; Switch parameter that must only be defined when the EpisodeNumber= entry is not a regular number
 
(e.g. "12–13" for two episodes described in one table entry).
 
If the first episode number is even, define pass "on". If the first episode number is odd, pass "off".
 
--]]
 
function p.sublist(frame)
 
return main(frame, true)
 
end
 
 
--[[
 
Public function which is used to create an Episode row
 
for an Episode Table used for lists of episodes where all tables are on the same page.
 
 
For tables which are on different pages see p.sublist().
 
 
For complete parameter documentation, see the documentation at p.sublist().
 
--]]
 
function p.list(frame)
 
return main(frame, false)
 
 
end
 
end
  
 
return p
 
return p

Revision as of 09:32, 27 January 2019

Module:Episode list creates a table row, for use in a list of episodes tables, primarily for television. This module can be used in conjunction with Module:Episode table which creates a consistent and Manual of Style ready table, or with a manually created table. See Template:Episode list for further explanation and documentation.

Usage

Create a standard Episode list with:

  • {{#invoke:Episode list|list}}

Create a sublist which removes episode summaries on the transcluded page with:

  • {{#invoke:Episode list|sublist}}

Tracking categories

<section begin=Tracking/>

<section end=Tracking/>


local p = {}

local getArgs
local yesno = require('Module:Yesno')
local mm = require('Module:Math')
local contrast_ratio = require('Module:Color contrast')._ratio
local HTMLcolor = mw.loadData( 'Module:Color contrast/colors' )

function p.sublist(frame)
	return main(frame,true)
end

function p.list(frame)
	return main(frame,false)
end

function idtrim(val,search)
	local valfind = string.find(val, search)
	if valfind == nil then
		return val
	else
		return string.sub(val, 0, valfind-1)
	end
end

function main(frame, sublist)
	if not getArgs then
		getArgs = require('Module:Arguments').getArgs
	end
	local args

	-- Most parameters should still display when blank, so don't remove blanks
	if sublist then
		args = getArgs(frame, {removeBlanks = false, wrappers = 'Template:Episode list/sublist'})
	else
		args = getArgs(frame, {removeBlanks = false, wrappers = 'Template:Episode list'})
	end
	
	local title = mw.title.getCurrentTitle()
	local page_title = mw.title.getCurrentTitle().text
	local initiallist_title = args['1'] or ''
	local cellValueTBA = false
	
	-- Is this list on the same page as the page directly calling the template?
	local on_initial_page
	
	-- Only sublist had anything about hiding, so only it needs to even check
	if sublist then
		on_initial_page = mw.uri.anchorEncode(page_title) == mw.uri.anchorEncode(initiallist_title)
		-- avoid processing ghost references
		if not on_initial_page then
			args.ShortSummary = nil
		end
	else
		-- Normal lists can ALWAYS show the summary
		on_initial_page = true
	end
	
	-- Declare all the possible <td>/<th> tags here, and the return string
	local EpisodeNumber,EpisodeNumber2,Title,Aux1,DirectedBy,WrittenBy,
			DirectedBy,Aux2,Aux3,OriginalAirDate,AltDate,ProdCode,
			Viewers,Aux4,return_table
	
	-- Need just this parameter removed if blank, no others
	if args.ShortSummary then
		if not args.ShortSummary:find('%S') then
			args.ShortSummary = nil
		end
	end

	-- Default color to light blue
	local line_color = args.LineColor or 'CCCCFF'
	
	-- Add # to color if necessary, and set to default color if invalid
	if HTMLcolor[line_color] == nil then
		line_color = '#'..(mw.ustring.match(line_color, '^[%s#]*([a-fA-F0-9]*)[%s]*$') or '')
		if line_color == '#' then
			line_color = '#CCCCFF'
		end
	end
	
	-- List of parameter names to test
	-- Keep this order as is
	local cell_names = {
		'EpisodeNumber2',
		'Title',
		'Aux1',
		'DirectedBy',
		'WrittenBy',
		'Aux2',
		'Aux3',
		'OriginalAirDate',
		'AltDate',
		'ProdCode',
		'Viewers',
		'Aux4'
	}
	
	-- Is there a way to call a variable by its name stored as a string? Doubt it
	-- This list matches strings with the table cell variables
	local td_tags = {
		['EpisodeNumber2'] = EpisodeNumber2,
		['Title'] = Title,
		['Aux1'] = Aux1,
		['DirectedBy'] = DirectedBy,
		['WrittenBy'] = WrittenBy,
		['DirectedBy'] = DirectedBy,
		['Aux2'] = Aux2,
		['Aux3'] = Aux3,
		['OriginalAirDate'] = OriginalAirDate,
		['AltDate'] = AltDate,
		['ProdCode'] = ProdCode,
		['Viewers'] = Viewers,
		['Aux4'] = Aux4,
	}
	
	local table_row = mw.html.create('tr')
				:addClass('vevent')
				:css('text-align','center')
	
	local row_color = yesno(args.RowColor, false)
	if args.RowColor and string.lower(args.RowColor) == 'on' then
		row_color = true
	end

	local top_color
	local epn = mm._cleanNumber(args.EpisodeNumber) or 1
	if args.TopColor then
		top_color = '#'..args.TopColor
	elseif row_color and on_initial_page and mm._mod(epn,2) == 0 then
		top_color = '#E9E9E9'
	elseif on_initial_page and args.ShortSummary then
		top_color = '#F2F2F2'
	else
		top_color = 'inherit'
	end
		
	table_row:css('background',top_color)
	
	-- This will decide the colspan= of the summary cell
	-- Start as 1 because EpisodeNumber is always created
	local nonnil_params = 1
	
	-- Created separately because it is the only <th> tag
	
	if args.EpisodeNumber then
		if (args.EpisodeNumber == '') then args.EpisodeNumber = frame:expandTemplate{title='TableTBA'}; end
		EpisodeNumber = mw.html.create('th')
				:attr('scope','row')
				:attr('id','ep'..idtrim(idtrim(args.EpisodeNumber,' ----'),'<'))
				:css('text-align','center')
				:wikitext(args.EpisodeNumber)
		table_row:css('background',top_color)
		table_row:node(EpisodeNumber)
	end
	
	-- The wikitext in the Title cell is a little more involved than the others
	local function add_title()
		local title_string = ''
		
		-- Surround the Title with quotes; no quotes if empty
		if args.Title and args.Title:find('%S') then
			title_string = title_string..'"'..args.Title..'"'
		end
		
		if args.RTitle then
			title_string = title_string..args.RTitle
		end
		
		-- Surround the AltTitle with quotes; no quotes if empty
		if args.AltTitle and args.AltTitle:find('%S') then
			title_string = title_string..'<br>"'..args.AltTitle..'"'
		end
			
		if args.RAltTitle then
			title_string = title_string..args.RAltTitle
		end
		return title_string
	end
	
	local categories = ''

	for _,v in ipairs(cell_names) do
		-- Title is in the middle, so it's probably better to just switch back and again instead of doing 2 nodes
		-- and then title, and then the rest in a loop
		if v == 'Title' then
			-- If Title is blank, then set Raw Title to TBA
			if args.Title == '' and (args.RTitle == '' or not args.RTitle) then args.RTitle = frame:expandTemplate{title='TableTBA'}; end
			nonnil_params = nonnil_params + 1
			local title_text = add_title()
			td_tags[v] = mw.html.create('td')
			td_tags[v]:wikitext(title_text)
					:addClass('summary')
					:css('text-align','left')
			table_row:node(td_tags[v])
		elseif args[v] then
			-- Air dates that don't use {{Start date}}
			if v == 'OriginalAirDate' and args[v] ~= '' and string.match(args[v], '%d%d%d%d') ~= nil and string.match(args[v], '2C2C2C') == nil and string.find(args[v],'dtstart') == nil and on_initial_page and title.namespace == 0 then
				categories = categories..'[[Category:Episode lists with unformatted air dates]]' 
			end
			-- Alternate air dates that do use {{Start date}}
			if v == 'AltDate' and args[v] ~= '' and string.find(args[v],'dtstart') ~= nil and on_initial_page and title.namespace == 0 then
				categories = categories..'[[Category:Episode lists with incorrectly formatted alternate air dates]]' 
			end
			-- Set empty cells to TBA/TBD
			if args[v] == '' then
				-- Set to N/A if viewers haven't been available for four weeks, else set it as TBD
				if v == 'Viewers' and args.OriginalAirDate and args.OriginalAirDate ~= '' then
					local month, day, year = args.OriginalAirDate:gsub("&nbsp;"," "):match("(%a+) (%d+), (%d+)")
					if month == nil then
						day, month, year = args.OriginalAirDate:gsub("&nbsp;"," "):match("(%d+) (%a+) (%d+)")
					end
					if day == nil then
						args[v] = frame:expandTemplate{title='TableTBA',args={'TBD'}};
					else
						local MONTHS = {January=1, February=2, March=3, April=4, May=5, June=6, July=7, August=8, September=9, October=10, November=11, December=12}
						local seconds = os.time()-os.time({year=year,month=MONTHS[month],day=day,hour=0,min=0,sec=0})
						if seconds >= 60*60*24*7*4 then args[v] = frame:expandTemplate{title='TableTBA',args={'N/A'}};
						else args[v] = frame:expandTemplate{title='TableTBA',args={'TBD'}}; end
					end
				else args[v] = frame:expandTemplate{title='TableTBA'}; end
			end
			nonnil_params = nonnil_params + 1
			td_tags[v] = mw.html.create('td')
			td_tags[v]:wikitext(args[v])
			table_row:node(td_tags[v])
		end
		if args[v] == "TBA" then cellValueTBA = true end
	end

	-- Production code also has an additional attribute, so add it separately here
	if td_tags.ProdCode and args.ProdCode and (string.find(args.ProdCode,'TBA') == nil) then
		td_tags.ProdCode:attr('id','pc'..idtrim(idtrim(args.ProdCode,' ----'),'<'))
	end
	
	-- add these categories only in the mainspace and only if they are on the page where the template is used
	if on_initial_page and title.namespace == 0 then
		if args.LineColor and args.LineColor ~= '' then
			local black_cr = contrast_ratio{args.LineColor, 'black', ['error'] = 0}
			local white_cr = contrast_ratio{'white', args.LineColor, ['error'] = 0}
			if frame:expandTemplate{title='ColorToLum',args={args.LineColor}} == '' then
				categories = categories..'[[Category:Episode lists with faulty line colors]]' 
			elseif black_cr < 7 and white_cr < 7 then
				categories = categories..'[[Category:Episode lists with non-compliant line colors]]' 
			end
		else
			categories = categories..'[[Category:Episode list using the default LineColor]]'
		end
		
		if args.TopColor and args.TopColor ~= '' then
			categories = categories..'[[Category:Episode lists with row deviations]]'

			-- Track top colors that have a color contrast rating below AAA with
			-- respect to text color, link color, or visited link color. See
			-- [[WP:COLOR]] for more about color contrast requirements.
			local text_cr = contrast_ratio{args.TopColor, 'black', ['error'] = 0}
			local link_cr = contrast_ratio{args.TopColor, '#0B0080', ['error'] = 0}
			local visited_link_cr = contrast_ratio{args.TopColor, '#0645AD', ['error'] = 0}
			if text_cr < 7 or link_cr < 7 or visited_link_cr < 7 then
				categories = categories..'[[Category:Episode lists with invalid top colors]]'
			end
		end
	end
	
	if cellValueTBA == true and title.namespace == 0 then categories = categories .. "[[Category:Episode lists with TBA values]]" end
	
	-- Do not show the summary if this is being transcluded on the initial list page
	-- Do include it on all other lists
	if on_initial_page and args.ShortSummary then
		local bottom_wrapper = mw.html.create('tr')
					:addClass('expand-child')
		-- fix for lists in the Short Summary
		local ss = args.ShortSummary
		if ss:match('^[*:;#]') or ss:match('^{|') then
			ss = '<span></span>\n' .. ss
		end
		if ss:match('\n[*:;#]') then
			ss = ss .. '\n<span></span>'
		end
		local ShortSummary = mw.html.create('td')
					:addClass('description')
					:css('border-bottom','solid 3px '..line_color)
					:attr('colspan',nonnil_params)
					:newline()
					:wikitext(ss)
		bottom_wrapper:node(ShortSummary)
		return tostring(table_row)..tostring(bottom_wrapper)..categories
	else
		return tostring(table_row)..categories
	end
end

return p