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 undefined template. local function makeTemplateLink(s) local openb = 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 failed. 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 failed. " .. "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') ret[#ret + 1] = Category.new('Wikipedia CD Selection-GAs') 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 failed." },	FPO = { id = 'FPO', name = 'Featured portal', icon = 'Cscr-featured.svg', text = "The $2 Portal is a featured portal, " .. "which means it has been " .. "identified " .. "as one of the best portals on Wikipedia. " .. "If you see a way this portal can be updated or improved without " .. "compromising previous work, please feel free to contribute.", 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.", categories = function (articleHistoryObj) return {Category.new(				'Wikipedia featured portal candidates (contested)',				articleHistoryObj.currentTitle.text			)} end },	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 ---

}