local p = {}
local function conceal(text, class)
class = class or ''
return '<span style="display:none; speak:none;" class="topicWatch-' .. class .. '">' .. text .. '</span>' -- содержимое шаблона {{~}}
end
local function findInTable(table, value)
for k, v in pairs(table) do
if v == value then
return true
end
end
return false
end
local function cleanSectionHeading(heading)
-- The following patterns reproduce [[Участник:Jack who built the house/transferHeadingToSummary.js]]
heading = mw.ustring.gsub(heading, '%[%[:?[^|%]]*|([^%]]*)%]%]', '%1')
heading = mw.ustring.gsub(heading, '%[%[:?([^%]]*)%]%]', '%1')
heading = mw.ustring.gsub(heading, "'''(.-)'''", '%1')
heading = mw.ustring.gsub(heading, "''(.-)''", '%1')
heading = mw.ustring.gsub(heading, '</?%w+ ?/?>', '')
heading = mw.ustring.gsub(heading, '<%w+ [%w ]-=[^<>]->', '')
heading = mw.ustring.gsub(heading, ' +', ' ')
heading = mw.text.trim(heading)
return heading
end
local function sectionHeadingToLink(sectionHeading)
local sectionHeadingLink = sectionHeading
-- The following reproduces processURI function of [[Участник:Jack who built the house/copyWikilinks.js]]
--[[sectionHeadingLink = mw.ustring.gsub(sectionHeadingLink, '<', '%%3C')
sectionHeadingLink = mw.ustring.gsub(sectionHeadingLink, '>', '%%3E')
sectionHeadingLink = mw.ustring.gsub(sectionHeadingLink, '%[', '%%5B')
sectionHeadingLink = mw.ustring.gsub(sectionHeadingLink, '%]', '%%5D')
sectionHeadingLink = mw.ustring.gsub(sectionHeadingLink, '{', '%%7B')
sectionHeadingLink = mw.ustring.gsub(sectionHeadingLink, '|', '%%7C')
sectionHeadingLink = mw.ustring.gsub(sectionHeadingLink, '}', '%%7D')
sectionHeadingLink = mw.ustring.gsub(sectionHeadingLink, ' ', '.C2.A0')]]
return '#' .. sectionHeadingLink
end
local function killHeadingMarkers(content)
content = mw.ustring.gsub(
content,
string.char(127) .. '\'"`UNIQ%-%-h%-%d+%-%-QINU`"\'' .. string.char(127),
''
)
return content
end
function p.main(frame)
if not getArgs then
getArgs = require('Модуль:Arguments').getArgs
end
local yesno = require('Module:Yesno')
local args = getArgs(frame, {removeBlanks = false})
local ru = mw.getLanguage('ru')
local errorInfo = {}
-- обрабатываем параметры
local talkpageMode = args['режим'] == 'страницы'
local afdMode = args['режим'] == 'КУ'
local pageListMode = args['режим'] == 'список страниц'
local standardMode
if not talkpageMode and not afdMode and not pageListMode then
standardMode = true
end
local separateTopicListPage, separateTopicList
if standardMode and not args[1] then
separateTopicListPage = mw.title.new(args['список'] or mw.title.getCurrentTitle().prefixedText .. '/список')
if separateTopicListPage.exists then
local content = separateTopicListPage:getContent()
if content:find('{{') then
content = frame:preprocess(content)
end
separateTopicList = mw.text.split(content, '\n')
end
if not separateTopicList or (separateTopicList[1] == '' and not separateTopicList[2]) then
separateTopicList = {}
end
end
local afdItems, nominationsNum
if afdMode then
local afdListPage = mw.title.new('Тептар:К удалению') -- Участник:Jack who built the house/песочница2
nominationsNum = tonumber(args['номинаций']) or 50
afdItems = {}
local afdListContent = afdListPage:getContent()
afdListContent = mw.ustring.gsub(afdListContent, '<small>.-<\/small>', '')
afdListContent = mw.ustring.gsub(afdListContent, '<s>.-<\/s>', '')
local iterator = mw.ustring.gmatch(afdListContent, '{{Удаление статей|([^|]+)|([^\n]+)}}')
reversedIteratorTable = {}
for day, topics in iterator do
table.insert(reversedIteratorTable, 1, {day = day, topics = topics})
end
for k, v in pairs(reversedIteratorTable) do
day = v.day
topics = v.topics
local afdPage = 'Тептар:К удалению/' .. ru:formatDate('j xg Y', day)
local iterator = mw.text.gsplit(topics, ' • ', true)
for v2 in iterator do
if v2 ~= '' then
v2 = cleanSectionHeading(v2)
table.insert(afdItems, afdPage .. '#' .. v2)
end
if #afdItems >= nominationsNum + 50 then break end
end
if #afdItems >= nominationsNum + 50 then break end
end
end
local topicsToShow = tonumber(args['тем']) or 10000
-- число тем, содержимое которых выводить непосредственно на странице, а не ссылаться на другую
local fullTopicsToShow = not pageListMode and (
tonumber(args['полных тем'])
or (
afdMode and 1000 or 10
)
)
if topicsToShow == 0 and fullTopicsToShow == 0 then return '' end
local style = args['стиль'] == 'форумный' and args['стиль'] or 'wikitable';
local showTopicCount
if args['показывать количество тем'] then
showTopicCount = yesno(args['показывать количество тем'], true)
else
showTopicCount = true
end
local reloadLink
if args['обновить'] then
reloadLink = yesno(args['обновить'], false)
else
reloadLink = false
end
local sortFullTopics, sortTopics
if afdMode then
sortFullTopics = false
sortTopics = false
elseif args['сортировка полных тем'] then
sortFullTopics = yesno(args['сортировка полных тем'], false)
sortTopics = true
else
sortFullTopics = true
sortTopics = true
end
-- проверяем и обрабатываем части названий, чистим от дубликатов
-- wrongItems — элементы, с которыми что-то не так уже на этапе распознавания адреса
-- itemsToRemove — элементы, которые предлагается удалить из списка отслеживания
-- errorInfo (объявлено выше) — сообщения об ошибке
local items, wrongItems, itemsToRemove = {}, {}, {}
for k, v in pairs(separateTopicList or afdItems or args) do
if type(k) == 'number' then
if v ~= '' then
local newItem = {
originalFullTitle = v,
titleObject = mw.title.new(v),
}
if newItem.titleObject and newItem.titleObject.prefixedText ~= '' then
if newItem.titleObject.fragment ~= '' then
newItem.sectionHeading = mw.text.encode(mw.uri.decode(newItem.titleObject.fragment), '<>%[%]{|}')
if not talkpageMode and not pageListMode then
newItem.resultMode = false
newItem.sectionHeading = mw.ustring.gsub(newItem.sectionHeading, '\\итог$', function (s)
newItem.resultMode = true
return ''
end)
newItem.sectionHeading = mw.ustring.gsub(newItem.sectionHeading, '\\\\\\.*$', function (s) -- \\\Итог
newItem.subsectionHeading = s
return ''
end)
end
end
if not newItem.sectionHeading and not talkpageMode and not pageListMode then
table.insert(wrongItems, v)
table.insert(itemsToRemove, v)
else
local found = false
for k2, v2 in pairs(items) do
if v2.titleObject.prefixedText == newItem.titleObject.prefixedText and (not newItem.sectionHeading or v2.sectionHeading == newItem.sectionHeading) and (not newItem.subsectionHeading or v2.subsectionHeading == newItem.subsectionHeading) then
found = true
break
end
end
if not found then
table.insert(items, newItem)
else
table.insert(itemsToRemove, v)
end
end
else
table.insert(wrongItems, v)
table.insert(itemsToRemove, v)
end
else
table.insert(itemsToRemove, v)
end
end
end
if #wrongItems > 0 then
local wrongItemsString =
#wrongItems == 1
and 'Что-то не так с элементом'
or 'Что-то не так со следующими элементами:'
for k, v in pairs(wrongItems) do
if k ~= 1 then
wrongItemsString = wrongItemsString .. ', '
end
wrongItemsString = wrongItemsString .. ' «' .. v .. '»'
end
wrongItemsString = wrongItemsString .. '.'
table.insert(errorInfo, wrongItemsString)
end
-- запрашиваем данные
local allData = {}
local talkpageCount
local onlyPageTitle
local pageListData
if talkpageMode then
talkpageCount = 0
local parse_talkpage_content = require('Модуль:Get page content')._parse_talkpage_content
for k, v in pairs(items) do
local argsToPass = {}
argsToPass[1] = v.titleObject
argsToPass['короткие заголовки'] = not items[2] and true or false
if fullTopicsToShow == 0 then
argsToPass['только статистика'] = true
end
local allDataFromPage = parse_talkpage_content(argsToPass)
if type(allDataFromPage) == 'table' then
if allDataFromPage[1] then
local pageTitle = v.titleObject.prefixedText
talkpageCount = talkpageCount + 1
for k2, v2 in pairs(allDataFromPage) do
v2.pageTitle = pageTitle
v2.canonicalPath = v2.pageTitle .. '#' .. v2.sectionHeading .. (v2.subsectionHeading and '\\\\\\' .. v2.subsectionHeading or '')
table.insert(allData, v2)
end
if talkpageCount == 1 then
onlyPageTitle = pageTitle
end
elseif allDataFromPage.pageNotExistMessage then
table.insert(itemsToRemove, v.originalFullTitle)
table.insert(errorInfo, allDataFromPage.pageNotExistMessage)
end
else
table.insert(errorInfo, 'Не удалось получить данные о странице «' .. v.titleObject.prefixedText .. '» от модуля получения содержимого страницы.')
end
end
elseif pageListMode then
pageListData = {}
local parse_talkpage_content = require('Модуль:Get page content')._parse_talkpage_content
for k, v in pairs(items) do
local argsToPass = {}
argsToPass[1] = v.titleObject
argsToPass['только статистика'] = true
argsToPass['режим списков страниц'] = true
local allDataFromPage = parse_talkpage_content(argsToPass)
if type(allDataFromPage) == 'table' then
if allDataFromPage[1] then
local pageTitle = v.titleObject.prefixedText
local pageData = {
num = k,
pageTitle = pageTitle,
msgCount = 0,
topicCount = 0,
lastMsgDateTimestamp = 0
}
for k2, v2 in pairs(allDataFromPage) do
if v2.msgCount then
pageData.msgCount = pageData.msgCount + v2.msgCount
if v2.lastMsgDateTimestamp > pageData.lastMsgDateTimestamp then
--pageData.lastMsgDate = v2.lastMsgDate
pageData.lastMsgDateString = v2.lastMsgDateString
pageData.lastMsgDateTimestamp = v2.lastMsgDateTimestamp
pageData.lastMsgAuthor = v2.lastMsgAuthor
end
end
pageData.topicCount = pageData.topicCount + 1
if v2.warningHeading and not pageData.warningHeading then
pageData.warningHeading = v2.warningHeading
end
end
table.insert(pageListData, pageData)
elseif allDataFromPage.pageNotExistMessage then
table.insert(itemsToRemove, v.originalFullTitle)
table.insert(errorInfo, allDataFromPage.pageNotExistMessage)
end
else
table.insert(errorInfo, 'Не удалось получить данные о странице «' .. v.titleObject.prefixedText .. '» от модуля получения содержимого страницы.')
end
end
else
local parse_section_content = require('Модуль:Get page content')._parse_section_content
for k, v in pairs(items) do
local argsToPass = {}
table.insert(argsToPass, v.titleObject)
table.insert(argsToPass, v.sectionHeading)
argsToPass['итог'] = v.resultMode
argsToPass['подраздел'] = v.subsectionHeading
argsToPass['как данные'] = true
if fullTopicsToShow == 0 then
argsToPass['только статистика'] = true
else
argsToPass['стандартный заголовок'] = true
end
if afdMode then
argsToPass['режим КУ'] = true
end
local data = parse_section_content(argsToPass)
if type(data) == 'table' then
if data.pageNotExistMessage then
table.insert(itemsToRemove, v.originalFullTitle)
table.insert(errorInfo, data.pageNotExistMessage)
elseif data.sectionNotExistMessage then
table.insert(itemsToRemove, v.originalFullTitle)
table.insert(errorInfo, data.sectionNotExistMessage)
else
if topicsToShow ~= 0 and data.msgCount then
data.pageTitle = v.titleObject.prefixedText
data.sectionHeading = v.sectionHeading
if argsToPass['подраздел'] then
data.subsectionHeading = argsToPass['подраздел']
end
data.canonicalPath = data.pageTitle .. '#' .. data.sectionHeading .. (data.subsectionHeading and '\\\\\\' .. data.subsectionHeading or '')
end
if afdMode then
if not data.closureHeading then
table.insert(allData, data)
if #allData >= nominationsNum then break end
end
else
table.insert(allData, data)
end
end
else
table.insert(errorInfo, 'Не удалось получить данные о странице «' .. v.titleObject.prefixedText .. '» от модуля получения содержимого страницы.')
end
end
end
for k, v in pairs(allData) do
allData[k].num = k
end
-- если включена сортировка и полных тем, и тем в таблице, мы можем сразу отсортировать общий массив
if sortTopics and (fullTopicsToShow == 0 or sortFullTopics) then
table.sort(allData, function (data1, data2)
-- благодаря 10000 - dataN.num темы частично сохраняют изначальный порядок
local lastMsgDate1Timestamp = data1.lastMsgDateTimestamp or 10000 - data1.num
local lastMsgDate2Timestamp = data2.lastMsgDateTimestamp or 10000 - data2.num
return lastMsgDate1Timestamp > lastMsgDate2Timestamp
end)
end
-- считаем число тем и страниц, откладываем отсутствующие
local pages, topics, fullTopics = {}, {}, {}
local randomNum
if allData[1] then
if fullTopicsToShow ~= 0 then
randomNum = tostring(os.clock()):sub(-7)
end
for k, v in pairs(allData) do
table.insert(fullTopics, v)
if v.msgCount then
table.insert(topics, v)
if not findInTable(pages, v.pageTitle) then
table.insert(pages, v.pageTitle)
end
end
end
end
-- если отключена сортировка полных тем, сортируем здесь только темы в таблице
if sortTopics and (fullTopicsToShow ~= 0 and not sortFullTopics) then
table.sort(topics, function (data1, data2)
-- благодаря 10000 - dataN.num темы частично сохраняют изначальный порядок
local lastMsgDate1Timestamp = data1.lastMsgDateTimestamp or 10000 - data1.num
local lastMsgDate2Timestamp = data2.lastMsgDateTimestamp or 10000 - data2.num
return lastMsgDate1Timestamp > lastMsgDate2Timestamp
end)
end
if #topics > topicsToShow then
pages = {}
for k, v in pairs(topics) do
if not findInTable(pages, v.pageTitle) then
table.insert(pages, v.pageTitle)
end
if k == topicsToShow then
for i = k + 1, #topics do
table.remove(topics, k + 1)
end
break
end
end
end
-- формируем шапку
local headerContent = ''
if talkpageMode and talkpageCount == 1 then
headerContent = headerContent .. '<div style="font-size:1.5em;">[[' .. onlyPageTitle .. ']]</div>\n'
elseif afdMode then
headerContent = headerContent .. '<div style="font-size:1.5em;">' .. #topics .. ' ' .. ru:plural(#topics, 'самая старая незакрытая номинация', 'самые старые незакрытые номинации', 'самых старых незакрытых номинаций') .. ' «[[ВП:К удалению|К удалению]]»</div>\n'
end
if showTopicCount then
if standardMode or talkpageMode then
headerContent = headerContent .. '<p><b>' .. #topics .. '</b> ' .. ru:plural(#topics, 'тема', 'темы', 'тем') .. ' на <b>' .. #pages .. '</b> ' .. ru:plural(#pages, 'странице', 'страницах')
elseif afdMode then
if #pages ~= 0 then
headerContent = headerContent .. '<p>За <b>' .. #pages .. '</b> ' .. ru:plural(#pages, 'день', 'дня', 'дней')
end
elseif pageListMode then
headerContent = headerContent .. '<p><b>' .. #pageListData .. '</b> ' .. ru:plural(#pageListData, 'страница', 'страницы', 'страниц')
end
if separateTopicListPage then
headerContent = headerContent .. ' <b>·</b> <span class="plainlinks">[' .. separateTopicListPage:fullUrl('action=edit') .. ' Редактировать список тем]</span>\n'
end
headerContent = headerContent .. '</p>\n'
end
if reloadLink then
headerContent = headerContent .. '<p ' .. (
not false -- пока оставим
and 'style="margin-top:1.5em;"'
or ''
) .. '><span style="font-size:1.5em;" class="plainlinks purgelink">[' .. mw.title.getCurrentTitle():fullUrl('action=purge') .. ' Обновить]</span> <b>·</b> обновлялось в ' .. ru:formatDate('H:i j xg Y') .. ' (UTC)'
end
if reloadLink or separateTopicPage then
headerContent = headerContent .. '</p>\n'
end
if not afdMode and not pageListMode and fullTopicsToShow > 50 and #topics > 50 then
headerContent = headerContent .. '<p style="font-size:85%;">Для более быстрой загрузки страницы и экономии ресурсов сервера сократите число тем, содержимое которых выводится на странице, уменьшив значение параметра <code>полных тем</code> в шаблоне.</p>\n'
end
-- формируем таблицу
local outFragmentLink_title = 'Ссылка прямо на реплику в настоящий момент работает только при включенном гаджете «Удобные обсуждения»'
if pageListData and pageListData[1] then
local tableContent =
'{| class="wikitable wide sortable" style="line-height:1.4;"\n'
.. '! width="2%" | №'
.. '!! Страница '
.. '!! width="25%" class="nowrap" | Последнее сообщение '
.. '!! width="10%" | Тем '
.. '!! width="10%" | Сообщений\n'
for k, v in pairs(pageListData) do
if v.msgCount then
tableContent = tableContent
.. '|-\n'
.. '| style="text-align:center;" | ' .. v.num .. '\n'
.. '| ' .. conceal(v.pageTitle, 'wikilink') .. '[[' .. v.pageTitle .. '|<span style="display:block; font-size:110%;">' .. v.pageTitle .. (
v.warningHeading
and '<span style="display:inline-block; margin-left:1em; padding:0 8px; border-radius:5px; font-size:83.33%; line-height:1.5; letter-spacing:1px; background-color:#a07; color:#f9f9f9; white-space:nowrap;">ПРЕДУПР.</span>'
or ''
) .. '</span>]]\n'
.. '| style="/* Chrome */ word-break:break-word; /* ? */ word-wrap:break-word;" | ' .. (
v.msgCount > 0
and conceal(v.lastMsgDateTimestamp, 'lastMsgDate') .. '[[' .. v.pageTitle .. '#' .. v.lastMsgDateString .. '_' .. v.lastMsgAuthor .. '|<span style="display:block; text-decoration:inherit;" class="topicWatch-outFragmentLink" title="' .. outFragmentLink_title .. '">' .. v.lastMsgDateString .. '<br>от ' .. v.lastMsgAuthor .. '</span>]]\n'
or '—\n'
)
.. '| style="text-align:center;" | ' .. conceal(v.msgCount, 'topicCount') .. v.topicCount .. '\n'
.. '| style="text-align:center;" | ' .. conceal(v.msgCount, 'msgCount') .. v.msgCount .. '\n'
end
end
tableContent = tableContent .. '|}\n'
headerContent = headerContent .. tableContent
elseif topicsToShow ~= 0 and #topics ~= 0 then
local needHighlightOutLinks = fullTopicsToShow ~= 0 and fullTopicsToShow < math.min(#topics, topicsToShow)
local labelColors =
afdMode
and {
closure = '#800',
preclosure = '#25820e',
challengedClosure = '#a07',
partialClosure = '#00a',
}
or {
closure = '#999',
preclosure = '#999',
challengedClosure = '#999',
partialClosure = '#999',
}
local tableContent
if style == 'wikitable' then
tableContent =
'{| class="wikitable wide sortable topicWatch-topicTable"' .. (fullTopicsToShow ~= 0 and ' id="topicTable' .. randomNum .. '"' or '') .. ' style="line-height:1.4;"\n'
.. (talkpageMode and talkpageCount > 1 and '' or '! width="2%" | № !')
.. '! Тема '
.. '!! width="25%" class="nowrap" | Последнее сообщение '
.. '!! width="10%" | Сообщений '
.. '!! width="10%" | Авторов\n'
elseif style == 'форумный' then
tableContent =
'{| cellspacing="0" cellpadding="0" style="margin:1em 0; padding:8px 13px; border:1px solid #afd2e9; background:#f1f7fb; line-height:1.4;"\n'
.. '|\n'
.. '{| cellspacing="0" cellpadding="0" class="sortable topicWatch-topicTable"' .. (fullTopicsToShow ~= 0 and ' id="topicTable' .. randomNum .. '"' or '') .. '\n'
.. '|-\n'
.. (talkpageMode and talkpageCount > 1 and '' or '! style="border-bottom:1px solid #afd2e9; padding:2px 1.5em 4px 0; text-align:right; font-weight:normal;" | № !')
.. '! style="border-bottom:1px solid #afd2e9; padding:2px 2em 4px 0; text-align:left; font-weight:normal;" | ' .. (talkpageMode and talkpageCount == 1 and '' or '<span style="visibility:hidden;">§ </span>') .. 'Тема '
.. '!! style="border-bottom:1px solid #afd2e9; padding:2px 2em 4px 0; text-align:left; font-weight:normal;" class="nowrap" | Последнее сообщение '
.. '!! style="border-bottom:1px solid #afd2e9; padding:2px 1.5em 4px 0; text-align:left; font-weight:normal;" | Сообщений\n'
.. '|-\n'
.. '| colspan="3" style="padding-top:6px;" |\n'
end
for k, v in pairs(topics) do
local labels = ( -- может быть предварительный после оспоренного, поэтому ярлык оспаривания раньше
v.challengedClosureHeading
and '<span style="display:inline-block; margin-left:1em; padding:0 8px; border-radius:5px; font-size:83.33%; line-height:1.5; letter-spacing:1px; background-color:' .. labelColors.challengedClosure .. '; color:#f9f9f9; white-space:nowrap;" title="В теме есть подраздел с названием «' .. v.challengedClosureHeading .. '»"' .. (afdMode and '' or ' class="topicWatch-label-challengedClosure"') .. '>ОСПОРЕНО</span>'
or ''
) .. (
v.preclosureHeading
and '<span style="display:inline-block; margin-left:1em; padding:0 8px; border-radius:5px; font-size:83.33%; line-height:1.5; letter-spacing:1px; background-color:' .. labelColors.preclosure .. '; color:#f9f9f9; white-space:nowrap;" title="В теме есть подраздел с названием «' .. v.preclosureHeading .. '»"' .. (afdMode and '' or ' class="topicWatch-label-preclosure"') .. '>ПРЕДЫТОГ</span>'
or ''
) .. (
v.partialClosureHeading
and '<span style="display:inline-block; margin-left:1em; padding:0 8px; border-radius:5px; font-size:83.33%; line-height:1.5; letter-spacing:1px; background-color:' .. labelColors.partialClosure .. '; color:#f9f9f9; white-space:nowrap;" title="В теме есть подподраздел с названием «' .. v.partialClosureHeading .. '»"' .. (afdMode and '' or ' class="topicWatch-label-partialClosure"') .. '>ЧАСТ. ИТОГ</span>'
or ''
) .. (
v.closureHeading
and '<span style="display:inline-block; margin-left:1em; padding:0 8px; border-radius:5px; font-size:83.33%; line-height:1.5; letter-spacing:1px; background-color:' .. labelColors.closure .. '; color:#f9f9f9; white-space:nowrap;" title="В теме есть подраздел с названием «' .. v.closureHeading .. '»"' .. (afdMode and '' or ' class="topicWatch-label-closure"') .. '>ИТОГ</span>'
or ''
)
local topicString, lastMsgString, msgCountString, authorCountString, numString
local topicAttrs, lastMsgAttrs, msgCountAttrs, authorCountAttrs, numAttrs
if style == 'wikitable' then
numString = v.num
topicString = conceal(v.canonicalPath, 'wikilink') .. '[[' .. (
k <= fullTopicsToShow
and (
talkpageMode and talkpageCount == 1
and v.sectionHeadingLink
or (
v.subsectionHeading
and v.subsectionHeading .. ' (' .. v.sectionHeadingLink .. ')'
or v.sectionHeadingLink
) .. ' ← ' .. v.pageTitle
)
or v.pageTitle .. (
v.subsectionHeading
and v.subsectionHeading .. ' (' .. v.sectionHeadingLink .. ')'
or v.sectionHeadingLink
)
) .. '|<span ' .. (k <= fullTopicsToShow and fullTopicsToShow ~= 0 and '' or 'title="Откроется на отдельной странице" ') .. (
talkpageMode and talkpageCount == 1
and 'style="display:block; font-size:110%;">'
or 'style="display:block;"><span style="visibility:hidden;">§ </span><small>' .. v.pageTitle .. '</small><br><span style="display:inline-block;">§ </span>'
) .. v.sectionHeading .. labels .. '</span>]]' -- TODO: учёт подраздела
lastMsgString = conceal(v.lastMsgDateTimestamp, 'lastMsgDate') .. (
k <= fullTopicsToShow
and '[[#' .. v.lastMsgAnchor .. '|<span style="display:block; text-decoration:inherit;">'
or '[[' .. v.pageTitle .. '#' .. v.lastMsgAnchor .. '|<span style="display:block; text-decoration:inherit;" class="topicWatch-outFragmentLink" title="' .. outFragmentLink_title .. '">'
) .. v.lastMsgDateString .. '<br>от ' .. v.lastMsgAuthor .. '</span>]]'
msgCountString = conceal(v.msgCount, 'msgCount') .. v.msgCount
authorCountString = conceal(#v.authors, 'authorCount') .. '<span style="border-bottom:1px dotted; cursor:help;" title="' .. table.concat(v.authors, ', ') .. '">' .. #v.authors .. '</span>'
numAttrs = 'style="text-align:center;"'
topicAttrs = ''
lastMsgAttrs = 'style="/* Chrome */ word-break:break-word; /* ? */ word-wrap:break-word;"'
msgCountAttrs = 'style="text-align:center;"'
authorCountAttrs = 'style="text-align:center;"'
elseif style == 'форумный' then
numString = talkpageMode and talkpageCount == 1
and '<span style="font-size:110%; visibility:hidden;">l</span>' .. v.num .. '<span style="font-size:110%; visibility:hidden;">l</span>' -- способ, рекомендуемый Горбуновым, чтобы строки были на одной линии
or v.num
topicString = conceal(v.canonicalPath, 'wikilink') .. '[[' .. v.pageTitle .. (
v.subsectionHeading
and v.subsectionHeading .. ' (' .. v.sectionHeadingLink .. ')'
or v.sectionHeadingLink
) .. '|' .. (
talkpageMode and talkpageCount == 1
and '<span style="display:block; font-size:110%;">'
or '<span style="display:block;"><span style="display:inline-block;"><span style="visibility:hidden;">§ </span><small>' .. mw.ustring.gsub(v.pageTitle, 'Тептар:Форум/', '') .. '</small></span><br><span style="display:inline-block;">§ </span>'
) .. v.sectionHeading .. labels .. '</span>]]'
lastMsgString = conceal(v.lastMsgDateTimestamp, 'lastMsgDate') .. (
k <= fullTopicsToShow
and '[[#' .. v.lastMsgAnchor .. '|<span style="display:block; text-decoration:inherit;">'
or '[[' .. v.pageTitle .. '#' .. v.lastMsgAnchor .. '|<span style="display:block; text-decoration:inherit;" class="topicWatch-outFragmentLink" title="' .. outFragmentLink_title .. '">'
) .. v.lastMsgDateString .. '<br>от ' .. v.lastMsgAuthor .. '</span>]]'
msgCountString = conceal(v.msgCount, 'msgCount') .. '<span style="border-bottom:1px dotted; cursor:help;" title="От ' .. #v.authors .. ' ' .. ru:plural(#v.authors , 'автора', 'авторов') .. ': ' .. table.concat(v.authors, ', ') .. '">' .. v.msgCount .. '</span>'
numAttrs = 'style="padding:3px 0; vertical-align:top; text-align:right; padding-right:8px;"'
topicAttrs = 'style="padding:3px 2em 3px 0; vertical-align:top;"'
lastMsgAttrs = 'style="padding:3px 0.5em 3px 0; vertical-align:top; /* Chrome */ word-break:break-word; /* ? */ word-wrap:break-word;"'
msgCountAttrs = 'style="padding:3px 0; vertical-align:top; text-align:center; vertical-align:top;"'
end
tableContent = tableContent
.. '|-' .. (style ~= 'форумный' and needHighlightOutLinks and k > fullTopicsToShow and ' style="background-color:#f2f2f2;"' or '') .. '\n'
.. (talkpageMode and talkpageCount > 1 and '' or '| ' .. numAttrs .. ' | ' .. numString .. '\n')
.. '| ' .. topicAttrs .. ' | ' .. topicString .. '\n'
.. '| ' .. lastMsgAttrs .. ' | ' .. lastMsgString .. '\n'
.. '| ' .. msgCountAttrs .. ' | ' .. msgCountString .. '\n'
.. (style == 'форумный' and '' or '| ' .. authorCountAttrs .. ' | ' .. authorCountString .. '\n')
end
tableContent = tableContent .. '|}\n'
if style == 'форумный' then
tableContent = tableContent .. '|}\n'
end
headerContent = headerContent .. tableContent
end
-- формируем сообщение(-я) об ошибке
if not items[1] then
if standardMode then
table.insert(errorInfo, 'В списке тем для отслеживания пока пусто.')
elseif talkpageMode or pageListMode then
table.insert(errorInfo, 'В списке страниц пусто.')
elseif afdMode then
table.insert(errorInfo, 'Не удалось найти темы.')
end
end
if errorInfo[1] then
headerContent = headerContent
.. '<div style="font-style:italic; margin:1em 0;">\n'
.. table.concat(errorInfo, '<br>')
.. '</div>\n'
end
local itemsToRemoveString
if itemsToRemove[1] then
itemsToRemoveString = '<ul style="display:none;" class="topicWatch-itemsToRemove">\n'
for k, v in pairs(itemsToRemove) do
itemsToRemoveString = itemsToRemoveString .. '<li>' .. v .. '</li>\n'
end
itemsToRemoveString = itemsToRemoveString .. '</ul>\n'
headerContent = headerContent .. itemsToRemoveString
end
-- формируем сами темы
local content = ''
if fullTopicsToShow ~= 0 then
headerContent = headerContent .. '__TOC__\n'
for k, v in pairs(fullTopics) do
if v.msgCount then
v.sectionContent = mw.ustring.gsub(v.sectionContent, v.lastMsgDateString .. ' %(UTC%)', '<cite id="' .. v.lastMsgAnchor:gsub('"', '"') .. '" style="font-style:normal;">%0</cite>')
end
content = content
.. killHeadingMarkers(frame:preprocess(v.sectionContent)) .. '\n'
.. '<div style="margin-top:1em;">' .. (topicsToShow ~= 0 and '[[#topicTable' .. randomNum .. '|↑ К списку тем]]' or '[[#toc|↑ К содержанию]]') .. '</div>\n'
if k == fullTopicsToShow then break end
end
end
content = headerContent .. content
return content
end
return p