Module:Progress box
Appearance
![]() | This module depends on the following other modules: |
![]() | This module uses TemplateStyles: |
This module implements Template:Progress box. Please see the template page for usage instructions.
-- This module implements [[Template:Progress box]]
local makePurgeLink = require('Module:Purge')._main
local lang = mw.language.getContentLanguage()
local CONFIG_MODULE = 'Module:Progress box/config'
-------------------------------------------------------------------------------
-- Message mixin
--
-- This function is mixed into all of the other classes
-------------------------------------------------------------------------------
local function message(self, key, ...)
local msg = self._cfg[key]
if not msg then
error(string.format("no message found with key '%s'", tostring(key)), 2)
end
if select('#', ...) > 0 then
return mw.message.newRawMessage(msg, ...):plain()
else
return msg
end
end
-------------------------------------------------------------------------------
-- Category class
-------------------------------------------------------------------------------
local Category = {}
Category.__index = Category
Category.message = message
function Category.new(data)
local self = setmetatable({}, Category)
self._cfg = data.cfg
self._category = data.category
return self
end
function Category:getCategory()
return self._category
end
function Category:makeCategoryLink(display)
local cat = self:getCategory()
display = display or cat
return string.format('[[:Category:%s|%s]]', cat, display)
end
function Category:getCount()
-- @TODO: implement formatnum
if not self._count then
self._count = mw.site.stats.pagesInCategory(self:getCategory(), 'pages')
end
return self._count
end
function Category:exists()
return mw.title.makeTitle(14, self:getCategory()).exists
end
-------------------------------------------------------------------------------
-- DatedCategory class
-- Inherits from Category
-------------------------------------------------------------------------------
local DatedCategory = {}
DatedCategory.__index = DatedCategory
setmetatable(DatedCategory, Category)
function DatedCategory.new(data)
local self = setmetatable(Category.new(data), {__index = DatedCategory})
self._date = data.date
self._dateFormat = data.dateFormat or self:message('date-format')
self._formattedDate = self:formatDate(self._date)
self._category = self:message(
'dated-category-format',
data.undatedCategory,
self._formattedDate,
data.from or '',
data.suffix or ''
)
self._category = self._category:match('^%s*(.-)%s*$') -- trim whitespace
return self
end
function DatedCategory:formatDate(date)
return lang:formatDate(self._dateFormat, date)
end
function DatedCategory:getDate()
return self._date
end
function DatedCategory:getFormattedDate()
return self._formattedDate
end
-------------------------------------------------------------------------------
-- ProgressBox class
-------------------------------------------------------------------------------
local ProgressBox = {}
ProgressBox.__index = ProgressBox
ProgressBox.message = message
function ProgressBox.new(args, cfg, title)
local self = setmetatable({}, ProgressBox)
-- Argument defaults
args = args or {}
self._cfg = cfg or mw.loadData(CONFIG_MODULE)
self._title = title or mw.title.getCurrentTitle()
-- Set data
self._float = args.float or 'left'
self._margin = args.float == 'none' and 'auto' or nil
self._header = args[1]
self._frame = mw.getCurrentFrame()
-- Make the undated category object
do
local undatedCategory = args[2] or args[1]
if not undatedCategory then
error('no category specified', 3)
end
self._undatedCategoryObj = Category.new{
cfg = self._cfg,
category = undatedCategory,
}
end
-- Make datedCategory objects
self._datedCategories = {}
do
local cfg = self._cfg
local undatedCategory = self._undatedCategoryObj:getCategory()
local from = args.from or self:message('dated-category-format-from')
local suffix = args.suffix
local currentDate = lang:formatDate('Y-m')
local date = self:findEarliestCategoryDate()
local dateFormat = self:message('date-format')
while date <= currentDate do
local datedCategoryObj = DatedCategory.new{
cfg = cfg,
undatedCategory = undatedCategory,
from = from,
suffix = suffix,
date = date,
dateFormat = dateFormat,
}
if datedCategoryObj:getCount() > 0 then
table.insert(self._datedCategories, datedCategoryObj)
end
date = ProgressBox.incrementDate(date)
end
end
-- Make all-article category object
do
local allCategory
if args[3] then
allCategory = args[3]
else
allCategory = self:message(
'all-articles-category-format',
self._undatedCategoryObj:getCategory()
)
allCategory = self._frame:preprocess(allCategory)
end
self._allCategoryObj = Category.new{
cfg = self._cfg,
category = allCategory,
}
end
return self
end
-- Increments a date in the format YYYY-MM
function ProgressBox.incrementDate(date)
local year, month = date:match('^(%d%d%d%d)%-(%d%d)$')
year = tonumber(year)
month = tonumber(month)
if not year or not month then
error(string.format("error parsing date '%s'", tostring(date)), 2)
end
month = month + 1
if month > 12 then
month = 1
year = year + 1
end
return string.format('%04d-%02d', year, month)
end
function ProgressBox:findEarliestCategoryDate()
return self:message('start-date')
end
function ProgressBox:isCollapsed()
return self._title.namespace ~= 10 -- is not in template namespace
end
function ProgressBox:makeTotalLabel()
local display = self:message('all-articles-heading')
if self._allCategoryObj:exists() then
return self._allCategoryObj:makeCategoryLink(display)
else
return display
end
end
function ProgressBox:getTotalCount()
if self._allCategoryObj:exists() then
return self._allCategoryObj:getCount()
else
local count = 0
for i, obj in ipairs(self._datedCategories) do
count = count + obj:getCount()
end
count = count + self._undatedCategoryObj:getCount()
return count
end
end
function ProgressBox:__tostring()
data = data or {}
local root = mw.html.create('table')
-- Base classes and styles
root
:addClass('infobox')
:css('float', self._float)
:css('clear', self._float)
:css('margin', self._margin)
:css('width', '22em')
-- Header row
root:tag('tr'):tag('th')
:attr('colspan', 2)
:addClass('navbox-title')
:css('padding', '0.2em')
:css('font-size', '125%')
:wikitext(self._header)
-- Refresh row
root:tag('tr'):tag('th')
:attr('colspan', 2)
:css('text-align', 'center')
:wikitext(makePurgeLink{self:message('purge-link-display')})
-- Subtotals
local subtotalTable = root
:tag('tr')
:tag('th')
:attr('colspan', 2)
:css('padding', 0)
:tag('table')
:addClass('collapsible')
:addClass(self:isCollapsed() and 'collapsed' or nil)
:css('width', '100%')
:css('margin', 0)
for i, datedCategoryObj in ipairs(self._datedCategories) do
subtotalTable
:tag('tr')
:tag('td')
:wikitext(datedCategoryObj:makeCategoryLink(
datedCategoryObj:getFormattedDate()
))
:done()
:tag('td')
:css('text-align', 'right')
:wikitext(datedCategoryObj:getCount())
end
-- Undated articles
subtotalTable
:tag('tr')
:tag('td')
:wikitext(self._undatedCategoryObj:makeCategoryLink(
self:message('undated-category-link-display')
))
:done()
:tag('td')
:wikitext(self._undatedCategoryObj:getCount())
-- Total
root
:tag('tr')
:css('font-size', '110%')
:tag('th')
:wikitext(string.format("'''%s'''", self:makeTotalLabel()))
:done()
:tag('td')
:css('text-align', 'right')
:wikitext(string.format("'''%d'''", self:getTotalCount()))
return tostring(root)
end
-------------------------------------------------------------------------------
-- Exports
-------------------------------------------------------------------------------
local p = {}
function p._exportClasses()
return {
Category = Category,
DatedCategory = DatedCategory,
ProgressBox = ProgressBox,
}
end
function p._main(args, cfg, title)
return tostring(ProgressBox.new(args, cfg, title))
end
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {
wrappers = 'Template:Progress box'
})
return p._main(args)
end
return p