<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://mywikibiz.com/index.php?action=history&amp;feed=atom&amp;title=Module%3AProgress_box</id>
	<title>Module:Progress box - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://mywikibiz.com/index.php?action=history&amp;feed=atom&amp;title=Module%3AProgress_box"/>
	<link rel="alternate" type="text/html" href="https://mywikibiz.com/index.php?title=Module:Progress_box&amp;action=history"/>
	<updated>2026-06-21T16:03:11Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.35.3</generator>
	<entry>
		<id>https://mywikibiz.com/index.php?title=Module:Progress_box&amp;diff=479037&amp;oldid=prev</id>
		<title>Zoran: Pywikibot 6.4.0</title>
		<link rel="alternate" type="text/html" href="https://mywikibiz.com/index.php?title=Module:Progress_box&amp;diff=479037&amp;oldid=prev"/>
		<updated>2021-07-16T05:25:23Z</updated>

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