Модуль:WikiProject

Материал из Народные Сказки
Версия от 15:24, 16 июля 2023; ru>Andras
(разн.) ← Предыдущая версия | Текущая версия (разн.) | Следующая версия → (разн.)

project_statistics

Формирует таблицу со статистикой статей проекта (см. {{Статистика проекта}}).

Параметры

1 или name Название проекта.
featured Если непустой и не ноль, добавляет в таблицу статусные статьи.
list Если непустой и не ноль, добавляет в таблицу списки.
align Выравнивание таблицы — по левому краю (left), по центру (center) или по правому краю (right). По умолчанию — по правому краю.
nocat Если параметр не задан или пуст, также включает страницу в проектные категории, чтобы они не были пустыми.
minus Вычитает из числа страниц в категории указанное в данном параметре число. Используется для компенсации непустого nocat.

category_description

Формирует описания проектных категорий («Статьи проекта X», «Статьи проекта X по уровню/важности», «Статьи проекта X уровня N», «Статьи проекта X энной важности», «Статьи проекта X уровня N энной важности»). Проставляет метку __HIDDENCAT__ и верхние категории. Не принимает параметры: всю необходимую информацию берёт из заголовка категории.

По умолчанию также добавляет на страницу категории таблицу со статистикой проекта с параметрами: |featured=1|list=1|minus=1|nocat=1. Отключить таблицу можно задав непустой параметр notable. Остальные параметры будут переданы в функцию, формирующую таблицу статистики — см. #project_statistics.


local wp = {}

local class_info = {
	['ИС'] = {
		category = 'Избранные статьи проекта %s',
		color = '#33CCFF',
		image = '[[Файл:Featured article star.svg|Избранная статья|14px|alt=🌟]]',
		shortname = 'Избр.',
		sortkey = ' 0'
	},
	['ИСП'] = {
		category = 'Избранные списки проекта %s',
		color = '#33CCFF',
		image = '[[Файл:Feat_lists.svg|Избранный список|14px|alt=☰]]',
		shortname = 'Избр.',
		sortkey = ' 1'
	},
	['ХС'] = {
		category = 'Хорошие статьи проекта %s',
		color = '#90EE90',
		image = '[[Файл:Blue star unboxed.svg|Хорошая статья|14px|alt=✪]]',
		shortname = 'Хор.',
		sortkey = ' 2'
	},
	['ДС'] = {
		category = 'Добротные статьи проекта %s',
		color = '#90EE90',
		image = '[[Файл:Crystal Clear action bookmark Silver approved.svg|Добротная статья|14px|alt=✔]]',
		shortname = 'Добр.',
		sortkey = ' 3'
	},
	['I'] = {
		category = 'Статьи проекта %s I уровня',
		color = '#CCFF99',
		image = '',
		shortname = 'I',
		sortkey = ' 4'
	},
	['II'] = {
		category = 'Статьи проекта %s II уровня',
		color = '#FFEE00',
		image = '',
		shortname = 'II',
		sortkey = ' 5'
	},
	['III'] = {
		category = 'Статьи проекта %s III уровня',
		color = '#FFA07A',
		image = '',
		shortname = 'III',
		sortkey = ' 6'
	},
	['IV'] = {
		category = 'Статьи проекта %s IV уровня',
		color = '#FF6347',
		image = '',
		shortname = 'IV',
		sortkey = ' 7'
	},
	['Список'] = {
		category = 'Списки проекта %s',
		color = '#AA88FF',
		image = '',
		shortname = 'Список',
		sortkey = ' 8'
	},
	['неизвестный'] = {
		category = 'Статьи проекта %s неизвестного уровня',
		color = '#FFFFF',
		image = '',
		shortname = 'Неизв.',
		sortkey = ' 9'
	},
}

local importance_info = {
	['высшая'] = {
		category = ' высшей важности',
		color = '#FCC200',
		shortname = 'Высш.',
		sortkey = ' 0'
	},
	['высокая'] = {
		category = ' высокой важности',
		color = '#FFDF00',
		shortname = 'Выс.',
		sortkey = ' 1'
	},
	['средняя'] = {
		category = ' средней важности',
		color = '#FBEC5D',
		shortname = 'Сред.',
		sortkey = ' 2'
	},
	['низкая'] = {
		category = ' низкой важности',
		color = '#FFEC8B',
		shortname = 'Низ.',
		sortkey = ' 3'
	},
	['неизвестная'] = {
		category = ' неизвестной важности',
		color = '#FFFFFF',
		shortname = 'Неизв.',
		sortkey = ' 9'
	},
}

-- Вспомогательные строковые функции

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 param_to_boolean( param )
	return param ~= nil and param ~= '' and param ~= '0'
end


--[[
Аналог шаблона «Статистика проекта/Категория», только с общепринятыми названиями уровней и
важностей. Для неизвестного уровня используется параметр 'неизвестный', для неизвестной важности —
'неизвестная'. Если оставить эти параметры пустыми, уровень/важность указана не будет.

— form_cat_name( 'Музыка', 'ИС', 'высшая' )
→ 'Избранные статьи проекта Музыка высшей важности'
— form_cat_name( 'Музыка', 'I', 'неизвестная' )
→ 'Статьи проекта Музыка I уровня неизвестной важности'
— form_cat_name( 'Музыка', '', 'средняя')
→ 'Статьи проекта Музыка средней важности'
]]
local function form_cat_name( project, class, importance )
	local result

	if class_info[class] ~= nil then
		result = string.format(class_info[class].category, project)
	else
		result = 'Статьи проекта ' .. project
	end

	if importance_info[importance] ~= nil then
		result = result .. importance_info[importance].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

--[[
Составляет табличку со статистикой статей проекта по уровню и важности. Если параметр nocat не
задан, также добавляет страницу во все проектные категории и в категорию
«Категория:Википедия:Статистика по проектам».
]]
function wp.project_statistics( frame )
	local name = frame.args['1'] or frame.args['name'] or ''
	if 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=&lt;includeonly&gt;1&lt;/includeonly&gt;|minus=1}}</code>'
	end
	local minus = tonumber(frame.args['minus']) or 0
	local align = frame.args['align'] or 'right'
	local featured = param_to_boolean( frame.args['featured'] )
	local list = param_to_boolean( frame.args['list'] )
	local nocat = param_to_boolean( frame.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 result = '{| class="wikitable" '
	if align == 'left' or align == 'center' or align == 'right' then
		result = result .. 'align="' .. align .. '" '
	end
	result = result .. 'style="text-align: center; font-size: 11px; margin-top: 3px; margin-bottom: 3px; margin-left: 9px;"\n'
	result = result .. '! colspan="7" | [[Проект:' .. name .. '/Оценки|Статьи]] проекта «[[Проект:' .. name .. '|' .. name .. ']]»\n'

	result = result .. '|-\n! rowspan="2" | [[:Категория:Статьи проекта ' .. name .. ' по уровню|Уровень<br>качества]]'
	result = result .. ' !! colspan="6" | [[:Категория:Статьи проекта ' .. name .. ' по важности|Важность]]\n'

	result = result .. '|-\n'
	for _, importance in ipairs(displayed_importances) do
		info = importance_info[importance]
		importance_pages[importance] = 0
		result = result .. '! style="background: ' .. info.color .. '; text-align: center;" |\n'
		result = result .. '[[:Категория:' .. form_cat_name( name, '', importance ) .. '|' .. info.shortname .. ']]\n'
	end
	result = result .. '! [[:Категория:Статьи проекта ' .. name .. '|Всего]]\n'

	for _, class in ipairs(displayed_classes) do
		info = class_info[class]

		local class_pages = 0
		local class_catname = form_cat_name( name, class, '' )

		result = result .. '|-\n!style="background: ' .. info.color .. '; text-align: center;" | '
		if info.image ~= '' then
			result = result .. info.image .. ' '
		end
		result = result .. '[[:Категория:' .. class_catname .. '|' .. info.shortname .. ']]\n'

		for _, importance in ipairs(displayed_importances) do
			result = result .. '| '

			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

				result = result .. '[[:Категория:' .. catname .. '|' .. pages .. ']]'
			end

			result = result .. '\n'
		end

		result = result .. '| \'\'\'[[:Категория:' .. class_catname .. '|' .. class_pages .. ']]\'\'\'\n'
	end

	result = result .. '|-\n! [[:Категория:Статьи проекта ' .. name .. '|Всего]]\n'
	for _, importance in ipairs(displayed_importances) do
		result = result .. '| \'\'\'[[:Категория:' .. form_cat_name( name, '', importance ) .. '|' .. importance_pages[importance] .. ']]\'\'\'\n'
	end
	result = result .. '| \'\'\' [[:Категория:Статьи проекта ' .. name .. '|' .. all_pages .. ']]\'\'\'\n'

	result = result .. '|-\n!colspan="8" style="font-weight: normal" | <small>Статистика обновляется автоматически '
	result = result .. frame:expandTemplate{ title = 'Очистить кэш', args = { ['1'] = '&#x21BB;' } }
	result = result .. '</small>\n'

	result = result .. '|}'

	local sortkey = '|+'
	if not nocat then
		result = result .. '\n\n[[Категория:РуСказки:Статистика по проектам|' .. name .. ']]'
		for _, class in ipairs( displayed_classes ) do
			result = result .. '\n[[Категория:' .. form_cat_name( name, class, '' ) .. sortkey .. ']]'
		end
		for _, importance in ipairs(displayed_importances) do
			result = result .. '\n[[Категория:' .. form_cat_name( name, '', importance ) .. sortkey .. ']]'
		end
		for _, class in ipairs( displayed_classes ) do
			for _, importance in ipairs(displayed_importances) do
				result = result .. '\n[[Категория:' .. form_cat_name( name, class, importance ) .. sortkey .. ']]'
			end
		end
	end

	return result
end

--[[
Заполняет страницу для категории: заполняет верхние категории, добавляет __HIDDENCAT__.
]]
function wp.category_description( frame )
	local title = mw.title.getCurrentTitle()
	if title.namespace ~= 14 then
		return ''
	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 result = ''
	if not param_to_boolean( frame.args['notable'] ) then
		frame.args['name'] = project
		if frame.args['align'] == nil then
			frame.args['align'] = 'right'
		end
		if frame.args['minus'] == nil then
			frame.args['minus'] = '1'
		end
		if frame.args['featured'] == nil then
			frame.args['featured'] = '1'
		end
		if frame.args['list'] == nil then
			frame.args['list'] = '1'
		end
		frame.args['nocat'] = '1'
		if mw.isSubsting() then
			result = '{{Статистика проекта|' .. project
			result = result .. '|align=' .. frame.args['align']
			result = result .. '|minus=' .. frame.args['minus']
			result = result .. '|featured=' .. frame.args['featured']
			result = result .. '|list=' .. frame.args['list']
			result = result .. '|nocat=1}}\n'
		else
			result = wp.project_statistics( frame ) .. '\n'
		end
	end

	if class == '' and importance == '' then
		-- Статьи проекта X
		if mw.isSubsting() then
			result = result .. '{{Индекс категории АБВ (удобный)|depth=2}}'
		else
			result = result .. frame:expandTemplate{ title = 'Индекс категории АБВ (удобный)', args = { ['depth'] = '2' } }
		end
		result = result .. '__HIDDENCAT__\n[[Категория:Проект:' .. project .. ']]'
	elseif class == '*' then
		-- Статьи проекта X по уровню
		if mw.isSubsting() then
			result = result .. '{{Метакатегория}}'
		else
			result = result .. frame:expandTemplate{ title = 'Метакатегория' }
		end
		result = result .. '\n[[Категория:РуСказки:Статьи проектов по уровню|' .. project .. ']]'
		result = result .. '\n[[Категория:Статьи проекта ' .. project .. '|*]]'
	elseif importance == '*' then
		-- Статьи проекта X по важности
		if mw.isSubsting() then
			result = result .. '{{Метакатегория}}'
		else
			result = result .. frame:expandTemplate{ title = 'Метакатегория' }
		end
		result = result .. '\n[[Категория:РуСказки:Статьи по важности|' .. project .. ']]'
		result = result .. '\n[[Категория:Статьи проекта ' .. project .. '|*]]'
	elseif importance == '' then
		-- Статьи проекта X уровня N
		result = result .. '__HIDDENCAT__'
		if class == 'Список' then
			result = result .. '\n[[Категория:Списки по проектам|' .. project .. ']]'
		elseif class == 'ИСП' then
			result = result .. '\n[[Категория:Избранные списки по проектам|' .. project .. ']]'
		elseif class == 'ИС' then
			result = result .. '\n[[Категория:Избранные статьи по проектам|' .. project .. ']]'
		elseif class == 'ХС' then
			result = result .. '\n[[Категория:Хорошие статьи по проектам|' .. project .. ']]'
		elseif class == 'ДС' then
			result = result .. '\n[[Категория:Добротные статьи по проектам|' .. project .. ']]'
		end
		result = result .. '\n[[Категория:Статьи проекта ' .. project .. ' по уровню|' .. class_info[class].sortkey .. ']]'
	elseif class == '' then
		-- Статьи проекта X энной важности
		result = result .. '__HIDDENCAT__'
		result = result .. '\n[[Категория:Статьи' .. importance_info[importance].category .. '|' .. project .. ']]'
		result = result .. '\n[[Категория:Статьи проекта ' .. project .. ' по важности|' .. importance_info[importance].sortkey .. ']]'
	else
		-- Статьи проекта X уровня N энной важности
		result = result .. '__HIDDENCAT__'
		result = result .. '\n[[Категория:' .. form_cat_name( project, class, '' ) .. '|' .. importance_info[importance].sortkey .. ']]'
		result = result .. '\n[[Категория:' .. form_cat_name( project, '', importance ) .. '|' .. class_info[class].sortkey .. ']]'
	end

	return result
end

return wp