Module:Navbox
Tools
Actions
General
Print/export
Documentation for this module may be created atModule:Navbox/doc
---- This module implements {{Navbox}}--localp={}localnavbar=require('Module:Navbar')._navbarlocalgetArgs-- lazily initializedlocalargslocalborderlocallistnumslocalODD_EVEN_MARKER='\127_ODDEVEN_\127'localRESTART_MARKER='\127_ODDEVEN0_\127'localREGEX_MARKER='\127_ODDEVEN(%d?)_\127'localfunctionstriped(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.localorphanCat='[[Category:Navbox orphans]]'ifborder=='subgroup'andargs.orphan~='yes'then-- No change; striping occurs in outermost navbox.returnwikitext..orphanCatendlocalfirst,second='odd','even'ifargs.evenoddthenifargs.evenodd=='swap'thenfirst,second=second,firstelsefirst=args.evenoddsecond=firstendendlocalchangeriffirst==secondthenchanger=firstelselocalindex=0changer=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=0returnfirstendindex=index+1returnindex%2==1andfirstorsecondendendlocalregex=orphanCat:gsub('([%[%]])','%%%1')return(wikitext:gsub(regex,''):gsub(REGEX_MARKER,changer))-- () omits gsub countendlocalfunctionprocessItem(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'endifnowrapitems=='yes'thenlocallines={}forlinein(item..'\n'):gmatch('([^\n]*)\n')dolocalprefix,content=line:match('^([*:;#]+)%s*(.*)')ifprefixandnotcontent:match('^<span class="nowrap">')thenline=prefix..'<span class="nowrap">'..content..'</span>'endtable.insert(lines,line)enditem=table.concat(lines,'\n')endifitem:match('^[*:;#]')thenreturn'\n'..item..'\n'endreturnitemendlocalfunctionrenderNavBar(titleCell)ifargs.navbar~='off'andargs.navbar~='plain'andnot(notargs.nameandmw.getCurrentFrame():getParent():getTitle():gsub('/sandbox$','')=='Template:Navbox')thentitleCell:wikitext(navbar{args.name,mini=1,fontstyle=(args.basestyleor'')..';'..(args.titlestyleor'')..';background:none transparent;border:none;-moz-box-shadow:none;-webkit-box-shadow:none;box-shadow:none; padding:0;'})endend---- Title row--localfunctionrenderTitleRow(tbl)ifnotargs.titlethenreturnendlocaltitleRow=tbl:tag('tr')ifargs.titlegroupthentitleRow:tag('th'):attr('scope','row'):addClass('navbox-group'):addClass(args.titlegroupclass):cssText(args.basestyle):cssText(args.groupstyle):cssText(args.titlegroupstyle):wikitext(args.titlegroup)endlocaltitleCell=titleRow:tag('th'):attr('scope','col')ifargs.titlegroupthentitleCell:css('border-left','2px solid #fdfdfd'):css('width','100%')endlocaltitleColspan=2ifargs.imageleftthentitleColspan=titleColspan+1endifargs.imagethentitleColspan=titleColspan+1endifargs.titlegroupthentitleColspan=titleColspan-1endtitleCell: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--localfunctiongetAboveBelowColspan()localret=2ifargs.imageleftthenret=ret+1endifargs.imagethenret=ret+1endreturnretendlocalfunctionrenderAboveRow(tbl)ifnotargs.abovethenreturnendtbl: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.titleandnilormw.uri.anchorEncode(args.above)):wikitext(processItem(args.above,args.nowrapitems))endlocalfunctionrenderBelowRow(tbl)ifnotargs.belowthenreturnendtbl: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--localfunctionrenderListRow(tbl,index,listnum)localrow=tbl:tag('tr')ifindex==1andargs.imageleftthenrow: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))endifargs['group'..listnum]thenlocalgroupCell=row:tag('th')-- id for aria-labelledby attribute, if lone group with no title or aboveiflistnum==1andnot(args.titleorargs.aboveorargs.group2)thengroupCell:attr('id',mw.uri.anchorEncode(args.group1))endgroupCell:attr('scope','row'):addClass('navbox-group'):addClass(args.groupclass):cssText(args.basestyle):css('width',args.groupwidthor'1%')-- If groupwidth not specified, minimize widthgroupCell:cssText(args.groupstyle):cssText(args['group'..listnum..'style']):wikitext(args['group'..listnum])endlocallistCell=row:tag('td')ifargs['group'..listnum]thenlistCell:css('text-align','left'):css('border-left-width','2px'):css('border-left-style','solid')elselistCell:attr('colspan',2)endifnotargs.groupwidththenlistCell:css('width','100%')endlocalrowstyle-- usually nil so cssText(rowstyle) usually adds nothingifindex%2==1thenrowstyle=args.oddstyleelserowstyle=args.evenstyleendlocallistText=args['list'..listnum]localoddEven=ODD_EVEN_MARKERiflistText: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"')andRESTART_MARKERor'odd'endlistCell: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==1andargs.list1padding)orargs.listpaddingor'0em 0.25em'):wikitext(processItem(listText,args.nowrapitems))ifindex==1andargs.imagethenrow: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))endend---- Tracking categories--localfunctionneedsHorizontalLists()ifborder=='subgroup'orargs.tracking=='no'thenreturnfalseendlocallistClasses={['plainlist']=true,['hlist']=true,['hlist hnum']=true,['hlist hwrap']=true,['hlist vcard']=true,['vcard hlist']=true,['hlist vevent']=true,}returnnot(listClasses[args.listclass]orlistClasses[args.bodyclass])end-- there are a lot of list classes in the wild, so we have a function to find-- them and add their TemplateStyleslocalfunctionaddListStyles()localframe=mw.getCurrentFrame()-- TODO?: Should maybe take a table of classes for e.g. hnum, hwrap as above-- I'm going to do the stupid thing first though-- Also not sure hnum and hwrap are going to live in the same TemplateStyles-- as hlistlocalfunction_addListStyles(htmlclass,templatestyles)localclass_args={-- rough order of probability of use'bodyclass','listclass','aboveclass','belowclass','titleclass','navboxclass','groupclass','titlegroupclass','imageclass'}localpatterns={'^'..htmlclass..'$','%s'..htmlclass..'$','^'..htmlclass..'%s','%s'..htmlclass..'%s'}localfound=falsefor_,arginipairs(class_args)dofor_,patterninipairs(patterns)doifmw.ustring.find(args[arg]or'',pattern)thenfound=truebreakendendiffoundthenbreakendendiffoundthenreturnframe:extensionTag{name='templatestyles',args={src=templatestyles}}elsereturn''endendreturn_addListStyles('hlist','Flatlist/styles.css')endlocalfunctionhasBackgroundColors()for_,keyinipairs({'titlestyle','groupstyle','basestyle','abovestyle','belowstyle'})doiftostring(args[key]):find('background',1,true)thenreturntrueendendendlocalfunctionhasBorders()for_,keyinipairs({'groupstyle','basestyle','abovestyle','belowstyle'})doiftostring(args[key]):find('border',1,true)thenreturntrueendendendlocalfunctionisIllegible()localstyleratio=require('Module:Color contrast')._styleratioforkey,styleinpairs(args)doiftostring(key):match("style$")thenifstyleratio{mw.text.unstripNoWiki(style)}<4.5thenreturntrueendendendreturnfalseendlocalfunctiongetTrackingCategories()localcats={}ifneedsHorizontalLists()thentable.insert(cats,'Navigational boxes without horizontal lists')endifhasBackgroundColors()thentable.insert(cats,'Navboxes using background colours')endifisIllegible()thentable.insert(cats,'Potentially illegible navboxes')endifhasBorders()thentable.insert(cats,'Navboxes using borders')endreturncatsendlocalfunctionrenderTrackingCategories(builder)localtitle=mw.title.getCurrentTitle()iftitle.namespace~=10thenreturnend-- not in template spacelocalsubpage=title.subpageTextifsubpage=='doc'orsubpage=='sandbox'orsubpage=='testcases'thenreturnendfor_,catinipairs(getTrackingCategories())dobuilder:wikitext('[[Category:'..cat..']]')endend---- Main navbox tables--localfunctionrenderMainTable()localtbl=mw.html.create('table'):addClass('nowraplinks'):addClass(args.bodyclass)ifargs.titleand(args.state~='plain'andargs.state~='off')thenifargs.state=='collapsed'thenargs.state='mw-collapsed'endtbl:addClass('mw-collapsible'):addClass(args.stateor'autocollapse')endtbl:css('border-spacing',0)ifborder=='subgroup'orborder=='none'thentbl:addClass('navbox-subgroup'):cssText(args.bodystyle):cssText(args.style)else-- regular navbox - bodystyle and style will be applied to the wrapper tabletbl:addClass('navbox-inner'):css('background','transparent'):css('color','inherit')endtbl:cssText(args.innerstyle)renderTitleRow(tbl)renderAboveRow(tbl)fori,listnuminipairs(listnums)dorenderListRow(tbl,i,listnum)endrenderBelowRow(tbl)returntblendfunctionp._navbox(navboxArgs)args=navboxArgslistnums={}fork,_inpairs(args)doiftype(k)=='string'thenlocallistnum=k:match('^list(%d+)$')iflistnumthentable.insert(listnums,tonumber(listnum))endendendtable.sort(listnums)border=mw.text.trim(args.borderorargs[1]or'')ifborder=='child'thenborder='subgroup'end-- render the main body of the navboxlocaltbl=renderMainTable()-- get templatestyleslocalframe=mw.getCurrentFrame()localbase_templatestyles=frame:extensionTag{name='templatestyles',args={src='Module:Navbox/styles.css'}}localtemplatestyles=''ifargs.templatestylesandargs.templatestyles~=''thentemplatestyles=frame:extensionTag{name='templatestyles',args={src=args.templatestyles}}end-- render the appropriate wrapper around the navbox, depending on the border paramlocalres=mw.html.create()-- 'navbox-styles' exists for two reasons:-- 1. To wrap the styles to work around phab: T200206 more elegantly. Instead-- of combinatorial rules, this ends up being linear number of CSS rules.-- 2. To allow MobileFrontend to rip the styles out with 'nomobile' such that-- they are not dumped into the mobile view.res:tag('div'):addClass('navbox-styles'):addClass('nomobile'):wikitext(base_templatestyles..templatestyles..addListStyles()):done()ifborder=='none'thenlocalnav=res:tag('div'):attr('role','navigation'):node(tbl)-- aria-labelledby title, otherwise above, otherwise lone groupifargs.titleorargs.aboveor(args.group1andnotargs.group2)thennav:attr('aria-labelledby',mw.uri.anchorEncode(args.titleorargs.aboveorargs.group1))elsenav:attr('aria-label','Navbox')endelseifborder=='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-- NOTE: args.wrapclass is an enWS customization!localnav=res:tag('div'):attr('role','navigation'):addClass('navbox'):addClass('ws-noexport noprint'):addClass(args.wrapclass):cssText(args.bodystyle):cssText(args.style):css('padding','3px'):node(tbl)-- aria-labelledby title, otherwise above, otherwise lone groupifargs.titleorargs.aboveor(args.group1andnotargs.group2)thennav:attr('aria-labelledby',mw.uri.anchorEncode(args.titleorargs.aboveorargs.group1))elsenav:attr('aria-label','Navbox')endendif(args.nocator'false'):lower()=='false'thenrenderTrackingCategories(res)endreturnstriped(tostring(res))endfunctionp.navbox(frame)ifnotgetArgsthengetArgs=require('Module:Arguments').getArgsendargs=getArgs(frame,{wrappers={'Template:Navbox','Template:Navbox subgroup'}})ifframe.args.borderthen-- This allows Template:Navbox_subgroup to use {{#invoke:Navbox|navbox|border=...}}.args.border=frame.args.borderend-- Read the arguments in the order they'll be output in, to make references number in the right order.local__=args.title_=args.abovefori=1,20do_=args["group"..tostring(i)]_=args["list"..tostring(i)]end_=args.belowreturnp._navbox(args)endreturnp