Документация
![]() |
local p = {}
local colorContrastModule = require('Модуль:Color contrast')
local htmlColor = mw.loadData('Модуль:Color contrast/colors')
local delinkModule = require('Модуль:Delink')
local mathModule = require('Модуль:Math')
local tableEmptyCellModule = require('Модуль:Пустая ячейка таблицы')
local yesNoModule = require('Модуль:Yesno')
local match = mw.ustring.match
local find = mw.ustring.find
local sub = mw.ustring.sub
local gsub = mw.ustring.gsub
local len = mw.ustring.len
local lower = mw.ustring.lower
local row
local nonNilParams = 0
local cellValueTBA = false
local trackingCategories = ''
local trackingCategoryList = {
['air_dates'] = '[[Категория:Википедия:Списки эпизодов с неоформленной датой показа]]',
['alt_air_dates'] = '[[Категория:Википедия:Списки эпизодов с неверно оформленной датой показа]]',
['faulty_line_colors'] = '[[Категория:Википедия:Списки эпизодов с неверным цветом границ]]',
['non_compliant_line_colors'] = '[[Категория:Википедия:Списки эпизодов с неверным цветом границ]]',
['default_line_colors'] = '[[Категория:Википедия:Списки эпизодов с неверным цветом границ]]',
['row_deviations'] = '[[Категория:Википедия:Списки эпизодов с отклонениями строк]]',
['invalid_top_colors'] = '[[Категория:Википедия:Потенциально нечитаемые таблицы эпизодов]]',
['tba_values'] = '[[Категория:Википедия:Списки эпизодов с незаполненными ячейками]]',
['nonmatching_numbered_parameters'] = '[[Категория:Википедия:Списки эпизодов с неверными параметрами]]',
['raw_unformatted_storyteleplay'] = '[[Категория:Википедия:Списки эпизодов с неоформленными сюжетом или телесценарием]]'
}
local cellNameList = {
'Aux1', 'Столбец1',
'DirectedBy', 'Режиссёр', 'Режиссер',
'WrittenBy', 'Сценарист',
'Aux2', 'Столбец2',
'Aux3', 'Столбец3',
'OriginalAirDate', 'ДатаПоказа',
'AltDate', 'ДатаПоказа2',
'Guests', 'Гости',
'MusicalGuests', 'Персоны',
'ProdCode', 'ПродКод',
'Viewers', 'Зрителей',
'Aux4', 'Столбец4'
}
-- Список взаимоисключающих параметров
local excludeList = {
['Guests'] = 'Aux1', ['Гости'] = 'Столбец2',
['MusicalGuests'] = 'Aux2', ['Персоны'] = 'Столбец3'
}
-- Список ячеек, имеющих группы параметров
local parameterGroupCells = {}
local firstParameterGroupCell
-- Список параметров заголовка для списков с несколькими названиями.
local titleList = {
'Title', 'Название',
'RTitle', 'НазваниеПрим',
'AltTitle', 'Название2',
'RAltTitle', 'Название2Прим',
'NativeTitle', 'НазваниеОригинал',
'TranslitTitle', 'НазваниеТранслит'
}
-- Локальная функция для получения номера эпизода или производственного кода,
-- без какого-либо дополнительного текста.
local function idTrim(val, search)
local valFind = find(val, search)
if (valFind == nil) then
return val
else
return sub(val, 0, valFind - 1)
end
end
-- Локальная функция для проверки того, что параметр имеет значение.
local function hasValue(param)
if (param ~= nil and param ~= '') then
return true
else
return false
end
end
-- Локальная функция для создания транслитерации.
local function langSpan(translitNativeTitle, langCode)
local line = mw.html.create('span')
if hasValue(langCode) then
line
:attr('lang', langCode)
:attr('xml:lang', langCode)
:css('font-style', 'normal')
:wikitext(translitNativeTitle)
end
return tostring(line)
end
-- Локальная функция для создания аббревиатуры
local function abbr(text, title)
local abbr = mw.html.create('abbr')
abbr
:attr('title', title)
:wikitext(text)
return tostring(abbr)
end
-- Локальная функция для создания ячейки Таблицы эпизодов.
local function createTableData(text, rowSpan, textAlign)
if (rowSpan ~= nil and tonumber(rowSpan) > 1) then
row:tag('td')
:attr('rowspan', rowSpan)
:wikitext(text)
else
row:tag('td')
:css('text-align', textAlign)
:wikitext(text)
end
end
-- Локальная функция для добавления отслеживающей категории на страницу.
local function addTrackingCategory(category)
trackingCategories = trackingCategories .. category
end
-- Локальная функция для создания Краткого Содержания.
local function createShortSummaryRow(args, lineColor, linetop)
-- исправление Краткого Содержания
local shortSummaryText = args.ShortSummary or args['КраткоеСодержание']
if hasValue(shortSummaryText) and (match(shortSummaryText, '^[*:;#]') or match(shortSummaryText, '^{|')) then
shortSummaryText = '<span></span>\n' .. shortSummaryText
end
if hasValue(shortSummaryText) and (match(shortSummaryText, '\n[*:;#]')) then
shortSummaryText = shortSummaryText .. '\n<span></span>'
end
if (linetop) then
shortSummaryText = nil
end
local shortSummaryCell = mw.html.create('td')
shortSummaryCell
:addClass('description')
:css('border-bottom', 'solid 3px ' .. lineColor)
:attr('colspan', nonNilParams)
:newline()
:wikitext(shortSummaryText)
local cell = mw.html.create('tr')
cell
:addClass('expand-child')
:node(shortSummaryCell)
if (linetop) then
local lencell = len(cell)
cell = sub(cell, 1, lencell - 10)
end
return tostring(cell)
end
-- Локальная функция для добавления отслеживающей категории при проблемах с цветом.
local function addTopColorTrackingCategories(args)
if (hasValue(args.TopColor or args['ЦветСтроки']) or '#eaecf0') then
addTrackingCategory(trackingCategoryList['row_deviations'])
-- Проверка контрастности в соответствии с [[ВП:ЦВЕТ]].
local textContrastRatio = colorContrastModule._ratio{args.TopColor or args['ЦветСтроки'], 'black', ['error'] = 0}
local linkContrastRatio = colorContrastModule._ratio{args.TopColor or args['ЦветСтроки'], '#0B0080', ['error'] = 0}
local visitedLinkContrastRatio = colorContrastModule._ratio{args.TopColor or args['ЦветСтроки'], '#0645AD', ['error'] = 0}
if (textContrastRatio < 4.5 or linkContrastRatio < 3 or visitedLinkContrastRatio < 3) then
addTrackingCategory(trackingCategoryList['invalid_top_colors'])
end
end
end
-- Локальная функция для добавления отслеживающей категории при проблемах с цветом границы.
local function addLineColorTrackingCategories(args)
if (hasValue(args.LineColor or args['ЦветГраницы']) or '#a2a9b1') then
local blackContrastRatio = colorContrastModule._ratio{args.LineColor or args['ЦветГраницы'], 'black', ['error'] = 0}
local whiteContrastRatio = colorContrastModule._ratio{'white', args.LineColor or args['ЦветГраницы'], ['error'] = 0}
if (args.LineColor or args['ЦветГраницы']) == '' then
addTrackingCategory(trackingCategoryList['faulty_line_colors'])
elseif (blackContrastRatio < 3 and whiteContrastRatio < 3) then
addTrackingCategory(trackingCategoryList['non_compliant_line_colors'])
end
else
addTrackingCategory(trackingCategoryList['default_line_colors'])
end
end
-- Локальная функция для удаления вики-ссылок из повторяющейся информации в ячейках.
local function removeWikilinks(args, v)
return delinkModule._delink {args[v]}
end
-- Локальная функция для установки текста пустой ячейки либо 'TBD' - to be announced, либо 'н/д' - нет данных.
local function setTBDStatus(args, awaitingText, expiredText)
local year, day, month, seconds
local OriginalAirDate = args.OriginalAirDate or args['ДатаПоказа']
if OriginalAirDate == nil or OriginalAirDate == '' then
return tableEmptyCellModule._main({alt_text=awaitingText, title_text=awaitingText})
end
OriginalAirDate = gsub(OriginalAirDate, ' ', ' ')
if match(OriginalAirDate, '{{[Ss]tart date') or match(OriginalAirDate, '-') then
OriginalAirDate = gsub(OriginalAirDate, '[%s|-]+', ' ')
year, month, day = match(OriginalAirDate, '(%d+) (%d+) (%d+)')
elseif match(OriginalAirDate, ',') then
month, day, year = match(OriginalAirDate, '([%a%A]+) (%d+), (%d+)')
elseif match(OriginalAirDate, '[./]') then
OriginalAirDate = gsub(OriginalAirDate, '[%s./|]+', ' ')
day, month, year = match(OriginalAirDate, '(%d+) (%d+) (%d+)')
else
OriginalAirDate = gsub(OriginalAirDate, '[%s.,-/|]+', ' ')
day, month, year = match(OriginalAirDate, '(%d+) ([%a%A]+) (%d+)')
end
if day == nil then
return tableEmptyCellModule._main({alt_text = 'TBD'})
end
-- Список месяцев.
local monthList = {
['января'] = 1, ['январь'] = 1, ['january'] = 1, ['1'] = 1, 1,
['февраля'] = 2, ['февраль'] = 2, ['february'] = 2, ['2'] = 2, 2,
['марта'] = 3, ['март'] = 3, ['march'] = 3, ['3'] = 3, 3,
['апреля'] = 4, ['апрель'] = 4, ['april'] = 4, ['4'] = 4, 4,
['мая'] = 5, ['май'] = 5, ['may'] = 5, ['5'] = 5, 5,
['июня'] = 6, ['июнь'] = 6, ['june'] = 6,['6'] = 6, 6,
['июля'] = 7, ['июль'] = 7, ['july'] = 7, ['7'] = 7, 7,
['августа'] = 8, ['август'] = 8, ['august'] = 8, ['8'] = 8, 8,
['сентября'] = 9, ['сентябрь'] = 9, ['september'] = 9, ['9'] = 9, 9,
['октября'] = 10, ['октябрь'] = 10, ['october'] = 10, ['10'] = 10, 10,
['ноября'] = 11, ['ноябрь'] = 11, ['november'] = 11, ['11'] = 11, 11,
['декабря'] = 12, ['декабрь'] = 12, ['december'] = 12, ['12'] = 12, 12
}
local monthnumber = monthList[lower(month)]
if not monthnumber then
error('Неверный месяц ' .. month)
end
seconds = os.time() - os.time({year=year, month=monthnumber, day=day, hour=0, min=0, sec=0})
-- 60 * 60 * 24 * 7 * 4 = 2419200 секунд в 4-х неделях
if seconds >= 2419200 then
return tableEmptyCellModule._main({alt_text=expiredText, title_text=expiredText})
end
return tableEmptyCellModule._main({alt_text=awaitingText, title_text=awaitingText})
end
-- Local function which is used to create an empty cell.
local function createEmptyCell(args, v, unsetParameterGroup)
if (unsetParameterGroup) then
args[v] = tableEmptyCellModule._main({alt_text='н/д'})
elseif (v == 'Viewers' or v == 'Зрителей' and hasValue(args.OriginalAirDate or args['ДатаПоказа'])) then
args[v] = setTBDStatus(args, 'TBD', 'н/д')
elseif (v == 'DirectedBy' and v == 'Режиссёр' and v == 'Режиссер'
or v == 'WrittenBy' and v == 'Сценарист') then
args[v] = setTBDStatus(args, 'TBA', 'Неизвестно')
else
args[v] = tableEmptyCellModule._main({})
end
end
-- Air dates that don't use {{Start date}}
local function checkUsageOfDateTemplates(args, v, onInitialPage, title)
if (v == 'OriginalAirDate' or v == ' ДатаПоказа'
and args[v] ~= ''
and match(args[v], '%d%d%d%d') ~= nil
and match(args[v], '2C2C2C') == nil
and 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' or v == 'ДатаПоказа2'
and args[v] ~= ''
and 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 or args['ПродКод']) and find(args.ProdCode or args['ПродКод'], 'TBA') == nil) then
row:tag('td')
:attr('id', 'pc' .. idTrim(idTrim(args.ProdCode or args['ПродКод'], ' ----'), '<'))
:css('text-align', 'center')
:wikitext(args.ProdCode or args['ПродКод'])
elseif ((args.ProdCode == '' or args['ПродКод'] == '')
and find(args.ProdCode or args['ПродКод'] or '', 'TBA') ~= nil) then
createEmptyCell(args, v, false)
createTableData(args.ProdCode or args['ПродКод'], 1, 'center')
else
-- ProductionCode parameter not used; Do nothing.
end
nonNilParams = nonNilParams + 1
end
--[[
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 parameter names (Title, Aux).
The function returns the args as non-numbered prameter names.
]] --
local function extractDataFromNumberedSerialArgs(args, i, numberOfParameterGroups, title)
for _, v in ipairs(cellNameList) do
local parameter = v
local numberedParameter = v .. '_' .. i
local excludeParameter = excludeList[parameter] or 'NULL' .. parameter
local excludeNumberParameter = (excludeList[numberedParameter] or 'NULL' .. parameter) .. '_' .. i
if (not hasValue(args[numberedParameter]) and not hasValue(args[excludeNumberParameter])
and hasValue(parameterGroupCells[parameter]) and not hasValue(args[excludeParameter])) then
if (v ~= 'ProdCode' and v ~= 'ПродКод') then
createEmptyCell(args, parameter, true)
else
args[parameter] = ''
end
if (title.namespace == 0) then
addTrackingCategory(trackingCategoryList['nonmatching_numbered_parameters'])
end
elseif (hasValue(args[numberedParameter]) and not hasValue(args[excludeNumberParameter])) then
args[parameter] = args[numberedParameter]
end
end
return args
end
--[[
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()
-- createEpisodeNumberCellSecondary()
-- createTitleCell()
]] --
local function createCells(args, isSerial, currentRow, onInitialPage, title, numberOfParameterGroups)
for k, v in ipairs(cellNameList) do
if (v == 'ProdCode' and v == 'ПродКод') then
createProductionCodeCell(args, v)
elseif (args[v]) then
-- Set empty cells to TBA/TBD
if (args[v] == '') then
createEmptyCell(args, v, false)
elseif (v == 'WrittenBy' or v == 'Сценарист' and title.namespace == 0) then
if ((find(args[v], "''Сюжет") ~= nil
or find(args[v], "''Сценарий") ~= nil
or find(args[v], "''Телесценарий") ~= nil
or find(args[v], "''Телепередача") ~= nil
or find(args[v], "''Передача") ~= nil)
and find(args[v], '8202') == nil) then
--   is the hairspace added through {{StoryTeleplay}}
addTrackingCategory(trackingCategoryList['raw_unformatted_storyteleplay'])
end
end
-- If serial titles need to be centered and not left, then this should be removed.
local textAlign = 'center'
if (v == 'Aux1' or v == 'Столбец1' 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
local thisRowspan
if (firstParameterGroupCell and k < firstParameterGroupCell) then
thisRowspan = numberOfParameterGroups
else
thisRowspan = 1
end
if (currentRow == 1 or (currentRow > 1 and k >= (firstParameterGroupCell or 0))) then
createTableData(args[v], thisRowspan, textAlign)
end
nonNilParams = nonNilParams + 1
checkUsageOfDateTemplates(args, v, onInitialPage, title)
end
if (args[v] == 'TBA') then
cellValueTBA = true
end
end
end
--[[
Local function which is used to create the Title cell text.
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,
then the values of line 2 will be placed on line 1 instead.
--]]
local function createTitleText(args)
local titleString = ''
local isCellPresent = false
local useSecondLine = false
local lineBreakUsed = false
-- Surround the Title with quotes; No quotes if empty.
if (args.Title ~= nil or args['Название'] ~= nil) then
-- Название с подрезкой лишних кавычек
local mainTitle = args.Title or args['Название']
if (args.Title == '' or args['Название'] == '') then
isCellPresent = true
else
titleString = "«'''" .. mainTitle .. "'''»"
useSecondLine = true
isCellPresent = true
end
end
if (args.RTitle ~= nil or args['НазваниеПрим'] ~= nil) then
if (args.RTitle == '' or args['НазваниеПрим'] == '') then
isCellPresent = true
else
titleString = titleString .. (args.RTitle or args['НазваниеПрим'])
useSecondLine = true
isCellPresent = true
end
end
-- Surround the AltTitle/TranslitTitle with quotes; No quotes if empty.
if (args.AltTitle or args['Название2'] or args.TranslitTitle or args['НазваниеТранслит']) then
isCellPresent = true
if (useSecondLine) then
titleString = titleString .. '<br>'
lineBreakUsed = true
end
if (hasValue(args.AltTitle or args['Название2'])) then
-- Название2 с подрезкой лишних кавычек и исправление конфликта с <ref> и с {{comment}}
local altTitle
if (find(args.AltTitle or args['Название2'], 'ref') ~= nil) then
altTitle = gsub(args.AltTitle or args['Название2'], '<ref>^[*.]$', '')
else
altTitle = gsub(args.AltTitle or args['Название2'], "'''", '')
end
if (find(args.AltTitle or args['Название2'], '{{comment|') ~= nil) then
altTitle = gsub(altTitle, "'", '')
end
titleString = titleString .. "«''" .. altTitle .. "''»"
elseif (hasValue(args.TranslitTitle or args['НазваниеТранслит'])) then
if (hasValue(args.NativeTitleLangCode or args['КодЯзыка'])) then
titleString = titleString ..
abbr('транслит', 'транслитерация') ..
'.: «' ..
langSpan(args.TranslitTitle or args['НазваниеТранслит'],
args.NativeTitleLangCode or args['КодЯзыка']) .. '»'
else
titleString = titleString ..
abbr('транслит', 'транслитерация') ..
'.: «' .. (args.TranslitTitle or args['НазваниеТранслит']) .. '»'
end
end
end
if (args.NativeTitle ~= nil or args['НазваниеОригинал'] ~= nil) then
if (args.NativeTitle == '' or args['НазваниеОригинал'] == '') then
isCellPresent = true
else
isCellPresent = true
if (useSecondLine and lineBreakUsed == false) then
titleString = titleString .. '<br>'
end
if (hasValue(args.NativeTitleLangCode or args['КодЯзыка'])) then
local languageCode = 'Lang-' .. (args.NativeTitleLangCode or args['КодЯзыка'])
titleString = titleString .. ' (' ..
abbr('ориг', 'оригинал') .. '.: ' ..
langSpan(args.NativeTitle or args['НазваниеОригинал'],
args.NativeTitleLangCode or args['КодЯзыка']) .. ')'
else
titleString = titleString .. ' (' ..
abbr('ориг', 'оригинал') .. '.: ' ..
(args.NativeTitle or args['НазваниеОригинал']) .. ')'
end
end
end
if (args.RAltTitle ~= nil or args['Название2Прим'] ~= nil) then
if (args.RAltTitle == '' or args['Название2Прим'] == '') then
isCellPresent = true
else
isCellPresent = true
if (useSecondLine and lineBreakUsed == false) then
titleString = titleString .. '<br>'
end
titleString = titleString .. (args.RAltTitle or args['Название2Прим'])
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
local parameter = v
local numberedParameter = v .. '_' .. i
args[parameter] = args[numberedParameter]
if (nextGroupValid == false and hasValue(args[numberedParameter])) then
nextGroupValid = true
end
end
return args, nextGroupValid
end
-- Local function which is used to process the multi title list.
local function processMultiTitleList(args, numberOfParameterGroups)
local nativeTitleLangCode = args.NativeTitleLangCode or args['КодЯзыка']
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, numberOfParameterGroups do
local args, nextGroupValid = extractDataFromNumberedTitleArgs(args, i)
if (nextGroupValid) then
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
return titleText
end
-- Local function which is used to create a Title cell.
local function createTitleCell(args, numberOfParameterGroups, multiTitleListEnabled, isSerial)
local titleText
local isCellPresent
if (multiTitleListEnabled) then
titleText, isCellPresent = processMultiTitleList(args, numberOfParameterGroups)
else
titleText, isCellPresent = createTitleText(args)
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 = 'left'
end
-- If title is the first cell, create it with a !scope='row'
if (nonNilParams == 0) then
if (isSerial) then
row:tag('th')
:addClass('summary')
:attr('scope', 'row')
:attr('rowspan', numberOfParameterGroups)
:css('text-align', textAlign)
:wikitext(titleText)
else
row:tag('th')
:addClass('summary')
:attr('scope', 'row')
:css('text-align', textAlign)
:wikitext(titleText)
end
else
if (isSerial) then
row:tag('td')
:addClass('summary')
:attr('rowspan', numberOfParameterGroups)
:css('text-align', textAlign)
:wikitext(titleText)
else
row:tag('td')
:addClass('summary')
:css('text-align', textAlign)
:wikitext(titleText)
end
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, numberOfParameterGroups, episodeText)
local epID = match(episodeNumber, '^%w+')
row:tag('th')
:attr('scope', 'row')
:attr('rowspan', numberOfParameterGroups)
:attr('id', epID and 'ep' .. epID or '')
: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
local episodeNumber2
-- Used for double episodes that need a visual '–' or '<hr>' added.
local divider
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 (match(episodeNumber, '^(%w+)%s*[%s%-–/&]%s*(%w+)$')) then
episodeNumber1, episodeNumber2 = match(episodeNumber, '^(%w+)%s*[%s%-–/&]%s*(%w+)$')
divider = '–'
else
episodeNumber1, episodeNumber2 = match(episodeNumber, '^(%w+)%s*[%s%-–/&].-[%s%-–/&]%s*(%w+)$') -- 3 or more elements
divider = '–'
end
if (not episodeNumber1) then
return episodeNumber
elseif (not episodeNumber2) then
return match(episodeNumber, '%w+')
else
return episodeNumber1 .. divider .. episodeNumber2
end
end
end
-- Local function which is used to create EpisodeNumber2 and EpisodeNumber3 cells.
local function _createEpisodeNumberCellSecondary(episodeValue, numberOfParameterGroups)
if (episodeValue) then
local episodeText = getEpisodeText(episodeValue)
if (nonNilParams == 0) then
createTableRowEpisodeNumberHeader(episodeValue, numberOfParameterGroups, episodeText)
else
createTableData(episodeText, numberOfParameterGroups, 'center')
end
nonNilParams = nonNilParams + 1
end
end
-- Local function which is used to create seconday episode number cells.
local function createEpisodeNumberCellSecondary(args, numberOfParameterGroups)
_createEpisodeNumberCellSecondary(args.EpisodeNumber2 or args['НомерЭпизода2'], numberOfParameterGroups)
_createEpisodeNumberCellSecondary(args.EpisodeNumber3 or args['НомерЭпизода3'], numberOfParameterGroups)
end
-- Local function which is used to create an EpisodeNumber cell.
local function createEpisodeNumberCell(args, numberOfParameterGroups)
if (args.EpisodeNumber or args['НомерЭпизода']) then
local episodeText = getEpisodeText(args.EpisodeNumber or args['НомерЭпизода'])
createTableRowEpisodeNumberHeader(args.EpisodeNumber or args['НомерЭпизода'], numberOfParameterGroups, 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, numberOfParameterGroups, multiTitleListEnabled, onInitialPage, title)
createEpisodeNumberCell(args, 1)
createEpisodeNumberCellSecondary(args, 1)
createTitleCell(args, numberOfParameterGroups, multiTitleListEnabled, false)
createCells(args, false, 1, onInitialPage, title, numberOfParameterGroups)
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, numberOfParameterGroups, onInitialPage, title, topColor)
createEpisodeNumberCell(args, numberOfParameterGroups)
createEpisodeNumberCellSecondary(args, numberOfParameterGroups)
createTitleCell(args, numberOfParameterGroups, false, true)
for i = 1, numberOfParameterGroups do
args = extractDataFromNumberedSerialArgs(args, i, numberOfParameterGroups, title)
createCells(args, true, i, onInitialPage, title, numberOfParameterGroups)
if (i ~= numberOfParameterGroups) then
row = row:done()-- Use done() to close the 'tr' tag in rowspaned rows.
:tag('tr')
:css('background', topColor)
end
end
end
-- Local function which is used to retrieve the NumParts value.
local function getnumberOfParameterGroups(args)
for k, v in ipairs(cellNameList) do
local numberedParameter = v .. '_' .. 1
if (args[numberedParameter]) then
parameterGroupCells[v] = true
if not firstParameterGroupCell then
firstParameterGroupCell = k
end
end
end
if (hasValue(args.NumParts or args['КоличествоЧастей'])) then
return (args.NumParts or args['КоличествоЧастей']), true
else
return 1, false
end
end
-- Local function which is used to retrieve the remainder value after x has been divided by y
local function mathMod(x, y)
local ret = x % y
if not (0 <= ret and ret < y) then
ret = 0
end
return ret
end
-- Local function which is used to retrieve the Top Color value.
local function getTopColor(args, rowColorEnabled, onInitialPage)
local episodeNumber = mathModule._cleanNumber(args.EpisodeNumber or args['НомерЭпизода']) or 1
if (args.TopColor or args['ЦветСтроки']) then
if (find(args.TopColor or args['ЦветСтроки'], '#')) then
return args.TopColor or args['ЦветСтроки']
else
return '#' .. (args.TopColor or args['ЦветСтроки'])
end
elseif (rowColorEnabled and onInitialPage and mathMod(episodeNumber, 2) == 0) then
return '#E9E9E9'
elseif (onInitialPage and (args.ShortSummary or args['КраткоеСодержание'])) then
return '#F2F2F2'
else
return 'inherit'
end
end
-- Local function which is used to retrieve the Row Color value.
local function isRowColorEnabled(args)
local RowColor = args.RowColor or args['ЧередованиеЦвета']
local rowColorEnabled = yesNoModule(RowColor, false)
if args.RowColor ~= nil or args['ЧередованиеЦвета'] ~= nil then
rowColorEnabled = true
end
return rowColorEnabled
end
-- Local function which is used to retrieve the Line Color value.
local function getLineColor(args)
-- Default color to light blue
local lineColor = args.LineColor or args['ЦветГраницы'] or 'CCCCFF'
-- Add # to color if necessary, and set to default color if invalid
if (htmlColor[lineColor] == nil) then
lineColor = '#' .. (match(lineColor, '^[%s#]*([a-fA-F0-9]*)[%s]*$') or '')
if (lineColor == '#') then
lineColor = '#CCCCFF'
end
end
return lineColor
end
-- Local function which is used to check if the table is located on the page
-- currently viewed, or on a transcluded page instead.
-- If it is on a transcluded page, the episode summary should not be shown.
local function isOnInitialPage(args, sublist, pageTitle, initiallistTitle)
-- This should be the only check needed, however, it was previously implemented with two templates
-- with one of them not requiring an article name, so for backward compatability, the whole sequence is kept.
local onInitialPage
-- Only sublist had anything about hiding, so only it needs to even check
if (sublist) then
local pageTitleMatch = match(pageTitle, 'Список эпизодов', 1) -- Результат: Список эпизодов или nil
if (not hasValue(initiallistTitle) and pageTitleMatch == 'Список эпизодов') then -- Автоопределение страницы 'Список эпизодов ...'
onInitialPage = true
elseif hasValue(initiallistTitle) then
onInitialPage = mw.uri.anchorEncode(pageTitle) == mw.uri.anchorEncode(initiallistTitle)
end
else
onInitialPage = false
end
return onInitialPage
end
-- Local function which does the actual main process.
local function _main(args, sublist, linetop)
local title = mw.title.getCurrentTitle()
local pageTitle = title.text
local initiallistTitle = args['1'] or ''
-- Is this list on the same page as the page directly calling the template?
local onInitialPage = isOnInitialPage(args, sublist, pageTitle, initiallistTitle)
-- Need just this parameter removed if blank, no others
if (hasValue(args.ShortSummary or args['КраткоеСодержание']) == false) then
args.ShortSummary = nil
args['КраткоеСодержание'] = nil
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 numberOfParameterGroups, multiTitleListEnabled = getnumberOfParameterGroups(args)
if (multiTitleListEnabled and (not args.Title_2 or args['Название_2'])) then
createMultiRowCells(args, numberOfParameterGroups, onInitialPage, title, topColor)
else
createSingleRowCells(args, numberOfParameterGroups, 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
local pageTitleMatch = match(pageTitle, 'Список эпизодов', 1)
if (pageTitleMatch == 'Список эпизодов' or title.namespace ~= 0) then
trackingCategories = ''
end
-- Do not show the summary if this is being transcluded on the initial list page
-- Do include it on all other lists
if (not onInitialPage and (args.ShortSummary or args['КраткоеСодержание'])) then
local bottomWrapper = createShortSummaryRow(args, lineColor)
return tostring(root) .. tostring(bottomWrapper) .. trackingCategories
elseif (linetop) then
local bottomWrapper = createShortSummaryRow(args, lineColor)
local bottomWrapperLen = len(bottomWrapper)
local bottomWrapperEnd = sub(bottomWrapper, 1, bottomWrapperLen - 10)
return tostring(root) .. tostring(bottomWrapperEnd) .. trackingCategories
else
return tostring(root) .. trackingCategories
end
end
-- Local function which handles both module entry points.
local function main(frame, sublist, linetop)
local getArgs = require('Модуль: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 = 'Шаблон:Список серий/sublist'})
elseif (linetop) then
args = getArgs(frame, {removeBlanks = false, wrappers = 'Шаблон:Список серий/шапка'})
else
args = getArgs(frame, {removeBlanks = false, wrappers = 'Шаблон:Список серий'})
end
-- args['1'] = mw.getCurrentFrame():getParent():getTitle()
return _main(args, sublist, linetop, frame)
end
--------------------------------------------------------------------------------
-- Экспорт
--------------------------------------------------------------------------------
function p.sublist(frame)
return main(frame, true, false)
end
function p.linetop(frame)
return main(frame, false, true)
end
function p.list(frame)
return main(frame, false, false)
end
return p