Модуль:Hatnote

* См. статью wikipedia:ru:Модуль: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 '§&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('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)

```