Документация

This is a meta-module that provides various functions for making hatnotes. It implements the {{hatnote}} template, for use in hatnotes at the top of pages, and the {{format link}} template, which is used to format a wikilink for use in hatnotes. It also contains a number of helper functions for use in other Lua hatnote modules.

Use from wikitext

The functions in this module cannot be used directly from #invoke, and must be used through templates instead. Please see Template:Hatnote and Template:Format link for documentation.

Use from other Lua modules

To load this module from another Lua module, use the following code.

local mHatnote = require('Module:Hatnote')

You can then use the functions as documented below.

Hatnote

mHatnote._hatnote(s, options)

Formats the string s as a hatnote. This encloses s in the tags <div class="hatnote"></div>. Options are provided in the options table. Options include:

  • options.extraclasses - a string of extra classes to provide
  • options.selfref - if this is not nil or false, adds the class "selfref", used to denote self-references to Wikipedia (see Template:Selfref))

The CSS of the hatnote class is defined in MediaWiki:Common.css.

Example 1
mHatnote._hatnote('This is a hatnote.')

Produces: <div class="hatnote">This is a hatnote.</div>

Displays as:

Example 2
mHatnote._hatnote('This is a hatnote.', {extraclasses = 'boilerplate seealso', selfref = true})

Produces: <div class="hatnote boilerplate seealso selfref">This is a hatnote.</div>

Displayed as:

mHatnote._formatLink{link = link, display = display, italicizePage = true, italicizeSection = true}

Formats link as a wikilink for display in hatnote templates, with optional display value display. Categories and files are automatically escaped with the colon trick, and links to sections are automatically formatted as page § section, rather than the MediaWiki default of page#section.

If italicizePage is true then the page portion of the link is italicized, and if italicizePage is true then the section portion of the link is italicized.

Examples
mHatnote._formatLink{link = 'Lion'} → [[Lion]] → Шаблон:Format hatnote link
mHatnote._formatLink{link = 'Lion#Etymology'} → [[Lion#Etymology|Lion §&nbsp;Etymology]] → Шаблон:Format hatnote link
mHatnote._formatLink{link = 'Category:Lions'} → [[:Category:Lions]] → Шаблон:Format hatnote link
mHatnote._formatLink{link = 'Lion#Etymology', display = 'Etymology of lion'} → [[Lion#Etymology|Etymology of lion]] → Шаблон:Format hatnote link
mHatnote._formatLink{link = 'Quo warranto#Philippines', italicizePage = true} → [[Quo warranto#Philippines|<i>Quo warranto</i> §&nbsp;Philippines]] → Шаблон:Format hatnote link
mHatnote._formatLink{link = 'Cybercrime Prevention Act of 2012#Disini v. Secretary of Justice', italicizeSection = true} → [[Cybercrime Prevention Act of 2012#Disini v. Secretary of Justice|Cybercrime Prevention Act of 2012 §&nbsp;<i>Disini v. Secretary of Justice</i>]] → Шаблон:Format hatnote link

Format pages

mHatnote.formatPages(...)

Formats a list of pages using the _formatLink function, and returns the result as an array. For example, the code mHatnote.formatPages('Lion', 'Category:Lions', 'Lion#Etymology') would produce an array like {'Lion', 'Category:Lions', 'Lion § Etymology'}.

Format page tables

mHatnote.formatPageTables(...)

Takes a list of page/display tables, formats them with the _formatLink function, and returns the result as an array. Each item in the list must be a table. The first value in the table is the link, and is required. The second value in the table is the display value, and is optional. For example, the code mHatnote.formatPages({'Lion', 'the Lion article'}, {'Category:Lions'}, {'Lion#Etymology', 'the etymology of lion'}) would produce an array like {'the Lion article', 'Category:Lions', 'the etymology of lion'}.

Find namespace id

mHatnote.findNamespaceId(link, removeColon)

Finds the namespace id of the string link, which should be a valid page name, with or without the section name. This function will not work if the page name is enclosed with square brackets. When trying to parse the namespace name, colons are removed from the start of the link by default. This is helpful if users have specified colons when they are not strictly necessary. If you do not need to check for initial colons, set removeColon to false.

Examples
mHatnote.findNamespaceId('Lion') → 0
mHatnote.findNamespaceId('Category:Lions') → 14
mHatnote.findNamespaceId(':Category:Lions') → 14
mHatnote.findNamespaceId(':Category:Lions', false) → 0 (the namespace is detected as ":Category", rather than "Category")

Make wikitext error

mHatnote.makeWikitextError(msg, helpLink, addTrackingCategory)

Formats the string msg as a red wikitext error message, with optional link to a help page helpLink. Normally this function also adds Шаблон:Clc. To suppress categorization, pass false as third parameter of the function (addTrackingCategory).

Examples:

mHatnote.makeWikitextError('an error has occurred')Error: an error has occurred.
mHatnote.makeWikitextError('an error has occurred', 'Template:Example#Errors')Error: an error has occurred (help).

Examples

For an example of how this module is used in other Lua modules, see Module:Main

local get_args = require('Module:Arguments').getArgs
local mError
local yesno = function (v) return require('Module:Yesno')(v, true) end

local p, tr = {}, {}
local current_title = mw.title.getCurrentTitle()
local tracking_categories = {
	no_prefix = 'Википедия:Страницы с модулем Hatnote без указания префикса',
	no_links = 'Википедия:Страницы с модулем Hatnote без ссылок',
	red_link = 'Википедия:Страницы с модулем Hatnote с красной ссылкой',
	bad_format = 'Википедия:Страницы с модулем Hatnote с некорректно заполненными параметрами',
	unparsable_link = 'Википедия:Страницы с модулем Hatnote с нечитаемой ссылкой',
	formatted = 'Википедия:Страницы с модулем Hatnote с готовым форматированием',
}

local function index(t1, t2)
	return setmetatable(t1, {__index = t2})
end

local function concat(e1, e2) 
	return tostring(e1) .. tostring(e2)
end

function tr.define_categories(tracked_cases)
	local categories = setmetatable({}, {
		__tostring = function (self) return table.concat(self) end, 
		__concat = concat
	})

	function categories:add(element, nocat)
		if not nocat then
			local cat_name
			if tracked_cases and tracked_cases[element] then
				cat_name = tracked_cases[element]
			else
				cat_name = element
			end
			table.insert(self, string.format('[[Категория:%s]]', cat_name))
		end
	end
	
	return categories
end

function tr.error(msg, categories, preview_only)
	local current_frame = mw.getCurrentFrame()
	local parent_frame = current_frame:getParent()
	local res_frame_title = parent_frame and parent_frame:getTitle() ~= current_title.prefixedText and
		parent_frame:getTitle() or
		current_frame:getTitle()
	if not preview_only or current_frame:preprocess('{{REVISIONID}}') == '' then
		mError = require('Module:Error')
		return mError.error{
			tag = 'div',
			string.format('Ошибка в [[%s]]: %s.' 
				.. (preview_only and '<br><small>Это сообщение показывается только во время предпросмотра.</small>' or ''), res_frame_title, msg)
		} .. categories
	else 
		return categories
	end
end

function p.parse_link(frame)
	local args = get_args(frame)
	local link = args[1]:gsub('\n', '')
	local label
	
	link = mw.text.trim(link:match('^%[%[([^%]]+)%]%]$') or link)
	if link:sub(1, 1) == '/' then
		label = link
		link = current_title.prefixedText .. link
	end
	link = link:match(':?(.+)')
	if link:match('|') then
		link, label = link:match('^([^%|]+)%|(.+)$')
	end
	
	if not mw.title.new(link) then
		return nil, nil
	end
	
	return link, label
end

function p.format_link(frame)
	-- {{ссылка на раздел}}
	local args = get_args(frame)
	local link, section, label = args[1], args[2], args[3]
	
	if not link then
		link = current_title.prefixedText
		if section then
			link = '#' .. section
			label = label or '§&nbsp;' .. section
		end
	else
		local parsed_link, parsed_label = p.parse_link{link}
		if parsed_link then
			link = parsed_link
		else
			return link
		end
		if section and not link:match('#') then
			link = link .. '#' .. section
			if parsed_label then
				parsed_label = parsed_label .. '#' .. section
			end
		end
		
		label = (label or parsed_label or link):gsub('^([^#]-)#(.+)$', '%1 §&nbsp;%2')
	end
	
	if label and label ~= link then
		return string.format('[[:%s|%s]]', link, label)
	else
		return string.format('[[:%s]]', link)
	end
end

function p.remove_precision(frame)
	-- {{без уточнения}}
	local args = get_args(frame)
	local title = args[1]
	
	return title:match('^(.+)%s+%b()$') or title
end

function p.is_disambig(frame)
	local args = get_args(frame)
	local title = args[1]
	local page = mw.title.new(title)
	
	if not page or not page.exists or mw.title.equals(page, current_title) then
		return false
	end
	
	local page_content = page:getContent()
	local mw_list_content = mw.title.new('MediaWiki:Disambiguationspage'):getContent()
	local lang = mw.language.getContentLanguage()
	for template in mw.ustring.gmatch(mw_list_content, '%*%s?%[%[Шаблон:([^%]]+)') do
		if page_content:match('{{' .. template) or page_content:match('{{' .. lang:lcfirst(template)) then 
			return true
		end
	end
	return false
end

function p.list(frame)
	local args = get_args(frame, {trim = false})
	local list_sep = args.list_sep or args['разделитель списка'] or ', '
	local last_list_sep = yesno(args.natural_join) ~= false and ' и ' or list_sep
	local links_ns = args.links_ns or args['ПИ ссылок']
	local bold_links = yesno(args.bold_links or args['ссылки болдом'])

	local res_list = {}
	local tracked = {
		red_link = false,
		bad_format = false,
		formatted = false,
		unparsable_link = false
	}
	
	local i = 1
	while args[i] do
		local link = args[i]
		local label = args['l' .. i]
		
		local element = ''
		if link:match('<span') then -- TODO: переписать
			tracked.formatted = true
			element = link -- for {{не переведено}}
		else
			local bad_format = (link:match('|') or link:match('[%[%]]')) ~= nil
			local parsed_link, parsed_label = p.parse_link{link}
			
			if parsed_link then
				tracked.bad_format = tracked.bad_format or bad_format
				if links_ns then
					parsed_label = parsed_label or parsed_link
					parsed_link = mw.site.namespaces[links_ns].name .. ':' .. parsed_link
				end
			
				local title = mw.title.new(parsed_link)
				tracked.red_link = tracked.red_link or not (title.isExternal or title.exists)
				element = p.format_link{parsed_link, nil, label or parsed_label}
			else
				tracked.unparsable_link = true
				element = link
			end
		end
		
		if bold_links then
			element = string.format('<b>%s</b>', element)
		end
		
		table.insert(res_list, element)
		i = i + 1
	end
	
	return setmetatable(res_list, {
		__index = tracked,
		__tostring = function (self) return mw.text.listToText(self, list_sep, last_list_sep) end,
		__concat = concat,
		__pairs = function (self) return pairs(tracked) end
	})
end

function p.hatnote(frame)
	local args = get_args(frame)
	local text = args[1]
	local id = args.id
	local extraclasses = args.extraclasses
	local hide_disambig = yesno(args.hide_disambig)
	
	local res = mw.html.create('div')
		:attr('id', id)
		:addClass('hatnote')
		:addClass(extraclasses)
		:wikitext(text)
	
	if hide_disambig then
		res:addClass('dabhide')
	end
	
	return res
end

function p.main(frame, _tracking_categories)
	local args = get_args(frame, {trim = false})
	
	local prefix = args.prefix or args['префикс']
	local prefix_plural = args.prefix_plural or args['префикс мн. ч.']
	local sep = args.sep or args['разделитель'] or ' '
	local dot = yesno(args.dot or args['точка']) and '.' or ''
	local nocat = yesno(args.nocat)
	local preview_error = yesno(args.preview_error)
	local empty_list_message = args.empty_list_message or 'Не указано ни одной страницы'
	
	categories = tr.define_categories(index(_tracking_categories or {}, tracking_categories))

	if not prefix then
		categories:add('no_prefix', nocat)
		return tr.error('Не указан префикс', categories)
	end
	if not args[1] then
		categories:add('no_links', nocat)
		return tr.error(empty_list_message, categories, preview_error)
	end
	
	if args[2] and prefix_plural then
		prefix = prefix_plural
	end
	
	local list = p.list(args)
	
	for k, v in pairs(list) do
		if type(v) == 'boolean' and v then
			categories:add(k, nocat)
		end
	end
	
	return p.hatnote(index({prefix .. sep .. list .. dot}, args)) .. categories
end

return index(p, tr)