Модуль:NumberOf

З пляцоўкі Вікіпедыя
Jump to navigation Jump to search
(i) Дакументацыя

Дадзены модуль выкарыстоўваецца для паказу і абнаўлення статыстыкі на старонцы Спіс Вікіпедый. Падстаронкі з дадзенымі гэтага модуля перыядычна абнаўляюцца ботам MBHbot. Калі ласка, не праўце модуль самастойна!

Выкарыстанне

  • {{#invoke:NumberOf|Editions}} — вывад спісу Вікіпедый па мовах, з поўнай статыстыкай.
  • {{#invoke:NumberOf|Today|wiki=en|param=articles}} — вывад колькасці артыкулаў канкрэтнага моўнага раздзелу Вікіпедыі (нефарматаванае значэнне). Прыклад: у Англійскай Вікіпедыі налічваецца 6398087 артыкулаў.
  • {{#invoke:NumberOf|Today|wiki=en|param=articles|fmt=N}} — Той жа параметр (фарматаванае значэнне). Прыклад: у Англійскай Вікіпедыі налічваецца 6 398 087 артыкулаў.

Канкрэтны моўны раздзел Вікіпедыі пазначаецца функцыяй wiki (абавязковая функцыя) і кодам мовы. Напрыклад у кодах вышэй прысутнічае функцыя wiki=en, дзе en — код Англійскай Вікіпедыі. Змяняючы апошні можна паказваць статыстыку любога моўнага раздзела. Коды для ўсіх моўных раздзелаў можна знайсці ў спісе Вікіпедый

Функцыя Today у кодах вышэй паказае статыстыку раздзелаў па стане на 0:00 (UTC) сённяшняй даты, інфармацыя бярэцца з падстаронкі NumberOf/today, якая абнаўляецца раз у суткі ботам MBHbot. Па тым жа прынцыпе можна адлюстроўваць больш актуальную статыстыку на дадзены момант, для гэтага патрэбна змяніць функцыю Today на функцыю Now, апошняя будзе выводзіць інфармацыю з падстаронкі NumberOf/data, якая абнаўляецца ботам раз у 2 гадзіны. Калі ласка, не праўце модулі самастойна! Пры неабходнасці зменаў звярніцеся на старонку размоў дадзенага модуля.

Увага! Беларускі раздзел Вікіпедыі праз дадзены модуль таксама абнаўляецца раз у дзве гадзіны. Але для яго існуе статыстыка ў рэальным часе, каб яе выкарыстаць, скарыстайцеся шаблонам NUMBEROF.

Функцыі

Коды вышэй, якія паказваюць колькасць артыкулаў, па тым жа прынцыпе могуць адлюстроўваць іншыя паказчыкі канкрэтнага моўнага раздзела, для гэтага дастаткова змяніць у кодзе функцыю articles на адну з наступных:

  • admins — колькасць адміністратараў,
  • activeusers — колькасць актыўных удзельнікаў,
  • date — дата абнаўлення дадзеных у модулі,
  • depth — глыбіня раздзела,
  • edits — колькасць правак у раздзеле,
  • files — колькасць файлаў,
  • pages — колькасць старонак,
  • pos — месца раздзела па колькасці артыкулаў (гл. спіс Вікіпедый),
  • users — колькасць удзельнікаў.


Каб пазбегнуць паломак старонак, якія выкарыстоўваюць гэты модуль, пажадана эксперыментаваць у пясочніцы для модуляў.


-- Модуль для выкарыстання серыі NUMBEROF і старонкі [[Вікіпедыя:Спіс Вікіпедый]]

local p = {}

-- Важнейшыя пераменныя
local mwlang = mw.getContentLanguage()
local langs = mw.loadData('Module:NumberOf/lang')

-- Раздзелы Вікіпедыі закрытыя для рэдагавання
local readOnly = {
	aa = true,
	cho = true,
	ho = true,
	hz = true,
	ii = true,
	kj = true,
	kr = true,
	lrc = true,
	mh = true,
	mus = true,
	ng = true
}

-- Праверка пустэчы параметра
local function isEmpty(s)
	return s == nil or s == ''
end

-- Акругленне да сотых
local function round(n)
	return math.floor(n * 100) / 100
end

-- Фарміраванне даты
local function formatDate(val)
	return mwlang:formatDate('j xg Y, G:i', val) .. ' (UTC)'
end

-- Даўжыня табліцы
local function tableLength(t)
	local count = 0
	for _ in pairs(t) do count = count + 1 end
	return count
end

-- Вылічэнне вікі па дададзеным нумары
local function calculatePosition(pos, info)
	pos = tonumber(pos)
	for key in pairs(info) do
		if key ~= 'total' and info[key]['pos'] == pos then
			return key
		end
	end
	
	return ''
end

-- Рэндэрынг неабходнага параметра з старонкі з дадзенымі
local function getParam(f, info)
	-- Парсінг параметраў шаблона
	local wiki = f.wiki
	local param = f.param
	local fmt = f.fmt
	
	-- Калі няма абавязковых параметраў, выводзіцца нуль
	local result
	if isEmpty(wiki) or isEmpty(param) then
		result = 0
	else
		-- Прыбіраем NUMBEROF з легасі-кода параметраў
		param = param:lower():gsub('numberof','')
		
		if param == 'date' then
			result = formatDate(info['total']['date'])
			return result
		end
		
		if param == 'pos' and tonumber(wiki) ~= nil then
			-- 
			result = calculatePosition(wiki, info)
			return result
		end
		
		-- Разлікі для агульнай колькасці раздзелаў
		if wiki == 'total' then
			if param == 'all' then
				result = tableLength(info) - 1
			end
			if param == 'active' then
				result = tableLength(info) - 1 - tableLength(readOnly)
			end
		end
		
		local obj = info[wiki]
		if obj ~= nil then
			if param ~= nil and info[wiki][param] ~= nil then
				result = info[wiki][param]
				
				-- Фарматуем значэнне, калі зададзены параметр
				if not isEmpty(fmt) and type(result) == 'number' then
					if param == 'depth' then
						result = math.floor(result * 100) / 100
					end
					result = mwlang:formatNum(result)
				end
			end
		else
			result = 0
		end
	end
	return tostring(result)
end

-- Вывад спасылкі на моўны раздзел
local function renderLink(val, text)
	local text = (isEmpty(text) and val or text)
	
	local result = ''
	if val ~= mwlang:getCode() then
		result = result .. '[[:' .. val ..  ':|'
		
		if readOnly[val] == true then
			result = result .. string.format('<s title="Дадзены раздзел закрыты, і даступны толькі ў рэжыме для чытання">%s</s>', text)
		else
			result = result .. text
		end
		
		result = result .. ']]'
	else
		result = result .. text
	end
	return result
end

-- Вывад назвы мовы
local function renderLang(val, frame)
	local text = langs[val] and langs[val][1] or mwlang:ucfirst(mw.language.fetchLanguageName(val))
	local link = langs[val] and langs[val][2] or nil
	local result = text
	if readOnly[val] == true then
		result = '<s title="Дадзены раздзел закрыты, і даступны толькі ў рэжыме для чытання">' .. text .. '</s> (закрыты)'
	end
	
	if not isEmpty(link) then
		result = string.format('[[:%s|%s]]', link, result)
	end

	if val == mwlang:getCode() then
		result = result .. ' [[File:Watch-icon-hl.svg|16px|text-top|alt=(наш раздзел)|link=]]'
	end
	
	return result
end

-- Функцыя для вываду ячэйкі
local function renderNum(val, key, stats)
	local text = mwlang:formatNum(val)
	if isEmpty(stats) or val == 0 then
		return text
	end
	
	return string.format(
		'[[:%s:%s|%s]]',
		key,
		stats,
		text
	)
end

-- Функцыя для вываду радка табліцы
local function createRow(key, val, frame)
	local result = mw.html.create('tr')
		:css('text-align', 'right')
	if key == mwlang:getCode() then
		result
			:css('background', '#edb5f7')
			:css('font-weight', 'bold')
	end
	
	result:tag('td')
		:wikitext(val['pos'])
	
	result:tag('td')
		:wikitext(renderLink(key))
	
	result:tag('td')
		:wikitext(renderLang(key, frame))
		:css('text-align', 'left')
	
	result:tag('td')
		:wikitext(renderNum(val['articles'], key, 'Special:Statistics'))
	
	result:tag('td')
		:wikitext(renderNum(val['pages']))
	
	result:tag('td')
		:wikitext(renderNum(val['edits']))
	
	result:tag('td')
		:wikitext(renderNum(round(val['depth'])))
	
	result:tag('td')
		:wikitext(renderNum(val['users'], key, 'Special:ListUsers'))
	
	result:tag('td')
		:wikitext(renderNum(val['activeusers'], key, 'Special:ActiveUsers'))
	
	result:tag('td')
		:wikitext(renderNum(val['admins'], key, 'Special:ListAdmins'))
	
	result:tag('td')
		:wikitext(renderNum(val['files'], key, 'Special:ListFiles'))
	
	return result
end

-- Функцыя для вываду шапкі табліцы
local function createHeader()
	local result = mw.html.create('table')
		:addClass('wikitable sortable')
		:attr('style', 'font-feature-settings:"tnum" 1; margin:0.25em 0; width:100%;')
		:css('width', '100%')
		:css('margin', '0.25em 0')
	
	result:tag('tr')
	
	local cells = {
		'№',
		'Код',
		'Мова',
		'Артыкулаў',
		'Старонак',
		'Правак',
		'<abbr title="Глыбіня">Глыб.</abbr>',
		'Удзельнікаў',
		'<abbr title="Актыўных удзельнікаў">(акт.)</abbr>',
		'<abbr title="Адміністратараў">Адм.</abbr>',
		'Файлаў',
	}
	
	for i, val in ipairs(cells) do
		result
			:tag('th')
			:attr('scope', 'col')
			:css('text-align', (val == 'Язык' and 'left' or 'right'))
			:css('width', (val == 'Язык' and '25%' or nil))
			:wikitext(val)
	end
	
	return result
end

-- Функцыя для вываду дна табліцы
local function createFooter(frame, hide)
		-- Параметр hide адказвае за аптычнае выраўнованне табліц
	local val = frame['total']
	local cellStyle = 'text-align:right;'
	local cellStyleHide = 'color:transparent; padding:0; white-space:nowrap;'
	if hide then
		cellStyle = 'padding:0;' .. cellStyle
	end
	
	-- aa — закрыты раздзел з самай вялікай глыбінёй
	local num = tableLength(frame) - 1
	local depth = (hide and round(frame['aa']['depth']) or round(val['depth']))
	local result = mw.html.create('tr')
		:addClass('sortbottom' .. (hide and ' nomobile' or ''))
		:attr('style', (hide and ' line-height:0; visibility:hidden; white-space:nowrap;' or ''))
	
	if hide then
		result:attr('aria-hidden', 'true')
	end
	
	result:tag('th')
		:wikitext(string.format('<span aria-hidden="true">%s</span>', num))
		:attr('style', cellStyleHide)
	
	-- zh-classical — самая доўгая назва раздзела
	result:tag('th')
		:wikitext('<span aria-hidden="true">zh-classical</span>')
		:attr('style', cellStyleHide)
	
	result:tag('th')
		:attr('scope', 'col')
		:wikitext('Усяго')
		:attr('style', cellStyle)
		:css('text-align', 'left')
	
	result:tag('th')
		:attr('scope', 'col')
		:wikitext(renderNum(val['articles']))
		:attr('style', cellStyle)
	
	result:tag('th')
		:attr('scope', 'col')
		:wikitext(renderNum(val['pages']))
		:attr('style', cellStyle)
	
	result:tag('th')
		:attr('scope', 'col')
		:wikitext(renderNum(val['edits']))
		:attr('style', cellStyle)
	
	result:tag('th')
		:attr('scope', 'col')
		:wikitext(renderNum(depth))
		:attr('style', cellStyle)
	
	result:tag('th')
		:attr('scope', 'col')
		:wikitext(renderNum(val['users']))
		:attr('style', cellStyle)
	
	result:tag('th')
		:attr('scope', 'col')
		:wikitext(renderNum(val['activeusers']))
		:attr('style', cellStyle)
	
	result:tag('th')
		:attr('scope', 'col')
		:wikitext(renderNum(val['admins']))
		:attr('style', cellStyle)
	
	result:tag('th')
		:attr('scope', 'col')
		:wikitext(renderNum(val['files']))
		:attr('style', cellStyle)
	
	return result
end

-- Функцыя для вываду ў {{NUMBEROF}}
function p.Now(frame)
	local data = mw.loadData('Модуль:NumberOf/data')
	
	return getParam(frame.args, data)
end

-- Функцыя для вываду ў {{TODAYNUMBEROF}}
function p.Today(frame)
	local data = mw.loadData('Модуль:NumberOf/today')
	
	return getParam(frame.args, data)
end

-- Функцыя для вываду ў [[Вікіпедыя:Спіс Вікіпедый]]
function p.Editions(frame)
	local data = mw.loadData('Модуль:NumberOf/today')
	local length = tableLength(data)
	local result = ''
	
	-- Таблица для збору раздзелаў па велічыні
	local sorted = {
		[1000000] = {},
		[100000] = {},
		[10000] = {},
		[1000] = {},
		[0] = {}
	}
	local sortedKeys = { 0, 1000, 10000, 100000, 1000000 }
	
	-- Запаўняем пустымі элементамі кожную табліцу
	for i = #sortedKeys, 1, -1 do
		local n = sortedKeys[i]
		for j = 1, length, 1 do
			table.insert(sorted[n], false)
		end
	end
	
	-- Сартаванне раздзелаў па пазіцыі і велічыні
	for key, val in pairs(data) do
		local curr = data[key]
		if key ~= 'total' then
			if curr['articles'] <= 1000 then
				sorted[ 0 ][ tonumber(curr['pos']) ] = key
			else
				for i = #sortedKeys, 2, -1 do
					local n = sortedKeys[i]
					if curr['articles'] / n > 1 then
						sorted[ n ][ tonumber(curr['pos']) ] = key
						break
					end
				end
			end
		end
	end
	
	-- Вывад табліцы
	for i = #sortedKeys, 1, -1 do
		if i ~= #sortedKeys then
			result = result .. '\n'
		end
		
		local n = sortedKeys[i]
		if n == 0 then 
			result = result .. '=== Меньш за 1 000 артыкулаў ==='
		else
			result = result .. string.format('=== Больш за %s артыкулаў ===', mwlang:formatNum(n))
		end
		
		-- Аўтаматычны скрол для недастаткова шырокіх манітораў
		local section = mw.html.create('div')
			:attr('style', 'overflow-x:auto; overflow-y:hidden;')
		
		local sectionTable = createHeader()

		-- Вывад радкоў табліцы
		for _, val in ipairs(sorted[n]) do
			if val ~= false then
				local curr = data[val]
				sectionTable:node(createRow(val, curr, frame))
			end
		end
		
		-- Вывад дна табліцы
		sectionTable:node(createFooter(data, (n ~= 0)))
		section:node(sectionTable)
		
		result = result .. '\n' .. tostring(section)
	end
	
	return result
end

return p