Модуль:WikiProject
ХӀокху модулах лаьцна хааман Модуль:WikiProject/doc агӀо кхолла мега
require( 'strict' )
local p = {}
local yesno = require( 'Module:Yesno' )
local getArgs = require( 'Module:Arguments' ).getArgs
local module_styles_page = 'Module:WikiProject/styles.css'
local templatestyles_page = 'Шаблон:Статья проекта/styles.css'
local templatestyles_class = 'ts-Статья_проекта-rating '
local hiddencat = '__HIDDENCAT__'
local class_info = {
['ис'] = {
category = 'Избранные статьи проекта %s',
class = 'level-fa',
image = '[[Файл:Small Skew Star SVG.svg|baseline|link=|Избранная статья]]',
shortname = 'Избр.',
sortKey = ' 0'
},
['исп'] = {
category = 'Избранные списки проекта %s',
class = 'level-fl',
image = '[[Файл:Feat_lists.svg|14px|baseline|link=|Избранный список]]',
shortname = 'ИСП',
sortKey = ' 1'
},
['хс'] = {
category = 'Хорошие статьи проекта %s',
class = 'level-ga',
image = '[[Файл:Blue star unboxed.svg|13px|baseline|link=|Хорошая статья]]',
shortname = 'Хор.',
sortKey = ' 2'
},
['дс'] = {
category = 'Добротные статьи проекта %s',
class = 'level-aa',
image = '[[Файл:Crystal Clear action bookmark Silver approved.svg|baseline|14px|link=|Добротная статья]]',
shortname = 'Добр.',
sortKey = ' 3'
},
['i'] = {
category = 'Статьи проекта %s I уровня',
class = 'level-1',
shortname = 'I',
sortKey = ' 4'
},
['ii'] = {
category = 'Статьи проекта %s II уровня',
class = 'level-2',
shortname = 'II',
sortKey = ' 5'
},
['iii'] = {
category = 'Статьи проекта %s III уровня',
class = 'level-3',
shortname = 'III',
sortKey = ' 6'
},
['iv'] = {
category = 'Статьи проекта %s IV уровня',
class = 'level-4',
shortname = 'IV',
sortKey = ' 7'
},
['список'] = {
category = 'Списки проекта %s',
class = 'level-list',
shortname = 'Список',
sortKey = ' 8'
},
['неизвестный'] = {
category = 'Статьи проекта %s неизвестного уровня',
shortname = 'Неизв.',
sortKey = ' 9'
},
}
local importance_info = {
['высшая'] = {
category = ' высшей важности',
class = 'importance-highest',
shortname = 'Высш.',
sortKey = ' 0'
},
['высокая'] = {
category = ' высокой важности',
class = 'importance-high',
shortname = 'Выс.',
sortKey = ' 1'
},
['средняя'] = {
category = ' средней важности',
class = 'importance-medium',
shortname = 'Сред.',
sortKey = ' 2'
},
['низкая'] = {
category = ' низкой важности',
class = 'importance-low',
shortname = 'Низ.',
sortKey = ' 3'
},
['неизвестная'] = {
category = ' неизвестной важности',
shortname = 'Неизв.',
sortKey = ' 9'
},
}
-- Вспомогательные строковые функции
local function isEmpty( val )
return val == nil or val == ''
end
local function startsWith( str, prefix )
return mw.ustring.sub( str, 1, mw.ustring.len( prefix ) ) == prefix
end
local function cutPrefix( str, length )
return mw.ustring.sub( str, length + 1 )
end
local function endsWith( str, suffix )
return mw.ustring.sub( str, -mw.ustring.len( suffix ) ) == suffix
end
local function cutSuffix( str, length )
return mw.ustring.sub( str, 1, -length - 1 )
end
-- Функции для доступа к данным
local function getInfo( data, key )
if isEmpty( key ) then
return nil
end
key = key and mw.ustring.lower( key )
return data[ key ]
end
local function getClassInfo( class )
return getInfo( class_info, class )
end
local function getImportanceInfo( importance )
return getInfo( importance_info, importance )
end
--[[
Аналог шаблона «Статистика проекта/Категория», только с общепринятыми названиями уровней и
важностей. Для неизвестного уровня используется параметр 'неизвестный', для неизвестной важности —
'неизвестная'. Если оставить эти параметры пустыми, уровень/важность указана не будет.
— form_cat_name( 'Музыка', 'ИС', 'высшая' )
→ 'Избранные статьи проекта Музыка высшей важности'
— form_cat_name( 'Музыка', 'I', 'неизвестная' )
→ 'Статьи проекта Музыка I уровня неизвестной важности'
— form_cat_name( 'Музыка', '', 'средняя')
→ 'Статьи проекта Музыка средней важности'
]]
local function form_cat_name( project, class, importance )
local result = ''
local classInfo = getClassInfo( class )
if classInfo ~= nil then
result = string.format( classInfo.category, project )
else
result = 'Статьи проекта ' .. project
end
local importanceInfo = getImportanceInfo( importance )
if importanceInfo ~= nil then
result = result .. importanceInfo.category
end
return result
end
--[[
Обратная предыдущей функция: парсит название категории и возвращает таблицу вида
{ project, class, importance, is_error }, где is_error принимает значение true, если
название категории имеет некорректный вид.
]]
local function parse_cat_name( category )
-- Эх, если бы тут были полноценные регулярные выражения... =\
local result = {
project = '',
class = '',
importance = '',
is_error = false
}
if endsWith( category, ' по уровню' ) then
if not startsWith( category, 'Статьи проекта ' ) then
result.is_error = true
return result
end
category = cutPrefix( category, 15 )
category = cutSuffix( category, 10 )
result.project = category
result.class = '*'
return result
end
if endsWith( category, ' по важности' ) then
if not startsWith( category, 'Статьи проекта ' ) then
result.is_error = true
return result
end
category = cutPrefix( category, 15 )
category = cutSuffix( category, 12 )
result.project = category
result.importance = '*'
return result
end
if endsWith( category, ' высшей важности' ) then
category = cutSuffix( category, 16 )
result.importance = 'высшая'
elseif endsWith( category, ' высокой важности' ) then
category = cutSuffix( category, 17)
result.importance = 'высокая'
elseif endsWith( category, ' средней важности' ) then
category = cutSuffix( category, 17 )
result.importance = 'средняя'
elseif endsWith( category, ' низкой важности' ) then
category = cutSuffix( category, 16 )
result.importance = 'низкая'
elseif endsWith( category, ' неизвестной важности' ) then
category = cutSuffix( category, 21 )
result.importance = 'неизвестная'
end
if startsWith( category, 'Избранные статьи проекта ' ) then
category = cutPrefix( category, 25 )
result.class = 'ИС'
elseif startsWith( category, 'Избранные списки проекта ' ) then
category = cutPrefix( category, 25 )
result.class = 'ИСП'
elseif startsWith( category, 'Хорошие статьи проекта ' ) then
category = cutPrefix( category, 23 )
result.class = 'ХС'
elseif startsWith( category, 'Добротные статьи проекта ' ) then
category = cutPrefix( category, 25 )
result.class = 'ДС'
elseif startsWith( category, 'Списки проекта ' ) then
category = cutPrefix( category, 15 )
result.class = 'Список'
elseif startsWith( category, 'Статьи проекта ' ) then
category = cutPrefix( category, 15 )
else
result.is_error = true
end
if endsWith( category, ' I уровня' ) then
if result.class ~= '' then
result.is_error = true
end
category = cutSuffix( category, 9 )
result.class = 'I'
elseif endsWith( category, ' II уровня' ) then
if result.class ~= '' then
result.is_error = true
end
category = cutSuffix( category, 10 )
result.class = 'II'
elseif endsWith( category, ' III уровня' ) then
if result.class ~= '' then
result.is_error = true
end
category = cutSuffix( category, 11 )
result.class = 'III'
elseif endsWith( category, ' IV уровня' ) then
if result.class ~= '' then
result.is_error = true
end
category = cutSuffix( category, 10 )
result.class = 'IV'
elseif endsWith( category, ' неизвестного уровня' ) then
if result.class ~= '' then
result.is_error = true
end
category = cutSuffix( category, 20 )
result.class = 'неизвестный'
end
result.project = category
return result
end
--[[
Выводит код категории на основе имени и сортировочного ключа / текста ссылки (в случае ссылок)
]]
local function get_cat_link( name, after, isLink )
if isEmpty( name ) then
return ''
end
return string.format(
'[[%sКатегория:%s%s]]',
isLink == true and ':' or '',
name,
not isEmpty( after ) and '|' .. after or ''
)
end
--[[
Добавление заголовка таблицы с правильными классами в get_project_statistics
]]
local function add_table_header( html, info, catName, scope )
local headerText = get_cat_link( catName, info.shortname, true )
if info.image then
headerText = info.image .. ' ' .. headerText
end
return html:tag( 'th' )
:attr( 'scope', scope or 'row' )
:addClass( templatestyles_class .. (info.class or '') )
:wikitext( headerText )
end
--[[
Замена шаблону «Статья проекта/Категория» в рамках {{Статья проекта}}, кроме части с «Статьи несуществующего проекта»
]]
function p._get_page_categories( name, class, importance )
if isEmpty( name ) then
return
end
-- Поддержка арабских цифр
local romanNumerals = {
'i',
'ii',
'iii',
'iv',
}
if tonumber( class ) ~= nil then
class = romanNumerals[ tonumber( class ) ]
end
class = not isEmpty( class ) and mw.ustring.lower( class )
importance = not isEmpty( importance ) and mw.ustring.lower( importance )
local classOrUnknown = getClassInfo( class ) ~= nil and class or 'неизвестный'
local importanceOrUnknown = getImportanceInfo( importance ) ~= nil and importance or 'неизвестная'
-- Статьи проекта X
return get_cat_link( form_cat_name( name, nil, nil ) )
-- Статьи проекта X Y важности
.. get_cat_link( form_cat_name( name, nil, importanceOrUnknown ) )
-- Статьи проекта X Y уровня
.. get_cat_link( form_cat_name( name, classOrUnknown, nil ) )
-- Статьи проекта X Y уровня A важности
.. get_cat_link( form_cat_name( name, classOrUnknown, importanceOrUnknown ) )
end
function p.page_categories( frame )
local args = getArgs( frame )
local name = args[ '1' ] or args[ 'name' ]
local class = args[ 'class' ]
local importance = args[ 'importance' ]
return p._get_page_categories( name, class, importance )
end
--[[
Защищает шаблоны от подстановки через подстановку их же самих с переданными параметрами
]]
function p._substing( frame )
local args = getArgs( frame, {
parentOnly = true,
} )
local mTemplateInvocation = require( 'Module:Template invocation' )
local name = mTemplateInvocation.name( frame:getParent():getTitle() )
return mTemplateInvocation.invocation( name, args )
end
--[[
Составляет табличку со статистикой статей проекта по уровню и важности. Если параметр nocat не
задан, также добавляет страницу во все проектные категории и в категорию
«Категория:Википедия:Статистика по проектам».
]]
function p._get_project_statistics( name, args )
local frame = mw.getCurrentFrame()
if isEmpty( name ) then
local title = mw.title.getCurrentTitle()
local project
if title.namespace == 104 then
project = title.rootText
else
project = 'Проект'
end
return 'Скопируйте стандартную строку: <code>{{Статистика проекта|' .. project ..
'|featured=1|list=1|nocat=<includeonly>1</includeonly>|minus=1}}</code>'
end
local minus = tonumber( args['minus'] ) or 0
local align = args['align'] or 'right'
local featured = yesno( args['featured'] )
local list = yesno( args['list'] )
local nocat = yesno( args['nocat'] )
local displayed_importances = { 'высшая', 'высокая', 'средняя', 'низкая', 'неизвестная' }
local displayed_classes
if featured and list then
displayed_classes = { 'ИС', 'ИСП', 'ХС', 'ДС', 'I', 'II', 'III', 'IV', 'список', 'неизвестный' }
elseif featured then
displayed_classes = { 'ИС', 'ХС', 'ДС', 'I', 'II', 'III', 'IV', 'неизвестный' }
elseif list then
displayed_classes = { 'I', 'II', 'III', 'IV', 'список', 'неизвестный' }
else
displayed_classes = { 'I', 'II', 'III', 'IV', 'неизвестный' }
end
local all_pages = 0
local importance_pages = {}
local wrapper = mw.html.create( 'div' )
:addClass( 'ts-module-WikiProject-wrapper' )
local result = wrapper:tag( 'table' )
:addClass( 'ts-module-WikiProject-table wikitable' )
if align == 'left' or align == 'center' or align == 'right' then
wrapper:addClass( 'is-' .. align )
end
result:tag( 'caption' )
:wikitext( '[[Проект:' .. name .. '/Оценки|Статьи]] проекта [[Проект:' .. name .. '|«' .. name .. '»]]' )
:done()
result:tag( 'tr' )
:tag( 'th' )
:attr( 'scope', 'col' )
:attr( 'rowspan', 2 )
:wikitext( get_cat_link( 'Статьи проекта ' .. name .. ' по уровню', 'Уровень<br>качества', true ) )
:tag( 'th' )
:attr( 'scope', 'colgroup' )
:attr( 'colspan', 6 )
:wikitext( get_cat_link( 'Статьи проекта ' .. name .. ' по важности', 'Важность', true ) )
:done()
result:tag( 'tr' )
for _, importance in ipairs(displayed_importances) do
local info = getImportanceInfo( importance )
importance_pages[ importance ] = 0
add_table_header( result, info, form_cat_name( name, '', importance ), 'col' )
end
result:tag( 'th' )
:attr( 'scope', 'col' )
:wikitext( get_cat_link( 'Статьи проекта ' .. name, 'Всего', true ) )
:done()
for _, class in ipairs(displayed_classes) do
local info = getClassInfo( class )
local class_pages = 0
local tr = result:tag( 'tr' )
local class_catname = form_cat_name( name, class, '' )
add_table_header( tr, info, class_catname )
for _, importance in ipairs(displayed_importances) do
local td = tr:tag( 'td' )
local catname = form_cat_name( name, class, importance )
local pages = mw.site.stats.pagesInCategory( catname, 'pages' ) - minus
if pages > 0 then
all_pages = all_pages + pages
class_pages = class_pages + pages
importance_pages[importance] = importance_pages[importance] + pages
td:wikitext( get_cat_link( catname, pages, true ) )
end
end
tr:tag( 'td' )
:addClass( 'ts-module-WikiProject-table-total' )
:wikitext( get_cat_link( class_catname, class_pages, true ) )
end
local totalTr = result:tag( 'tr' )
:addClass( 'ts-module-WikiProject-table-total' )
totalTr:tag( 'th' )
:attr( 'scope', 'row' )
:wikitext( get_cat_link( 'Статьи проекта ' .. name, 'Всего', true ) )
for _, importance in ipairs(displayed_importances) do
totalTr:tag( 'td' )
:wikitext( get_cat_link( form_cat_name( name, '', importance ), importance_pages[importance], true ) )
end
totalTr:tag( 'td' )
:wikitext( get_cat_link( 'Статьи проекта ' .. name, all_pages, true ) )
local footer = 'Статистика обновляется автоматически ' ..
'[' .. frame:expandTemplate{ title = 'очистить кэш', args = { ['1'] = 'обновить' } } .. ']'
wrapper:tag( 'div' )
:wikitext( footer )
local cats = ''
local sortKey = '*'
if not nocat then
cats = cats .. get_cat_link( 'Википедия:Статистика по проектам', name )
for _, class in ipairs( displayed_classes ) do
cats = cats .. get_cat_link( form_cat_name( name, class, '' ), sortKey )
end
for _, importance in ipairs(displayed_importances) do
cats = cats .. get_cat_link( form_cat_name( name, '', importance ), sortKey )
end
for _, class in ipairs( displayed_classes ) do
for _, importance in ipairs(displayed_importances) do
cats = cats .. get_cat_link( form_cat_name( name, class, importance ), sortKey )
end
end
end
return frame:extensionTag{
name = 'templatestyles',
args = { src = module_styles_page }
} .. frame:extensionTag{
name = 'templatestyles',
args = { src = templatestyles_page }
} .. tostring( wrapper ) .. cats
end
function p.project_statistics( frame )
local args = getArgs( frame )
local name = args[ '1' ] or args[ 'name' ]
if mw.isSubsting() then
return p._substing( frame )
end
return p._get_project_statistics( name, args )
end
--[[
Заполняет страницу для категории: заполняет верхние категории, добавляет __HIDDENCAT__.
]]
function p.category_description( frame )
local args = getArgs( frame )
local title = mw.title.getCurrentTitle()
if title.namespace ~= 14 then
return ''
end
if mw.isSubsting() then
return p._substing( frame )
end
local parsed_title = parse_cat_name( title.text )
if parsed_title.is_error then
return '<strong class="error">Ошибка модуля WikiProject: не удалось распарсить заголовок.</strong>'
end
local project = parsed_title.project
local class = parsed_title.class
local importance = parsed_title.importance
local name = args.name
local result = ''
if class == '' and importance == '' then
-- Статьи проекта X
result = result .. frame:expandTemplate{ title = 'Индекс категории АБВ (удобный)', args = { ['depth'] = '2' } }
result = result .. '\n' .. get_cat_link( 'Проект:' .. project )
elseif class == '*' then
-- Статьи проекта X по уровню
result = result .. frame:expandTemplate{ title = 'метакатегория' }
result = result .. '\n' .. get_cat_link( 'Википедия:Статьи проектов по уровню', project )
result = result .. '\n' .. get_cat_link( 'Статьи проекта ' .. project, '*' )
elseif importance == '*' then
-- Статьи проекта X по важности
result = result .. frame:expandTemplate{ title = 'метакатегория' }
result = result .. '\n' .. get_cat_link( 'Википедия:Статьи по важности', project )
result = result .. '\n' .. get_cat_link( 'Статьи проекта ' .. project, '*' )
elseif importance == '' then
-- Статьи проекта X уровня N
result = result .. hiddencat
if class == 'Список' then
result = result .. '\n' .. get_cat_link( 'Списки по проектам', project )
elseif class == 'ИСП' then
result = result .. '\n' .. get_cat_link( 'Избранные списки по проектам', project )
elseif class == 'ИС' then
result = result .. '\n' .. get_cat_link( 'Избранные статьи по проектам', project )
elseif class == 'ХС' then
result = result .. '\n' .. get_cat_link( 'Хорошие статьи по проектам', project )
elseif class == 'ДС' then
result = result .. '\n' .. get_cat_link( 'Добротные статьи по проектам', project )
elseif class == 'неизвестный' then
result = result .. '\n' .. get_cat_link( 'Статьи неизвестного уровня', project )
else
result = result .. '\n' .. get_cat_link( 'Статьи ' .. class .. ' уровня', project )
end
result = result .. '\n' .. get_cat_link( 'Статьи проекта ' .. project .. ' по уровню', getClassInfo( class ).sortKey )
elseif class == '' then
-- Статьи проекта X энной важности
result = result .. hiddencat
result = result .. '\n' .. get_cat_link( 'Статьи' .. getImportanceInfo( importance ).category, project )
result = result .. '\n' .. get_cat_link( 'Статьи проекта ' .. project .. ' по важности', getImportanceInfo( importance ).sortKey )
else
-- Статьи проекта X уровня N энной важности
result = result .. '\n' .. get_cat_link( form_cat_name( project, class, '' ), getImportanceInfo( importance ).sortKey )
result = result .. '\n' .. get_cat_link( form_cat_name( project, '', importance ), getClassInfo( class ).sortKey )
end
if not yesno( args['notable'] ) then
name = project
if args['align'] == nil then
args['align'] = 'right'
end
if args['minus'] == nil then
args['minus'] = '1'
end
if args['featured'] == nil then
args['featured'] = '1'
end
if args['list'] == nil then
args['list'] = '1'
end
args['nocat'] = '1'
result = result .. p._get_project_statistics( name, args )
end
return result
end
return p