Module:Infobox/sandbox
Appearance
From Wikipedia, the free encyclopedia
This is the module sandbox page for Module:Infobox (diff).
See also the companion subpage for test cases.
See also the companion subpage for test cases.
Warning This Lua module is used on approximately 4,480,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.
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.
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.
This module depends on the following other modules:
CSS This module uses TemplateStyles:
Module:Infobox is a module that implements the {{Infobox }} template. Please see the template page for usage instructions.
Tracking categories
[edit ]The above documentation is transcluded from Module:Infobox/doc. (edit | history)
Editors can experiment in this module's sandbox (edit | diff) and testcases (edit) pages.
Add categories to the /doc subpage. Subpages of this module.
Editors can experiment in this module's sandbox (edit | diff) and testcases (edit) pages.
Add categories to the /doc subpage. Subpages of this module.
localp={} localargs={} localorigArgs={} localroot localempty_row_categories={} localcategory_in_empty_row_pattern='%[%[%s*[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]%s*:[^]]*]]' localhas_rows=false locallists={ plainlist_t={ patterns={ '^plainlist$', '%splainlist$', '^plainlist%s', '%splainlist%s' }, found=false, styles='Plainlist/styles.css' }, hlist_t={ patterns={ '^hlist$', '%shlist$', '^hlist%s', '%shlist%s' }, found=false, styles='Hlist/styles.css' } } localfunctionhas_list_class(args_to_check) for_,listinpairs(lists)do ifnotlist.foundthen for_,arginpairs(args_to_check)do for_,patterninipairs(list.patterns)do ifmw.ustring.find(argor'',pattern)then list.found=true break end end iflist.foundthenbreakend end end end end localfunctionfixChildBoxes(sval,tt) localfunctionnotempty(s)returnsands:match('%S')end ifnotempty(sval)then localmarker='<span class=special_infobox_marker>' locals=sval -- start moving templatestyles and categories inside of table rows localslast='' whileslast~=sdo slast=s s=mw.ustring.gsub(s,'(</[Tt][Rr]%s*>%s*)(%[%[%s*[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]%s*:[^]]*%]%])','%2%1') s=mw.ustring.gsub(s,'(</[Tt][Rr]%s*>%s*)(127円[^127円]*UNIQ%-%-templatestyles%-%x+%-QINU[^127円]*127円)','%2%1') end -- end moving templatestyles and categories inside of table rows s=mw.ustring.gsub(s,'(<%s*[Tt][Rr])',marker..'%1') s=mw.ustring.gsub(s,'(</[Tt][Rr]%s*>)','%1'..marker) ifs:match(marker)then s=mw.ustring.gsub(s,marker..'%s*'..marker,'') s=mw.ustring.gsub(s,'([\r\n]|-[^\r\n]*[\r\n])%s*'..marker,'%1') s=mw.ustring.gsub(s,marker..'%s*([\r\n]|-)','%1') s=mw.ustring.gsub(s,'(</[Cc][Aa][Pp][Tt][Ii][Oo][Nn]%s*>%s*)'..marker,'%1') s=mw.ustring.gsub(s,'(<%s*[Tt][Aa][Bb][Ll][Ee][^<>]*>%s*)'..marker,'%1') s=mw.ustring.gsub(s,'^(%{|[^\r\n]*[\r\n]%s*)'..marker,'%1') s=mw.ustring.gsub(s,'([\r\n]%{|[^\r\n]*[\r\n]%s*)'..marker,'%1') s=mw.ustring.gsub(s,marker..'(%s*</[Tt][Aa][Bb][Ll][Ee]%s*>)','%1') s=mw.ustring.gsub(s,marker..'(%s*\n|%})','%1') end ifs:match(marker)then localsubcells=mw.text.split(s,marker) s='' fork=1,#subcellsdo ifk==1then s=s..subcells[k]..'</'..tt..'></tr>' elseifk==#subcellsthen localrowstyle=' style="display:none"' ifnotempty(subcells[k])thenrowstyle=''end s=s..'<tr'..rowstyle..'><'..tt..' colspan=2>\n'.. subcells[k] elseifnotempty(subcells[k])then if(k%2)==0then s=s..subcells[k] else s=s..'<tr><'..tt..' colspan=2>\n'.. subcells[k]..'</'..tt..'></tr>' end end end end -- the next two lines add a newline at the end of lists for the PHP parser -- [[Special:Diff/849054481]] -- remove when [[:phab:T191516]] is fixed or OBE s=mw.ustring.gsub(s,'([\r\n][%*#;:][^\r\n]*)$','%1\n') s=mw.ustring.gsub(s,'^([%*#;:][^\r\n]*)$','%1\n') s=mw.ustring.gsub(s,'^([%*#;:])','\n%1') s=mw.ustring.gsub(s,'^(%{%|)','\n%1') returns else returnsval end end -- Cleans empty tables localfunctioncleanInfobox() root=tostring(root) ifhas_rows==falsethen root=mw.ustring.gsub(root,'<table[^<>]*>%s*</table>','') end end -- Returns the union of the values of two tables, as a sequence. localfunctionunion(t1,t2) localvals={} fork,vinpairs(t1)do vals[v]=true end fork,vinpairs(t2)do vals[v]=true end localret={} fork,vinpairs(vals)do table.insert(ret,k) end returnret end -- Returns a table containing the numbers of the arguments that exist -- for the specified prefix. For example, if the prefix was 'data', and -- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}. localfunctiongetArgNums(prefix) localnums={} fork,vinpairs(args)do localnum=tostring(k):match('^'..prefix..'([1-9]%d*)$') ifnumthentable.insert(nums,tonumber(num))end end table.sort(nums) returnnums end -- Adds a row to the infobox, with either a header cell -- or a label/data cell combination. localfunctionaddRow(rowArgs) ifrowArgs.headerandrowArgs.header~='_BLANK_'then has_rows=true has_list_class({rowArgs.rowclass,rowArgs.class,args.headerclass}) root :tag('tr') :addClass(rowArgs.rowclass) :cssText(rowArgs.rowstyle) :tag('th') :attr('colspan','2') :addClass('infobox-header') :addClass(rowArgs.class) :addClass(args.headerclass) -- @deprecated next; target .infobox-<name> .infobox-header :cssText(args.headerstyle) :cssText(rowArgs.rowcellstyle) :wikitext(fixChildBoxes(rowArgs.header,'th')) ifrowArgs.datathen root:wikitext( '[[Category:Pages using infobox templates with ignored data cells]]' ) end elseifrowArgs.dataandrowArgs.data:gsub(category_in_empty_row_pattern,''):match('^%S')then has_rows=true has_list_class({rowArgs.rowclass,rowArgs.class}) localrow=root:tag('tr') row:addClass(rowArgs.rowclass) row:cssText(rowArgs.rowstyle) ifrowArgs.labelthen row :tag('th') :attr('scope','row') :addClass('infobox-label') -- @deprecated next; target .infobox-<name> .infobox-label :cssText(args.labelstyle) :cssText(rowArgs.rowcellstyle) :wikitext(rowArgs.label) :done() end localdataCell=row:tag('td') dataCell :attr('colspan',notrowArgs.labeland'2'ornil) :addClass(notrowArgs.labeland'infobox-full-data'or'infobox-data') :addClass(rowArgs.class) -- @deprecated next; target .infobox-<name> .infobox(-full)-data :cssText(rowArgs.datastyle) :cssText(rowArgs.rowcellstyle) :wikitext(fixChildBoxes(rowArgs.data,'td')) else table.insert(empty_row_categories,rowArgs.dataor'') end end localfunctionrenderTitle() ifnotargs.titlethenreturnend has_rows=true has_list_class({args.titleclass}) root :tag('caption') :addClass('infobox-title') :addClass(args.titleclass) -- @deprecated next; target .infobox-<name> .infobox-title :cssText(args.titlestyle) :wikitext(args.title) end localfunctionrenderAboveRow() ifnotargs.abovethenreturnend has_rows=true has_list_class({args.aboveclass}) root :tag('tr') :tag('th') :attr('colspan','2') :addClass('infobox-above') :addClass(args.aboveclass) -- @deprecated next; target .infobox-<name> .infobox-above :cssText(args.abovestyle) :wikitext(fixChildBoxes(args.above,'th')) end localfunctionrenderBelowRow() ifnotargs.belowthenreturnend has_rows=true has_list_class({args.belowclass}) root :tag('tr') :tag('td') :attr('colspan','2') :addClass('infobox-below') :addClass(args.belowclass) -- @deprecated next; target .infobox-<name> .infobox-below :cssText(args.belowstyle) :wikitext(fixChildBoxes(args.below,'td')) end localfunctionaddSubheaderRow(subheaderArgs) ifsubheaderArgs.dataand subheaderArgs.data:gsub(category_in_empty_row_pattern,''):match('^%S')then has_rows=true has_list_class({subheaderArgs.rowclass,subheaderArgs.class}) localrow=root:tag('tr') row:addClass(subheaderArgs.rowclass) localdataCell=row:tag('td') dataCell :attr('colspan','2') :addClass('infobox-subheader') :addClass(subheaderArgs.class) :cssText(subheaderArgs.datastyle) :cssText(subheaderArgs.rowcellstyle) :wikitext(fixChildBoxes(subheaderArgs.data,'td')) else table.insert(empty_row_categories,subheaderArgs.dataor'') end end localfunctionrenderSubheaders() ifargs.subheaderthen args.subheader1=args.subheader end ifargs.subheaderrowclassthen args.subheaderrowclass1=args.subheaderrowclass end localsubheadernums=getArgNums('subheader') fork,numinipairs(subheadernums)do addSubheaderRow({ data=args['subheader'..tostring(num)], -- @deprecated next; target .infobox-<name> .infobox-subheader datastyle=args.subheaderstyle, rowcellstyle=args['subheaderstyle'..tostring(num)], class=args.subheaderclass, rowclass=args['subheaderrowclass'..tostring(num)] }) end end localfunctionaddImageRow(imageArgs) ifimageArgs.dataand imageArgs.data:gsub(category_in_empty_row_pattern,''):match('^%S')then has_rows=true has_list_class({imageArgs.rowclass,imageArgs.class}) localrow=root:tag('tr') row:addClass(imageArgs.rowclass) localdataCell=row:tag('td') dataCell :attr('colspan','2') :addClass('infobox-image') :addClass(imageArgs.class) :cssText(imageArgs.datastyle) :wikitext(fixChildBoxes(imageArgs.data,'td')) else table.insert(empty_row_categories,imageArgs.dataor'') end end localfunctionrenderImages() ifargs.imagethen args.image1=args.image end ifargs.captionthen args.caption1=args.caption end localimagenums=getArgNums('image') fork,numinipairs(imagenums)do localcaption=args['caption'..tostring(num)] localdata=mw.html.create():wikitext(args['image'..tostring(num)]) ifcaptionthen data :tag('div') :addClass('infobox-caption') -- @deprecated next; target .infobox-<name> .infobox-caption :cssText(args.captionstyle) :wikitext(caption) end addImageRow({ data=tostring(data), -- @deprecated next; target .infobox-<name> .infobox-image datastyle=args.imagestyle, class=args.imageclass, rowclass=args['imagerowclass'..tostring(num)] }) end end -- When autoheaders are turned on, preprocesses the rows localfunctionpreprocessRows() ifnotargs.autoheadersthenreturnend localrownums=union(getArgNums('header'),getArgNums('data')) table.sort(rownums) locallastheader fork,numinipairs(rownums)do ifargs['header'..tostring(num)]then iflastheaderthen args['header'..tostring(lastheader)]=nil end lastheader=num elseifargs['data'..tostring(num)]and args['data'..tostring(num)]:gsub( category_in_empty_row_pattern,'' ):match('^%S')then localdata=args['data'..tostring(num)] ifdata:gsub(category_in_empty_row_pattern,''):match('%S')then lastheader=nil end end end iflastheaderthen args['header'..tostring(lastheader)]=nil end end -- Gets the union of the header and data argument numbers, -- and renders them all in order localfunctionrenderRows() localrownums=union(getArgNums('header'),getArgNums('data')) table.sort(rownums) fork,numinipairs(rownums)do addRow({ header=args['header'..tostring(num)], label=args['label'..tostring(num)], data=args['data'..tostring(num)], datastyle=args.datastyle, class=args['class'..tostring(num)], rowclass=args['rowclass'..tostring(num)], -- @deprecated next; target .infobox-<name> rowclass rowstyle=args['rowstyle'..tostring(num)], rowcellstyle=args['rowcellstyle'..tostring(num)] }) end end localfunctionrenderNavBar() ifnotargs.namethenreturnend has_rows=true root :tag('tr') :tag('td') :attr('colspan','2') :addClass('infobox-navbar') :wikitext(require('Module:Navbar')._navbar{ args.name, mini=1, }) end localfunctionrenderItalicTitle() localitalicTitle=args['italic title']andmw.ustring.lower(args['italic title']) ifitalicTitle==''oritalicTitle=='force'oritalicTitle=='yes'then root:wikitext(require('Module:Italic title')._main({})) end end -- Categories in otherwise empty rows are collected in empty_row_categories. -- This function adds them to the module output. It is not affected by -- args.decat because this module should not prevent module-external categories -- from rendering. localfunctionrenderEmptyRowCategories() for_,sinipairs(empty_row_categories)do root:wikitext(s) end end -- Render tracking categories. args.decat == turns off tracking categories. localfunctionrenderTrackingCategories() ifargs.decat=='yes'thenreturnend ifargs.child=='yes'then ifargs.titlethen root:wikitext( '[[Category:Pages using embedded infobox templates with the title parameter]]' ) end elseif#(getArgNums('data'))==0andmw.title.getCurrentTitle().namespace==0then root:wikitext('[[Category:Articles using infobox templates with no data rows]]') end end --[=[ Loads the templatestyles for the infobox. TODO: FINISH loading base templatestyles here rather than in MediaWiki:Common.css. There are 4-5000 pages with 'raw' infobox tables. See [[Mediawiki_talk:Common.css/to_do#Infobox]] and/or come help :). When we do this we should clean up the inline CSS below too. Will have to do some bizarre conversion category like with sidebar. ]=] localfunctionloadTemplateStyles() localframe=mw.getCurrentFrame() localhlist_templatestyles='' iflists.hlist_t.foundthen hlist_templatestyles=frame:extensionTag{ name='templatestyles',args={src=lists.hlist_t.styles} } end localplainlist_templatestyles='' iflists.plainlist_t.foundthen plainlist_templatestyles=frame:extensionTag{ name='templatestyles',args={src=lists.plainlist_t.styles} } end -- See function description localbase_templatestyles=frame:extensionTag{ name='templatestyles',args={src='Module:Infobox/styles.css'} } localtemplatestyles='' ifargs['templatestyles']then templatestyles=frame:extensionTag{ name='templatestyles',args={src=args['templatestyles']} } end localchild_templatestyles='' ifargs['child templatestyles']then child_templatestyles=frame:extensionTag{ name='templatestyles',args={src=args['child templatestyles']} } end localgrandchild_templatestyles='' ifargs['grandchild templatestyles']then grandchild_templatestyles=frame:extensionTag{ name='templatestyles',args={src=args['grandchild templatestyles']} } end returntable.concat({ -- hlist -> plainlist -> base is best-effort to preserve old Common.css ordering. -- this ordering is not a guarantee because the rows of interest invoking -- each class may not be on a specific page hlist_templatestyles, plainlist_templatestyles, base_templatestyles, templatestyles, child_templatestyles, grandchild_templatestyles }) end -- common functions between the child and non child cases localfunctionstructure_infobox_common() renderSubheaders() renderImages() preprocessRows() renderRows() renderBelowRow() renderNavBar() renderItalicTitle() renderEmptyRowCategories() renderTrackingCategories() cleanInfobox() end -- Specify the overall layout of the infobox, with special settings if the -- infobox is used as a 'child' inside another infobox. localfunction_infobox() ifargs.child~='yes'then root=mw.html.create('table') root :addClass(args.subbox=='yes'and'infobox-subbox'or'infobox') :addClass(args.bodyclass) -- @deprecated next; target .infobox-<name> :cssText(args.bodystyle) has_list_class({args.bodyclass}) renderTitle() renderAboveRow() else root=mw.html.create() root :wikitext(args.title) end structure_infobox_common() returnloadTemplateStyles()..root end -- If the argument exists and isn't blank, add it to the argument table. -- Blank arguments are treated as nil to match the behaviour of ParserFunctions. localfunctionpreprocessSingleArg(argName) iforigArgs[argName]andorigArgs[argName]~=''then args[argName]=origArgs[argName] end end -- Assign the parameters with the given prefixes to the args table, in order, in -- batches of the step size specified. This is to prevent references etc. from -- appearing in the wrong order. The prefixTable should be an array containing -- tables, each of which has two possible fields, a "prefix" string and a -- "depend" table. The function always parses parameters containing the "prefix" -- string, but only parses parameters in the "depend" table if the prefix -- parameter is present and non-blank. localfunctionpreprocessArgs(prefixTable,step) iftype(prefixTable)~='table'then error("Non-table value detected for the prefix table",2) end iftype(step)~='number'then error("Invalid step value detected",2) end -- Get arguments without a number suffix, and check for bad input. fori,vinipairs(prefixTable)do iftype(v)~='table'ortype(v.prefix)~="string"or (v.dependandtype(v.depend)~='table')then error('Invalid input detected to preprocessArgs prefix table',2) end preprocessSingleArg(v.prefix) -- Only parse the depend parameter if the prefix parameter is present -- and not blank. ifargs[v.prefix]andv.dependthen forj,dependValueinipairs(v.depend)do iftype(dependValue)~='string'then error('Invalid "depend" parameter value detected in preprocessArgs') end preprocessSingleArg(dependValue) end end end -- Get arguments with number suffixes. locala=1-- Counter variable. localmoreArgumentsExist=true whilemoreArgumentsExist==truedo moreArgumentsExist=false fori=a,a+step-1do forj,vinipairs(prefixTable)do localprefixArgName=v.prefix..tostring(i) iforigArgs[prefixArgName]then -- Do another loop if any arguments are found, even blank ones. moreArgumentsExist=true preprocessSingleArg(prefixArgName) end -- Process the depend table if the prefix argument is present -- and not blank, or we are processing "prefix1" and "prefix" is -- present and not blank, and if the depend table is present. ifv.dependand(args[prefixArgName]or(i==1andargs[v.prefix]))then forj,dependValueinipairs(v.depend)do localdependArgName=dependValue..tostring(i) preprocessSingleArg(dependArgName) end end end end a=a+step end end -- Parse the data parameters in the same order that the old {{infobox}} did, so -- that references etc. will display in the expected places. Parameters that -- depend on another parameter are only processed if that parameter is present, -- to avoid phantom references appearing in article reference lists. localfunctionparseDataParameters() preprocessSingleArg('autoheaders') preprocessSingleArg('child') preprocessSingleArg('bodyclass') preprocessSingleArg('subbox') preprocessSingleArg('bodystyle') preprocessSingleArg('title') preprocessSingleArg('titleclass') preprocessSingleArg('titlestyle') preprocessSingleArg('above') preprocessSingleArg('aboveclass') preprocessSingleArg('abovestyle') preprocessArgs({ {prefix='subheader',depend={'subheaderstyle','subheaderrowclass'}} },10) preprocessSingleArg('subheaderstyle') preprocessSingleArg('subheaderclass') preprocessArgs({ {prefix='image',depend={'caption','imagerowclass'}} },10) preprocessSingleArg('captionstyle') preprocessSingleArg('imagestyle') preprocessSingleArg('imageclass') preprocessArgs({ {prefix='header'}, {prefix='data',depend={'label'}}, {prefix='rowclass'}, {prefix='rowstyle'}, {prefix='rowcellstyle'}, {prefix='class'} },50) preprocessSingleArg('headerclass') preprocessSingleArg('headerstyle') preprocessSingleArg('labelstyle') preprocessSingleArg('datastyle') preprocessSingleArg('below') preprocessSingleArg('belowclass') preprocessSingleArg('belowstyle') preprocessSingleArg('name') -- different behaviour for italics if blank or absent args['italic title']=origArgs['italic title'] preprocessSingleArg('decat') preprocessSingleArg('templatestyles') preprocessSingleArg('child templatestyles') preprocessSingleArg('grandchild templatestyles') end -- If called via #invoke, use the args passed into the invoking template. -- Otherwise, for testing purposes, assume args are being passed directly in. functionp.infobox(frame) ifframe==mw.getCurrentFrame()then origArgs=frame:getParent().args else origArgs=frame end parseDataParameters() return_infobox() end -- For calling via #invoke within a template functionp.infoboxTemplate(frame) origArgs={} fork,vinpairs(frame.args)doorigArgs[k]=mw.text.trim(v)end parseDataParameters() return_infobox() end returnp