Модуль:Вложенный список

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
Документация

Данный модуль реализует шаблоны {{Вложенный список}}, {{Вложенный список/2}} и {{Вложенный список/3}}. Он был создан, чтобы сделать единую точку управления всеми тремя шаблонами, с помощью которой стало возможно заменить выводимый шаблонами код на более доступный и семантичный.

Код вызова модуля: {{#invoke:Вложенный список|main}}.

Категории

[[Категория:Википедия:Страницы с ошибками шаблона Вложенный список]] — ставится в случаях:

  • несуществования страницы или отсутствия текста при попытке вставить вложенный список (например, в случае некорректной разметки в нём);
  • наличия ошибок (например, петлей в шаблонах, исправляющихся через использование {{NL2}} и {{NL3}}) в выводе вложенного списка.
  • наличия шаблона {{неоднозначность}} в выводе вложенного списка.
  • наличия шаблонов типа {{ФИО}} в выводе вложенного списка.
  • наличия шаблонов типа {{TOC right}} в выводе вложенного списка.
  • наличия шаблона {{примечания}} в выводе вложенного списка.
  • вложенных списков с неправильной вложенностью (через :* или с ; в начале, что является некорректной разметкой с точки зрения доступности).
  • вложенных списков с заголовками (== и т. п.) в выводе.
require( 'strict' )
--
-- Implements {{Вложенный список}} in one module
-- Allows us to potentially move towards a more accessible markup for the template when the time is right
-- Previously, the template broke the lists {{Вложенный список}} or {{NL2}} or {{NL3}} are in
-- Heavily borrows from https://en.wikipedia.org/wiki/Module:Excerpt_slideshow
--
local getArgs = require('Module:Arguments').getArgs

local templatePageName = 'Вложенный список'
local disambigPageName = ' (значения)'
local errorCat = 'Википедия:Страницы с ошибками шаблона Вложенный список'

local noTitle = 'Нет названия страницы.'
local noContent = 'Ошибка при включении страницы «[[%s]]».'

-- Adds a replacement to a redirected variant when substed
local substWithRedirects = true

local p = {}

local function addWarning( title, message )
	if title ~= nil and message == nil then
		message = string.format( noContent, title )
	end
	mw.addWarning( string.format( '[[Template:%s|%s]]: %s', templatePageName, templatePageName, message ) )
end

--[[
	@param {String} wikitext: Wikitext of just the list (i.e. each line is a list item)
	@param {String} symbol:   Special character used in the wikitext markup for the list, e.g. '*' or '#'
	@param {String} outerTag: Text portion of the tag for each list or sublist, e.g. 'ul' or 'ol'
	@param {String} innerTag: Text portion of the tag for each list item, e.g. 'li'
]]
local wikitextToHtmlList = function( wikitext, symbol, outerTag, innerTag )
	local listParts = {}
	for level, item in mw.ustring.gmatch( '\n' .. wikitext .. '\n', '\n(%' .. symbol .. '+)(.-)%f[\n]' ) do
	    table.insert( listParts, { level=level, item=item } )
	end
	table.insert( listParts, { level='', item='' } )
	
	local htmlList = {}
	for i, this in ipairs( listParts ) do
		local isFirstItem = ( i == 1 )
		local isLastItem = ( i == #listParts )
	    local lastLevel = isFirstItem and '' or listParts[ i - 1 ][ 'level' ]
	    local tags
	    if #lastLevel == #this.level then
	    	tags = '</'..innerTag..'><'..innerTag..'>'
	    elseif #this.level > #lastLevel then
	    	tags = string.rep( '<'..outerTag..'><'..innerTag..'>', #this.level - #lastLevel )
	    elseif isLastItem then
	    	tags = string.rep( '</'..innerTag..'></'..outerTag..'>', #lastLevel )
	    else -- ( #this.level < #lastLevel ) and not last item
	    	tags = string.rep( '</'..innerTag..'></'..outerTag..'>', #lastLevel - #this.level ) .. '</'..innerTag..'><'..innerTag..'>'
	    end
	    table.insert( htmlList, tags .. this.item )
	end
	return table.concat( htmlList )
end


--[[
	@param {String} wikitext: Wikitext excertp containg zero or more lists
	@param {String} symbol:   Special character used in the wikitext markup for the list, e.g. '*' or '#'
	@param {String} outerTag: Text portion of the tag for each list or sublist, e.g. 'ul' or 'ol'
	@param {String} innerTag: Text portion of the tag for each list item, e.g. 'li'
]]
local gsubWikitextLists = function( wikitext, symbol, outerTag, innerTag )
	-- temporarily remove list linebreaks... 
	wikitext = mw.ustring.gsub( wikitext .. '\n', '\n%' .. symbol, '¿¿¿' .. symbol )
	-- ...so we can grab the whole list (and just the list)...
	return mw.ustring.gsub(
		wikitext,
		'¿¿¿%'..symbol..'[^\n]+', 
		function( listWikitext )
			-- ...and then reinstate linebreaks...
			listWikitext = mw.ustring.gsub( listWikitext, '¿¿¿%' .. symbol, '\n' .. symbol )
			-- ...and finally do the conversion
			return wikitextToHtmlList( listWikitext, symbol, outerTag, innerTag )
		end
	)
end

-- Protects the templates from substitution by substituting them with their own parameters
function p._substing( frame )
	local args = getArgs( frame, {
		parentOnly = true,
	} )
	local mTemplateInvocation = require( 'Module:Template invocation' )
	local name = mTemplateInvocation.name( frame:getParent():getTitle() )
	
	if substWithRedirects then
		name = mw.ustring.gsub( name, 'Вложенный список/?', 'NL' )
	end
	
	return mTemplateInvocation.invocation( name, args )
end


function p.main( frame )
	local args = getArgs(frame)
	
	local title = args[ 1 ]
	local displayedTitle = args[ 2 ] and '|' .. args[ 2 ] or ''
	local appendedText = args[ 3 ] and ' ' .. args[ 3 ] or ''
	
	if mw.isSubsting() then
		return p._substing( frame )
	end
	
	if title == nil or title == '' then
		addWarning( nil, noTitle )
		return '<div class="error">' .. noTitle .. '</div>'
	end
	
	-- Render a disambig page name without its bracketed suffix
	if mw.ustring.find( title, disambigPageName, 1, true ) ~= nil then
		displayedTitle = '|' .. mw.ustring.gsub( title, '^%s*(.+)%s+%b()%s*$', '%1' )
	end
	
	local intro = string.format( '<span class="dabhide">[[%s%s]]</span>%s:', title, displayedTitle, appendedText)
	-- frame:expandTemplate is used because mw.title:getContent() does not handle redirects
	local sublistExists, sublist = pcall(function ()
		return frame:expandTemplate{ title = ':' .. title }
	end)
	
	-- The page does not exist or returns empty
	if sublistExists ~= true or mw.text.trim( sublist ) == '' then
		local errorText = string.format( noContent, title )
		addWarning( title, errorText )
		return intro .. '<div class="error">' .. errorText .. '</div>'
			.. string.format( '[[Category:%s]]', errorCat )
	end
	
	-- Replace list markers with HTML list openers
	sublist = gsubWikitextLists( '\n' .. sublist, '*', 'ul', 'li' )
	
	-- Replace double line breaks to avoid breaking the list
	sublist = mw.ustring.gsub( mw.text.trim( sublist ), '\n\n', '<p>' )
	
	-- Merge adjacent lists
	sublist = mw.ustring.gsub( mw.text.trim( sublist ), '</ul>\n<ul>', '' )
	
	-- Replace remaining
	sublist = mw.ustring.gsub( mw.text.trim( sublist ), '\n', '<br>' )
	
	-- Detect common errors
	mw.log( sublist )
	if mw.ustring.find( sublist, 'class="error' ) ~= nil
		or mw.ustring.find( sublist, 'id="disambig"' ) ~= nil -- contains {{disambig}} in code
		or mw.ustring.find( sublist, 'class="hatnote' ) ~= nil -- contains {{hatnote}} in code
		or mw.ustring.find( sublist, '__TOC__' ) ~= nil -- contains __TOC__ in code
		or mw.ustring.find( sublist, 'UNIQ--references' ) ~= nil -- contains {{references}} in code
		or mw.ustring.find( sublist, '%:%*' ) ~= nil -- incorrect list markup
		or mw.ustring.find( sublist, '<br>;%s*[А-ЯA-Z]' ) ~= nil -- incorrect bold text markup
		or mw.ustring.find( sublist, '<[brp]+>==' ) ~= nil -- incorrect heading markup
	then
		sublist = sublist .. string.format( '[[Category:%s]]', errorCat )
		addWarning( title )
	end
	
	return intro .. sublist
end

return p