Модуль:Navbox
Модуль рэалізуе шаблон {{Навігацыйная табліца}}.
--
-- Рэалізуе {{Навігацыйная табліца}} і {{Падгрупы навігацыйнай табліцы}}.
-- Асноўны аб'ём кода запазычаны з англійскага Module:Navbox.
--
local p = {}
local getArgs -- lazily initialized
local yesno -- lazily initialized
local args
local border
local listnums = {}
local ODD_EVEN_MARKER = '\127_ODDEVEN_\127'
local RESTART_MARKER = '\127_ODDEVEN0_\127'
local REGEX_MARKER = '\127_ODDEVEN(%d?)_\127'
local maintitle
local name
local navigation
local navbar
local above
local image
local below
local titlegroup
local titlegroupclass
local titlegroupstyle
local titlestyle
local groupstyle
local bodystyle
local basestyle
local liststyle
local evenodd_VARIABLE
local abovestyle
local belowstyle
local imageleft
local imageleftstyle
local style
local groupwidth
local listpadding
local bodyclass
local titleclass
local aboveclass
local belowclass
local groupclass
local listclass
local imageclass
local function striped(wikitext)
-- Return wikitext with markers replaced for odd/even striping.
-- Child (subgroup) navboxes are flagged with a category that is removed
-- by parent navboxes. The result is that the category shows all pages
-- where a child navbox is not contained in a parent navbox.
local orphanCat = '[[Катэгорыя:Навігацыйныя шаблоны без бацькі]]'
if border == 'subgroup' and args.orphan ~= 'yes' then
-- No change; striping occurs in outermost navbox.
return wikitext .. orphanCat
end
local first, second = 'odd', 'even'
if evenodd_VARIABLE then
if evenodd_VARIABLE == 'swap' then
first, second = second, first
else
first = evenodd_VARIABLE
second = first
end
end
local changer
if first == second then
changer = first
else
local index = 0
changer = function (code)
if code == '0' then
-- Current occurrence is for a group before a nested table.
-- Set it to first as a valid although pointless class.
-- The next occurrence will be the first row after a title
-- in a subgroup and will also be first.
index = 0
return first
end
index = index + 1
return index % 2 == 1 and first or second
end
end
local regex = orphanCat:gsub('([%[%]])', '%%%1')
return (wikitext:gsub(regex, ''):gsub(REGEX_MARKER, changer)) -- () omits gsub count
end
local function addNewline(s)
if s:match('^[*:;#]') or s:match('^{|') then
return '\n' .. s ..'\n'
else
return s
end
end
local function renderNavBar(titleCell)
if navbar ~= 'off' and navbar ~= 'plain' and not (not name and mw.getCurrentFrame():getParent():getTitle():gsub('/пясочніца$', '') == 'Шаблон:Навігацыйная табліца') then
-- Check color contrast of the gear icon
local styleratio = require('Module:Color contrast')._styleratio
local gearColor = ''
local contrastStyle = titlestyle or basestyle
local gearStyleBlack = (contrastStyle and mw.text.unstripNoWiki(contrastStyle) .. '; color:#666;' or '')
local gearStyleWhite = (contrastStyle and mw.text.unstripNoWiki(contrastStyle) .. '; color:#fff;' or '')
if styleratio{gearStyleBlack} < styleratio{gearStyleWhite} then
gearColor = ' white'
end
--- Gear creation
titleCell
:tag('span')
:addClass('navbox-gear')
:css('float', 'left')
:css('text-align', 'left')
:css('width', '5em')
:css('margin-right', '0.5em')
:wikitext('[[Выява:Wikipedia interwiki section gear icon' .. gearColor .. '.svg|14px|Прагляд гэтага шаблона|link=Шаблон:' .. name .. '|alt=⛭]]')
end
end
--
-- Title row
--
local function renderTitleRow(tbl)
if not maintitle then return end
local titleRow = tbl:tag('tr')
if titlegroup then
titleRow
:tag('th')
:attr('scope', 'row')
:addClass('navbox-group')
:addClass(titlegroupclass)
:cssText(basestyle)
:cssText(groupstyle)
:cssText(titlegroupstyle)
:wikitext(titlegroup)
end
local titleCell = titleRow:tag('th'):attr('scope', 'col')
if titlegroup then
titleCell
:css('border-left', '2px solid #fdfdfd')
:css('width', '100%')
end
local titleColspan = 2
if imageleft then titleColspan = titleColspan + 1 end
if image then titleColspan = titleColspan + 1 end
if titlegroup then titleColspan = titleColspan - 1 end
titleCell
:cssText(basestyle)
:cssText(titlestyle)
:addClass('navbox-title')
:attr('colspan', titleColspan)
renderNavBar(titleCell)
titleCell
:tag('div')
:attr('id', mw.uri.anchorEncode(maintitle))
:addClass(titleclass)
:css('font-size', '114%')
:css('margin', '0 5em')
:wikitext(addNewline(maintitle))
end
--
-- Above/Below rows
--
local function getAboveBelowColspan()
local ret = 2
if imageleft then ret = ret + 1 end
if image then ret = ret + 1 end
return ret
end
local function renderAboveRow(tbl)
if not above then return end
tbl:tag('tr')
:tag('td')
:addClass('navbox-abovebelow')
:addClass(aboveclass)
:cssText(basestyle)
:cssText(abovestyle)
:attr('colspan', getAboveBelowColspan())
:tag('div')
:wikitext(addNewline(above))
end
local function renderBelowRow(tbl)
if not below then return end
tbl:tag('tr')
:tag('td')
:addClass('navbox-abovebelow')
:addClass(belowclass)
:cssText(basestyle)
:cssText(belowstyle)
:attr('colspan', getAboveBelowColspan())
:tag('div')
:wikitext(addNewline(below))
end
--
-- List rows
--
local function haveSubgroups()
for i = 1, 23 do
if (args['group' .. i] or args['загаловак' .. i] or args['група' .. i]) and (args['list' .. i] or args['спіс' .. i]) then
return true
end
end
return false
end
local function renderListRow(tbl, index, listnum)
local row = tbl:tag('tr')
if index == 1 and imageleft then
row
:tag('td')
:addClass('navbox-image')
:addClass(imageclass)
:css('width', '1px')
:css('padding', '0px 7px 0px 0px')
:cssText(imageleftstyle)
:attr('rowspan', #listnums)
:tag('div')
:wikitext(addNewline(imageleft))
end
if (args['group' .. listnum] or args['загаловак' .. listnum] or args['група' .. listnum]) then
local groupCell = row:tag('th')
groupCell
:attr('scope', 'row')
:addClass('navbox-group')
:addClass(groupclass)
:cssText(basestyle)
:css('width', groupwidth or '1px') -- If groupwidth not specified, minimize width
groupCell
:cssText(groupstyle)
:cssText(args['group' .. listnum .. 'style'] or args['стыль_групы' .. listnum] or args['загаловак' .. listnum .. 'стыль'] or args['стыль_загалоўка' .. listnum])
:wikitext(args['group' .. listnum] or args['загаловак' .. listnum] or args['група' .. listnum])
end
local listCell = row:tag('td')
if (args['group' .. listnum] or args['загаловак' .. listnum] or args['група' .. listnum]) then
listCell
:css('text-align', 'left')
:css('border-left-width', '2px')
:css('border-left-style', 'solid')
else
if haveSubgroups() then
listCell
:attr('colspan', 2)
end
end
if not groupwidth then
listCell:css('width', '100%')
end
local listText = args['list' .. listnum] or args['спіс' .. listnum]
local oddEven = ODD_EVEN_MARKER
if listText:sub(1, 12) == '</div><table' then
-- Assume list text is for a subgroup navbox so no automatic striping for this row.
oddEven = listText:find('<th[^>]*"navbox%-title"') and RESTART_MARKER or 'odd'
end
listCell
:css('padding', '0px')
:cssText(liststyle)
:cssText(args['list' .. listnum .. 'style'] or args['спіс' .. listnum .. 'стыль'] or args['стыль_спісу' .. listnum])
:addClass('navbox-list')
:addClass('navbox-' .. oddEven)
:addClass(listclass)
:tag('div')
:css('padding', args['list' .. listnum .. 'padding'] or args['спіс' .. listnum .. 'водступ'] or args['водступ_спісу' .. listnum] or listpadding or '0em 0.25em')
:wikitext(addNewline(listText))
if index == 1 and image then
row
:tag('td')
:addClass('navbox-image')
:addClass(imageclass)
:css('width', '1px')
:css('padding', '0px 0px 0px 7px')
:cssText(imagestyle)
:attr('rowspan', #listnums)
:tag('div')
:wikitext(addNewline(image))
end
end
--
-- Tracking categories
--
local function needsChangetoSubgroups()
for i = 1, 23 do
if (args['group' .. i] or args['загаловак' .. i] or args['група' .. i]) and not (args['list' .. i] or args['спіс' .. i]) then
return true
end
end
return false
end
local function needsHorizontalLists()
if border == 'subgroup' or args.tracking == 'no' or args['назіральныя катэгорыі'] == 'no' then
return false
end
local listClasses = {
['plainlist'] = true, ['hlist'] = true, ['hlist hnum'] = true,
['hlist hwrap'] = true, ['hlist vcard'] = true, ['vcard hlist'] = true,
['hlist vevent'] = true, ['hlist hlist-items-nowrap'] = true, ['hlist-items-nowrap'] = true,
}
return not (listClasses[listclass] or listClasses[bodyclass])
end
local function hasBackgroundColors()
return args["стыль_асноўнага_загалоўка"] or args["стыль_загалоўка"] or args["стыль_загалоўкаў"]
end
local function isIllegible()
local styleratio = require('Module:Color contrast')._styleratio
for key, style in pairs(args) do
if tostring(key):match("style$") or tostring(key):match("^стыль") then
if styleratio{mw.text.unstripNoWiki(style)} < 4.5 then
return true
end
end
end
return false
end
local function getTrackingCategories()
local cats = {}
if needsChangetoSubgroups() then table.insert(cats, 'Навігацыйныя шаблоны з памылковым выкарыстаннем загалоўкаў') end
if needsHorizontalLists() then table.insert(cats, 'Навігацыйныя шаблоны без гарызантальных спісаў') end
if isIllegible() then table.insert(cats, 'Патэнцыйна нечытэльныя навігацыйныя шаблоны') end
if hasBackgroundColors() then table.insert(cats, 'Навігацыйныя шаблоны з нестандартнымі колерамі') end
return cats
end
local function renderTrackingCategories(builder)
local title = mw.title.getCurrentTitle()
if title.namespace ~= 10 then return end -- not in template space
local subpage = title.subpageText
if subpage == 'doc' or subpage == 'пясочніца' or subpage == 'тэсты' then return end
for i, cat in ipairs(getTrackingCategories()) do
builder:wikitext('[[Катэгорыя:' .. cat .. ']]')
end
end
--
-- Main navbox tables
--
local function renderMainTable()
local tbl = mw.html.create('table')
:addClass('nowraplinks')
:addClass(bodyclass)
if maintitle and (args.state ~= 'plain' and args.state ~= 'off') then
tbl
:addClass('collapsible')
:addClass(args.state or 'autocollapse')
end
tbl:css('border-spacing', 0)
if border == 'subgroup' or border == 'none' then
tbl
:addClass('navbox-subgroup')
:cssText(bodystyle)
:cssText(style)
else -- regular navbox - bodystyle and style will be applied to the wrapper table
tbl
:addClass('navbox-inner')
:css('background', 'transparent')
:css('color', 'inherit')
end
tbl:cssText(args.innerstyle)
renderTitleRow(tbl)
renderAboveRow(tbl)
for i, listnum in ipairs(listnums) do
renderListRow(tbl, i, listnum)
end
renderBelowRow(tbl)
return tbl
end
function p._navbox(navboxArgs)
args = navboxArgs
if not yesno then
yesno = require('Module:Yesno');
end
for k, v in pairs(args) do
local listnum = ('' .. k):match('^list(%d+)$') or ('' .. k):match('^спіс(%d+)$')
if listnum then table.insert(listnums, tonumber(listnum)) end
end
table.sort(listnums)
border = mw.text.trim(args.border or args[1] or '')
if border == 'child' then
border = 'subgroup'
end
maintitle = args.title or args['загаловак']
navbar = args.navbar or args['спасылка_на_прагляд']
name = args.name or args['імя']
navigation = yesno(args.navigation or args['навігацыя'], '')
above = args.above or args['уверсе']
image = args.image or args['выява']
imagestyle = args.imagestyle or args['стыль_выявы']
imageleft = args.imageleft or args['выява2'] or args['выява_злева']
imageleftstyle = args.imageleftstyle or args.imagestyle2 or args['стыль_выявы_злева']
below = args.below or args['унізе']
titlestyle = args.titlestyle or args['стыль_асноўнага_загалоўка'] or args['стыль_загалоўка']
groupstyle = args.groupstyle or args['стыль_загалоўкаў'] or args['стыль_груп']
bodystyle = args.bodystyle or args['стыль_цела']
basestyle = args.basestyle or args['базавы_стыль'] or args['стыль_базавы']
style = args.style or args['стыль']
liststyle = args.liststyle or args['стыль_спісаў']
abovestyle = args.abovestyle or args['стыль_уверсе']
belowstyle = args.belowstyle or args['стыль_унізе']
evenodd_VARIABLE = args.evenodd or args['цотнасць'] or args['цотныя_няцотныя']
titlegroup = args.titlegroup or args['група-загаловак']
titlegroupclass = args.titlegroupclass or args['клас_групы-загалоўка']
titlegroupstyle = args.titlegroupstyle or args['стыль_групы-загалоўка']
groupwidth = args.groupwidth or args['шырыня_загалоўкаў'] or args['шырыня_груп']
listpadding = args.listpadding or args['водступ_спісаў']
bodyclass = args.bodyclass or args['клас_цела']
titleclass = args.titleclass or args['клас_загалоўка'] or args['клас_асноўнага_загалоўка']
aboveclass = args.aboveclass or args['клас_уверсе']
belowclass = args.belowclass or args['клас_унізе']
groupclass = args.groupclass or args['клас_загалоўкаў'] or args['клас_груп']
listclass = args.listclass or args['клас_спісаў']
imageclass = args.imageclass or args['клас_выявы']
-- render the main body of the navbox
local tbl = renderMainTable()
-- render the appropriate wrapper around the navbox, depending on the border param
local res = mw.html.create()
if border == 'none' then
res:node(mw.html.create('div')
:addClass('navbox-styles')
:wikitext(mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Module:Navbox/styles.css' } }
)
:done())
local nav = res:tag('div')
:attr('role', 'navigation')
:node(tbl)
if maintitle then
nav:attr('aria-labelledby', mw.uri.anchorEncode(maintitle))
else
nav:attr('aria-label', 'Навігацыйны шаблон')
end
if name and name ~= '-' then
nav:attr('data-name', name)
end
if navigation == true then
nav:attr('data-navboxnavigation', '1')
elseif navigation == false then
nav:attr('data-navboxnavigation', '0')
end
elseif border == 'subgroup' then
-- We assume that this navbox is being rendered in a list cell of a parent navbox, and is
-- therefore inside a div with padding:0em 0.25em. We start with a </div> to avoid the
-- padding being applied, and at the end add a <div> to balance out the parent's </div>
res
:wikitext('</div>') -- XXX: hack due to lack of unclosed support in mw.html.
:node(tbl)
:wikitext('<div>') -- XXX: hack due to lack of unclosed support in mw.html.
else
res:node(mw.html.create('div')
:addClass('navbox-styles')
:wikitext(mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Module:Navbox/styles.css' } }
)
:done())
local nav = res:tag('div')
:attr('role', 'navigation')
:addClass('navbox')
:cssText(bodystyle)
:cssText(style)
:css('padding', '3px')
:node(tbl)
if maintitle then
nav:attr('aria-labelledby', mw.uri.anchorEncode(maintitle))
else
nav:attr('aria-label', 'Навігацыйны шаблон')
end
if name and name ~= '-' then
nav:attr('data-name', name)
end
if navigation == true then
nav:attr('data-navboxnavigation', '1')
elseif navigation == false then
nav:attr('data-navboxnavigation', '0')
end
end
renderTrackingCategories(res)
return striped(tostring(res))
end
function p.navbox(frame)
if not getArgs then
getArgs = require('Module:Arguments').getArgs
end
if not yesno then
yesno = require('Module:Yesno');
end
args = getArgs(frame, {wrappers = {'Шаблон:Навігацыйная табліца', 'Шаблон:Падгрупы навігацыйнай табліцы'}})
if frame.args.border then
-- This allows Template:Navbox_subgroup to use {{#invoke:Navbox|navbox|border=...}}.
args.border = frame.args.border
end
-- Read the arguments in the order they'll be output in, to make references number in the right order.
local _
_ = maintitle
_ = above
for i = 1, 23 do
_ = args["group" .. tostring(i)] and args["загаловак" .. tostring(i)] and args["група" .. tostring(i)]
_ = args["list" .. tostring(i)] and args["спіс" .. tostring(i)]
end
_ = below
return p._navbox(args)
end
return p