Module:Article history/config/sandbox

-------------------------------------------------------------------------------

-- 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%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', 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 featured article; " ..

"it (or a previous version of it) has been identified " ..

"as one of the best articles produced by the Wikipedia community. " ..

"Even so, if you can update or improve it, 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 former featured article. " ..

"Please see the links under Article milestones below for its original nomination page " ..

"(for older articles, check 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 featured article candidate. " ..

"Please view the links under Article milestones below to see why " ..

"the nomination was archived. For older candidates, please check the " ..

"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 featured list, " ..

"which means it has been identified as one of the best " ..

"lists produced by the Wikipedia community. " ..

"If you can update or improve it, 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 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 " ..

"featured list standard, you may " ..

"renominate the article to " ..

"become a featured list."

},

FFLC = {

id = 'FFLC',

name = 'Former featured list candidate',

icon = 'Cscr-former.svg',

iconCaption = 'Former FLC',

text = "$1 is a former 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 " ..

"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 " ..

"under the good article criteria. " ..

"If you can improve it further, please do so. " ..

"''If it no longer meets these criteria, you can " ..

"reassess it''."

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 nominee, " ..

"but did not meet the 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 " ..

"renominated. " ..

"Editors may also seek a 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, " ..

"but it has been removed from the list. " ..

"There are suggestions below for improving the article to meet the " ..

"good article criteria. " ..

"Once these issues have been addressed, the article can be " ..

"renominated. " ..

"Editors may also seek a 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 " ..

"former featured topic series. " ..

"If it has improved again to " ..

"featured topic standard, " ..

"you may renominate " ..

"the topic to become a featured topic."

},

FFTC = {

id = 'FFTC',

name = 'Former featured topic candidate',

icon = 'Cscr-former.svg',

text = "This article is part of a former " ..

"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 identified " ..

"as a 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 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 " ..

"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 %s series, %s."

local otherBlurb = "It is also %s the %s series, %s."

local finalBlurb = "%s identified as among the best series of " ..

"articles produced by the Wikipedia community. " ..

"If you can update or improve %s, please do so."

local main = 'the main article in'

local notMain = 'part of'

local featuredLink = 'a featured topic'

local featuredNoLink = 'a featured topic'

local goodLink = 'a 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(

"%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 = {

FAC = {

id = 'FAC',

name = 'Featured article candidate',

results = {

promoted = {

id = 'promoted',

text = 'Promoted',

aliases = {'pass', 'passed'}

},

['not promoted'] = {

id = 'not promoted',

text = 'Not promoted',

aliases = {'fail', 'failed'}

}

}

},

FAR = {

id = 'FAR',

name = 'Featured article review',

aliases = {'FARC'},

results = {

kept = {

id = 'kept',

text = 'Kept',

aliases = {'pass', 'passed', 'keep'}

},

demoted = {

id = 'demoted',

text = 'Demoted',

aliases = {'fail', 'failed', 'remove', 'removed'}

},

merged = {

id = 'merged',

text = 'Merged',

aliases = {'merge'}

}

},

categories = function (articleHistoryObj, actionObj)

local ret = {}

local result = actionObj.resultId

if result == 'demoted' or result == 'merged' then

local status = articleHistoryObj:getStatusId()

local sortKey = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText

if status == 'FA' or status == 'FL' then

sortKey = '#' .. sortKey

end

ret[#ret + 1] = Category.new(

'Wikipedia former featured articles',

sortKey

)

end

return ret

end

},

BP = {

id = 'BP',

name = 'Brilliant prose',

results = {

nominated = {

id = 'nominated',

text = 'Nominated',

aliases = {'pass', 'promoted', 'nom'}

}

}

},

RBP = {

id = 'RBP',

name = 'Refreshing brilliant prose',

results = {

kept = {

id = 'kept',

text = 'Kept',

aliases = {'pass', 'passed', 'keep'}

},

['not kept'] = {

id = 'not kept',

text = 'Not kept',

aliases = {'fail', 'failed', 'remove', 'removed', 'demoted'}

}

},

categories = function (articleHistoryObj, actionObj)

local ret = {}

if actionObj.resultId == 'not kept' then

ret[#ret + 1] = Category.new(

'Wikipedia former brilliant prose',

articleHistoryObj.currentTitle.text

)

end

return ret

end

},

FLC = {

id = 'FLC',

name = 'Featured list candidate',

results = {

promoted = {

id = 'promoted',

text = 'Promoted',

aliases = {'pass', 'passed'}

},

['not promoted'] = {

id = 'not promoted',

text = 'Not promoted',

aliases = {'fail', 'failed'}

}

}

},

FLR = {

id = 'FLR',

name = 'Featured list removal candidate',

results = {

kept = {

id = 'kept',

text = 'Kept',

aliases = {'pass', 'passed', 'keep'}

},

demoted = {

id = 'demoted',

text = 'Demoted',

aliases = {'fail', 'failed', 'remove', 'removed'}

},

merged = {

id = 'merged',

text = 'Merged',

aliases = {'merge'}

}

},

categories = function (articleHistoryObj, actionObj)

local ret = {}

local result = actionObj.resultId

if result == 'demoted' or result == 'merged' then

local sortKey

if articleHistoryObj:getStatusId() == 'FL' then

sortKey = '#' .. articleHistoryObj.currentTitle.subjectPageTitle.prefixedText

else

sortKey = articleHistoryObj.currentTitle.text

end

ret[#ret + 1] = Category.new(

'Wikipedia former featured lists',

sortKey

)

end

return ret

end

},

FTC = {

id = 'FTC',

name = 'Featured topic candidate',

results = {

promoted = {

id = 'promoted',

text = 'Promoted',

aliases = {'pass', 'passed'}

},

['not promoted'] = {

id = 'not promoted',

text = 'Not promoted',

aliases = {'fail', 'failed'}

}

}

},

FTR = {

id = 'FTR',

name = 'Featured topic removal candidate',

results = {

kept = {

id = 'kept',

text = 'Kept',

aliases = {'pass', 'passed', 'keep'}

},

demoted = {

id = 'demoted',

text = 'Demoted',

aliases = {'fail', 'failed', 'remove', 'removed'}

},

merged = {

id = 'merged',

text = 'Merged',

aliases = {'merge'}

}

}

},

FPOC = {

id = 'FPOC',

name = 'Featured portal candidate',

results = {

promoted = {

id = 'promoted',

text = 'Promoted',

aliases = {'pass', 'passed'}

},

['not promoted'] = {

id = 'not promoted',

text = 'Not promoted',

aliases = {'fail', 'failed'}

}

}

},

FPOR = {

id = 'FPOR',

name = 'Featured portal review',

results = {

kept = {

id = 'kept',

text = 'Kept',

aliases = {'pass', 'passed', 'keep'}

},

demoted = {

id = 'demoted',

text = 'Demoted',

aliases = {'fail', 'failed', 'remove', 'removed'}

},

merged = {

id = 'merged',

text = 'Merged',

aliases = {'merge'}

}

}

},

GAN = {

id = 'GAN',

name = 'Good article nominee',

aliases = {'GAC'},

results = {

listed = {

id = 'listed',

text = 'Listed',

aliases = {'pass', 'passed', 'promoted'}

},

['not listed'] = {

id = 'not listed',

text = 'Not listed',

aliases = {'fail', 'failed', 'not promoted'}

}

},

categories = function (articleHistoryObj, actionObj)

local ret = {}

if actionObj.resultId == 'not listed' then

local status = articleHistoryObj:getStatusId()

if status ~= 'FA'

and status ~= 'GA'

and status ~= 'FFA'

then

ret[#ret + 1] = Category.new(

'Former good article nominees',

articleHistoryObj.currentTitle.text

)

end

end

return ret

end

},

GAR = {

id = 'GAR',

name = 'Good article reassessment',

results = {

kept = {

id = 'kept',

text = 'Kept',

aliases = {'pass', 'passed', 'keep'}

},

delisted = {

id = 'delisted',

text = 'Delisted',

aliases = {'fail', 'failed'}

},

listed = {

id = 'listed',

text = 'Listed'

},

['not listed'] = {

id = 'not listed',

text = 'Not listed'

}

},

categories = function (articleHistoryObj, actionObj)

local ret = {}

if actionObj.resultId == 'delisted' then

local status = articleHistoryObj:getStatusId()

if status ~= 'FA'

and status ~= 'GA'

then

ret[#ret + 1] = Category.new(

'Delisted good articles',

articleHistoryObj.currentTitle.text

)

end

end

end

},

GTC = {

id = 'GTC',

name = 'Good topic candidate',

results = {

promoted = {

id = 'promoted',

text = 'Promoted',

aliases = {'pass', 'passed'}

},

['not promoted'] = {

id = 'not promoted',

text = 'Not promoted',

aliases = {'fail', 'failed'}

}

}

},

GTR = {

id = 'GTR',

name = 'Good topic removal candidate',

results = {

kept = {

id = 'kept',

text = 'Kept',

aliases = {'pass', 'passed', 'keep'}

},

demoted = {

id = 'demoted',

text = 'Demoted',

aliases = {'fail', 'failed', 'remove', 'removed'}

},

merged = {

id = 'merged',

text = 'Merged',

aliases = {'merge'}

}

}

},

PR = {

id = 'PR',

name = 'Peer review',

results = {

reviewed = {

id = 'reviewed',

text = 'Reviewed',

aliases = {'_BLANK'}

},

['not reviewed'] = {

id = 'not reviewed',

text = 'Not reviewed',

}

},

categories = {'Old requests for peer review'}

},

WPR = {

id = 'WPR',

name = function (articleHistoryObj, actionObj)

local names = {

approved = 'WikiProject approved revision',

copyedited = 'Guild of Copy Editors',

collaboration = 'WikiProject collaboration',

maindate = "Today's featured article"

}

local result = actionObj.resultId

return result and names[result] or 'WikiProject peer review'

end,

results = {

approved = {

id = 'approved',

text = function(articleHistoryObj, actionObj)

if actionObj.oldid then

local url = mw.uri.fullUrl(

articleHistoryObj.currentTitle.prefixedText,

{diff = 'cur', oldid = actionObj.oldid}

)

return string.format(

'[%s %s]',

tostring(url),

'Diff to current version'

)

else

error(string.format(

"No oldid detected for the approved version; " ..

"please set the 'action%doldid' parameter " ..

"or give the 'action%dresult' parameter a " ..

"different value.",

actionObj.paramNum,

actionObj.paramNum

))

end

end,

aliases = {'approved version'}

},

copyedited = {

id = 'copyedited',

text = 'Copyedited',

aliases = {'copyedit', 'proofread'}

},

maindate = {

id = 'maindate',

text = 'Main Page'

},

collaborated = {

id = 'collaborated',

text = 'Collaborated',

aliases = {'cotw', 'collaboration'}

},

reviewed = {

id = 'reviewed',

text = 'Reviewed',

aliases = {'_BLANK'}

}

},

categories = function (articleHistoryObj, actionObj)

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 = {

id = 'WAR',

name = 'WikiProject A-class review',

results = {

approved = {

id = 'approved',

text = 'Approved',

aliases = {'pass', 'passed'}

},

['not approved'] = {

id = 'not approved',

text = 'Not approved',

aliases = {'fail', 'failed', 'not reviewed'}

},

reviewed = {

id = 'reviewed',

text = 'Reviewed',

aliases = {'_BLANK'}

},

kept = {

id = 'kept',

text = 'Kept',

aliases = {'keep'}

},

demoted = {

id = 'demoted',

text = 'Demoted',

aliases = {'demote'}

}

}

},

AFD = {

id = 'AFD',

name = 'Articles for deletion',

results = {

kept = {

id = 'kept',

text = 'Kept',

aliases = {'withdrawn', 'keep'}

},

deleted = {

id = 'deleted',

text = 'Deleted',

aliases = {'delete'}

},

merged = {

id = 'merged',

text = 'Merged',

aliases = {'merge'}

},

['no consensus'] = {

id = 'no consensus',

text = 'No consensus'

},

['speedily kept'] = {

id = 'speedily kept',

text = 'Speedily kept',

aliases = {'speedy keep'}

},

['speedily deleted'] ={

id = 'speedily deleted',

text = 'Speedily deleted',

aliases = {'speedy delete'}

},

redirected = {

id = 'redirected',

text = 'Redirected',

aliases = {'redirect'}

},

renamed = {

id = 'renamed',

text = 'Renamed',

aliases = {'rename', 'move', 'moved'}

},

}

},

MFD = {

id = 'MFD',

name = 'Miscellany for deletion',

results = {

kept = {

id = 'kept',

text = 'Kept',

aliases = {'withdrawn', 'keep'}

},

deleted = {

id = 'deleted',

text = 'Deleted',

aliases = {'delete'}

},

merged = {

id = 'merged',

text = 'Merged',

aliases = {'merge'}

},

['no consensus'] = {

id = 'no consensus',

text = 'No consensus'

},

['speedily kept'] = {

id = 'speedily kept',

text = 'Speedily kept',

aliases = {'speedy keep'}

},

['speedily deleted'] = {

id = 'speedily deleted',

text = 'Speedily deleted',

aliases = {'speedy delete'}

},

redirected = {

id = 'redirected',

text = 'Redirected',

aliases = {'redirect'}

},

renamed = {

id = 'renamed',

text = 'Renamed',

aliases = {'rename', 'move', 'moved'}

},

}

},

TFD = {

id = 'TFD',

name = 'Templates for discussion',

results = {

kept = {

id = 'kept',

text = 'Kept',

aliases = {'withdrawn', 'keep'}

},

deleted = {

id = 'deleted',

text = 'Deleted',

aliases = {'delete'}

},

merged = {

id = 'merged',

text = 'Merged',

aliases = {'merge'}

},

['no consensus'] = {

id = 'no consensus',

text = 'No consensus'

},

['speedily kept'] = {

id = 'speedily kept',

text = 'Speedily kept',

aliases = {'speedy keep'}

},

['speedily deleted'] = {

id = 'speedily deleted',

text = 'Speedily deleted',

aliases = {'speedy delete'}

},

redirected = {

text = 'Redirected',

aliases = {'redirect'}

},

renamed = {

id = 'renamed',

text = 'Renamed',

aliases = {'rename', 'move', 'moved'}

},

}

},

CSD = {

id = 'CSD',

name = 'Candidate for speedy deletion',

results = {

kept = {

id = 'kept',

text = 'Kept',

aliases = {'withdrawn', 'keep'}

},

deleted = {

id = 'deleted',

text = 'Deleted',

aliases = {'delete', 'speedily deleted', 'speedy delete'}

},

['speedily kept'] = {

id = 'speedily kept',

text = 'Speedily kept',

aliases = {'speedy keep'}

},

redirected = {

id = 'redirected',

text = 'Redirected',

aliases = {'redirect'}

},

prod = {

id = 'prod',

text = 'Converted to proposed deletion',

aliases = {'prodded'}

},

afd = {

id = 'afd',

text = 'Sent to articles for deletion',

aliases = {'afded'}

},

renamed = {

id = 'renamed',

text = 'Renamed',

aliases = {'rename', 'move', 'moved'}

},

}

},

PROD = {

id = 'PROD',

name = 'Proposed deletion',

results = {

kept = {

id = 'kept',

text = 'Kept',

aliases = {'withdrawn', 'keep'}

},

deleted = {

id = 'deleted',

text = 'Deleted',

aliases = {'delete'}

},

['speedily kept'] = {

id = 'speedily kept',

text = 'Speedily kept',

aliases = {'speedy keep'}

},

['speedily deleted'] = {

id = 'speedily deleted',

text = 'Speedily deleted',

aliases = {'speedy delete'}

},

redirected = {

id = 'redirected',

text = 'Redirected',

aliases = {'redirect'}

},

afd = {

id = 'afd',

text = 'Sent to articles for deletion',

aliases = {'afded'}

},

renamed = {

id = 'renamed',

text = 'Renamed',

aliases = {'rename', 'move', 'moved'}

},

}

},

DRV = {

id = 'DRV',

name = 'Deletion review',

results = {

endorsed = {

id = 'endorsed',

text = 'Endorsed',

aliases = {'endorse'}

},

relisted = {

id = 'relisted',

text = 'Relisted',

aliases = {'relist'}

},

overturned = {

id = 'overturned',

text = 'Overturned',

aliases = {'overturn'}

},

restored = {

id = 'restored',

text = 'Restored',

aliases = {'restore'}

},

['no consensus'] = {

id = 'no consensus',

text = 'No consensus'

}

}

}

},

-------------------------------------------------------------------------------

-- Collapsible notices

-------------------------------------------------------------------------------

-- The collapsibleNotices table contains configuration tables for notices that

-- go in the collapsible part of the template, underneath the actions.

-- 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 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 = '' .. fact .. ''

end

local blurb = "A " .. fact .. " appeared on " ..

"Wikipedia's Main Page in the " ..

"\"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

},

-- ITN

{

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 " ..

"\"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

},

-- On This Day

{

id = 'OTD',

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 " ..

"\"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

},

-- Article Collaboration and Improvement Drive

{

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 ' ..

'Article Collaboration and Improvement Drive ' ..

'for the week of %s.'

local date = validateDate('aciddate', args.aciddate)

return string.format(blurb, date)

end

},

-- League of Copy Editors

{

id = 'LOCE',

isActive = function (articleHistoryObj)

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 ' ..

'League of Copyeditors.'

}

},

-------------------------------------------------------------------------------

-- Notice bar icons

-------------------------------------------------------------------------------

-- This table holds configuration tables for notice bar icons that don't appear

-- as part of a row. Other notice bar icons are handled in the statuses,

-- notices, actions, and collapsibleNotices tables.

-- It accepts the following fields:

-- 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.

-- icon: the filename of the notice bar icon, minus the "File:" prefix.

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,

},

-------------------------------------------------------------------------------

-- Parameters

-------------------------------------------------------------------------------

-- The parameter values used to generate the page actions. These are used as

-- Lua patterns, so any of the magic characters *+-.^$%[] should be escaped

-- with a preceding % symbol.

actionParamPrefix = 'action',

actionParamSuffixes = {

[''] = 'code',

date = 'date',

link = 'link',

result = 'resultCode',

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',

-------------------------------------------------------------------------------

-- Messages

-------------------------------------------------------------------------------

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 (help).',

['error-message-nohelp'] = 'Error: $1.',

['warning-help'] = 'Warning: $1 (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

-------------------------------------------------------------------------------

}