Модуль:Hatnote: различия между версиями
Перейти к навигации
Перейти к поиску
(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: | Строка 1: | ||
− | + | local get_args = require('Module:Arguments').getArgs | |
− | + | local mError | |
− | + | local yesno = function (v) return require('Module:Yesno')(v, true) end | |
− | |||
− | |||
− | |||
− | |||
− | local | + | 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 | + | local function index(t1, t2) |
− | + | return setmetatable(t1, {__index = t2}) | |
− | + | end | |
− | |||
− | |||
− | local function | + | local function concat(e1, e2) |
− | + | return tostring(e1) .. tostring(e2) | |
− | |||
− | |||
− | |||
end | end | ||
− | + | function tr.define_categories(tracked_cases) | |
− | + | local categories = setmetatable({}, { | |
− | + | __tostring = function (self) return table.concat(self) end, | |
− | + | __concat = concat | |
+ | }) | ||
− | function | + | 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 | + | 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 | end | ||
− | function p. | + | 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 = | + | link = current_title.prefixedText .. link |
end | end | ||
− | + | link = link:match(':?(.+)') | |
− | if | + | if link:match('|') then |
− | + | link, label = link:match('^([^%|]+)%|(.+)$') | |
− | + | end | |
− | + | ||
− | + | if not mw.title.new(link) then | |
+ | return nil, nil | ||
end | end | ||
− | return | + | |
+ | return link, label | ||
end | end | ||
− | function p. | + | 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 '§ ' .. section | |
− | + | end | |
− | |||
− | |||
else | 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 § %2') | ||
end | end | ||
− | + | ||
− | + | if label and label ~= link then | |
− | if | + | return string.format('[[:%s|%s]]', link, label) |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
else | else | ||
− | + | return string.format('[[:%s]]', link) | |
end | end | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
− | local | + | function p.remove_precision(frame) |
− | + | -- {{без уточнения}} | |
− | + | local args = get_args(frame) | |
− | (( | + | local title = args[1] |
− | + | ||
+ | return title:match('^(.+)%s+%b()$') or title | ||
+ | end | ||
− | function p. | + | function p.is_disambig(frame) |
− | + | local args = get_args(frame) | |
− | + | local title = args[1] | |
− | local | + | local page = mw.title.new(title) |
− | + | ||
− | + | if not page or not page.exists or mw.title.equals(page, current_title) then | |
− | local | + | 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 | end | ||
− | + | return false | |
− | |||
− | return | ||
end | 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 args = | + | 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 | end | ||
− | return | + | |
− | + | 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 | end | ||
− | function p. | + | function p.hatnote(frame) |
− | + | local args = get_args(frame) | |
− | + | local text = args[1] | |
− | + | local id = args.id | |
− | local | + | local extraclasses = args.extraclasses |
− | local | + | local hide_disambig = yesno(args.hide_disambig) |
− | + | ||
− | if | + | local res = mw.html.create('div') |
− | + | :attr('id', id) | |
+ | :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) | |
− | + | 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)) | ||
− | return | + | 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 | end | ||
− | return p | + | return index(p, tr) |
Версия от 09:38, 28 августа 2023
Для документации этого модуля может быть создана страница Модуль:Hatnote/doc
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 '§ ' .. 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 § %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('navigation-not-searchable')
: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)