local yesno = require('Module:Yesno')
local mMessageBox = require('Module:Message box')
local TEMPLATE_PAGE = 'Template:Old XfD multi'
-------------------------------------------------------------------------------
-- Helper functions
-------------------------------------------------------------------------------
local function exists(page)
local success, exists = pcall(function ()
local title = mw.title.new(page)
return title.exists
end)
return success and exists
end
local function getAfdPage(page)
if page and mw.title.new(page) then
if mw.title.new(page).namespace ~= 0 then
return page
else
return 'Wikipedia:Articles for deletion/' .. page
end
else return nil
end
end
local function getVfdPage(page)
if page and mw.title.new(page) then
if mw.title.new(page).rootPageTitle.fullText == 'Wikipedia:Votes for deletion' then
return page
else
return 'Wikipedia:Votes for deletion/' .. page
end
else return nil
end
end
local function makeWikilink(page, display)
display = display or 'discussion'
if page then
return string.format('[[%s|%s]]', page, display)
else
return display --probably a bad title
end
end
local function makeUrlLink(page, display)
display = display or 'discussion'
return string.format('[%s %s]', page, display)
end
local function pageTypeName(title)
local display = mw.ustring.lower(title.subjectNsText)
local pageTypes = {
[''] = 'article',
['user'] = 'user page',
['wikipedia'] = 'project page',
['mediawiki'] = 'interface page',
['help'] = 'help page'
}
if pageTypes[display] then display = pageTypes[display] end
return display
end
local function cleanupTitle(title)
if not title then return title end
title = mw.uri.decode(title, 'PATH')
title = string.gsub(title, '|.*', '')
title = string.gsub(title, '[%[%]{}]', '')
return title
end
local function venueFromPage(page)
local mainpage = string.lower(page)
mainpage = string.match(mainpage or '','wikipedia:.*')
mainpage = string.gsub(mainpage or '', '/.*','')
mainpage = string.gsub(mainpage or '', '_',' ')
if mainpage == "wikipedia:categories for discussion" then
return "CfD"
elseif mainpage == "wikipedia:templates for discussion" or mainpage == "wikipedia:templates for deletion" then
return "TfD"
elseif mainpage == "wikipedia:files for discussion" then
return "FfD"
elseif mainpage == "wikipedia:redirects for discussion" then
return "RfD"
elseif mainpage == "wikipedia:miscellany for deletion" then
return "MfD"
else
return "AfD"
end
end
local function getXfdVenue(rowData)
local venue = venueFromPage(rowData[1].page or rowData[1].link)
for index, row in ipairs(rowData) do
if venueFromPage(row.page or row.link) ~= venue then
return "XfD"
end
end
return venue
end
local function deletionOnlyVenue(venue, date)
local year = tonumber(string.match(date, "%d%d%d%d"))
local month = string.lower(string.match(date, "%a+"))
if venue == "MfD" or (venue == "AfD" and (year < 2026 or (year == 2026 and (month == 'january' or month == 'february' or month == 'march')))) then
return true
end
return false
end
-------------------------------------------------------------------------------
-- OldAfdMulti class
-------------------------------------------------------------------------------
local OldAfdMulti = {}
OldAfdMulti.__index = OldAfdMulti
function OldAfdMulti.new(args)
local self = setmetatable({}, OldAfdMulti)
self.currentTitle = mw.title.getCurrentTitle()
-- Preprocess the row args for easier looping.
self.rowData = {}
for k, v in pairs(args) do
if type(k) == 'string' then
local prefix, num = k:match('^(.-)([1-9][0-9]*)$')
if prefix and num then
num = tonumber(num)
if prefix == 'result' or
prefix == 'date' or
prefix == 'page' or
prefix == 'link' or
prefix == 'caption' or
prefix == 'votepage' or
prefix == 'merge' or
prefix == 'action'
then
self.rowData[num] = self.rowData[num] or {}
self.rowData[num][prefix] = v
if v and v ~= '' and prefix=='merge' then
self.isMerge = true
end
end
end
end
end
-- Set aliases for parameters ending in "1".
if self.rowData[1] then
self.rowData[1].result = self.rowData[1].result or args.result
self.rowData[1].date = self.rowData[1].date or args.date
self.rowData[1].page = self.rowData[1].page or args.page
self.rowData[1].votepage = self.rowData[1].votepage or args.votepage
self.rowData[1].link = self.rowData[1].link or args.link
self.rowData[1].caption = self.rowData[1].caption or args.caption
self.rowData[1].merge = self.rowData[1].merge or args.merge
self.rowData[1].action = self.rowData[1].action or args.action
elseif args.result or
args.date or
args.page or
args.votepage or
args.link or
args.caption or
args.merge or
args.action
then
self.rowData[1] = {
result = args.result,
date = args.date,
page = args.page,
votepage = args.votepage,
link = args.link,
caption = args.caption,
merge = args.merge,
action = args.action
}
end
-- Remove any gaps in the array we made.
local function compressSparseArray(t)
local ret, nums = {}, {}
for num, data in pairs(t) do
nums[#nums + 1] = num
end
table.sort(nums)
for i, num in ipairs(nums) do
ret[i] = t[num]
end
return ret
end
self.rowData = compressSparseArray(self.rowData)
-- Set aliases that apply to all of the data tables.
for i, data in ipairs(self.rowData) do
data.page = data.page or data.votepage
data.page = cleanupTitle(data.page)
data.votepage = nil
end
-- Set collapsedness
self.collapse = tonumber(args.collapse)
if not self.collapse then
self.collapse = yesno(args.collapse)
end
-- Set other properties
self.isNumbered = yesno(args.numbered)
self.isSmall = yesno(args.small)
self.pageType = args.type or pageTypeName(self.currentTitle)
if args.merge and args.merge ~= '' then
self.isMerge = true
end
if args.action and args.action ~= '' and (args.deletion == '' or (not args.deletion)) then
if #self.rowData > 1 then
self.deletion = 'discussion'
else
self.deletion = args.action
end
else
self.deletion = args.deletion
end
return self
end
function OldAfdMulti:renderResult(result)
return result or "'''Keep'''"
end
function OldAfdMulti:renderDate(date)
if date then
return date
else
self.hasMissingDate = true
return string.format(
'<sup>%s[[%s|date missing]]%s</sup>',
mw.text.nowiki('['),
TEMPLATE_PAGE,
mw.text.nowiki(']')
)
end
end
function OldAfdMulti:renderPageText(linkFunc, page, caption)
return string.format(', see %s.', linkFunc(page, caption))
end
function OldAfdMulti:renderRow(result, date, link, merge, action)
local result = self:renderResult(result)
local date = self:renderDate(date)
local mergeText = ''
local actionText = ''
if merge and merge ~= '' then
mergeText = string.format('Merge into [[:%s]]: ', merge)
end
if action and action ~= '' and mergeText == '' then
actionText = string.format('Nominated for %s, result: ', action)
end
if link then
return string.format('%s%s%s, %s, see %s.', actionText, mergeText, result, date, link)
else
return string.format('%s%s%s, %s', actionText, mergeText, result, date)
end
end
function OldAfdMulti:renderFirstRow(data)
local link
if data.link then
link = makeUrlLink(data.link, data.caption)
else
local page = data.page or self.currentTitle.text
link = makeWikilink(getAfdPage(page), data.caption)
end
return self:renderRow(data.result, data.date, link, data.merge, data.action)
end
function OldAfdMulti:renderSubsequentRow(data)
local link
if data.page then
link = makeWikilink(getAfdPage(data.page), data.caption)
elseif data.link then
link = makeUrlLink(data.link, data.caption)
end
return self:renderRow(data.result, data.date, link, data.merge, data.action)
end
function OldAfdMulti:renderRows()
local root = mw.html.create()
local nRows = #self.rowData
local i = nRows
local nCollapsedRows
if type(self.collapse) == 'number' then
nCollapsedRows = self.collapse
elseif self.collapse then
nCollapsedRows = nRows
else
nCollapsedRows = 0
end
local hasNormalRows = nRows - nCollapsedRows > 0
local function makeList(isCollapsed, header)
local tableRoot = root:tag('table')
tableRoot
:addClass(isCollapsed and 'mw-collapsible mw-collapsed' or nil)
:css('width', '100%')
if header then
tableRoot
:tag('tr')
:tag('th')
:wikitext(header)
end
return tableRoot
:tag('tr')
:tag('td')
:tag(self.isNumbered and 'ol' or 'ul')
end
local function renderRow(html, method, data)
html
:tag('li')
:attr('value', self.isNumbered and i or nil)
:wikitext(self[method](self, data))
end
-- Render normal rows
if hasNormalRows then
local normalList = makeList(false)
while i > 1 and i > nCollapsedRows do
renderRow(normalList, 'renderSubsequentRow', self.rowData[i])
i = i - 1
end
if i == 1 and i > nCollapsedRows then
renderRow(normalList, 'renderFirstRow', self.rowData[i])
i = i - 1
end
end
-- Render collapsed rows
if nCollapsedRows > 0 then
local header
if hasNormalRows then
header = 'Older deletion discussions:'
elseif nRows > 1 then
header = 'Deletion discussions:'
else
header = 'Deletion discussion:'
end
local collapsedList = makeList(true, header)
while i > 1 do
renderRow(collapsedList, 'renderSubsequentRow', self.rowData[i])
i = i - 1
end
renderRow(collapsedList, 'renderFirstRow', self.rowData[i])
end
return tostring(root)
end
function OldAfdMulti:renderFirstRowOnly()
local data = self.rowData[1] or {}
local caption = data.caption or "the discussion"
local bold = "'''"
local link
if data.link then
link = makeUrlLink(data.link, caption)
else
local page = data.page or self.currentTitle.text
if exists(getAfdPage(page)) then
link = bold .. makeWikilink(getAfdPage(page), caption) .. bold
elseif exists(getVfdPage(page)) then
link = bold .. makeWikilink(getVfdPage(page), caption) .. bold
else
link = caption -- Make this an error?
end
end
local result = self:renderResult(data.result or "'''keep'''")
return string.format(
'The result of %s was %s.',
link, result
)
end
function OldAfdMulti:renderBannerText()
local nRows = #self.rowData
local ret = {}
local venue = getXfdVenue(self.rowData)
if self.isMerge then
if nRows < 1 or not self.rowData[1].date then
ret[#ret + 1] = string.format(
'This %s was nominated for [[Wikipedia:Merging|merging]] into %s.',
self.pageType,
self.rowData[1].merge
)
elseif nRows == 1 and self.rowData[1].date then
ret[#ret + 1] = string.format(
'This %s was nominated for [[Wikipedia:Merging#Merging|merging]] into [[:%s]] on %s.',
self.pageType,
self.rowData[1].merge,
self.rowData[1].date
)
else
ret[#ret + 1] = string.format(
'This %s was nominated at [[WP:' .. venue .. '|'..venue..']].',
self.pageType
)
end
elseif self.deletion then
if nRows < 1 or not self.rowData[1].date then
ret[#ret + 1] = string.format(
'This %s was previously nominated for %s.',
self.pageType,
self.deletion
)
elseif nRows == 1 and self.rowData[1].date then
ret[#ret + 1] = string.format(
'This %s was nominated for %s on %s.',
self.pageType,
self.deletion,
self.rowData[1].date
)
else
ret[#ret + 1] = string.format(
'This %s was nominated for %s.',
self.pageType,
self.deletion
)
end
else
if nRows < 1 or not self.rowData[1].date then
ret[#ret + 1] = string.format(
'This %s was previously nominated at [[WP:'..venue..'|'..venue..']].',
self.pageType
)
elseif nRows == 1 and self.rowData[1].date then
local venueString = 'at [[WP:'..venue..'|'..venue..']]'
if deletionOnlyVenue(venue, self.rowData[1].date) then
venueString = 'for [[WP:Deletion policy|deletion]]'
end
ret[#ret + 1] = string.format(
'This %s was nominated %s on %s.',
self.pageType,
venueString,
self.rowData[1].date
)
else
ret[#ret + 1] = string.format(
'This %s was nominated at [[WP:'..venue..'|'..venue..']].',
self.pageType
)
end
end
if nRows > 1 then
ret[#ret + 1] = ' '
if self.isSmall then
ret[#ret + 1] = 'Review prior discussions if considering re-nomination:'
else
ret[#ret + 1] = 'Please review the prior discussions if you are considering re-nomination:'
end
ret[#ret + 1] = '\n'
ret[#ret + 1] = self:renderRows()
else
ret[#ret + 1] = ' '
ret[#ret + 1] = self:renderFirstRowOnly()
end
return table.concat(ret)
end
function OldAfdMulti:renderBanner()
return mMessageBox.main('tmbox', {
small = self.isSmall,
type = 'notice',
image = '[[File:Clipboard.svg|35px|Articles for deletion]]',
smallimage = 'none',
text = self:renderBannerText()
})
end
function OldAfdMulti:renderTrackingCategories()
local ret = {}
if self.hasMissingDate and self.currentTitle.isTalkPage then
ret[#ret + 1] = '[[Category:Old XfD multi templates with errors]]'
end
return table.concat(ret)
end
function OldAfdMulti:__tostring()
return self:renderBanner() .. self:renderTrackingCategories()
end
-------------------------------------------------------------------------------
-- Exports
-------------------------------------------------------------------------------
local p = {}
function p._main(args)
local afd = OldAfdMulti.new(args)
return tostring(afd)
end
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {
wrappers = TEMPLATE_PAGE
})
return p._main(args)
end
return p