VOOZH about

URL: https://en.wikipedia.org/wiki/Module:Navbox

⇱ Module:Navbox - Wikipedia


Jump to content
From Wikipedia, the free encyclopedia
👁 Image
Module documentation
[view] [edit] [history] [purge]
👁 Warning
This Lua module is used on approximately 4,810,000 pages, or roughly 7% of all pages.
To avoid major disruption and server load, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Consider discussing changes on the talk page before implementing them.
👁 Image
This module is rated as ready for general use. It has reached a mature state, is considered relatively stable and bug-free, and may be used wherever appropriate. It can be mentioned on help pages and other Wikipedia resources as an option for new users. To minimise server load and avoid disruptive output, improvements should be developed through sandbox testing rather than repeated trial-and-error editing.
👁 Page template-protected
This module is currently protected from editing.
See the protection policy and protection log for more details. Please discuss any changes on the talk page; you may submit an edit request to ask an administrator to make an edit if it is uncontroversial or supported by consensus. You may also request that this page be unprotected.
👁 Image
This module depends on the following other modules:
👁 CSS
This module uses TemplateStyles:
Related pages

This module implements the {{Navbox}}, {{Navbox with columns}}, and {{Navbox with collapsible groups}} templates.

Usage

{{|navbox}}

{{|collapsible}}

{{|columns}}

Please see the template page for usage instructions.

Tracking/maintenance categories

See also

require('strict')
localp={}
localcfg=mw.loadData('Module:Navbox/configuration')
localinArray=require("Module:TableTools").inArray
localgetArgs-- lazily initialized
localhiding_templatestyles={}
-- global passthrough variables
localpassthrough={
[cfg.arg.above]=true,[cfg.arg.aboveclass]=true,[cfg.arg.abovestyle]=true,
[cfg.arg.basestyle]=true,
[cfg.arg.below]=true,[cfg.arg.belowclass]=true,[cfg.arg.belowstyle]=true,
[cfg.arg.bodyclass]=true,
[cfg.arg.groupclass]=true,
[cfg.arg.image]=true,[cfg.arg.imageclass]=true,[cfg.arg.imagestyle]=true,
[cfg.arg.imageleft]=true,[cfg.arg.imageleftstyle]=true,
[cfg.arg.listclass]=true,
[cfg.arg.name]=true,
[cfg.arg.navbar]=true,
[cfg.arg.state]=true,
[cfg.arg.title]=true,[cfg.arg.titleclass]=true,[cfg.arg.titlestyle]=true,
argHash=true
}
-- helper functions
localandnum=function(s,n)returnstring.format(cfg.arg[s..'_and_num'],n)end
localisblank=function(v)return(vor'')==''end
localfunctionconcatstrings(s)
localr=table.concat(s,'')
ifr:match('^%s*$')thenreturnnilend
returnr
end
localfunctionconcatstyles(s)
localr=''
for_,vinipairs(s)do
v=mw.text.trim(v,"%s;")
ifnotisblank(v)thenr=r..v..';'end
end
ifisblank(r)thenreturnnilend
returnr
end
localfunctiongetSubgroup(args,listnum,listText,prefix)
localsubArgs={
[cfg.arg.border]=cfg.keyword.border_subgroup,
[cfg.arg.navbar]=cfg.keyword.navbar_plain,
argHash=0
}
localhasSubArgs=false
localsubgroups_and_num=prefixand{prefix}orcfg.arg.subgroups_and_num
fork,vinpairs(args)do
k=tostring(k)
for_,winipairs(subgroups_and_num)do
w=string.format(w,listnum).."_"
if(#k>#w)and(k:sub(1,#w)==w)then
subArgs[k:sub(#w+1)]=v
hasSubArgs=true
subArgs.argHash=subArgs.argHash+(vand#vor0)
end
end
end
returnhasSubArgsandp._navbox(subArgs)orlistText
end
-- Main functions
functionp._navbox(args)
ifargs.type==cfg.keyword.with_collapsible_groupsthen
returnp._withCollapsibleGroups(args)
elseifargs.type==cfg.keyword.with_columnsthen
returnp._withColumns(args)
end
localfunctionstriped(wikitext,border)
-- 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.
localorphanCat=cfg.category.orphan
ifborder==cfg.keyword.border_subgroupandargs[cfg.arg.orphan]~=cfg.keyword.orphan_yesthen
-- No change; striping occurs in outermost navbox.
returnwikitext..orphanCat
end
localfirst,second=cfg.class.navbox_odd_part,cfg.class.navbox_even_part
ifargs[cfg.arg.evenodd]then
ifargs[cfg.arg.evenodd]==cfg.keyword.evenodd_swapthen
first,second=second,first
else
first=args[cfg.arg.evenodd]
second=first
end
end
localchanger
iffirst==secondthen
changer=first
else
localindex=0
changer=function(code)
ifcode=='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
returnfirst
end
index=index+1
returnindex%2==1andfirstorsecond
end
end
localregex=orphanCat:gsub('([%[%]])','%%%1')
return(wikitext:gsub(regex,''):gsub(cfg.marker.regex,changer))-- () omits gsub count
end
localfunctionprocessItem(item,nowrapitems)
ifitem: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
ifnowrapitems==cfg.keyword.nowrapitems_yesthen
locallines={}
forlinein(item..'\n'):gmatch('([^\n]*)\n')do
localprefix,content=line:match('^([*:;#]+)%s*(.*)')
ifprefixandnotcontent:match(cfg.pattern.nowrap)then
line=string.format(cfg.nowrap_item,prefix,content)
end
table.insert(lines,line)
end
item=table.concat(lines,'\n')
end
ifitem:match('^[*:;#]')then
return'\n'..item..'\n'
end
returnitem
end
localfunctionhas_navbar()
returnargs[cfg.arg.navbar]~=cfg.keyword.navbar_off
andargs[cfg.arg.navbar]~=cfg.keyword.navbar_plain
and(
args[cfg.arg.name]
ormw.getCurrentFrame():getParent():getTitle():gsub(cfg.pattern.sandbox,'')
~=cfg.pattern.navbox
)
end
-- extract text color from css, which is the only permitted inline CSS for the navbar
localfunctionextract_color(css_str)
-- return nil because navbar takes its argument into mw.html which handles
-- nil gracefully, removing the associated style attribute
returnmw.ustring.match(';'..css_str..';','.*;%s*([Cc][Oo][Ll][Oo][Rr]%s*:%s*.-)%s*;')ornil
end
localfunctionrenderNavBar(titleCell)
ifhas_navbar()then
localnavbar=require('Module:Navbar')._navbar
titleCell:wikitext(navbar{
[cfg.navbar.name]=args[cfg.arg.name],
[cfg.navbar.mini]=1,
[cfg.navbar.fontstyle]=extract_color(
(args[cfg.arg.basestyle]or'')..';'..(args[cfg.arg.titlestyle]or'')
)
})
end
end
localfunctionrenderTitleRow(tbl)
ifnotargs[cfg.arg.title]thenreturnend
localtitleRow=tbl:tag('tr')
localtitleCell=titleRow:tag('th'):attr('scope','col')
localtitleColspan=2
ifargs[cfg.arg.imageleft]thentitleColspan=titleColspan+1end
ifargs[cfg.arg.image]thentitleColspan=titleColspan+1end
titleCell
:cssText(args[cfg.arg.basestyle])
:cssText(args[cfg.arg.titlestyle])
:addClass(cfg.class.navbox_title)
:attr('colspan',titleColspan)
renderNavBar(titleCell)
titleCell
:tag('div')
-- id for aria-labelledby attribute
:attr('id',mw.uri.anchorEncode(args[cfg.arg.title])..args.argHash)
:addClass(args[cfg.arg.titleclass])
:css('font-size','114%')
:css('margin','0 4em')
:wikitext(processItem(args[cfg.arg.title]))
end
localfunctiongetAboveBelowColspan()
localret=2
ifargs[cfg.arg.imageleft]thenret=ret+1end
ifargs[cfg.arg.image]thenret=ret+1end
returnret
end
localfunctionrenderAboveRow(tbl)
ifnotargs[cfg.arg.above]thenreturnend
tbl:tag('tr')
:tag('td')
:addClass(cfg.class.navbox_abovebelow)
:addClass(args[cfg.arg.aboveclass])
:cssText(args[cfg.arg.basestyle])
:cssText(args[cfg.arg.abovestyle])
:attr('colspan',getAboveBelowColspan())
:tag('div')
-- id for aria-labelledby attribute, if no title
:attr('id',(notargs[cfg.arg.title])and
(mw.uri.anchorEncode(args[cfg.arg.above])..args.argHash)
ornil)
:wikitext(processItem(args[cfg.arg.above],args[cfg.arg.nowrapitems]))
end
localfunctionrenderBelowRow(tbl)
ifnotargs[cfg.arg.below]thenreturnend
tbl:tag('tr')
:tag('td')
:addClass(cfg.class.navbox_abovebelow)
:addClass(args[cfg.arg.belowclass])
:cssText(args[cfg.arg.basestyle])
:cssText(args[cfg.arg.belowstyle])
:attr('colspan',getAboveBelowColspan())
:tag('div')
:wikitext(processItem(args[cfg.arg.below],args[cfg.arg.nowrapitems]))
end
localfunctionrenderListRow(tbl,index,listnum,listnums_size)
localrow=tbl:tag('tr')
ifindex==1andargs[cfg.arg.imageleft]then
row
:tag('td')
:addClass(cfg.class.noviewer)
:addClass(cfg.class.navbox_image)
:addClass(args[cfg.arg.imageclass])
:css('width','1px')-- Minimize width
:css('padding','0 2px 0 0')
:cssText(args[cfg.arg.imageleftstyle])
:attr('rowspan',listnums_size)
:tag('div')
:wikitext(processItem(args[cfg.arg.imageleft]))
end
localgroup_and_num=andnum('group',listnum)
localgroupstyle_and_num=andnum('groupstyle',listnum)
ifargs[group_and_num]then
localgroupCell=row:tag('th')
-- id for aria-labelledby attribute, if lone group with no title or above
iflistnum==1andnot(args[cfg.arg.title]orargs[cfg.arg.above]orargs[cfg.arg.group2])then
groupCell
:attr('id',mw.uri.anchorEncode(args[cfg.arg.group1])..args.argHash)
end
groupCell
:attr('scope','row')
:addClass(cfg.class.navbox_group)
:addClass(args[cfg.arg.groupclass])
:cssText(args[cfg.arg.basestyle])
-- If groupwidth not specified, minimize width
:css('width',args[cfg.arg.groupwidth]or'1%')
groupCell
:cssText(args[cfg.arg.groupstyle])
:cssText(args[groupstyle_and_num])
:wikitext(args[group_and_num])
end
locallistCell=row:tag('td')
ifargs[group_and_num]then
listCell
:addClass(cfg.class.navbox_list_with_group)
else
listCell:attr('colspan',2)
end
ifnotargs[cfg.arg.groupwidth]then
listCell:css('width','100%')
end
localrowstyle-- usually nil so cssText(rowstyle) usually adds nothing
ifindex%2==1then
rowstyle=args[cfg.arg.oddstyle]
else
rowstyle=args[cfg.arg.evenstyle]
end
locallist_and_num=andnum('list',listnum)
locallistText=inArray(cfg.keyword.subgroups,args[list_and_num])
andgetSubgroup(args,listnum,args[list_and_num])orargs[list_and_num]
localoddEven=cfg.marker.oddeven
iflistText:sub(1,12)=='</div><table'then
-- Assume list text is for a subgroup navbox so no automatic striping for this row.
oddEven=listText:find(cfg.pattern.navbox_title)andcfg.marker.restartorcfg.class.navbox_odd_part
end
localliststyle_and_num=andnum('liststyle',listnum)
locallistclass_and_num=andnum('listclass',listnum)
listCell
:css('padding','0')
:cssText(args[cfg.arg.liststyle])
:cssText(rowstyle)
:cssText(args[liststyle_and_num])
:addClass(cfg.class.navbox_list)
:addClass(cfg.class.navbox_part..oddEven)
:addClass(args[cfg.arg.listclass])
:addClass(args[listclass_and_num])
:tag('div')
:css('padding',
(index==1andargs[cfg.arg.list1padding])orargs[cfg.arg.listpadding]or'0 0.25em'
)
:wikitext(processItem(listText,args[cfg.arg.nowrapitems]))
ifindex==1andargs[cfg.arg.image]then
row
:tag('td')
:addClass(cfg.class.noviewer)
:addClass(cfg.class.navbox_image)
:addClass(args[cfg.arg.imageclass])
:css('width','1px')-- Minimize width
:css('padding','0 0 0 2px')
:cssText(args[cfg.arg.imagestyle])
:attr('rowspan',listnums_size)
:tag('div')
:wikitext(processItem(args[cfg.arg.image]))
end
end
localfunctionhas_list_class(htmlclass)
localpatterns={
'^'..htmlclass..'$',
'%s'..htmlclass..'$',
'^'..htmlclass..'%s',
'%s'..htmlclass..'%s'
}
forarg,_inpairs(args)do
iftype(arg)=='string'andmw.ustring.find(arg,cfg.pattern.class)then
for_,patterninipairs(patterns)do
ifmw.ustring.find(args[arg]or'',pattern)then
returntrue
end
end
end
end
returnfalse
end
-- there are a lot of list classes in the wild, so we add their TemplateStyles
localfunctionadd_list_styles()
localframe=mw.getCurrentFrame()
localfunctionadd_list_templatestyles(htmlclass,templatestyles)
ifhas_list_class(htmlclass)then
returnframe:extensionTag{
name='templatestyles',args={src=templatestyles}
}
else
return''
end
end
localhlist_styles=add_list_templatestyles('hlist',cfg.hlist_templatestyles)
localplainlist_styles=add_list_templatestyles('plainlist',cfg.plainlist_templatestyles)
-- a second workaround for [[phab:T303378]]
-- when that issue is fixed, we can actually use has_navbar not to emit the
-- tag here if we want
ifhas_navbar()andhlist_styles==''then
hlist_styles=frame:extensionTag{
name='templatestyles',args={src=cfg.hlist_templatestyles}
}
end
-- hlist -> plainlist is best-effort to preserve old Common.css ordering.
-- this ordering is not a guarantee because most navboxes will emit only
-- one of these classes [hlist_note]
returnhlist_styles..plainlist_styles
end
localfunctionneedsHorizontalLists(border)
ifborder==cfg.keyword.border_subgrouporargs[cfg.arg.tracking]==cfg.keyword.tracking_nothen
returnfalse
end
returnnothas_list_class(cfg.pattern.hlist)andnothas_list_class(cfg.pattern.plainlist)
end
localfunctionhasBackgroundColors()
for_,keyinipairs({cfg.arg.titlestyle,cfg.arg.groupstyle,
cfg.arg.basestyle,cfg.arg.abovestyle,cfg.arg.belowstyle})do
iftostring(args[key]):find('background',1,true)then
returntrue
end
end
returnfalse
end
localfunctionhasBorders()
for_,keyinipairs({cfg.arg.groupstyle,cfg.arg.basestyle,
cfg.arg.abovestyle,cfg.arg.belowstyle})do
iftostring(args[key]):find('border',1,true)then
returntrue
end
end
returnfalse
end
localfunctionisIllegible()
localstyleratio=require('Module:Color contrast')._styleratio
forkey,styleinpairs(args)do
iftostring(key):match(cfg.pattern.style)then
ifstyleratio{mw.text.unstripNoWiki(style)}<4.5then
returntrue
end
end
end
returnfalse
end
localfunctiongetTrackingCategories(border)
localcats={}
ifneedsHorizontalLists(border)thentable.insert(cats,cfg.category.horizontal_lists)end
ifhasBackgroundColors()thentable.insert(cats,cfg.category.background_colors)end
ifisIllegible()thentable.insert(cats,cfg.category.illegible)end
ifhasBorders()thentable.insert(cats,cfg.category.borders)end
returncats
end
localfunctionrenderTrackingCategories(builder,border)
localtitle=mw.title.getCurrentTitle()
iftitle.namespace~=10thenreturnend-- not in template space
localsubpage=title.subpageText
ifsubpage==cfg.keyword.subpage_docorsubpage==cfg.keyword.subpage_sandbox
orsubpage==cfg.keyword.subpage_testcasesthenreturnend
for_,catinipairs(getTrackingCategories(border))do
builder:wikitext('[[Category:'..cat..']]')
end
end
localfunctionrenderMainTable(border,listnums)
localtbl=mw.html.create('table')
:addClass(cfg.class.nowraplinks)
:addClass(args[cfg.arg.bodyclass])
localstate=args[cfg.arg.state]
ifargs[cfg.arg.title]andstate~=cfg.keyword.state_plainandstate~=cfg.keyword.state_offthen
ifstate==cfg.keyword.state_collapsedthen
state=cfg.class.collapsed
end
tbl
:addClass(cfg.class.collapsible)
:addClass(stateorcfg.class.autocollapse)
end
tbl:css('border-spacing',0)
ifborder==cfg.keyword.border_subgrouporborder==cfg.keyword.border_nonethen
tbl
:addClass(cfg.class.navbox_subgroup)
:cssText(args[cfg.arg.bodystyle])
:cssText(args[cfg.arg.style])
else-- regular navbox - bodystyle and style will be applied to the wrapper table
tbl
:addClass(cfg.class.navbox_inner)
:css('background','transparent')
:css('color','inherit')
end
tbl:cssText(args[cfg.arg.innerstyle])
renderTitleRow(tbl)
renderAboveRow(tbl)
locallistnums_size=#listnums
fori,listnuminipairs(listnums)do
renderListRow(tbl,i,listnum,listnums_size)
end
renderBelowRow(tbl)
returntbl
end
localfunctionadd_navbox_styles(hiding_templatestyles)
localframe=mw.getCurrentFrame()
-- This is a lambda so that it doesn't need the frame as a parameter
localfunctionadd_user_styles(templatestyles)
ifnotisblank(templatestyles)then
returnframe:extensionTag{
name='templatestyles',args={src=templatestyles}
}
end
return''
end
-- get templatestyles. load base from config so that Lua only needs to do
-- the work once of parser tag expansion
localbase_templatestyles=cfg.templatestyles
localtemplatestyles=add_user_styles(args[cfg.arg.templatestyles])
localchild_templatestyles=add_user_styles(args[cfg.arg.child_templatestyles])
-- The 'navbox-styles' div exists to wrap the styles to work around T200206
-- more elegantly. Instead of combinatorial rules, this ends up being linear
-- number of CSS rules.
returnmw.html.create('div')
:addClass(cfg.class.navbox_styles)
:wikitext(
add_list_styles()..-- see [hlist_note] applied to 'before base_templatestyles'
base_templatestyles..
templatestyles..
child_templatestyles..
table.concat(hiding_templatestyles)
)
:done()
end
-- work around [[phab:T303378]]
-- for each arg: find all the templatestyles strip markers, insert them into a
-- table. then remove all templatestyles markers from the arg
localstrip_marker_pattern='(\127[^\127]*UNIQ%-%-templatestyles%-%x+%-QINU[^\127]*\127)'
localargHash=0
fork,arginpairs(args)do
iftype(arg)=='string'then
formarkerinstring.gfind(arg,strip_marker_pattern)do
table.insert(hiding_templatestyles,marker)
end
argHash=argHash+#arg
args[k]=string.gsub(arg,strip_marker_pattern,'')
end
end
ifnotargs.argHashthenargs.argHash=argHashend
locallistnums={}
fork,_inpairs(args)do
iftype(k)=='string'then
locallistnum=k:match(cfg.pattern.listnum)
iflistnumandargs[andnum('list',tonumber(listnum))]then
table.insert(listnums,tonumber(listnum))
end
end
end
table.sort(listnums)
localborder=mw.text.trim(args[cfg.arg.border]orargs[1]or'')
ifborder==cfg.keyword.border_childthen
border=cfg.keyword.border_subgroup
end
-- render the main body of the navbox
localtbl=renderMainTable(border,listnums)
localres=mw.html.create()
-- render the appropriate wrapper for the navbox, based on the border param
ifborder==cfg.keyword.border_nonethen
res:node(add_navbox_styles(hiding_templatestyles))
localnav=res:tag('div')
:attr('role','navigation')
:node(tbl)
-- aria-labelledby title, otherwise above, otherwise lone group
ifargs[cfg.arg.title]orargs[cfg.arg.above]or(args[cfg.arg.group1]
andnotargs[cfg.arg.group2])then
nav:attr(
'aria-labelledby',
mw.uri.anchorEncode(
args[cfg.arg.title]orargs[cfg.arg.above]orargs[cfg.arg.group1]
)..args.argHash
)
else
nav:attr('aria-label',cfg.aria_label..args.argHash)
end
elseifborder==cfg.keyword.border_subgroupthen
-- 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
res:node(add_navbox_styles(hiding_templatestyles))
localnav=res:tag('div')
:attr('role','navigation')
:addClass(cfg.class.navbox)
:addClass(args[cfg.arg.navboxclass])
:cssText(args[cfg.arg.bodystyle])
:cssText(args[cfg.arg.style])
:css('padding','3px')
:node(tbl)
-- aria-labelledby title, otherwise above, otherwise lone group
ifargs[cfg.arg.title]orargs[cfg.arg.above]
or(args[cfg.arg.group1]andnotargs[cfg.arg.group2])then
nav:attr(
'aria-labelledby',
mw.uri.anchorEncode(
args[cfg.arg.title]orargs[cfg.arg.above]orargs[cfg.arg.group1]
)..args.argHash
)
else
nav:attr('aria-label',cfg.aria_label..args.argHash)
end
end
if(args[cfg.arg.nocat]orcfg.keyword.nocat_false):lower()==cfg.keyword.nocat_falsethen
renderTrackingCategories(res,border)
end
returnstriped(tostring(res),border)
end--p._navbox
functionp._withCollapsibleGroups(pargs)
-- table for args passed to navbox
localtargs={}
-- process args
localpassthroughLocal={
[cfg.arg.bodystyle]=true,
[cfg.arg.border]=true,
[cfg.arg.style]=true,
}
fork,vinpairs(pargs)do
ifkandtype(k)=='string'then
ifpassthrough[k]orpassthroughLocal[k]then
targs[k]=v
elseif(k:match(cfg.pattern.num))then
localn=k:match(cfg.pattern.num)
locallist_and_num=andnum('list',n)
if((k:match(cfg.pattern.listnum)ork:match(cfg.pattern.contentnum))
andtargs[list_and_num]==nil
andpargs[andnum('group',n)]==nil
andpargs[andnum('sect',n)]==nil
andpargs[andnum('section',n)]==nil)then
targs[list_and_num]=concatstrings({
pargs[list_and_num]or'',
pargs[andnum('content',n)]or''
})
if(targs[list_and_num]andinArray(cfg.keyword.subgroups,targs[list_and_num]))then
targs[list_and_num]=getSubgroup(pargs,n,targs[list_and_num])
end
elseif((k:match(cfg.pattern.groupnum)ork:match(cfg.pattern.sectnum)ork:match(cfg.pattern.sectionnum))
andtargs[list_and_num]==nil)then
localtitlestyle=concatstyles({
pargs[cfg.arg.groupstyle]or'',
pargs[cfg.arg.secttitlestyle]or'',
pargs[andnum('groupstyle',n)]or'',
pargs[andnum('sectiontitlestyle',n)]or''
})
localliststyle=concatstyles({
pargs[cfg.arg.liststyle]or'',
pargs[cfg.arg.contentstyle]or'',
pargs[andnum('liststyle',n)]or'',
pargs[andnum('contentstyle',n)]or''
})
localtitle=concatstrings({
pargs[andnum('group',n)]or'',
pargs[andnum('sect',n)]or'',
pargs[andnum('section',n)]or''
})
locallist=concatstrings({
pargs[list_and_num]or'',
pargs[andnum('content',n)]or''
})
iflistandinArray(cfg.keyword.subgroups,list)then
list=getSubgroup(pargs,n,list)
end
localabbr_and_num=andnum('abbr',n)
localstate=(pargs[abbr_and_num]andpargs[abbr_and_num]==pargs[cfg.arg.selected])
andcfg.keyword.state_uncollapsed
or(pargs[andnum('state',n)]orcfg.keyword.state_collapsed)
targs[list_and_num]=p._navbox({
cfg.keyword.border_child,
[cfg.arg.navbar]=cfg.keyword.navbar_plain,
[cfg.arg.state]=state,
[cfg.arg.basestyle]=pargs[cfg.arg.basestyle],
[cfg.arg.title]=title,
[cfg.arg.titlestyle]=titlestyle,
[andnum('list',1)]=list,
[cfg.arg.liststyle]=liststyle,
[cfg.arg.listclass]=pargs[andnum('listclass',n)],
[cfg.arg.image]=pargs[andnum('image',n)],
[cfg.arg.imageleft]=pargs[andnum('imageleft',n)],
[cfg.arg.listpadding]=pargs[cfg.arg.listpadding],
argHash=pargs.argHash
})
end
end
end
end
-- ordering of style and bodystyle
targs[cfg.arg.style]=concatstyles({targs[cfg.arg.style]or'',targs[cfg.arg.bodystyle]or''})
targs[cfg.arg.bodystyle]=nil
-- child or subgroup
iftargs[cfg.arg.border]==nilthentargs[cfg.arg.border]=pargs[1]end
returnp._navbox(targs)
end--p._withCollapsibleGroups
functionp._withColumns(pargs)
-- table for args passed to navbox
localtargs={}
-- tables of column numbers
localcolheadernums={}
localcolnums={}
localcolfooternums={}
-- process args
localpassthroughLocal={
[cfg.arg.evenstyle]=true,
[cfg.arg.groupstyle]=true,
[cfg.arg.liststyle]=true,
[cfg.arg.oddstyle]=true,
[cfg.arg.state]=true,
}
fork,vinpairs(pargs)do
ifpassthrough[k]orpassthroughLocal[k]then
targs[k]=v
elseiftype(k)=='string'then
ifk:match(cfg.pattern.listnum)then
localn=k:match(cfg.pattern.listnum)
targs[andnum('liststyle',n+2)]=pargs[andnum('liststyle',n)]
targs[andnum('group',n+2)]=pargs[andnum('group',n)]
targs[andnum('groupstyle',n+2)]=pargs[andnum('groupstyle',n)]
ifvandinArray(cfg.keyword.subgroups,v)then
targs[andnum('list',n+2)]=getSubgroup(pargs,n,v)
else
targs[andnum('list',n+2)]=v
end
elseif(k:match(cfg.pattern.colheadernum)andv~='')then
table.insert(colheadernums,tonumber(k:match(cfg.pattern.colheadernum)))
elseif(k:match(cfg.pattern.colnum)andv~='')then
table.insert(colnums,tonumber(k:match(cfg.pattern.colnum)))
elseif(k:match(cfg.pattern.colfooternum)andv~='')then
table.insert(colfooternums,tonumber(k:match(cfg.pattern.colfooternum)))
end
end
end
table.sort(colheadernums)
table.sort(colnums)
table.sort(colfooternums)
-- HTML table for list1
localcoltable=mw.html.create('table'):addClass('navbox-columns-table')
localrow,col
localtablestyle=((#colheadernums>0)or(notisblank(pargs[cfg.arg.fullwidth])))
and'width:100%'
or'width:auto; margin-left:auto; margin-right:auto'
coltable:cssText(concatstyles({
'border-spacing: 0px; text-align:left',
tablestyle,
pargs[cfg.arg.coltablestyle]or''
}))
--- Header row ---
if(#colheadernums>0)then
row=coltable:tag('tr')
fork,ninipairs(colheadernums)do
col=row:tag('th'):addClass('navbox-abovebelow')
col:cssText(concatstyles({
(k>1)and'border-left:2px solid #fdfdfd'or'',
'font-weight:bold',
pargs[cfg.arg.colheaderstyle]or'',
pargs[andnum('colheaderstyle',n)]or''
}))
col:attr('colspan',tonumber(pargs[andnum('colheadercolspan',n)]))
col:wikitext(pargs[andnum('colheader',n)])
end
end
--- Main columns ---
row=coltable:tag('tr'):css('vertical-align','top')
fork,ninipairs(colnums)do
ifk==1andisblank(pargs[andnum('colheader',1)])
andisblank(pargs[andnum('colfooter',1)])
andisblank(pargs[cfg.arg.fullwidth])then
localnopad=inArray(
{'off','0','0em','0px'},
mw.ustring.gsub(pargs[cfg.arg.padding]or'','[;%%]',''))
ifnotnopadthen
row:tag('td'):wikitext('&nbsp;&nbsp;&nbsp;')
:css('width',(pargs[cfg.arg.padding]or'5em'))
end
end
col=row:tag('td'):addClass('navbox-list')
col:cssText(concatstyles({
(k>1)and'border-left:2px solid #fdfdfd'or'',
'padding:0px',
pargs[cfg.arg.colstyle]or'',
((n%2==0)andpargs[cfg.arg.evencolstyle]orpargs[cfg.arg.oddcolstyle])or'',
pargs[andnum('colstyle',n)]or'',
'width:'..(pargs[andnum('colwidth',n)]orpargs[cfg.arg.colwidth]or'10em')
}))
localwt=pargs[andnum('col',n)]
ifwtandinArray(cfg.keyword.subgroups,wt)then
wt=getSubgroup(pargs,n,wt,cfg.arg.col_and_num)
end
col:tag('div'):newline():wikitext(wt):newline()
end
--- Footer row ---
if(#colfooternums>0)then
row=coltable:tag('tr')
fork,ninipairs(colfooternums)do
col=row:tag('td'):addClass('navbox-abovebelow')
col:cssText(concatstyles({
(k>1)and'border-left:2px solid #fdfdfd'or'',
'font-weight:bold',
pargs[cfg.arg.colfooterstyle]or'',
pargs[andnum('colfooterstyle',n)]or''
}))
col:attr('colspan',tonumber(pargs[andnum('colfootercolspan',n)]))
col:wikitext(pargs[andnum('colfooter',n)])
end
end
-- assign table to list1
targs[andnum('list',1)]=tostring(coltable)
ifisblank(pargs[andnum('colheader',1)])
andisblank(pargs[andnum('col',1)])
andisblank(pargs[andnum('colfooter',1)])then
targs[andnum('list',1)]=targs[andnum('list',1)]..
cfg.category.without_first_col
end
-- Other parameters
targs[cfg.arg.border]=pargs[cfg.arg.border]orpargs[1]
targs[cfg.arg.evenodd]=(notisblank(pargs[cfg.arg.evenodd]))andpargs[cfg.arg.evenodd]ornil
targs[cfg.arg.list1padding]='0px'
targs[andnum('liststyle',1)]='background:transparent;color:inherit;'
targs[cfg.arg.style]=concatstyles({pargs[cfg.arg.style],pargs[cfg.arg.bodystyle]})
targs[cfg.arg.tracking]='no'
returnp._navbox(targs)
end--p._withColumns
-- Template entry points
functionp.navbox(frame,boxtype)
localfunctionreadArgs(args,prefix)
localfunctionreadSubgroups(element,i)
ifinArray(cfg.keyword.subgroups,args[prefix..andnum(element,i)])then
for_,vinipairs(cfg.arg.subgroups_and_num)do
readArgs(args,prefix..string.format(v,i).."_")
end
readArgs(args,prefix..andnum('col',i).."_")
end
end
-- Read the arguments in the order they'll be output in, to make references
-- number in the right order.
local_
_=args[prefix..cfg.arg.title]
_=args[prefix..cfg.arg.above]
-- Limit this to 20 as covering 'most' cases (that's a SWAG) and because
-- iterator approach won't work here
localboxtype=args.typeorcfg.keyword[boxtype]
ifboxtype==cfg.keyword.with_columnsthen
fori=1,20do
_=args[prefix..andnum('colheader',i)]
end
fori=1,20do
readSubgroups('col',i)
end
fori=1,20do
_=args[prefix..andnum('colfooter',i)]
end
end
fori=1,20do
_=args[prefix..andnum('group',i)]
readSubgroups('list',i)
end
_=args[prefix..cfg.arg.below]
end
ifnotgetArgsthen
getArgs=require('Module:Arguments').getArgs
end
localargs=getArgs(frame,{wrappers={cfg.pattern[boxtypeor'navbox']}})
readArgs(args,"")
args.argHash=nil-- we shouldn't accept argHash passed from a template
args.type=args.typeorcfg.keyword[boxtype]
returnp['_navbox'](args)
end
p[cfg.keyword.with_collapsible_groups]=function(frame)
returnp.navbox(frame,'with_collapsible_groups')
end
p[cfg.keyword.with_columns]=function(frame)
returnp.navbox(frame,'with_columns')
end
returnp