Difference between revisions of "Template:Navbox"

(per discussion at WT:Lua, this needs to be initialized in a non-global context)
 
(25 intermediate revisions by 2 users not shown)
Line 1: Line 1:
−
--
+
<includeonly>{{#invoke:Navbox|navbox}}</includeonly><noinclude>
−
-- This module implements {{Navbox}}
+
{{Documentation}}
−
--
+
</noinclude>
−
 
 
−
local p = {}
 
−
 
 
−
local navbar = require('Module:Navbar')._navbar
 
−
local getArgs -- 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 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 = '[[Category:Navbox orphans]]'
 
−
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 args.evenodd then
 
−
if args.evenodd == 'swap' then
 
−
first, second = second, first
 
−
else
 
−
first = args.evenodd
 
−
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 processItem(item, nowrapitems)
 
−
if item:sub(1, 2) == '{|' then
 
−
-- Applying nowrap to lines in a table does not make sense.
 
−
-- Add newlines to compensate for trim of x in |parm=x in a template.
 
−
return '\n' .. item ..'\n'
 
−
end
 
−
if nowrapitems == 'yes' then
 
−
local lines = {}
 
−
for line in (item .. '\n'):gmatch('([^\n]*)\n') do
 
−
local prefix, content = line:match('^([*:;#]+)%s*(.*)')
 
−
if prefix and not content:match('^<span class="nowrap">') then
 
−
line = prefix .. '<span class="nowrap">' .. content .. '</span>'
 
−
end
 
−
table.insert(lines, line)
 
−
end
 
−
item = table.concat(lines, '\n')
 
−
end
 
−
if item:match('^[*:;#]') then
 
−
return '\n' .. item ..'\n'
 
−
end
 
−
return item
 
−
end
 
−
 
 
−
local function renderNavBar(titleCell)
 
−
 
 
−
if args.navbar ~= 'off' and args.navbar ~= 'plain' and not (not args.name and mw.getCurrentFrame():getParent():getTitle():gsub('/sandbox$', '') == 'Template:Navbox') then
 
−
titleCell:wikitext(navbar{
 
−
args.name,
 
−
mini = 1,
 
−
fontstyle = (args.basestyle or '') .. ';' .. (args.titlestyle or '') .. ';background:none transparent;border:none;-moz-box-shadow:none;-webkit-box-shadow:none;box-shadow:none; padding:0;'
 
−
})
 
−
end
 
−
 
 
−
end
 
−
 
 
−
--
 
−
--  Title row
 
−
--
 
−
local function renderTitleRow(tbl)
 
−
if not args.title then return end
 
−
 
 
−
local titleRow = tbl:tag('tr')
 
−
 
 
−
if args.titlegroup then
 
−
titleRow
 
−
:tag('th')
 
−
:attr('scope', 'row')
 
−
:addClass('navbox-group')
 
−
:addClass(args.titlegroupclass)
 
−
:cssText(args.basestyle)
 
−
:cssText(args.groupstyle)
 
−
:cssText(args.titlegroupstyle)
 
−
:wikitext(args.titlegroup)
 
−
end
 
−
 
 
−
local titleCell = titleRow:tag('th'):attr('scope', 'col')
 
−
 
 
−
if args.titlegroup then
 
−
titleCell
 
−
:css('border-left', '2px solid #fdfdfd')
 
−
:css('width', '100%')
 
−
end
 
−
 
 
−
local titleColspan = 2
 
−
if args.imageleft then titleColspan = titleColspan + 1 end
 
−
if args.image then titleColspan = titleColspan + 1 end
 
−
if args.titlegroup then titleColspan = titleColspan - 1 end
 
−
 
 
−
titleCell
 
−
:cssText(args.basestyle)
 
−
:cssText(args.titlestyle)
 
−
:addClass('navbox-title')
 
−
:attr('colspan', titleColspan)
 
−
 
 
−
renderNavBar(titleCell)
 
−
 
 
−
titleCell
 
−
:tag('div')
 
−
-- id for aria-labelledby attribute
 
−
:attr('id', mw.uri.anchorEncode(args.title))
 
−
:addClass(args.titleclass)
 
−
:css('font-size', '114%')
 
−
:css('margin', '0 4em')
 
−
:wikitext(processItem(args.title))
 
−
end
 
−
 
 
−
--
 
−
--  Above/Below rows
 
−
--
 
−
 
 
−
local function getAboveBelowColspan()
 
−
local ret = 2
 
−
if args.imageleft then ret = ret + 1 end
 
−
if args.image then ret = ret + 1 end
 
−
return ret
 
−
end
 
−
 
 
−
local function renderAboveRow(tbl)
 
−
if not args.above then return end
 
−
 
 
−
tbl:tag('tr')
 
−
:tag('td')
 
−
:addClass('navbox-abovebelow')
 
−
:addClass(args.aboveclass)
 
−
:cssText(args.basestyle)
 
−
:cssText(args.abovestyle)
 
−
:attr('colspan', getAboveBelowColspan())
 
−
:tag('div')
 
−
-- id for aria-labelledby attribute, if no title
 
−
:attr('id', args.title and nil or mw.uri.anchorEncode(args.above))
 
−
:wikitext(processItem(args.above, args.nowrapitems))
 
−
end
 
−
 
 
−
local function renderBelowRow(tbl)
 
−
if not args.below then return end
 
−
 
 
−
tbl:tag('tr')
 
−
:tag('td')
 
−
:addClass('navbox-abovebelow')
 
−
:addClass(args.belowclass)
 
−
:cssText(args.basestyle)
 
−
:cssText(args.belowstyle)
 
−
:attr('colspan', getAboveBelowColspan())
 
−
:tag('div')
 
−
:wikitext(processItem(args.below, args.nowrapitems))
 
−
end
 
−
 
 
−
--
 
−
--  List rows
 
−
--
 
−
local function renderListRow(tbl, index, listnum)
 
−
local row = tbl:tag('tr')
 
−
 
 
−
if index == 1 and args.imageleft then
 
−
row
 
−
:tag('td')
 
−
:addClass('navbox-image')
 
−
:addClass(args.imageclass)
 
−
:css('width', '1px')              -- Minimize width
 
−
:css('padding', '0px 2px 0px 0px')
 
−
:cssText(args.imageleftstyle)
 
−
:attr('rowspan', #listnums)
 
−
:tag('div')
 
−
:wikitext(processItem(args.imageleft))
 
−
end
 
−
 
 
−
if args['group' .. listnum] then
 
−
local groupCell = row:tag('th')
 
−
 
 
−
-- id for aria-labelledby attribute, if lone group with no title or above
 
−
if listnum == 1 and not (args.title or args.above or args.group2) then
 
−
groupCell
 
−
:attr('id', mw.uri.anchorEncode(args.group1))
 
−
end
 
−
 
 
−
groupCell
 
−
:attr('scope', 'row')
 
−
:addClass('navbox-group')
 
−
:addClass(args.groupclass)
 
−
:cssText(args.basestyle)
 
−
:css('width', args.groupwidth or '1%') -- If groupwidth not specified, minimize width
 
−
 
 
−
groupCell
 
−
:cssText(args.groupstyle)
 
−
:cssText(args['group' .. listnum .. 'style'])
 
−
:wikitext(args['group' .. listnum])
 
−
end
 
−
 
 
−
local listCell = row:tag('td')
 
−
 
 
−
if args['group' .. listnum] then
 
−
listCell
 
−
:css('text-align', 'left')
 
−
:css('border-left-width', '2px')
 
−
:css('border-left-style', 'solid')
 
−
else
 
−
listCell:attr('colspan', 2)
 
−
end
 
−
 
 
−
if not args.groupwidth then
 
−
listCell:css('width', '100%')
 
−
end
 
−
 
 
−
local rowstyle  -- usually nil so cssText(rowstyle) usually adds nothing
 
−
if index % 2 == 1 then
 
−
rowstyle = args.oddstyle
 
−
else
 
−
rowstyle = args.evenstyle
 
−
end
 
−
 
 
−
local listText = args['list' .. 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(args.liststyle)
 
−
:cssText(rowstyle)
 
−
:cssText(args['list' .. listnum .. 'style'])
 
−
:addClass('navbox-list')
 
−
:addClass('navbox-' .. oddEven)
 
−
:addClass(args.listclass)
 
−
:addClass(args['list' .. listnum .. 'class'])
 
−
:tag('div')
 
−
:css('padding', (index == 1 and args.list1padding) or args.listpadding or '0em 0.25em')
 
−
:wikitext(processItem(listText, args.nowrapitems))
 
−
 
 
−
if index == 1 and args.image then
 
−
row
 
−
:tag('td')
 
−
:addClass('navbox-image')
 
−
:addClass(args.imageclass)
 
−
:css('width', '1px')              -- Minimize width
 
−
:css('padding', '0px 0px 0px 2px')
 
−
:cssText(args.imagestyle)
 
−
:attr('rowspan', #listnums)
 
−
:tag('div')
 
−
:wikitext(processItem(args.image))
 
−
end
 
−
end
 
−
 
 
−
 
 
−
--
 
−
--  Tracking categories
 
−
--
 
−
 
 
−
local function needsHorizontalLists()
 
−
if border == 'subgroup' or args.tracking == '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,
 
−
}
 
−
return not (listClasses[args.listclass] or listClasses[args.bodyclass])
 
−
end
 
−
 
 
−
local function hasBackgroundColors()
 
−
for _, key in ipairs({'titlestyle', 'groupstyle', 'basestyle', 'abovestyle', 'belowstyle'}) do
 
−
if tostring(args[key]):find('background', 1, true) then
 
−
return true
 
−
end
 
−
end
 
−
end
 
−
 
 
−
local function hasBorders()
 
−
for _, key in ipairs({'groupstyle', 'basestyle', 'abovestyle', 'belowstyle'}) do
 
−
if tostring(args[key]):find('border', 1, true) then
 
−
return true
 
−
end
 
−
end
 
−
end
 
−
 
 
−
local function isIllegible()
 
−
local styleratio = require('Module:Color contrast')._styleratio
 
−
 
 
−
for key, style in pairs(args) do
 
−
if tostring(key):match("style$") then
 
−
if styleratio{mw.text.unstripNoWiki(style)} < 4.5 then
 
−
return true
 
−
end
 
−
end
 
−
end
 
−
return false
 
−
end
 
−
 
 
−
local function getTrackingCategories()
 
−
local cats = {}
 
−
if needsHorizontalLists() then table.insert(cats, 'Navigational boxes without horizontal lists') end
 
−
if hasBackgroundColors() then table.insert(cats, 'Navboxes using background colours') end
 
−
if isIllegible() then table.insert(cats, 'Potentially illegible navboxes') end
 
−
if hasBorders() then table.insert(cats, 'Navboxes using borders') 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 == 'sandbox' or subpage == 'testcases' then return end
 
−
 
 
−
for _, cat in ipairs(getTrackingCategories()) do
 
−
builder:wikitext('[[Category:' .. cat .. ']]')
 
−
end
 
−
end
 
−
 
 
−
--
 
−
--  Main navbox tables
 
−
--
 
−
local function renderMainTable()
 
−
local tbl = mw.html.create('table')
 
−
:addClass('nowraplinks')
 
−
:addClass(args.bodyclass)
 
−
 
 
−
if args.title 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(args.bodystyle)
 
−
:cssText(args.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
 
−
listnums = {}
 
−
 
 
−
for k, _ in pairs(args) do
 
−
if type(k) == 'string' then
 
−
local listnum = k:match('^list(%d+)$')
 
−
if listnum then table.insert(listnums, tonumber(listnum)) end
 
−
end
 
−
end
 
−
table.sort(listnums)
 
−
 
 
−
border = mw.text.trim(args.border or args[1] or '')
 
−
if border == 'child' then
 
−
border = 'subgroup'
 
−
end
 
−
 
 
−
-- 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
 
−
local nav = res:tag('div')
 
−
:attr('role', 'navigation')
 
−
:node(tbl)
 
−
-- aria-labelledby title, otherwise above, otherwise lone group
 
−
if args.title or args.above or (args.group1 and not args.group2) then
 
−
nav:attr('aria-labelledby', mw.uri.anchorEncode(args.title or args.above or args.group1))
 
−
else
 
−
nav:attr('aria-label', 'Navbox')
 
−
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>')
 
−
:node(tbl)
 
−
:wikitext('<div>')
 
−
else
 
−
local nav = res:tag('div')
 
−
:attr('role', 'navigation')
 
−
:addClass('navbox')
 
−
:cssText(args.bodystyle)
 
−
:cssText(args.style)
 
−
:css('padding', '3px')
 
−
:node(tbl)
 
−
-- aria-labelledby title, otherwise above, otherwise lone group
 
−
if args.title or args.above or (args.group1 and not args.group2) then
 
−
nav:attr('aria-labelledby', mw.uri.anchorEncode(args.title or args.above or args.group1))
 
−
else
 
−
nav:attr('aria-label', 'Navbox')
 
−
end
 
−
end
 
−
 
 
−
if (args.nocat or 'false'):lower() == 'false' then
 
−
renderTrackingCategories(res)
 
−
end
 
−
return striped(tostring(res))
 
−
end
 
−
 
 
−
function p.navbox(frame)
 
−
if not getArgs then
 
−
getArgs = require('Module:Arguments').getArgs
 
−
end
 
−
args = getArgs(frame, {wrappers = {'Template:Navbox', 'Template:Navbox subgroup'}})
 
−
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 _
 
−
_ = args.title
 
−
_ = args.above
 
−
for i = 1, 20 do
 
−
_ = args["group" .. tostring(i)]
 
−
_ = args["list" .. tostring(i)]
 
−
end
 
−
_ = args.below
 
−
 
 
−
return p._navbox(args)
 
−
end
 
−
 
 
−
return p
 

Latest revision as of 17:05, 13 August 2019

x


Script error: Lua error: Internal error: The interpreter exited with status 127.

<includeonly>{{#invoke:Navbox|navbox}}</includeonly><noinclude>
{{Documentation}}
</noinclude>