Module:Article history

This is an old revision of this page, as edited by Mr. Stradivarius (talk | contribs) at 10:54, 18 October 2014 (use a different scheme for making categories). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

-------------------------------------------------------------------------------
--                            Article history
--
-- This module allows editors to link to all the significant events in an
-- article's history, such as good article nominations and featured article
-- nominations. It also displays its current status, as well as other
-- information, such as the date it was featured on the main page.
-------------------------------------------------------------------------------

local CONFIG_PAGE = 'Module:Article history/config'
local WRAPPER_TEMPLATE = 'Template:Article history'

-------------------------------------------------------------------------------
-- Helper functions
-------------------------------------------------------------------------------

local function isPositiveInteger(num)
	return type(num) == 'number'
		and math.floor(num) == num
		and num > 0
		and num < math.huge
end

local function substituteParams(msg, ...)
	return mw.message.newRawMessage(msg, ...):plain()
end

-------------------------------------------------------------------------------
-- Action class
-- Action objects deal with a single action in the history of the article. We
-- use getter methods rather than properties for the name and result, etc., as
-- their processing needs to be delayed until after the status object has been
-- initialised. The status object needs to parse the action objects when it is
-- initialised, and the value of some names, etc., in the action objects depend
-- on the status object, so this is necessary to avoid errors/infinite loops.
-------------------------------------------------------------------------------

local Action = {}
Action.__index = Action

-- Properties to implement:
-- * id
-- * oldid
-- * paramNum
-- * cfg
-- * actionCfg
-- * currentTitle

function Action.new(data)
	-- Valid data table keys:
	-- code, result, link, paramNum, cfg, currentTitle
	local obj = setmetatable({}, Action)

	obj.cfg = data.cfg
	obj.currentTitle = data.currentTitle
	obj.paramNum = data.paramNum

	-- Set the ID
	obj.id = obj.cfg.actions[data.code] and obj.cfg.actions[data.code].id
	if not obj.id then
		-- @TODO: Error
	end

	-- Add a shortcut for this action's config.
	obj.actionCfg = obj.cfg.actions[obj.id]

	-- Set the oldid
	obj.oldid = tonumber(data.oldid)
	if obj.oldid and not isPositiveInteger(obj.oldid) then
		-- @TODO: Error
	end

	return obj
end

function Action:getName()
end

function Action:getLink()
end

function Action:getResult()
end

function Action:getText()
end

function Action:getCategory()
end

-------------------------------------------------------------------------------
-- Header
-- Header objects are displayed at the top of the template, above the
-- collapsed section. They usually have an image and a blurb.
-------------------------------------------------------------------------------

local Header = {}
Header.__index = Header

-------------------------------------------------------------------------------
-- Status class
-- Status objects deal with possible current statuses of the article.
-------------------------------------------------------------------------------

local Status = {}
Status.__index = Status

-------------------------------------------------------------------------------
-- DoubleStatus class
-- For when an article can have two distinct statuses, e.g. former featured
-- article status and good article status.
-------------------------------------------------------------------------------

local DoubleStatus = {}
DoubleStatus.__index = DoubleStatus

-------------------------------------------------------------------------------
-- Notice class
-- Notice objects contain notices about an article that aren't time-dependent
-- and aren't part of its current status, e.g. the topic area of a good
-- article, or the date the article was featured on DYK.
-------------------------------------------------------------------------------

local Notice = {}
Notice.__index = Notice

-------------------------------------------------------------------------------
-- ArticleHistory class
-- This class represents the whole template.
-------------------------------------------------------------------------------

local ArticleHistory = {}
ArticleHistory.__index = ArticleHistory

function ArticleHistory.new(args, cfg, currentTitle)
	local obj = setmetatable({}, ArticleHistory)

	-- Set input
	obj.args = args or {}
	obj.currentTitle = currentTitle or mw.title.getCurrentTitle()

	-- Define object structure
	obj.actions = {}
	
	-- Format the config
	local function substituteAliases(t, ret)
		-- This function substitutes strings found in an "aliases" subtable
		-- as keys in the parent table. It works recursively, so "aliases"
		-- subtables can be placed at any level. It assumes that tables will
		-- not be nested recursively, which should be true in the case of our
		-- config file.
		ret = ret or {}
		for k, v in pairs(t) do
			if k ~= 'aliases' then
				if type(v) == 'table' then
					local newRet = {}
					ret[k] = newRet
					if v.aliases then
						for _, alias in ipairs(v.aliases) do
							ret[alias] = newRet
						end
					end
					substituteAliases(v, newRet)
				else
					ret[k] = v
				end
			end
		end
		return ret
	end
	obj.cfg = substituteAliases(cfg or require(CONFIG_PAGE))
	
	-- Initialize action objects.
	do
		-- Filter the arguments for actions.
		local actionParams = {}
		local pattern = '^' .. obj.cfg.actionParamPrefix .. '([1-9][0-9]*)(.-)$'
		local suffixes = obj.cfg.actionParamSuffixes
		for k, v in pairs(obj.args) do
			if type(k) == 'string' then
				local num, suffix = key:match(pattern)
				if num and suffix and suffixes[suffix] then
					num = tonumber(num)
					local t = actionParams[num] or {}
					t[suffixes[suffix]] = v
					t.paramNum = num
					actionParams[num] = t
				end
			end
		end
		
		-- Sort the action parameters.
		local actionParamsSorted = {}
		for num, t in pairs(actionParams) do
			table.insert(actionParamsSorted, t)
		end
		table.sort(actionParamsSorted, function (t1, t2)
			return t1.num < t2.num
		end)
		
		-- Create the action objects.
		for _, t in ipairs(actionParamsSorted) do
			t.cfg = obj.cfg
			t.currentTitle = obj.currentTitle
			table.insert(obj.actions, Action.new(t))
		end
	end

	return obj
end

function ArticleHistory:getStatusId(code)
	-- Gets a status ID given a status code. If no code is specified, returns
	-- nil, and if the code is invalid, raises an error.
	if not code then
		return nil
	end
	local statuses = self.cfg.statuses
	code = mw.ustring.upper(code)
	if statuses[code] then
		return statuses[code].id
	else
		-- @TODO: Error
	end
end

function ArticleHistory:getStatusObj()
	-- Get the status object for the current status.
	if self.statusObj ~= nil then
		return self.statusObj
	end
	local statusId
	if self.cfg.getStatusIdFunction then
		statusId = self.cfg.getStatusIdFunction(self)
	else
		statusId = self:getStatusId(self.args.currentstatus)
	end
	if not statusId then
		self.statusObj = false
		return false
	end
	-- @TODO: Make new status object.
end

function ArticleHistory:renderBox()
end

function ArticleHistory:renderCategories()
	local ret = {}
	local categoryNsText = mw.site.namespaces[14].name

	local function makeCategory(cat, sortKey)
		if sortKey then
			return string.format('[[%s:%s|%s]]', categoryNsText, cat, sortKey)
		else
			return string.format('[[%s:%s]]', categoryNsText, cat)
		end
	end

	for _, actionObj in ipairs(self.actions) do
		ret[#ret + 1] = makeCategory(actionObj:getCategory())
	end

	return table.concat(ret)
end

function ArticleHistory:__tostring()
end

-------------------------------------------------------------------------------
-- Exports
-- These functions are called from Lua and from wikitext.
-------------------------------------------------------------------------------

local p = {}

function p._main(args)
end

function p.main(frame)
	local args = require('Module:Arguments').getArgs(frame, {
		wrappers = WRAPPER_TEMPLATE
	})
	return p._main(args)
end

function p._exportClasses()
	return {
		Action = Action,
		ImageRow = ImageRow,
		Status = Status,
		Notice = Notice,
		ArticleHistory = ArticleHistory
	}
end

return p