Module:Article history/config: Difference between revisions

Content deleted Content added
add id fields for tables that can have aliases
Update featured portal wording per request
 
(146 intermediate revisions by 17 users not shown)
Line 2:
-- Configuration data for [[Module:Article history]]
-------------------------------------------------------------------------------
 
local lang = mw.language.getContentLanguage()
local Category = require('Module:Article history/Category')
 
-------------------------------------------------------------------------------
-- Helper functions
-------------------------------------------------------------------------------
 
-- Makes a link to a template page surrounded by double curly braces. A
-- workalike for the {{tl}} template.
local function makeTemplateLink(s)
local openb = mw.text.nowiki('{{')
local closeb = mw.text.nowiki('}}')
return string.format('%s[[Template:%s|%s]]%s', openb, s, s, closeb)
end
 
-- Gets the Good Article topic for the given key. Uses
-- [[Module:Good article topics]].
local function getGoodArticleTopic(key)
if not key then
return nil
end
return require('Module:Good article topics')._main(key)
end
 
-- Returns the Good Article page link and display value for a given Good Article
-- key. If the key wasn't valid, the default Good Article page and display value
-- is returned instead.
local function getGoodArticleTopicLink(key)
local topic = getGoodArticleTopic(key)
local link, display
if topic then
link = 'Wikipedia:Good articles/' .. topic
display = topic .. ' good articles'
else
link = 'Wikipedia:Good articles'
display = 'good articles'
end
return link, display
end
 
-- Wrapper function for mw.language:formatDate, going through pcall to catch
-- invalid input errors.
local function getDate(format, date)
local success, result = pcall(lang.formatDate, lang, format, date)
if success then
return result
end
end
 
-- Gets the date in the format YYYYMMDD, as a number. Months and dates are
-- zero-padded. Results from this function are intended to be used in date
-- calculations.
local function getYmdDate(date)
date = getDate('Ymd', date)
if date then
return tonumber(date)
else
return nil
end
end
 
-- Gets the date in the format Month d, YYYY.
local function getLongDate(date)
return getDate('F j, Y', date)
end
 
-- Returns true if the given page is an existing title, and false or nil
-- otherwise
local function titleExists(page)
local success, title = pcall(mw.title.new, page)
return success and title.exists
end
 
-- Returns a truthy value if a date parameter for the given prefix has been
-- provided by the user.
local function isActiveDatedObject(articleHistoryObj, prefix)
local args = articleHistoryObj.args
local prefixArgs = articleHistoryObj.prefixArgs
return args[prefix .. 'date'] or prefixArgs[prefix]
end
 
-- Returns a date as formatted by getLongDate. If the date is invalid, it raises
-- an error using param as the parameter name containing the invalid date.
local function validateDate(param, date, articleHistoryObj)
local longDate = getLongDate(date)
if longDate then
return longDate
else
articleHistoryObj:raiseError(
string.format(
"invalid date '%s' detected in parameter '%s'",
tostring(date),
param
),
'Template:Article history#Invalid date'
)
end
end
 
-- Generates a data table for a date-related notice such as DYK and ITN. prefix
-- is the parameter prefix for that notice type (e.g. "dyk"), and suffixes is
-- an array of parameter suffixes in addition to "date" that is used by that
-- notice type (e.g. "entry" for the "dykentry" and "dyk2entry" parameters).
local function makeDateData(articleHistoryObj, prefix, suffixes)
local args = articleHistoryObj.args
local prefixArgs = articleHistoryObj.prefixArgs
 
-- Sanity checks
if prefixArgs[prefix] then
for _, t in ipairs(prefixArgs[prefix]) do
if not t.date then
articleHistoryObj:raiseError(
string.format(
"an argument starting with '%s%d' was detected, " ..
"but no '%s%ddate' parameter was specified",
prefix, t[1],
prefix, t[1]
),
'Template:Article history#No date parameter'
)
end
end
end
 
local data = {}
 
-- Organise the input
local function addData(sep)
local t = {}
local argPrefix = prefix .. sep
do
local key = argPrefix .. 'date'
t.date = validateDate(key, args[key], articleHistoryObj)
t.month, t.day, t.year = t.date:match('(%a+) (%d+), (%d+)')
t.day = tonumber(t.day)
t.year = tonumber(t.year)
t.ymdDate = getYmdDate(t.date)
end
for _, suffix in ipairs(suffixes) do
local key = argPrefix .. suffix
t[suffix] = args[key]
end
t.argPrefix = argPrefix
data[#data + 1] = t
end
if args[prefix .. 'date'] then
addData('')
end
if prefixArgs[prefix] then
for _, prefixData in ipairs(prefixArgs[prefix]) do
addData(tostring(prefixData[1]))
end
end
if #data < 1 then
error(string.format(
"no data items found for prefix '%s' and parameter checks failed'",
tostring(prefix)
))
end
 
return data
end
 
-- This makes the text for Main Page features such as DYKs and ITNs for the
-- dates contained in dateData (made with the makeDateData function).
-- The parameter $1 in the blurb will be replaced with the list of dates.
local function makeDateText(dateData, blurb, wantBold)
local bold = wantBold and "'''" or ""
local dates, doneLinks = {}, {}
for i, t in ipairs(dateData) do
local date
if t.link and not doneLinks[t.link] then
date = string.format('[[%s|%s]]', t.link, t.date)
doneLinks[t.link] = true
else
date = t.date
end
dates[i] = bold .. date .. bold
end
local dateList = mw.text.listToText(dates, ', ', ', and ')
return mw.message.newRawMessage(blurb, dateList):plain()
end
 
return {
 
-------------------------------------------------------------------------------
-- CONFIG TABLE START
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
-- Statuses
-- Configuration for possible current statuses of the article.
-------------------------------------------------------------------------------
 
-- The statuses table contain configuration tables for possible current statuses
-- of the article.
-- Each table can have the following fields:
--
-- id: the main ID for the status. This should be the same as the configuration
-- table key.
-- aliases: a table of ID aliases that can be used to access the config table.
-- icon: The status icon.
-- iconSize: The icon size, including "px" suffix. The default is defined in
-- defaultStatusIconSize.
-- iconMultiSize: The icon size if we are outputting multiple status rows. The
-- default is defaultMultiStatusIconSize.
-- text: The status text. This may be a string or a function. If it is a
-- function, it takes an article history object as input, and should return
-- the text string. If it is a string, it can have the following parameters:
-- $1 - The full page name of the article or subject page
-- $2 - The page name without the namespace name
-- categories: The categories set by the status. This may be an array of
-- category names, or a function. If it is a function, it takes an article
-- history object as the first parameter, and the current status object as
-- the second parameter, and should return an array of category objects.
-- noticeBarIcon: the icon to use for the notice bar. This can be a string, or
-- a function, or true. If it is a function it takes an article history
-- object as the first parameter, and should output the icon filename. If it
-- is true, it uses the value of icon. If it is nil then no notice bar icon
-- will be displayed.
-- noticeBarIconCaption: the caption to use for the notice bar icon. The status
-- name is used by default. This can be a string or a function. If it is a
-- function, it takes an article history object as its first parameter, and
-- should return the caption text. If this is absent, the icon caption is
-- used instead.
-- noticeBarIconSize: the size of the notice bar icon, including "px" suffix.
-- The default is set by defaultNoticeBarIconSize.
 
statuses = {
FA = {
id = 'FA',
name = 'Featured article',
icon = 'Featured article star.svg',
text = function (articleHistoryObj)
local articlePage = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
local actions = articleHistoryObj:getActionObjects()
local link
for i = #actions, 1, -1 do
local actionObj = actions[i]
if actionObj.id == 'FAC' then
link = actionObj.link
break
end
end
link = link or 'Wikipedia:Featured article candidates/' .. articlePage
local text = "'''%s''' is a [[Wikipedia:Featured articles|featured article]]; " ..
"it (or a previous version of it) has been '''[[%s|identified]]''' " ..
"as one of the best articles produced by the [[Wikipedia:Wikipedians|Wikipedia community]]. " ..
"Even so, if you can update or improve it, [[Wikipedia:Be bold|please do so]]."
return string.format(text, articlePage, link)
end,
categories = {'Wikipedia featured articles'}
},
FFA = {
id = 'FFA',
name = 'Former featured article',
icon = 'Featured article star - cross.svg',
iconSize = '48px',
text = "'''$1''' is a [[Wikipedia:Former featured articles|former featured article]]. " ..
"Please see the links under Article milestones below for its original nomination page " ..
"(for older articles, check [[Wikipedia:Featured article candidates/Archived nominations/Index|the nomination archive]]) " ..
"and why it was removed.",
categories = {'Wikipedia former featured articles'}
},
FFAC = {
id = 'FFAC',
name = 'Former featured article candidate',
aliases = {'FACFAILED'},
icon = 'Cscr-former.svg',
text = "'''$1''' is a former [[Wikipedia:Featured article candidates|featured article candidate]]. " ..
"Please view the links under Article milestones below to see why " ..
"the nomination was archived. For older candidates, please check the " ..
"[[Wikipedia:Featured article candidates/Archived nominations/Index|archive]]."
},
FL = {
id = 'FL',
name = 'Featured list',
icon = 'Featured article star.svg',
iconSize = '48px',
text = function (articleHistoryObj)
local articlePage = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
local actions = articleHistoryObj:getActionObjects()
local link
for i = #actions, 1, -1 do
local actionObj = actions[i]
if actionObj.id == 'FLC' then
link = actionObj.link
break
end
end
link = link or 'Wikipedia:Featured list candidates/' .. articlePage
local text = "'''%s''' is a [[Wikipedia:Featured lists|featured list]], " ..
"which means it has been '''[[%s|identified]]''' as one of the best " ..
"[[Wikipedia:Stand-alone lists|lists]] produced by the [[Wikipedia:Wikipedians|Wikipedia community]]. " ..
"If you can update or improve it, [[Wikipedia:Be bold|please do so]]."
return string.format(text, articlePage, link)
end,
categories = {'Wikipedia featured lists'}
},
FFL = {
id = 'FFL',
name = 'Former featured list',
icon = 'Cscr-featured-strike.svg',
text = "'''$1''' is a [[Wikipedia:Former featured lists|former featured list]]. " ..
"Please see the links under Article milestones below for its original " ..
"nomination page and why it was removed. If it has improved again to " ..
"[[Wikipedia:Featured list criteria|featured list standard]], you may " ..
"[[Wikipedia:Featured list candidates|renominate]] the article to " ..
"become a [[Wikipedia:Featured lists|featured list]]."
},
FFLC = {
id = 'FFLC',
name = 'Former featured list candidate',
icon = 'Cscr-former.svg',
iconCaption = 'Former FLC',
text = "'''$1''' is a former [[Wikipedia:Featured list candidates|featured list candidate]]. " ..
"Please view the link under Article milestones below to see why the nomination was archived. " ..
"Once the objections have been addressed you may " ..
"[[Wikipedia:Featured list candidates#Resubmitting nominations|resubmit]] " ..
"the article for featured list status.",
categories = {'Wikipedia featured list candidates (contested)'}
},
['FFA/GA'] = {
id = 'FFA/GA',
name = 'Former featured article, current good article',
isMulti = true,
statuses = {'FFA', 'GA'}
},
['FFAC/GA'] = {
id = 'FFAC/GA',
name = 'Former featured article candidate, current good article',
isMulti = true,
statuses = {'FFAC', 'GA'}
},
GA = {
id = 'GA',
name = 'Good article',
icon = 'Symbol support vote.svg',
iconSize = '40px',
iconMultiSize = '25px',
text = function (articleHistoryObj)
local link, display = getGoodArticleTopicLink(articleHistoryObj.args.topic)
local articlePage = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
local text = "'''%s''' has been listed as one of the '''''[[%s|%s]]''''' " ..
"under the [[Wikipedia:Good article criteria|good article criteria]]. " ..
"If you can improve it further, [[Wikipedia:Be bold|please do so]]. " ..
"<small>''If it no longer meets these criteria, you can " ..
"'''[[Wikipedia:Good article reassessment|reassess]]''' it''.</small>"
return string.format(text, articlePage, link, display)
end,
categories = function (articleHistoryObj)
local ret = {}
local title = articleHistoryObj.currentTitle
if title.namespace == 1 then
ret[#ret + 1] = Category.new('Wikipedia good articles')
local topic = getGoodArticleTopic(articleHistoryObj.args.topic)
if topic then
ret[#ret + 1] = Category.new(
topic .. ' good articles',
title.text
)
else
ret[#ret + 1] = Category.new(
'Good articles without topic parameter',
title.text
)
end
end
return ret
end
},
FGAN = {
id = 'FGAN',
name = 'Former good article nominee',
aliases = {'FAILEDGA'},
icon = 'Symbol oppose vote.svg',
text = function (articleHistoryObj)
local articlePage = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
local link, display = getGoodArticleTopicLink(articleHistoryObj.args.topic)
local text = "'''%s''' was a '''''[[%s|%s]]''''' nominee, " ..
"but did not meet the [[Wikipedia:Good article criteria|good article criteria]] " ..
"at the time. There may be suggestions below for improving the article. " ..
"Once these issues have been addressed, the article can be " ..
"[[Wikipedia:Good article nominations|renominated]]. " ..
"Editors may also seek a '''[[Wikipedia:Good article reassessment|reassessment]]''' " ..
"of the decision if they believe there was a mistake."
return string.format(text, articlePage, link, display)
end,
categories = {'Former good article nominees'}
},
DGA = {
id = 'DGA',
name = 'Delisted good article',
aliases = {'DELISTEDGA'},
icon = 'Symbol unsupport vote.svg',
iconCaption = 'Former good article',
text = function (articleHistoryObj)
local articlePage = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
local link, display = getGoodArticleTopicLink(articleHistoryObj.args.topic)
local text = "'''%s''' was one of the '''''[[%s|%s]]''''', " ..
"but it has been removed from the list. " ..
"There are suggestions below for improving the article to meet the " ..
"[[Wikipedia:Good article criteria|good article criteria]]. " ..
"Once these issues have been addressed, the article can be " ..
"[[Wikipedia:Good article nominations|renominated]]. " ..
"Editors may also seek a '''[[Wikipedia:Good article reassessment|reassessment]]''' " ..
"of the decision if they believe there was a mistake."
return string.format(text, articlePage, link, display)
end,
categories = {'Delisted good articles'}
},
FFT = {
id = 'FFT',
name = 'Part of former featured topic',
icon = 'Cscr-featured-strike.svg',
iconCaption = 'Former featured topic',
text = "This article is part of a " ..
"''[[Wikipedia:Former featured topics|former featured topic]]'' series. " ..
"If it has improved again to " ..
"[[Wikipedia:Featured topic criteria|featured topic standard]], " ..
"you may [[Wikipedia:Featured topic candidates|renominate]] " ..
"the topic to become a [[Wikipedia:Featured topic|featured topic]]."
},
FFTC = {
id = 'FFTC',
name = 'Former featured topic candidate',
icon = 'Cscr-former.svg',
text = "This article is part of a ''former'' " ..
"[[Wikipedia:Featured topic candidates|featured topic candidate]]. " ..
"Please view the links under Article milestones below to see why " ..
"the nomination was archived."
},
FPO = {
id = 'FPO',
name = 'Featured portal',
icon = 'Linecons big-star.svg',
text = "This portal was '''[[Wikipedia:Featured portal candidates/Portal:$2|identified]]''' " ..
"as a [[Wikipedia:Featured portals|featured portal]] " ..
"before the [[Wikipedia:Village pump (proposals)/Archive 138#RfC " ..
'about marking the Featured portals process as "historical"|process ended in 2017]].',
categories = function (articleHistoryObj)
return {Category.new(
'Wikipedia featured portals',
articleHistoryObj.currentTitle.text
)}
end
},
FFPO = {
id = 'FFPO',
name = 'Former featured portal',
icon = 'Featured article star - cross.svg',
text = "This portal is a [[Wikipedia:Former featured portals|former featured portal]]. " ..
"Please see the links under Portal milestones below for its " ..
"original nomination page and why it was removed.",
categories = function (articleHistoryObj)
return {Category.new(
'Wikipedia former featured portals',
articleHistoryObj.currentTitle.text
)}
end
},
FFPOC = {
id = 'FFPOC',
name = 'Former featured portal candidate',
icon = 'Cscr-former.svg',
text = "This portal is a '''''former''''' " ..
"[[Wikipedia:Featured portal candidates|featured portal candidate]]. " ..
"Please see the links under Portal milestones below for its " ..
"original nomination page and why the nomination failed."
},
PR = {
-- Peer review is a valid current status, but it doesn't trigger a
-- header row.
id = 'PR',
name = 'Peer reviewed',
noticeBarIcon = 'Nuvola apps kedit.svg'
},
NA = {
-- A valid current status, but doesn't trigger a header row.
id = 'NA',
noticeBarIcon = 'Nuvola apps kedit.svg'
},
-- The following are invalid statuses.
FAC = {
id = 'FAC',
text = function (articleHistoryObj)
articleHistoryObj:raiseError(
string.format(
'use the template %s to nominate an article for Featured article status',
makeTemplateLink('fac')
),
'Template:Article history#Featured article candidates'
)
end
},
FAR = {
id = 'FAR',
text = function (articleHistoryObj)
articleHistoryObj:raiseError(
string.format(
'use the template %s to nominate an article for Featured article review',
makeTemplateLink('FAR')
),
'Template:Article history#Featured article review'
)
end
},
STUB = {
id = 'STUB',
aliases = {'START', 'B', 'A'},
text = function (articleHistoryObj)
local currentStatusParam = articleHistoryObj.cfg.currentStatusParam
articleHistoryObj:raiseError(
string.format(
"do not use '%s' as value of the '%s' parameter; these " ..
'assessments are the responsibility of individual ' ..
'WikiProjects',
articleHistoryObj.args[currentStatusParam],
currentStatusParam
),
'Template:Article history#WikiProject assessments'
)
end
},
},
 
-- This function allows the generation of custom status ID. It takes an
-- articleHistory object as the first parameter, and should output the status
-- ID.
getStatusIdFunction = function (articleHistoryObj)
-- Get the status ID. The status code is the code passed in from the
-- arguments, and the ID is the value contained in the config.
local statusCode = articleHistoryObj.args[articleHistoryObj.cfg.currentStatusParam]
local statusId = articleHistoryObj:getStatusIdForCode(statusCode)
 
-- Check for former featured articles.
if statusId ~= 'FA'
and statusId ~= 'FL'
and statusId ~= 'FFA'
and statusId ~= 'FFL'
and statusId ~= 'FFA/GA'
then
local ffaObj
local actions = articleHistoryObj:getActionObjects()
for i = #actions, 1, -1 do
local actionObj = actions[i]
if actionObj.id == 'FAR' and actionObj.resultId == 'demoted' then
ffaObj = actionObj
break
end
end
if ffaObj then
if not statusId then
articleHistoryObj:raiseError(
'former featured articles should have a current status',
'Template:Article history#Former featured articles'
)
elseif statusId == 'GA' then
statusId = 'FFA/GA'
elseif statusId == 'DGA' then
statusId = 'FFA'
else
articleHistoryObj:raiseError(
string.format(
"'%s' is not a valid current status for former featured articles",
tostring(statusCode)
),
'Template:Article history#Former featured articles'
)
end
end
end
 
return statusId
end,
 
-------------------------------------------------------------------------------
-- Notices
-------------------------------------------------------------------------------
 
-- The notices table contains configuration tables for notices about the article
-- that are unrelated to its current status.
-- Each configuration table can have the following fields:
--
-- id: the main ID for the notice. This should be the same as the configuration
-- table key.
-- isActive: a function that should return a truthy value if the notice should
-- be displayed, and a falsy value if not. (Falsy values are false and nil,
-- and truthy values are everything else.) The function takes an article
-- history object as its first parameter.
-- makeData: a function that should return a table of data to be used by other
-- functions in this notice configuration table. It can be accessed using
-- noticeObj:getData().
-- icon: the filename of the notice icon, minus the "File:" prefix.
-- iconCaption: the icon caption.
-- iconSize: The icon size, including "px" suffix. The default is defined in
-- defaultIconSize.
-- text: The notice text. This may be a string or a function. If it is a
-- function, it takes an article history object as the first parameter, and
-- the current notice object as the second parameter, and should return the
-- text string.
-- categories: The categories set by the notice. This may be an array of
-- category names, or a function. If it is a function, it takes an article
-- history object as the first parameter, and the current notice object as
-- the second parameter, and should return an array of category objects.
-- noticeBarIcon: the icon to use for the notice bar. This can be a string, or
-- a function, or true. If it is a function it takes an article history
-- object as the first parameter, and should output the icon filename. If it
-- is true, it uses the value of icon. If it is nil then no notice bar icon
-- will be displayed.
-- noticeBarIconCaption: the caption to use for the notice bar icon. This can be
-- a string or a function. If it is a function, it takes an article history
-- object as its first parameter, and should return the caption text. If this
-- is absent, the icon caption is used instead.
-- noticeBarIconSize: the size of the notice bar icon, including "px" suffix.
-- The default is set by defaultNoticeBarIconSize.
 
notices = {
{
id = 'FT',
isActive = function (articleHistoryObj)
local args = articleHistoryObj.args
local prefixArgs = articleHistoryObj.prefixArgs
-- ftmain is included here because it leads to better error
-- messages than leaving it out, even though ftmain by itself is
-- invalid.
return args.ftname or args.ftmain or prefixArgs.ft
end,
makeData = function (articleHistoryObj)
local args = articleHistoryObj.args
local prefixArgs = articleHistoryObj.prefixArgs
local data = {}
local getTopicStatus = require('Module:FeaturedTopicSum').status
local yesno = require('Module:Yesno')
 
local function makeTopicData(name, isMain, paramNum)
if name then
return {
name = name,
isMain = yesno(isMain) or false,
status = getTopicStatus(name),
paramNum = paramNum
}
elseif isMain then
local num = paramNum and tostring(paramNum) or ''
articleHistoryObj:raiseError(
string.format(
"parameter 'ft%smain' is set, but no featured " ..
"topic name is set in parameter 'ft%sname'",
num, num
),
'Template:Article history#Featured topic names'
)
else
return nil
end
end
data[#data + 1] = makeTopicData(args.ftname, args.ftmain)
if prefixArgs.ft then
for _, t in ipairs(prefixArgs.ft) do
if t[1] > 1 then -- we use args.ftname instead of args.ft1name
data[#data + 1] = makeTopicData(t.name, t.main, t[1])
end
end
end
 
-- Check for rogue ft.. parameters
if #data < 1 then
articleHistoryObj:raiseError(
"a parameter starting with 'ft' was detected, but no " ..
"featured topic names were specified; " ..
"please check the parameter names",
'Template:Article history#Featured topic names'
)
end
 
-- Find if one of the topics is featured.
local isInFeaturedTopic = false
for _, topic in ipairs(data) do
if topic.status == 'FT' then
isInFeaturedTopic = true
break
end
end
data.isInFeaturedTopic = isInFeaturedTopic
 
return data
end,
icon = function (articleHistoryObj, noticeObj)
local data = noticeObj:getData(articleHistoryObj)
if not data then
return nil
end
if data.isInFeaturedTopic then
return 'Cscr-featuredtopic.svg'
else
return 'Support cluster.svg'
end
end,
iconCaption = function (articleHistoryObj, noticeObj)
local data = noticeObj:getData(articleHistoryObj)
if not data then
return nil
end
if data.isInFeaturedTopic then
return 'Featured topic star'
else
return 'Good topic star'
end
end,
iconSize = '48px',
text = function (articleHistoryObj, noticeObj)
local data = noticeObj:getData(articleHistoryObj)
if not data then
return nil
end
local article = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
 
local firstBlurb = "'''%s''' is %s the '''[[Wikipedia:Featured topics/%s|%s]] series''', %s."
local otherBlurb = "It is also %s the '''[[Wikipedia:Featured topics/%s|%s]] series''', %s."
local finalBlurb = "%s identified as among the best series of " ..
"articles produced by the [[Wikipedia:Wikipedians|Wikipedia community]]. " ..
"If you can update or improve %s, [[Wikipedia:Be bold|please do so]]."
local main = 'the main article in'
local notMain = 'part of'
local featuredLink = 'a [[Wikipedia:Featured topics|featured topic]]'
local featuredNoLink = 'a featured topic'
local goodLink = 'a [[Wikipedia:Good topics|good topic]]'
local goodNoLink = 'a good topic'
local thisSingular = 'This is'
local thisPlural = 'These are'
local itSingular = 'it'
local itPlural = 'them'
 
local hasFeaturedLink = false
local hasGoodLink = false
local text = {}
 
-- First topic
do
local topic = data[1]
local link
if topic.status == 'FT' then
link = featuredLink
hasFeaturedLink = true
else
link = goodLink
hasGoodLink = true
end
text[#text + 1] = string.format(
firstBlurb,
article,
topic.isMain and main or notMain,
topic.name,
topic.name,
link
)
end
 
-- Other topics
for i = 2, #data do
local topic = data[i]
local link
if topic.status == 'FT' then
if hasFeaturedLink then
link = featuredNoLink
else
link = featuredLink
hasFeaturedLink = true
end
else
if hasGoodLink then
link = goodNoLink
else
link = goodLink
hasGoodLink = true
end
end
text[#text + 1] = string.format(
otherBlurb,
topic.isMain and main or notMain,
topic.name,
topic.name,
link
)
end
 
-- Final blurb
do
local isPlural = #data > 1
text[#text + 1] = string.format(
finalBlurb,
isPlural and thisPlural or thisSingular,
isPlural and itPlural or itSingular
)
end
 
return table.concat(text, ' ')
end,
categories = function (articleHistoryObj, noticeObj)
local data = noticeObj:getData(articleHistoryObj)
if not data then
return nil
end
local status = articleHistoryObj:getStatusId()
local article = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
local cats = {}
 
local function addCat(cat, sort)
cats[#cats + 1] = Category.new(cat, sort)
end
 
-- Page-wide status categories
if status == 'FA' then
addCat('FA-Class Featured topics articles')
elseif status == 'FL' then
addCat('FL-Class Featured topics articles')
elseif status == 'FFA/GA' or status == 'FFAC/GA' or status == 'GA' then
addCat('GA-Class Featured topics articles')
else
addCat('Unassessed Featured topics articles')
end
 
-- Topic-specific status categories
local function addTopicCats(catFormat)
for _, topic in ipairs(data) do
addCat(string.format(catFormat, topic.name))
end
end
if status == 'FA' or status == 'FL' then
addTopicCats('Wikipedia featured topics %s featured content')
elseif status == 'FFA/GA' or 'GA' then
addTopicCats('Wikipedia featured topics %s good content')
else
addTopicCats('Wikipedia featured topics %s')
end
 
-- Importance categories
local hasTop, hasHigh, hasMid, hasLow -- These check for dupes
for _, topic in ipairs(data) do
local cat, sort
if topic.status == 'FT' then
if topic.isMain and not hasTop then
cat = 'Top-importance Featured topics articles'
sort = topic.name .. ' ' .. article
hasTop = true
elseif not topic.isMain and not hasHigh then
cat = 'High-importance Featured topics articles'
hasHigh = true
end
else
if topic.isMain and not hasMid then
cat = 'Mid-importance Featured topics articles'
sort = topic.name .. ' ' .. article
hasMid = true
elseif not topic.isMain and not hasLow then
cat = 'Low-importance Featured topics articles'
hasLow = true
end
end
if cat then
addCat(cat, sort)
end
end
 
return cats
end
},
 
-- Main page date
{
id = 'MAINDATE',
isActive = function (articleHistoryObj)
local args = articleHistoryObj.args
local status = articleHistoryObj:getStatusId()
return args.maindate or status == 'FA' or status == 'FL'
end,
makeData = function (articleHistoryObj)
local args = articleHistoryObj.args
local status = articleHistoryObj:getStatusId()
local data = {}
 
local function validateMainDate(argName, dataName, dataTimestampName)
data[dataName] = args[argName]
if data[dataName] then
data[dataTimestampName] = getYmdDate(data[dataName])
if not data[dataTimestampName] then
articleHistoryObj:raiseError(
string.format(
"invalid date '%s' detected in parameter '%s'",
data[dataName],
argName
),
'Template:Article history#Invalid date'
)
end
end
end
 
validateMainDate('maindate', 'mainDate', 'mainDateTimestamp')
if data.mainDate then
validateMainDate('maindate2', 'mainDate2', 'mainDate2Timestamp')
if data.mainDate2 and data.mainDateTimestamp >= data.mainDate2Timestamp then
articleHistoryObj:raiseError(
"the date in the 'maindate' parameter must be earlier than the date in the 'maindate2' parameter",
'Template:Article history#Main Page date order'
)
end
end
 
data.currentTimestamp = getYmdDate()
 
 
-- Whether the page is a list or not for the purposes of the Main
-- Page. The first Today's Featured List was on 13 June 2011, so
-- lists that were featured before then count as articles.
data.isList = (status == 'FL' or status == 'FFL')
and (not data.mainDate or data.mainDateTimestamp >= 20110613)
 
return data
end,
icon = 'Wikipedia-logo-v2.svg',
iconCaption = 'Main Page trophy',
text = function (articleHistoryObj, noticeObj)
local data = noticeObj:getData(articleHistoryObj)
if not data or not data.mainDate then
return nil
end
 
-- Build the blurb for all the possible combinations of past,
-- present and future appearances of maindate and maindate2.
local pagetype = data.isList and 'list' or 'article'
local mainDateLong = getLongDate(data.mainDate)
local mainDate2Long = data.mainDate2 and getLongDate(data.mainDate2)
local todaysFA = "Today's featured " .. pagetype
 
local function makeFeaturedLink(date, display)
return string.format(
"[[Wikipedia:Today's featured %s/%s|%s]]",
pagetype,
date,
display or date
)
end
 
local function isPast(timestamp)
return timestamp < data.currentTimestamp
end
 
local function isCurrent(timestamp)
return timestamp == data.currentTimestamp
end
 
local function isFuture(timestamp)
return timestamp > data.currentTimestamp
end
 
if data.mainDate2 then
if isPast(data.mainDateTimestamp) then
if isPast(data.mainDate2Timestamp) then
return string.format(
"This article appeared on Wikipedia's Main Page as %s on %s, and on %s.",
todaysFA,
makeFeaturedLink(mainDateLong),
makeFeaturedLink(mainDate2Long)
)
elseif isCurrent(data.mainDate2Timestamp) then
return string.format(
"This article is currently on Wikipedia's Main Page as %s. It also appeared previously on %s.",
makeFeaturedLink(mainDate2Long, todaysFA),
makeFeaturedLink(mainDateLong)
)
else
return string.format(
"This article appeared on Wikipedia's Main Page as %s on %s, and will appear again on %s.",
todaysFA,
makeFeaturedLink(mainDateLong),
makeFeaturedLink(mainDate2Long)
)
end
elseif isCurrent(data.mainDateTimestamp) then
if isFuture(data.mainDate2Timestamp) then
return string.format(
"This article is currently on Wikipedia's Main Page as %s, and will appear again on %s.",
makeFeaturedLink(mainDateLong, todaysFA),
makeFeaturedLink(mainDate2Long)
)
else
return nil
end
else
if isFuture(data.mainDate2Timestamp) then
return string.format(
"This article will appear on Wikipedia's Main Page as %s on %s, and again on %s.",
todaysFA,
makeFeaturedLink(mainDateLong),
makeFeaturedLink(mainDate2Long)
)
else
return nil
end
end
else
if isPast(data.mainDateTimestamp) then
return string.format(
"This article appeared on Wikipedia's Main Page as %s on %s.",
makeFeaturedLink(mainDateLong, todaysFA),
mainDateLong
)
elseif isCurrent(data.mainDateTimestamp) then
return string.format(
"This article is currently on Wikipedia's Main Page as %s.",
makeFeaturedLink(mainDateLong, todaysFA),
mainDateLong
)
else
return string.format(
"This article will appear on Wikipedia's Main Page as %s on %s.",
makeFeaturedLink(mainDateLong, todaysFA),
mainDateLong
)
end
end
end,
categories = function (articleHistoryObj, noticeObj)
local data = noticeObj:getData(articleHistoryObj)
if not data then
return nil
end
local status = articleHistoryObj:getStatusId()
local cats = {}
 
local pagetype = data.isList and 'lists' or 'articles'
if data.mainDate and data.mainDateTimestamp <= data.currentTimestamp then
cats[#cats + 1] = Category.new(string.format(
'Featured %s that have appeared on the main page',
pagetype
))
if data.mainDate2 and data.mainDate2Timestamp <= data.currentTimestamp then
cats[#cats + 1] = Category.new(string.format(
'Featured %s that have appeared on the main page twice',
pagetype
))
else
cats[#cats + 1] = Category.new(string.format(
'Featured %s that have appeared on the main page once',
pagetype
))
end
elseif status == 'FA' or status == 'FL' or data.mainDate then
cats[#cats + 1] = Category.new(string.format(
'Featured %s that have not appeared on the main page',
pagetype
))
end
return cats
end
}
},
 
-------------------------------------------------------------------------------
-- Actions
-------------------------------------------------------------------------------
 
-- The actions table contains configuration tables for actions such as featured
-- article candidacies and peer review, etc.
-- Each configuration table can have the following fields:
--
-- id: the main ID for the action. This should be the same as the configuration
-- table key.
-- name: the name of the action. This can be a string or a function. If it is
-- a function, it takes an article history object as its first parameter and
-- the action object as its second parameter, and should return the name.
-- results: a table of possible results for the action. Keys in the table should
-- be a result ID, e.g. "promoted" or "kept", and values should be a subtable
-- with the following fields:
-- id: the result ID. This should be the same as the table key. It will
-- also define a possible input value for the action's result parameter.
-- text: the displayed result text. This may be a string or a function. If it
-- is a function, it takes an article history object as the first
-- parameter and the current action object as the second parameter, and
-- should return the result string.
-- aliases: an array of result ID aliases. Each of these will define a valid
-- value for the action's result parameter.
-- text: The action text. This may be a string or a function. If it is a
-- function, it takes an article history object as the first parameter and
-- the current action object as the second parameter, and should return the
-- text string.
-- categories: The categories set by the notice. This may be an array of
-- category names, or a function. If it is a function, it takes an article
-- history object as the first parameter and the current action object as the
-- second parameter, and should return an array of category objects.
-- noticeBarIcon: the icon to use for the notice bar. This can be a string, or
-- a function, or true. If it is a function it takes an article history
-- object as the first parameter, and should output the icon filename. If it
-- is true, it uses the value of icon. If it is nil then no notice bar icon
-- will be displayed.
-- noticeBarIconCaption: the caption to use for the notice bar icon. This can be
-- a string or a function. If it is a function, it takes an article history
-- object as its first parameter, and should return the caption text. If this
-- is absent, the icon caption is used instead.
-- noticeBarIconSize: the size of the notice bar icon, including "px" suffix.
-- The default is set by defaultNoticeBarIconSize.
 
actions = {
Line 15 ⟶ 1,113:
results = {
promoted = {
id = 'promoted',
text = 'Promoted',
aliases = {'pass', 'passed'}
},
['not promoted'] = {
id = 'not promoted',
text = 'Not promoted',
aliases = {'fail', 'failed'}
}
},
validStatuses = {
FFAC = true,
FA = true,
FFA = true
}
},
Line 50 ⟶ 1,145:
}
},
categories = function (articleHistoryObj, actionObj)
validStatuses = {
FAlocal ret = true,{}
local result = actionObj.resultId
FFA = true
if result == 'demoted' or result == 'merged' then
},
local status = articleHistoryObj:getStatusId()
categories = {
function local (actionObj,sortKey = articleHistoryObj).currentTitle.subjectPageTitle.prefixedText
if status == 'FA' or status == 'FL' then
local result = actionObj:getResult()
sortKey = '#' .. sortKey
if result == 'demoted' or result == 'merged' then
local currentStatus = articleHistoryObj:getCurrentStatus()
local sortKey = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
if currentStatus == 'FA' or currentStatus == 'FL' then
sortKey = '#' .. sortKey
end
return 'Wikipedia former featured articles', sortKey
end
ret[#ret + 1] = Category.new(
'Wikipedia former featured articles',
sortKey
)
end
return ret
}
end
},
BP = {
Line 77 ⟶ 1,171:
aliases = {'pass', 'promoted', 'nom'}
}
},
validStatuses = {
}
},
Line 96 ⟶ 1,188:
}
},
categories = function (articleHistoryObj, actionObj)
validStatuses = {
FAlocal ret = true,{}
if actionObj.resultId == 'not kept' then
FFAC = true
ret[#ret + 1] = Category.new(
},
'Wikipedia former brilliant prose',
categories = {
function (actionObj, articleHistoryObj).currentTitle.text
)
if actionObj:getResult() == 'not kept' then
return 'Wikipedia former brilliant prose', articleHistoryObj.currentTitle.text
end
end
return ret
}
end
},
FLC = {
Line 113 ⟶ 1,204:
results = {
promoted = {
id = 'promoted',
text = 'Promoted',
aliases = {'pass', 'passed'}
},
['not promoted'] = {
id = 'not promoted',
text = 'Not promoted',
aliases = {'fail', 'failed'}
}
},
validStatuses = {
FFLC = true,
FL = true,
FFL = true
}
},
Line 147 ⟶ 1,235:
}
},
categories = function (articleHistoryObj, actionObj)
validStatuses = {
FLlocal ret = true,{}
local result = actionObj.resultId
FFL = true
if result == 'demoted' or result == 'merged' then
},
local sortKey
categories = {
function (actionObj, if articleHistoryObj:getStatusId() == 'FL' then
sortKey = '#' .. articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
local result = actionObj:getResult()
else
if result == 'demoted' or result == 'merged' then
local sortKey = articleHistoryObj.currentTitle.text
if articleHistoryObj:getCurrentStatus() == 'FL' then
sortKey = '#' .. articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
else
sortKey = articleHistoryObj.currentTitle.text
end
return 'Wikipedia former featured lists', sortKey
end
ret[#ret + 1] = Category.new(
'Wikipedia former featured lists',
sortKey
)
end
return ret
}
end
},
FTC = {
Line 180 ⟶ 1,267:
aliases = {'fail', 'failed'}
}
},
validStatuses = false, -- Any status
},
FTR = {
Line 202 ⟶ 1,288:
aliases = {'merge'}
}
},
validStatuses = false, -- Any status
},
FPOC = {
Line 219 ⟶ 1,304:
aliases = {'fail', 'failed'}
}
},
validStatuses = {
FFPOC = true,
FPO = true,
FFPO = true
}
},
Line 245 ⟶ 1,325:
aliases = {'merge'}
}
},
validStatuses = {
FPO = true,
FFPO = true
}
},
Line 267 ⟶ 1,343:
}
},
categories = function (articleHistoryObj, actionObj)
validStatuses = {
FGANlocal ret = true,{}
if actionObj.resultId == 'not listed' then
GA = true,
local status = articleHistoryObj:getStatusId()
DGA = true,
FFAC if status ~= true,'FA'
FA and status ~= true,'GA'
FFA and status ~= true'FFA'
}, then
ret[#ret + 1] = Category.new(
categories = {
'Former good article nominees',
function (actionObj, articleHistoryObj)
articleHistoryObj.currentTitle.text
if actionObj:getResult() == 'not listed' then
)
local currentStatus = articleHistoryObj:getCurrentStatus()
if currentStatus ~= 'FA'
and currentStatus ~= 'GA'
and currentStatus ~= 'FFA'
then
return 'Former good article nominees', articleHistoryObj.currentTitle.text
end
end
end
return ret
}
end
},
GAR = {
Line 312 ⟶ 1,383:
}
},
categories = function (articleHistoryObj, actionObj)
validStatuses = {
GAlocal ret = true,{}
if actionObj.resultId == 'delisted' then
DGA = true,
local status = articleHistoryObj:getStatusId()
FFAC = true,
FA if status ~= true,'FA'
FFA and status ~= true'GA'
}, then
ret[#ret + 1] = Category.new(
categories = {
'Delisted good articles',
function (actionObj, articleHistoryObj)
articleHistoryObj.currentTitle.text
if actionObj:getResult() == 'delisted' then
)
local currentStatus = articleHistoryObj:getCurrentStatus()
if currentStatus ~= 'FA'
and currentStatus ~= 'GA'
then
return 'Delisted good articles', articleHistoryObj.currentTitle.text
end
end
end
}end
},
GTC = {
Line 346 ⟶ 1,412:
aliases = {'fail', 'failed'}
}
},
validStatuses = false
},
GTR = {
Line 368 ⟶ 1,433:
aliases = {'merge'}
}
},
validStatuses = false
},
PR = {
Line 378 ⟶ 1,442:
id = 'reviewed',
text = 'Reviewed',
aliases = {'_BLANK'}
},
['not reviewed'] = {
Line 384 ⟶ 1,449:
}
},
validStatuses = false,
categories = {'Old requests for peer review'}
},
WPR = {
id = 'WPR',
name = function (actionObjarticleHistoryObj, articleHistoryObjactionObj)
local names = {
approved = 'WikiProject approved revision',
Line 396 ⟶ 1,460:
maindate = "Today's featured article"
}
local result = actionObj:getResult().resultId
return result and names[result] or 'WikiProject peer review'
end,
Line 402 ⟶ 1,466:
approved = {
id = 'approved',
text = function(actionObjarticleHistoryObj, articleHistoryObjactionObj)
if actionObj.oldid then
local url = mw.uri.fullUrl(
Line 443 ⟶ 1,507:
id = 'reviewed',
text = 'Reviewed',
aliases = {'_BLANK'} -- This is "Reviewed" if the reason is blank, but not absent.
}
},
categories = function (articleHistoryObj, actionObj)
validStatuses = false
local ret = {}
local result = actionObj.resultId
if result == 'copyedited' then
ret[1] = Category.new('Articles copy edited by the Guild of Copy Editors')
end
return ret
end
},
WAR = {
Line 465 ⟶ 1,536:
id = 'reviewed',
text = 'Reviewed',
aliases = {'_BLANK'}
},
kept = {
Line 476 ⟶ 1,547:
text = 'Demoted',
aliases = {'demote'}
},
},
validStatuses = false
},
AFD = {
Line 522 ⟶ 1,592:
text = 'Renamed',
aliases = {'rename', 'move', 'moved'}
},
},
validStatuses = false
},
MFD = {
id = 'MFD',
name = 'MiscellaneaMiscellany for deletion',
results = {
kept = {
Line 568 ⟶ 1,637:
text = 'Renamed',
aliases = {'rename', 'move', 'moved'}
},
},
validStatuses = false
},
TFD = {
Line 610 ⟶ 1,678:
},
renamed = {
id = 'renamed',
text = 'Renamed',
aliases = {'rename', 'move', 'moved'}
},
},
validStatuses = false
},
CSD = {
Line 628 ⟶ 1,696:
id = 'deleted',
text = 'Deleted',
aliases = {'delete', 'speedily deleted', 'speedy delete'}
},
merged = {
id = 'merged',
text = 'Merged',
aliases = {'merge'}
},
['no consensus'] = {
id = 'no consensus',
text = 'No consensus'
},
['speedily kept'] = {
Line 643 ⟶ 1,702:
text = 'Speedily kept',
aliases = {'speedy keep'}
},
['speedily deleted'] = {
id = 'speedily deleted',
text = 'Speedily deleted',
aliases = {'speedy delete'}
},
redirected = {
Line 653 ⟶ 1,707:
text = 'Redirected',
aliases = {'redirect'}
},
prod = {
id = 'prod',
text = 'Converted to [[WP:PROD|proposed deletion]]',
aliases = {'prodded'}
},
afd = {
id = 'afd',
text = 'Sent to [[WP:AFD|articles for deletion]]',
aliases = {'afded'}
},
renamed = {
Line 658 ⟶ 1,722:
text = 'Renamed',
aliases = {'rename', 'move', 'moved'}
},
},
validStatuses = false
},
PROD = {
Line 675 ⟶ 1,738:
text = 'Deleted',
aliases = {'delete'}
},
merged = {
id = 'merged',
text = 'Merged',
aliases = {'merge'}
},
['no consensus'] = {
id = 'no consensus',
text = 'No consensus'
},
['speedily kept'] = {
id = 'nospeedily consensuskept',
text = 'Speedily kept',
aliases = {'speedy keep'}
Line 699 ⟶ 1,753:
text = 'Redirected',
aliases = {'redirect'}
},
afd = {
id = 'afd',
text = 'Sent to [[WP:AFD|articles for deletion]]',
aliases = {'afded'}
},
renamed = {
Line 704 ⟶ 1,763:
text = 'Renamed',
aliases = {'rename', 'move', 'moved'}
},
},
validStatuses = false
},
DRV = {
Line 726 ⟶ 1,784:
text = 'Overturned',
aliases = {'overturn'}
},
restored = {
id = 'restored',
text = 'Restored',
aliases = {'restore'}
},
['no consensus'] = {
Line 731 ⟶ 1,794:
text = 'No consensus'
}
},
validStatuses = false
}
},
 
-------------------------------------------------------------------------------
-- Collapsible notices
-- Statuses
-------------------------------------------------------------------------------
 
-- The collapsibleNotices table contains configuration tables for notices that
statuses = {
-- go in the collapsible part of the template, underneath the actions.
FA = {
-- Each configuration table can have the following fields:
id = 'FA',
--
image = 'Featured article star.svg'
-- id: the main ID for the notice. This should be the same as the configuration
-- table key.
-- isActive: a function that should return a truthy value if the notice should
-- be displayed, and a falsy value if not. (Falsy values are false and nil,
-- and truthy values are everything else.) The function takes an article
-- history object as its first parameter.
-- makeData: a function that should return a table of data to be used by other
-- functions in this notice configuration table. It can be accessed using
-- noticeObj:getData().
-- icon: the filename of the notice icon, minus the "File:" prefix.
-- iconCaption: the icon caption.
-- iconSize: The icon size, including "px" suffix. The default is defined in
-- defaultIconSize.
-- text: The notice text. This may be a string or a function. If it is a
-- function, it takes an article history object as the first parameter, and
-- the current collapsible notice object as the second parameter, and should
-- return the text string.
-- categories: The categories set by the notice. This may be an array of
-- category names, or a function. If it is a function, it takes an article
-- history object as the first parameter, and the current collapsible notice
-- object as the second parameter, and should return an array of category
-- objects.
-- noticeBarIcon: the icon to use for the notice bar. This can be a string, or
-- a function, or true. If it is a function it takes an article history
-- object as the first parameter, and should output the icon filename. If it
-- is true, it uses the value of icon. If it is nil then no notice bar icon
-- will be displayed.
-- noticeBarIconCaption: the caption to use for the notice bar icon. This can be
-- a string or a function. If it is a function, it takes an article history
-- object as its first parameter, and should return the caption text. If this
-- is absent, the icon caption is used instead.
-- noticeBarIconSize: the size of the notice bar icon, including "px" suffix.
-- The default is set by defaultNoticeBarIconSize.
 
collapsibleNotices = {
-- DYK
{
id = 'DYK',
icon = 'Symbol question.svg',
iconCaption = 'Did You Know',
noticeBarIcon = true,
isActive = function (articleHistoryObj)
return isActiveDatedObject(articleHistoryObj, 'dyk')
end,
makeData = function (articleHistoryObj)
return makeDateData(articleHistoryObj, 'dyk', {'entry', 'nom', 'ignoreerror'})
end,
text = function (articleHistoryObj, collapsibleNoticeObj)
local data = collapsibleNoticeObj:getData(articleHistoryObj)
if not data then
return nil
end
for _, t in ipairs(data) do
local raPage = 'Wikipedia:Recent additions/' ..
getDate('Y/F#j F Y', t.date)
if not titleExists(raPage) then
raPage = 'Wikipedia:Recent additions'
end
t.link = raPage
end
local fact = 'fact from this article'
local nomPage = data[1].nom or ('Template:Did you know nominations/' .. articleHistoryObj.currentTitle.text)
if titleExists(nomPage) then
fact = '[[' .. nomPage .. '|' .. fact .. ']]'
end
local blurb = "A " .. fact .. " appeared on " ..
"Wikipedia's [[Main Page]] in the " ..
"''\"[[:Template:Did you know|Did you know?]]\"'' " ..
"column on $1."
return makeDateText(data, blurb, true)
end,
collapsibleText = function (articleHistoryObj, collapsibleNoticeObj)
local data = collapsibleNoticeObj:getData(articleHistoryObj)
if not data then
return nil
end
local ctext = {}
if #data == 1 and data[1].entry then
ctext[#ctext + 1] = string.format(
"The text of the entry was: ''Did you know %s''",
data[1].entry
)
else
local entries = {}
local lastEntryDate
for _, t in ipairs(data) do
entries[#entries + 1] = t.entry
lastEntryDate = t.date
end
if #entries == 1 then
ctext[#ctext + 1] = string.format(
"The text of the entry for %s was: ''Did you know %s''",
lastEntryDate, entries[1]
)
elseif #entries > 1 then
ctext[#ctext + 1] = 'The text of the entries was:\n'
local list = mw.html.create('ul')
for _, t in ipairs(data) do
if t.entry then
list:tag('li'):wikitext(string.format(
"%s: ''Did you know %s''",
t.date, t.entry
))
end
end
ctext[#ctext + 1] = tostring(list)
end
end
if #ctext > 0 then
return table.concat(ctext)
else
return nil
end
end,
categories = function (articleHistoryObj, collapsibleNoticeObj)
local data = collapsibleNoticeObj:getData(articleHistoryObj)
if not data then
return nil
end
local cats = {}
do
local status = articleHistoryObj:getStatusId()
local statusCat
if status == 'FA' then
statusCat = 'Wikipedia Did you know articles that are featured articles'
elseif status == 'FL' then
statusCat = 'Wikipedia Did you know articles that are featured lists'
elseif status == 'GA' or status == 'FFA/GA' then
statusCat = 'Wikipedia Did you know articles that are good articles'
else
statusCat = 'Wikipedia Did you know articles'
end
cats[#cats + 1] = Category.new(statusCat)
end
for _, t in ipairs(data) do
if not t.ignoreerror then
if t.entry then
local mCheckDYKEntry = require('Module:Check DYK hook')
if not mCheckDYKEntry._isValidHook(t.entry) then
cats[#cats + 1] = Category.new('Pages with a malformed DYK entry')
end
else
cats[#cats + 1] = Category.new('Pages with a missing DYK entry')
end
end
end
return cats
end
},
 
FFA = {
-- ITN
id = 'FFA',
{
image = 'Featured article star - cross.svg'
id = 'ITN',
isActive = function (articleHistoryObj)
return isActiveDatedObject(articleHistoryObj, 'itn')
end,
makeData = function (articleHistoryObj)
return makeDateData(articleHistoryObj, 'itn', {'link'})
end,
icon = 'Globe current.svg',
iconCaption = 'In the news',
noticeBarIcon = true,
noticeBarIconSize = '20px',
text = function (articleHistoryObj, collapsibleNoticeObj)
local data = collapsibleNoticeObj:getData(articleHistoryObj)
if not data then
return nil
end
local dates = {}
for _, t in ipairs(data) do
local date = {}
if t.link then
date.link = t.link
elseif t.ymdDate >= 20110701 then
date.link = string.format(
'Wikipedia:In the news/Candidates/%s %d',
t.month,
t.year
)
elseif t.ymdDate >= 20090101 then
date.link = string.format(
'Wikipedia:ITN archives/%d/%s',
t.year,
t.month
)
elseif t.ymdDate >= 20050101 then
date.link = string.format(
'Portal:Current events/%d %s %d',
t.year,
t.month,
t.day
)
end
date.date = t.date
dates[#dates + 1] = date
end
local intro
if #data > 1 then
intro = 'News items involving this article were'
else
intro = 'A news item involving this article was'
end
local blurb = intro ..
" featured on Wikipedia's [[Main Page]] in the " ..
"''\"[[Template:In the news|In the news]]\"'' column on $1."
return makeDateText(dates, blurb)
end,
categories = function (articleHistoryObj, collapsibleNoticeObj)
local cats = {}
cats[1] = Category.new('Wikipedia In the news articles')
return cats
end
},
 
FFAC = {
-- On This Day
id = 'FFAC',
{
aliases = {'FACFAILED'},
imageid = 'Cscr-former.svgOTD',
isActive = function (articleHistoryObj)
return isActiveDatedObject(articleHistoryObj, 'otd')
end,
makeData = function (articleHistoryObj)
return makeDateData(articleHistoryObj, 'otd', {'link', 'oldid'})
-- TODO: remove 'link' after it is no longer needed for tracking
end,
icon = 'Nuvola apps date.svg',
iconCaption = 'On this day...',
noticeBarIcon = true,
noticeBarIconSize = '20px',
text = function (articleHistoryObj, collapsibleNoticeObj)
local data = collapsibleNoticeObj:getData(articleHistoryObj)
if not data then
return nil
end
local dates = {}
for _, t in ipairs(data) do
local date = {}
date.date = t.date
date.link = t.link
if t.oldid then
-- TODO: Move this inside the main module
local oldid = tonumber(t.oldid)
if oldid and
math.floor(oldid) == oldid and
oldid > 0 and
oldid < math.huge
then
-- If the oldid is valid, it takes precedence over
-- explicit links.
date.link = 'Special:PermaLink/' .. t.oldid
else
collapsibleNoticeObj:addWarning(
string.format(
"invalid oldid '%s' detected in parameter '%s'; " ..
"if an oldid is specified it must be a positive integer",
t.oldid,
t.argPrefix .. 'oldid'
),
'Template:Article history#Invalid oldid'
)
end
end
dates[#dates + 1] = date
end
local intro
if #data > 1 then
intro = 'Facts from this article were'
else
intro = 'A fact from this article was'
end
local blurb = intro ..
" featured on Wikipedia's [[Main Page]] in the " ..
"''\"[[Wikipedia:Selected anniversaries|On this day...]]\"'' " ..
"column on $1."
return makeDateText(dates, blurb)
end,
categories = function (articleHistoryObj, collapsibleNoticeObj)
local cats = {}
cats[1] = Category.new('Selected anniversaries articles')
local data = collapsibleNoticeObj:getData(articleHistoryObj)
if data then
for _, t in ipairs(data) do
if t.link then
cats[#cats + 1] = Category.new(
'Article history templates with linked otd dates'
)
break
end
end
end
return cats
end
},
 
FL = {
-- Article Collaboration and Improvement Drive
id = 'FL',
{
image = 'Featured article star.svg'
id = 'ACID',
isActive = function (articleHistoryObj)
return articleHistoryObj.args.aciddate
end,
icon = 'Article Collaboration and Improvement Drive.svg',
iconCaption = 'Article Collaboration and Improvement Drive',
noticeBarIcon = true,
noticeBarIconSize = '20px',
text = function (articleHistoryObj)
local args = articleHistoryObj.args
local blurb = 'This article was on the ' ..
'[[WP:ACID|Article Collaboration and Improvement Drive]] ' ..
'for the week of %s.'
local date = validateDate('aciddate', args.aciddate)
return string.format(blurb, date)
end
},
FFL = {
id = 'FFL',
image = 'Cscr-featured-strike.svg'
},
FFLC = {
id = 'FFLC',
image = 'Cscr-former.svg'
},
GA = {
id = 'GA',
image = 'Symbol support vote.svg'
},
FGAN = {
id = 'FGAN',
aliases = {'FAILEDGA'},
image = 'Symbol unsupport vote.svg'
},
DGA = {
id = 'DGA',
aliases = {'DELISTEDGA'},
image = 'Symbol unsupport vote.svg'
},
FFT = {
id = 'FFT',
image = 'Cscr-featured-strike.svg'
},
FFTC = {
id = 'FFTC',
image = 'Cscr-former.svg'
},
FPO = {
id = 'FPO',
image = 'Cscr-former.svg'
},
FFPO = {
id = 'FFPO',
image = 'Featured article star - cross.svg'
},
FFPOC = {
id = 'FFPOC',
image = 'Cscr-former.svg'
},
},
 
-- League of Copy Editors
doubleStatuses = {
{
['FFA/GA'] = {
id = 'FFA/GALOCE',
isActive = function (articleHistoryObj)
statuses = {'FFA', 'GA'}
return articleHistoryObj.args.loceNotAnActiveOption
end,
icon = 'LoCiconRevised.png',
iconCaption = 'League of Copyeditors',
iconSize = '25px',
noticeBarIcon = true,
text = 'This article, or a portion of it, was copyedited by the ' ..
'[[WP:LoCE|League of Copyeditors]].'
}
},
 
-------------------------------------------------------------------------------
invalidStatuses = {
-- Notice bar icons
FAC = {
-------------------------------------------------------------------------------
id = 'FAC'
 
},
-- This table holds configuration tables for notice bar icons that don't appear
FAR = {
-- as part of a row. Other notice bar icons are handled in the statuses,
id = 'FAR'
-- notices, actions, and collapsibleNotices tables.
},
-- It accepts the following fields:
STUB = {
-- isActive: a function that should return a truthy value if the notice should
id = 'STUB',
-- be displayed, and a falsy value if not. (Falsy values are false and nil,
aliases = {'START', 'B', 'A'}
-- and truthy values are everything else.) The function takes an article
},
-- history object as its first parameter.
NA = {
-- icon: the filename of the notice bar icon, minus the "File:" prefix.
id = 'NA',
 
aliases = {'PR', ''}
noticeBarIcons = {
-- Peer review, or NA status
{
isActive = function (articleHistoryObj)
local status = articleHistoryObj:getStatusId()
-- @XXX: This is what the template does, but we should take into
-- account peer review actions as well.
return not status or status == 'PR' or status == 'NA'
end,
icon = 'Nuvola apps kedit.svg'
},
 
-- Wikipedia 1.0
{
isActive = function (articleHistoryObj)
return articleHistoryObj.args['v1.0NotAnActiveOption']
end,
icon = 'WP1 0 Icon.svg'
}
},
 
-------------------------------------------------------------------------------
-- Extra categories
-------------------------------------------------------------------------------
 
-- This table contains categories that don't appear as part of a row. It is an
-- array of functions; each function takes an article history object as input
-- and must return an array of category objects as output.
 
extraCategories = {
-- Four award
function (articleHistoryObj)
local yesno = require('Module:Yesno')
local ret = {}
local isFour = yesno(articleHistoryObj.args.four)
if isFour then
ret[#ret + 1] = Category.new('Wikipedia four award articles')
elseif isFour == false then
ret[#ret + 1] = Category.new('Wikipedia articles rejected for Four awards')
elseif articleHistoryObj:getStatusId() == 'FA' then
local isDYK = false
for _, obj in ipairs(articleHistoryObj:getCollapsibleNoticeObjects()) do
if obj.id == 'DYK' then
isDYK = true
break
end
end
if isDYK then
for _, obj in ipairs(articleHistoryObj:getActionObjects()) do
if obj.id == 'GAN' and obj.resultId == 'listed' then
ret[#ret + 1] = Category.new('Possible Wikipedia four award articles')
break
end
end
end
end
return ret
end,
 
-- Deletion to Quality award
function (articleHistoryObj)
local ret = {}
local status = articleHistoryObj:getStatusId()
if status == 'FA' or status == 'FL' or status == 'GA' then
local iAfd = 0
local hasAfd = false
local actionObjects = articleHistoryObj:getActionObjects()
for i, obj in ipairs(actionObjects) do
if obj.id == 'AFD' then
iAfd = i
hasAfd = true
break
end
end
if hasAfd then
local function hasNomination(id, result)
for i = iAfd + 1, #actionObjects do
local obj = actionObjects[i]
if obj.id == id and obj.resultId == result then
return true
end
end
return false
end
if status == 'GA' and hasNomination('GAN', 'listed') or
status == 'FL' and hasNomination('FLC', 'promoted') or
status == 'FA' and hasNomination('FAC', 'promoted')
then
ret[#ret + 1] = Category.new('Deletion to Quality Award candidates')
end
end
end
return ret
end,
},
 
Line 835 ⟶ 2,253:
actionParamPrefix = 'action',
actionParamSuffixes = {
[''] = 'idcode',
date = 'date',
link = 'link',
result = 'resultresultCode',
oldid = 'oldid'
},
 
-- The parameter used to set the current status.
currentStatusParam = 'currentstatus',
 
-------------------------------------------------------------------------------
-- Other settings
-------------------------------------------------------------------------------
 
-- If this number or fewer of collapsible rows are present (including actions
-- and collapsible notices) they will not be collapsed. If this is set to the
-- string "all", all rows will always be visible. Otherwise, the input must be
-- a number. The default is three rows.
uncollapsedRows = 3,
 
-- The default size for icons. The default is 30px.
defaultIconSize = '30px',
 
-- The default size for status icons. The default is 50px.
defaultStatusIconSize = '50px',
 
-- The default size for status icons for multi status templates. The default is 30px.
defaultMultiStatusIconSize = '30px',
 
-- The default size for notice bar icons. The default is 15px.
defaultNoticeBarIconSize = '15px',
 
-- The default size for collapsible status icons. The default is 50px.
defaultCollapsibleNoticeIconSize = '20px',
 
-------------------------------------------------------------------------------
Line 847 ⟶ 2,293:
 
msg = {
 
-- The heading for the collapsible table of actions if we are in the main
-- namespace or the talk namespace.
['milestones-header'] = 'Article milestones',
 
-- The heading for the collapsible table of actions if we are in a different
-- namespace.
-- $1 - the subject namespace name.
['milestones-header-other-ns'] = '$1 milestones',
 
-- The milestones date header.
['milestones-date-header'] = 'Date',
 
-- The milestones process header.
['milestones-process-header'] = 'Process',
 
-- The milestones result header.
['milestones-result-header'] = 'Result',
 
-- The format to display the action dates in. The syntax is the same as the
-- #time parser function.
['action-date-format'] = 'F j, Y',
 
-- The category to use if any errors are detected.
['error-category'] = 'Article history templates with errors',
 
-- Define boilerplate text for error messages and warnings, both with and
-- without help links.
-- $1 - the error message
-- $2 - a link to a help page and section for the error
['error-message-help'] = 'Error: $1 ([[$2|help]]).',
['error-message-nohelp'] = 'Error: $1.',
['warning-help'] = 'Warning: $1 ([[$2|help]]).',
['warning-nohelp'] = 'Warning: $1.',
 
-- Error for row objects that should output notice bar icons but for which no
-- icon values could be found.
['row-error-missing-icon'] = "notice bar icon config set to 'true' but no " ..
'image could be found',
 
-- A help link for row-error-missing-icon
['row-error-missing-icon-help'] = 'Template:Article history#Missing icon',
 
-- Error for action objects that aren't passed a code.
-- $1 - the parameter name for the code
['action-error-no-code'] = "no action code found in the '$1' parameter; " ..
"please add a code or remove other parameters starting with '$1'",
 
-- A help link for action-error-no-code
['action-error-no-code-help'] = 'Template:Article history#Action codes',
 
-- Error for action objects that are passed an invalid code.
-- $1 - the code that the user input
-- $2 - the parameter name for the code
['action-error-invalid-code'] = "invalid action code '$1' passed to the '$2' parameter",
 
-- A help link for action-error-invalid-code
['action-error-invalid-code-help'] = 'Template:Article history#Action codes',
 
-- Error for action objects with blank result parameters, where result
-- parameters are required for the action's ID.
-- $1 - the action ID
-- $2 - the result parameter name
['action-error-blank-result'] = "the '$1' action requires a result code; " ..
"please add a result code to parameter '$2'",
 
-- A help link for action-error-blank-result
['action-error-blank-result-help'] = 'Template:Article history#Action results',
 
-- Error for action objects with invalid result parameters.
-- $1 - the result code that the user input
-- $2 - the action ID
-- $3 - the result parameter name
['action-error-invalid-result'] = "invalid result '$1' for action '$2' " ..
"detected in parameter '$3'",
 
-- A help link for action-error-invalid-result
['action-error-invalid-result-help'] = 'Template:Article history#Action results',
 
-- Warning for action objects with invalid dates.
-- $1 - the date input by the user
-- $2 - the date parameter name
['action-warning-invalid-date'] = "invalid date '$1' detected in parameter '$2'",
 
-- A help link for action-warning-invalid-date
['action-warning-invalid-date-help'] = 'Template:Article history#Invalid date',
 
-- Error for action objects with no dates.
-- $1 - the parameter number
-- $2 - the date parameter name
-- $3 - the action parameter name
['action-warning-no-date'] = "no date specified for action $1; " ..
"please add a date to parameter '$2' or remove the other parameters " ..
"beginning with '$3'",
 
-- A help link for action-warning-no-date
['action-warning-no-date-help'] = 'Template:Article history#No date',
 
-- The text to display in place of the action date if it is missing.
['action-date-missing'] = '?',
 
-- Error for action objects with invalid oldids.
-- $1 - the oldid input by the user
-- $2 - the oldid parameter name
['action-warning-invalid-oldid'] = "invalid oldid '$1' detected in parameter '$2'; " ..
"if an oldid is specified it must be a positive integer",
 
-- A help link for action-warning-invalid-oldid
['action-warning-invalid-oldid-help'] = 'Template:Article history#Invalid oldid',
 
-- Error for invalid current status codes.
-- $1 - the code input by the user
['articlehistory-warning-invalid-status'] = "'$1' is not a valid status code",
 
-- A help link for articlehistory-warning-invalid-status
['articlehistory-warning-invalid-status-help'] = 'Template:Article history#Invalid status',
 
-- Warning for invocations that specify a current status without specifying any
-- actions.
['articlehistory-warning-status-no-actions'] = "a current status was supplied " ..
'without any actions',
 
-- A help link for articlehistory-warning-status-no-actions
['articlehistory-warning-status-no-actions-help'] = 'Template:Article history#No actions',
 
-- The text to display the current status at the bottom of the collapsible
-- table.
-- $1 - the current status name
['status-blurb'] = "Current status: '''$1'''",
 
-- The text to display at the bottom of the collapsible table if the current
-- status is unknown.
['status-unknown'] = '?',
 
}
 
-------------------------------------------------------------------------------
-- CONFIG TABLE END
-- End config
-------------------------------------------------------------------------------