Модуль:NumberOf: различия между версиями
Перейти к навигации
Перейти к поиску
Mansur700 (обсуждение | вклад) (Новая страница: «-- Модуль для шаблонов серии NUMBEROF и страницы Тептар:Список Тептар local p = {} -- Важнейшие п...») |
Adam (обсуждение | вклад) Нет описания правки |
||
Строка 15: | Строка 15: | ||
kj = true, | kj = true, | ||
kr = true, | kr = true, | ||
lrc = true, | |||
mh = true, | mh = true, | ||
mus = true, | mus = true, | ||
Строка 40: | Строка 41: | ||
for _ in pairs(t) do count = count + 1 end | for _ in pairs(t) do count = count + 1 end | ||
return count | 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 | end | ||
-- Рендеринг необходимого параметра из страницы с данными | -- Рендеринг необходимого параметра из страницы с данными | ||
local function | local function getParam(f, info) | ||
-- Парсинг параметров шаблона | -- Парсинг параметров шаблона | ||
local wiki = f.wiki | local wiki = f.wiki | ||
Строка 54: | Строка 67: | ||
result = 0 | result = 0 | ||
else | else | ||
-- Убираем NUMBEROF из легаси-кода параметров | |||
param = param:lower():gsub('numberof','') | |||
if param == 'date' then | if param == 'date' then | ||
result = formatDate(info['total']['date']) | result = formatDate(info['total']['date']) | ||
return result | |||
end | |||
if param == 'pos' and tonumber(wiki) ~= nil then | |||
-- | |||
result = calculatePosition(wiki, info) | |||
return result | return result | ||
end | end | ||
Строка 71: | Строка 93: | ||
local obj = info[wiki] | local obj = info[wiki] | ||
if obj ~= nil then | if obj ~= nil then | ||
if param ~= nil and info[wiki][param] ~= nil then | if param ~= nil and info[wiki][param] ~= nil then | ||
result = info[wiki][param] | result = info[wiki][param] | ||
Строка 101: | Строка 120: | ||
if readOnly[val] == true then | if readOnly[val] == true then | ||
result = result .. ' | result = result .. string.format('<s title="Данный раздел закрыт и доступен только в режиме для чтения">%s</s>', text) | ||
else | else | ||
result = result .. text | result = result .. text | ||
Строка 115: | Строка 134: | ||
-- Вывод названия языка | -- Вывод названия языка | ||
local function renderLang(val, frame) | local function renderLang(val, frame) | ||
local text = | 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> (закрыт)' | |||
result = | |||
end | end | ||
if | if not isEmpty(link) then | ||
result = | result = string.format('[[:%s|%s]]', link, result) | ||
end | end | ||
if val == mwlang:getCode() then | if val == mwlang:getCode() then | ||
result = result .. ' | result = result .. ' [[File:Mw-unwatch-icon.svg|16px|text-top|alt=(текущий раздел)|link=]]' | ||
end | end | ||
Строка 157: | Строка 153: | ||
-- Функция для вывода ячейки | -- Функция для вывода ячейки | ||
local function | local function renderNum(val, key, stats) | ||
local | local text = mwlang:formatNum(val) | ||
if | if isEmpty(stats) or val == 0 then | ||
return text | |||
end | end | ||
return string.format( | |||
'[[:%s:%s|%s]]', | |||
key, | |||
stats, | |||
text | |||
) | |||
end | end | ||
-- Функция для вывода ряда таблицы | -- Функция для вывода ряда таблицы | ||
local function createRow(key, val, frame) | local function createRow(key, val, frame) | ||
local result = ' | local result = mw.html.create('tr') | ||
:css('text-align', 'right') | |||
if key == mwlang:getCode() then | if key == mwlang:getCode() then | ||
result | result | ||
:css('background', '#d5fdf4') | |||
:css('font-weight', 'bold') | |||
end | end | ||
result | 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 | end | ||
-- Функция для вывода шапки таблицы | -- Функция для вывода шапки таблицы | ||
local function createHeader() | local function createHeader() | ||
local | 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 | return result | ||
end | end | ||
Строка 228: | Строка 254: | ||
-- Параметр hide отвечает за оптическое выравнивание таблиц | -- Параметр hide отвечает за оптическое выравнивание таблиц | ||
local val = frame['total'] | local val = frame['total'] | ||
local | local cellStyle = 'text-align:right;' | ||
local | local cellStyleHide = 'color:transparent; padding:0; white-space:nowrap;' | ||
if hide then | |||
cellStyle = 'padding:0;' .. cellStyle | |||
end | |||
-- aa — закрытый раздел с самой большой глубиной | -- aa — закрытый раздел с самой большой глубиной | ||
local num = tableLength(frame) - 1 | local num = tableLength(frame) - 1 | ||
local depth = (hide and round(frame['aa']['depth']) or round(val['depth'])) | local depth = (hide and round(frame['aa']['depth']) or round(val['depth'])) | ||
local result = ' | 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 — самое длинное название раздела | -- zh-classical — самое длинное название раздела | ||
result | 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 | return result | ||
Строка 258: | Строка 333: | ||
local data = mw.loadData('Модуль:NumberOf/data') | local data = mw.loadData('Модуль:NumberOf/data') | ||
return | return getParam(frame.args, data) | ||
end | end | ||
Строка 265: | Строка 340: | ||
local data = mw.loadData('Модуль:NumberOf/today') | local data = mw.loadData('Модуль:NumberOf/today') | ||
return | return getParam(frame.args, data) | ||
end | end | ||
-- Функция для вывода в [[ | -- Функция для вывода в [[Википедия:Список Википедий]] | ||
function p.Editions(frame) | function p.Editions(frame) | ||
local data = mw.loadData('Модуль:NumberOf/today') | local data = mw.loadData('Модуль:NumberOf/today') | ||
Строка 324: | Строка 399: | ||
-- Автоматический скролл для недостаточно широких мониторов | -- Автоматический скролл для недостаточно широких мониторов | ||
local section = mw.html.create('div') | |||
:attr('style', 'overflow-x:auto; overflow-y:hidden;') | |||
local sectionTable = createHeader() | |||
-- Вывод рядов таблицы | -- Вывод рядов таблицы | ||
Строка 330: | Строка 408: | ||
if val ~= false then | if val ~= false then | ||
local curr = data[val] | local curr = data[val] | ||
sectionTable:node(createRow(val, curr, frame)) | |||
end | end | ||
end | end | ||
-- Вывод подвала таблицы | -- Вывод подвала таблицы | ||
sectionTable:node(createFooter(data, (n ~= 0))) | |||
result = result .. '\n | section:node(sectionTable) | ||
result = result .. '\n' .. tostring(section) | |||
end | end | ||
Текущая версия от 11:18, 11 февраля 2022
Этот модуль оценён как готовый к использованию. Предполагается, что все баги устранены и он готов для широкого использования. Его можно указывать на справочных страницах и рекомендовать к использованию новым участникам. Для его изменения и тестирования, пожалуйста, используйте песочницу. |
Данный модуль используется для отображения и обновления шаблонов {{NUMBEROF}} и {{TODAYNUMBEROF}}, использующихся для отображения статистики по другим разделам Тептар. Помимо этого, с помощью данного модуля отображается список Тептар. Подстраницы с данными этого модуля периодично обновляются ботом Adam.
Функции и параметры[править код]
Доступные функции:
Editions
— функция (без параметров) для вывода таблиц с языковыми разделами Тептар, отсортированными по количеству статей (используется на странице Тептар:Список Тептар). Использует страницу Модуль:NumberOf/today в качестве списка данных (обновляется ботом ежедневно) и страницу Модуль:NumberOf/lang для отображения названий языков.Now
— функция для вывода наиболее актуальной статистики (используется в шаблоне {{NUMBEROF}}). Использует Модуль:NumberOf/data (обновляется ботом раз в 2 часа) в качестве списка данных.Today
— функция для вывода статистики по состоянию на начало текущего UTC-дня (используется в шаблоне {{TODAYNUMBEROF}}). Использует Модуль:NumberOf/today (обновляется ботом ежедневно) в качестве списка данных.
Параметры, используемые функциями Now
и Today
:
wiki
— код раздела Тептар (обязательный параметр; список кодов доступен в списке разделов Тептар);param
— необходимые данные (обязательный параметр):articles
— количество статей в разделе,admins
— количество администраторов,activeusers
— количество активных участников,date
— дата обновления данных в модуле,depth
— глубина раздела,edits
— количество правок в разделе,files
— количество файлов,pages
— количество страниц,pos
— место раздела по количеству статей (см. список Тептар),users
— количество участников.
fmt
— форматирование числа (принимает любое непустое значение).
Использование[править код]
Формат использования:
{{#invoke:NumberOf|Editions}}
{{#invoke:NumberOf|Now|wiki=
— 6451528 (неформатированное значение)en
|param=articles
}}{{#invoke:NumberOf|Now|wiki=
— 6 451 528 (форматированное значение)en
|param=articles
|fmt=N
}}
Дату последнего обновления страницы с данными можно узнать с помощью конструкции {{#invoke:NumberOf|Now|wiki=
(11 февраля 2022, 10:00 (UTC); параметр en
|param=date
}}wiki
может содержать любое непустое значение). На страницах с данными дата обновления шаблона представлена в UNIX-времени.
Представленные примеры с функцией Now
работают и с функцией Today
.
-- Модуль для шаблонов серии 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:Mw-unwatch-icon.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', '#d5fdf4')
: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 .. '=== Менее 1000 статей ==='
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