Edge Rewrite
// HTMLRewriter · presentation

This page was redesigned at the edge.

Cloudflare fetched the original article and streamed it through HTMLRewriter to apply an entirely new visual system without rebuilding the source page.

Jump to content

Module:Old XfD multi/sandbox

From Wikipedia, the free encyclopedia
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