Модуль:Hatnote: различия между версиями

Материал из in.wiki
Перейти к навигации Перейти к поиску
 
(Reordered helper functions (first by export status, then alphabetically) and migrated p.quote upstream from Module:Redirect hatnote (includes contributions by Tamzin and Nihiltres))
Строка 1: Строка 1:
local get_args = require('Module:Arguments').getArgs
+
--------------------------------------------------------------------------------
local mError
+
--                              Module:Hatnote                                --
local yesno = function (v) return require('Module:Yesno')(v, true) end
+
--                                                                            --
 +
-- This module produces hatnote links and links to related articles. It      --
 +
-- implements the {{hatnote}} and {{format link}} meta-templates and includes --
 +
-- helper functions for other Lua hatnote modules.                            --
 +
--------------------------------------------------------------------------------
  
local p, tr = {}, {}
+
local libraryUtil = require('libraryUtil')
local current_title = mw.title.getCurrentTitle()
+
local checkType = libraryUtil.checkType
local tracking_categories = {
+
local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg
no_prefix = 'Википедия:Страницы с модулем Hatnote без указания префикса',
+
local mArguments -- lazily initialise [[Module:Arguments]]
no_links = 'Википедия:Страницы с модулем Hatnote без ссылок',
+
local yesno -- lazily initialise [[Module:Yesno]]
red_link = 'Википедия:Страницы с модулем Hatnote с красной ссылкой',
+
local formatLink -- lazily initialise [[Module:Format link]] ._formatLink
bad_format = 'Википедия:Страницы с модулем Hatnote с некорректно заполненными параметрами',
 
unparsable_link = 'Википедия:Страницы с модулем Hatnote с нечитаемой ссылкой',
 
formatted = 'Википедия:Страницы с модулем Hatnote с готовым форматированием',
 
}
 
  
local function index(t1, t2)
+
local p = {}
return setmetatable(t1, {__index = t2})
+
 
 +
--------------------------------------------------------------------------------
 +
-- Helper functions
 +
--------------------------------------------------------------------------------
 +
 
 +
local function getArgs(frame)
 +
-- Fetches the arguments from the parent frame. Whitespace is trimmed and
 +
-- blanks are removed.
 +
mArguments = require('Module:Arguments')
 +
return mArguments.getArgs(frame, {parentOnly = true})
 
end
 
end
  
local function concat(e1, e2)
+
local function removeInitialColon(s)
return tostring(e1) .. tostring(e2)
+
-- Removes the initial colon from a string, if present.
 +
return s:match('^:?(.*)')
 
end
 
end
  
function tr.define_categories(tracked_cases)
+
function p.defaultClasses(inline)
local categories = setmetatable({}, {
+
-- Provides the default hatnote classes as a space-separated string; useful
__tostring = function (self) return table.concat(self) end,
+
-- for hatnote-manipulation modules like [[Module:Hatnote group]].
__concat = concat
+
return
})
+
(inline == 1 and 'hatnote-inline' or 'hatnote') .. ' ' ..
 
+
'navigation-not-searchable'
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
 
end
  
function tr.error(msg, categories, preview_only)
+
function p.disambiguate(page, disambiguator)
local current_frame = mw.getCurrentFrame()
+
-- Formats a page title with a disambiguation parenthetical,
local parent_frame = current_frame:getParent()
+
-- i.e. "Example" → "Example (disambiguation)".
local res_frame_title = parent_frame and parent_frame:getTitle() ~= current_title.prefixedText and
+
checkType('disambiguate', 1, page, 'string')
parent_frame:getTitle() or
+
checkType('disambiguate', 2, disambiguator, 'string', true)
current_frame:getTitle()
+
disambiguator = disambiguator or 'disambiguation'
if not preview_only or current_frame:preprocess('{{REVISIONID}}') == '' then
+
return mw.ustring.format('%s (%s)', page, disambiguator)
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
 
end
  
function p.parse_link(frame)
+
function p.findNamespaceId(link, removeColon)
local args = get_args(frame)
+
-- Finds the namespace id (namespace number) of a link or a pagename. This
local link = args[1]:gsub('\n', '')
+
-- function will not work if the link is enclosed in double brackets. Colons
local label
+
-- are trimmed from the start of the link by default. To skip colon
+
-- trimming, set the removeColon parameter to false.
link = mw.text.trim(link:match('^%[%[([^%]]+)%]%]$') or link)
+
checkType('findNamespaceId', 1, link, 'string')
if link:sub(1, 1) == '/' then
+
checkType('findNamespaceId', 2, removeColon, 'boolean', true)
label = link
+
if removeColon ~= false then
link = current_title.prefixedText .. link
+
link = removeInitialColon(link)
 
end
 
end
link = link:match(':?(.+)')
+
local namespace = link:match('^(.-):')
if link:match('|') then
+
if namespace then
link, label = link:match('^([^%|]+)%|(.+)$')
+
local nsTable = mw.site.namespaces[namespace]
 +
if nsTable then
 +
return nsTable.id
 +
end
 
end
 
end
+
return 0
if not mw.title.new(link) then
 
return nil, nil
 
end
 
 
return link, label
 
 
end
 
end
  
function p.format_link(frame)
+
function p.makeWikitextError(msg, helpLink, addTrackingCategory, title)
-- {{ссылка на раздел}}
+
-- Formats an error message to be returned to wikitext. If
local args = get_args(frame)
+
-- addTrackingCategory is not false after being returned from
local link, section, label = args[1], args[2], args[3]
+
-- [[Module:Yesno]], and if we are not on a talk page, a tracking category
+
-- is added.
if not link then
+
checkType('makeWikitextError', 1, msg, 'string')
link = current_title.prefixedText
+
checkType('makeWikitextError', 2, helpLink, 'string', true)
if section then
+
yesno = require('Module:Yesno')
link = '#' .. section
+
title = title or mw.title.getCurrentTitle()
label = label or '§&nbsp;' .. section
+
-- Make the help link text.
end
+
local helpText
 +
if helpLink then
 +
helpText = ' ([[' .. helpLink .. '|help]])'
 
else
 
else
local parsed_link, parsed_label = p.parse_link{link}
+
helpText = ''
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
 
end
+
-- Make the category text.
if label and label ~= link then
+
local category
return string.format('[[:%s|%s]]', link, label)
+
if not title.isTalkPage -- Don't categorise talk pages
 +
and title.namespace ~= 2 -- Don't categorise userspace
 +
and yesno(addTrackingCategory) ~= false -- Allow opting out
 +
then
 +
category = 'Hatnote templates with errors'
 +
category = mw.ustring.format(
 +
'[[%s:%s]]',
 +
mw.site.namespaces[14].name,
 +
category
 +
)
 
else
 
else
return string.format('[[:%s]]', link)
+
category = ''
 
end
 
end
 +
return mw.ustring.format(
 +
'<strong class="error">Error: %s%s.</strong>%s',
 +
msg,
 +
helpText,
 +
category
 +
)
 
end
 
end
  
function p.remove_precision(frame)
+
local curNs = mw.title.getCurrentTitle().namespace
-- {{без уточнения}}
+
p.missingTargetCat =
local args = get_args(frame)
+
--Default missing target category, exported for use in related modules
local title = args[1]
+
((curNs == 0) or (curNs == 14)) and
+
'Articles with hatnote templates targeting a nonexistent page' or nil
return title:match('^(.+)%s+%b()$') or title
 
end
 
  
function p.is_disambig(frame)
+
function p.quote(title)
local args = get_args(frame)
+
--Wraps titles in quotation marks. If the title starts/ends with a quotation
local title = args[1]
+
--mark, kerns that side as with {{-'}}
local page = mw.title.new(title)
+
local quotationMarks = {
+
["'"]=true, ['"']=true, ['“']=true, ["‘"]=true, ['”']=true, ["’"]=true
if not page or not page.exists or mw.title.equals(page, current_title) then
+
}
return false
+
local quoteLeft, quoteRight = -- Test if start/end are quotation marks
 +
quotationMarks[string.sub(title,  1,  1)],
 +
quotationMarks[string.sub(title, -1, -1)]
 +
if quoteLeft or quoteRight then
 +
title = mw.html.create("span"):wikitext(title)
 
end
 
end
+
if quoteLeft  then title:css("padding-left",  "0.15em") end
local page_content = page:getContent()
+
if quoteRight then title:css("padding-right", "0.15em") end
local mw_list_content = mw.title.new('MediaWiki:Disambiguationspage'):getContent()
+
return '"' .. tostring(title) .. '"'
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
 
end
  
function p.list(frame)
+
--------------------------------------------------------------------------------
local args = get_args(frame, {trim = false})
+
-- Hatnote
local list_sep = args.list_sep or args['разделитель списка'] or ', '
+
--
local last_list_sep = yesno(args.natural_join) ~= false and ' и ' or list_sep
+
-- Produces standard hatnote text. Implements the {{hatnote}} template.
local links_ns = args.links_ns or args['ПИ ссылок']
+
--------------------------------------------------------------------------------
local bold_links = yesno(args.bold_links or args['ссылки болдом'])
 
  
local res_list = {}
+
function p.hatnote(frame)
local tracked = {
+
local args = getArgs(frame)
red_link = false,
+
local s = args[1]
bad_format = false,
+
if not s then
formatted = false,
+
return p.makeWikitextError(
unparsable_link = false
+
'no text specified',
}
+
'Template:Hatnote#Errors',
+
args.category
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
 
end
+
return p._hatnote(s, {
return setmetatable(res_list, {
+
extraclasses = args.extraclasses,
__index = tracked,
+
selfref = args.selfref
__tostring = function (self) return mw.text.listToText(self, list_sep, last_list_sep) end,
 
__concat = concat,
 
__pairs = function (self) return pairs(tracked) end
 
 
})
 
})
 
end
 
end
  
function p.hatnote(frame)
+
function p._hatnote(s, options)
local args = get_args(frame)
+
checkType('_hatnote', 1, s, 'string')
local text = args[1]
+
checkType('_hatnote', 2, options, 'table', true)
local id = args.id
+
options = options or {}
local extraclasses = args.extraclasses
+
local inline = options.inline
local hide_disambig = yesno(args.hide_disambig)
+
local hatnote = mw.html.create(inline == 1 and 'span' or 'div')
+
local extraclasses
local res = mw.html.create('div')
+
if type(options.extraclasses) == 'string' then
:attr('id', id)
+
extraclasses = options.extraclasses
:addClass('hatnote')
 
:addClass('navigation-not-searchable')
 
:addClass(extraclasses)
 
:wikitext(text)
 
 
if hide_disambig then
 
res:addClass('dabhide')
 
 
end
 
end
 
return res
 
end
 
  
function p.main(frame, _tracking_categories)
+
hatnote
local args = get_args(frame, {trim = false})
+
:attr('role', 'note')
+
:addClass(p.defaultClasses(inline))
local prefix = args.prefix or args['префикс']
+
:addClass(extraclasses)
local prefix_plural = args.prefix_plural or args['префикс мн. ч.']
+
:addClass(options.selfref and 'selfref' or nil)
local sep = args.sep or args['разделитель'] or ' '
+
:wikitext(s)
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
+
return mw.getCurrentFrame():extensionTag{
categories:add('no_prefix', nocat)
+
name = 'templatestyles', args = { src = 'Module:Hatnote/styles.css' }
return tr.error('Не указан префикс', categories)
+
} .. tostring(hatnote)
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
 
end
  
return index(p, tr)
+
return p

Версия от 21:18, 5 сентября 2022

Для документации этого модуля может быть создана страница Модуль:Hatnote/doc

--------------------------------------------------------------------------------
--                              Module:Hatnote                                --
--                                                                            --
-- This module produces hatnote links and links to related articles. It       --
-- implements the {{hatnote}} and {{format link}} meta-templates and includes --
-- helper functions for other Lua hatnote modules.                            --
--------------------------------------------------------------------------------

local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg
local mArguments -- lazily initialise [[Module:Arguments]]
local yesno -- lazily initialise [[Module:Yesno]]
local formatLink -- lazily initialise [[Module:Format link]] ._formatLink

local p = {}

--------------------------------------------------------------------------------
-- Helper functions
--------------------------------------------------------------------------------

local function getArgs(frame)
	-- Fetches the arguments from the parent frame. Whitespace is trimmed and
	-- blanks are removed.
	mArguments = require('Module:Arguments')
	return mArguments.getArgs(frame, {parentOnly = true})
end

local function removeInitialColon(s)
	-- Removes the initial colon from a string, if present.
	return s:match('^:?(.*)')
end

function p.defaultClasses(inline)
	-- Provides the default hatnote classes as a space-separated string; useful
	-- for hatnote-manipulation modules like [[Module:Hatnote group]].
	return
		(inline == 1 and 'hatnote-inline' or 'hatnote') .. ' ' ..
		'navigation-not-searchable'
end

function p.disambiguate(page, disambiguator)
	-- Formats a page title with a disambiguation parenthetical,
	-- i.e. "Example" → "Example (disambiguation)".
	checkType('disambiguate', 1, page, 'string')
	checkType('disambiguate', 2, disambiguator, 'string', true)
	disambiguator = disambiguator or 'disambiguation'
	return mw.ustring.format('%s (%s)', page, disambiguator)
end

function p.findNamespaceId(link, removeColon)
	-- Finds the namespace id (namespace number) of a link or a pagename. This
	-- function will not work if the link is enclosed in double brackets. Colons
	-- are trimmed from the start of the link by default. To skip colon
	-- trimming, set the removeColon parameter to false.
	checkType('findNamespaceId', 1, link, 'string')
	checkType('findNamespaceId', 2, removeColon, 'boolean', true)
	if removeColon ~= false then
		link = removeInitialColon(link)
	end
	local namespace = link:match('^(.-):')
	if namespace then
		local nsTable = mw.site.namespaces[namespace]
		if nsTable then
			return nsTable.id
		end
	end
	return 0
end

function p.makeWikitextError(msg, helpLink, addTrackingCategory, title)
	-- Formats an error message to be returned to wikitext. If
	-- addTrackingCategory is not false after being returned from
	-- [[Module:Yesno]], and if we are not on a talk page, a tracking category
	-- is added.
	checkType('makeWikitextError', 1, msg, 'string')
	checkType('makeWikitextError', 2, helpLink, 'string', true)
	yesno = require('Module:Yesno')
	title = title or mw.title.getCurrentTitle()
	-- Make the help link text.
	local helpText
	if helpLink then
		helpText = ' ([[' .. helpLink .. '|help]])'
	else
		helpText = ''
	end
	-- Make the category text.
	local category
	if not title.isTalkPage -- Don't categorise talk pages
		and title.namespace ~= 2 -- Don't categorise userspace
		and yesno(addTrackingCategory) ~= false -- Allow opting out
	then
		category = 'Hatnote templates with errors'
		category = mw.ustring.format(
			'[[%s:%s]]',
			mw.site.namespaces[14].name,
			category
		)
	else
		category = ''
	end
	return mw.ustring.format(
		'<strong class="error">Error: %s%s.</strong>%s',
		msg,
		helpText,
		category
	)
end

local curNs = mw.title.getCurrentTitle().namespace
p.missingTargetCat =
	--Default missing target category, exported for use in related modules
	((curNs ==  0) or (curNs == 14)) and
	'Articles with hatnote templates targeting a nonexistent page' or nil

function p.quote(title)
	--Wraps titles in quotation marks. If the title starts/ends with a quotation
	--mark, kerns that side as with {{-'}}
	local quotationMarks = {
		["'"]=true, ['"']=true, ['“']=true, ["‘"]=true, ['”']=true, ["’"]=true
	}
	local quoteLeft, quoteRight = -- Test if start/end are quotation marks
		quotationMarks[string.sub(title,  1,  1)],
		quotationMarks[string.sub(title, -1, -1)]
	if quoteLeft or quoteRight then
		title = mw.html.create("span"):wikitext(title)
	end
	if quoteLeft  then title:css("padding-left",  "0.15em") end
	if quoteRight then title:css("padding-right", "0.15em") end
	return '"' .. tostring(title) .. '"'
end

--------------------------------------------------------------------------------
-- Hatnote
--
-- Produces standard hatnote text. Implements the {{hatnote}} template.
--------------------------------------------------------------------------------

function p.hatnote(frame)
	local args = getArgs(frame)
	local s = args[1]
	if not s then
		return p.makeWikitextError(
			'no text specified',
			'Template:Hatnote#Errors',
			args.category
		)
	end
	return p._hatnote(s, {
		extraclasses = args.extraclasses,
		selfref = args.selfref
	})
end

function p._hatnote(s, options)
	checkType('_hatnote', 1, s, 'string')
	checkType('_hatnote', 2, options, 'table', true)
	options = options or {}
	local inline = options.inline
	local hatnote = mw.html.create(inline == 1 and 'span' or 'div')
	local extraclasses
	if type(options.extraclasses) == 'string' then
		extraclasses = options.extraclasses
	end

	hatnote
		:attr('role', 'note')
		:addClass(p.defaultClasses(inline))
		:addClass(extraclasses)
		:addClass(options.selfref and 'selfref' or nil)
		:wikitext(s)

	return mw.getCurrentFrame():extensionTag{
		name = 'templatestyles', args = { src = 'Module:Hatnote/styles.css' }
	} .. tostring(hatnote)
end

return p