Module:Infobox
Creating a template step-by-step
Import Module:Infobox
local infobox = require('Module:Infobox')
Unpack the frame arguments
function p.main(frame)
local args = frame:getParent().args
...
Define an Infobox object
local ret = infobox.new(args)
Map your arguments to functions
ret:defineParams {
...
}
Parse your arguments
ret:cleanParams()
Initialise your HTML
ret:create()
Name your infobox
-- note: we don't use the "Template:" namespace prefix
ret:defineName('Infobox FooBar')
Give your infobox custom behaviour
ret:addClass(...)
ret:useSMW({ ... })
ret:defineLinks({ ... })
ret:caption()
Format your table
ret:addRow{ ... }
:addRow{ ... }
Finalise your template
ret:finish()
Functions
Public functions
For the example snippets below, ret
is an arbitrary infobox initiated as:
local ret = Infobox.new(args)
Priority
Certain functions rely on information created by other functions, and thus must be run in a particular order:
0 |
|
---|---|
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
nilParam
Infobox.nilParam()
Returns the value of the placeholder value Infobox.nil_param
. This value is generally not seen, but it is used to fill switchbox data as nil
causes unwanted behaviour.
isDefined
Infobox.isDefined(arg)
Checks whether the value arg
can be considered as defined.
new
Infobox.new(args)
Creates a new infobox object with args
as a table
of values passed from the template invocation.
This function also creates the top-level wrapper and sets a metatable for the infobox.
create
ret:create()
Creates the HTML tags used for the infobox itself. Will run maxVersion()
if it has not been run already.
defineName
ret:defineName(arg)
Defines the name of the infobox. This should be the base pagename; i.e. no "Template:" namespace prefix.
defineLinks
ret:defineLinks(tbl)
Defines any number of infobox bottom links in a table
whose elements are table
variables formatted as such:
{
{ link, label },
...
}
link
and label
should be string
variables that will, in a basic sense, define [[Link|label]]
.
In a more technical sense, link
and label
help form a string
for string.format()
, with the module using the equivalent of (but not exactly):
string.format('[[['..link..'|'..label..']]]',...)
The template name itself can be called up to 5 times by using "%s", in either link
or label
.
setMaxButtons
ret:setMaxButtons(n)
Changes the behaviour of buttons by defining the maximum number of buttons that are allowed to appear. If the version count exceeds the button count, their buttons will be replaced with a drop down menu. If not run, the maximum button count will be 5.
cleanParams
ret:cleanParams()
Parses the parameters with their mapped functions.
defineParams
ret:defineParams{
...
}
Maps parameters to functions as defined by a table
formatted as such:
{ name = <param>, func = <func>, dupes = true },
param
should be a string
that names the parameter as it will be in references for use in other functions.
func
should be a function
or instructions on how to find a function.
dupes
is a meta configuration that allows the parameter to be duplicated in switch data. Normally, these duplicate values are not needed, and they will be deleted if they are the same as the default values after all parameters have been parsed. Some parameters require duplication to function properly, such as display altering parameters defined with linkParams()
.
If duplicates are not needed, this parameter should be deleted.
- Predefined functions
If func
is a string
, then the module will attempt to use a predefined function.
Function | Use |
---|---|
name | Uses the parameter named "name". If "name" is blank or undefined, it will use the page name. |
release | Uses the parameters named "release" and "update" and formats it as such:
|
removal | Uses the parameters named "removal" and "removalupdate" and formats it the same as release
|
hasContent | If the parameter is defined and not blank, it will be used. Otherwise, ? (edit) will be used.
|
image | Currently functions the same as hasContent
|
numbers | Removes commas from the parameter and attempts to cast it to a number . If it works, the number is used, otherwise ? (edit)
|
- User-defined functions
If func
is a function
, then that function will be used to parse the parameter. User-defined functions allow for more robust formatting and guidelines.
As a general practice, user-defined functions should be located under the main
functions in the module. It is best to document these functions so that they may be changed by other editors if necessary.
In user-defined functions, circumstances where the edit button should be shown should return nil
, which is automatically handled by the module.
- Simple and complex definitions
Parameters may be mapped to functions in a straightforward manner by simply definining a name of or reference to a function, such as:
ret:defineParams{
{ name = 'foo', func = 'hasContent' },
{ name = 'bar', func = barFunc }
}
Simple definitions only pass the parameter from the master list named <name>. Some parameters need more interaction with other parameters. To do this, we require a complex definition. Complex definitions point to a user-defined function and map what parameters to pass. Complex definitions can also pass literal values or the uncleaned value with the use of flags.
Complex functions are defined as table
values formatted as such:
func = { name = <funcname>, params = { <paramname>, ... }, flag = <flags> }
A basic example for complex functions is:
ret:defineParams{
{ name = 'foo', func = { name = fooFunc, params = { 'bar', 'baz' } },
}
-- ...
-- ...
function fooFunc(arg1,arg2)
return arg1..arg2
end
In this example, we have a parameter named "foo", but we use the parameters passed to the template named "bar" and "baz". Parameters are passed in the order listed, so in the above, the parameter bar
is used for arg1
, and baz
is used for arg2
.
Flags define the behaviour of the parameters named. The following flag behaviours exist:
d
- Looks for the cleaned and parsed version of the parameter. If not cleaned, it will use the value passed to the template. If neither exist, it will usenil
. This is the default behaviour if no flag is defined.p
- Looks only at the value passed to the template. If it does not exist, it will usenil
.r
orl
- Uses the literal (or raw) value.
If flag
is a string
, then the behaviour defined by it will apply to every parameter passed. If flag
is a table
, then each flag will only define the behaviour of the respective parameter.
For example:
ret:defineParams{
{ name = 'foo', func = {
name = fooFunc,
params = { 'foo', 'bar', 'baz' },
flag = { 'd', 'p', 'l' },
},
}
In the above snippet, foo
will use the default behaviour and bar
will only look for the value passed to the template. The third parameter will use the string literal 'baz'
.
- Definition order
Parameters are defined in the order that they are coded. If a parameter relies on the cleaned value of another parameter, then the parameter dependent on the other will need to be defined after in the definition table.
addRow
ret:addRow(tbl)
Adds a new row to the template with columns and behaviour defined by tbl
, which should be a table
that holds cells defined as table
variables, formatted as such:
{
{ celltype, label, <attr1> = <value1>, <attr2> = <value2> ... },
...
}
celltype
and label
are string
values that define the fundamental display of the cell.
celltype | Output |
---|---|
th | Creates a <th> tag where the content is the value of label
|
td | Creates a <td> tag where the content is the value of label
|
argh | Creates a <th> tag where the content is the value of the parameter named label
|
argd | Creates a <td> tag where the content is the value of the parameter named label
|
The attributes are any of the available attributes defined inside the function. All functions that are ultimately run are documented in the Lua reference manual and are run on the tag for the specific table cell they are called on.
attr | Type | Use |
---|---|---|
attr | table | Passes the value to mw.html.attr() |
css | table | Passes the value to mw.html.css() |
colspan | number | Uses the value to run mw.html.attr('colspan',#) |
rowspan | number | Uses the value to run mw.html.attr('rowspan',#) |
title | string | Uses the value to run mw.html.attr('title',text) |
class | string | Passes the value to mw.html.addClass() |
class | table | Passes every value in the table to mw.html.addClass() |
If the template is a switch infobox, then data-attr-param="<paramname>"
will be added to the table cell.
This function will return the template, allowing further self functions to be performed.
wikitext
ret:wikitext(txt)
Appends wikitext to the top-level wrapper. Templates, etc. passed directly from Lua code will need explicit preprocessing prior to display properly.
This function will return the template, allowing further self functions to be performed.
ret:caption()
Adds a caption to the infobox based off the subject name, using the following priority for the text:
name
parametername1
parameter (if switch infobox){{PAGENAME}}
If the template is a switch infobox, this will also add data-attr-param="name"
to the caption
.
This function will return the template, allowing further self functions to be performed.
attr
ret:attr(arg)
Passes arg
to mw.html.attr()
.
This function will return the template, allowing further self functions to be performed.
float
ret:float(dir)
Changes the direction of the CSS style float
for the top level wrapper. By default, all infoboxes float right
.
This function will return the template, allowing further self functions to be performed.
css
ret:css(...)
Passes the arguments to mw.html.css()
.
This function will return the template, allowing further self functions to be performed.
addClass
ret:addClass(arg)
Passes arg
to mw.html.addClass()
.
This function will return the template, allowing further self functions to be performed.
addClasses
ret:attr(...)
Passes every argument to mw.html.addClass()
individually.
This function will return the template, allowing further self functions to be performed.
tag
ret:tag(arg)
Passes arg
to mw.html.tag()
.
This function will return the tag (not the template), allowing further self functions to be performed.
useSMW
ret:useSMW(tbl)
Tells the module to create properties for parameters, as well as defining those mappings with tbl
, a table
whose elements form an associated array formatted as such:
{
parameter = property,
...
}
When defined, properties will be defined for two separate properties: both "Property:<name>" and "Property:All <name>". If the template holds switch infobox data, then properties will be defined for "Property:<name><X>" for all applicable X. The "All <name>" properties exist to create storage for all applicable values. Keep this in mind, as "Property:<name>" will only ever store the default value.
By default, the module will define Property:Release date and Property:Is members only.
noSwitch
ret:noSwitch()
Forces the template to use only a single version, the default.
maxVersion
ret:maxVersion()
Returns the number of versions used by the infobox. When run the first time, this function will check and define the version count first. Subsequent calls will simply return the count.
linkParams
ret:linkParams{
paramName = linkedParam,
...
}
Links two parameters where one parameter (paramName
) is the parameter name of a cell's contents, and linkedParam
is the name of the parameter that contains the classes for the specified cell. It will only have an effect on switch infoboxes. Both parameters will need to be defined in the infobox with definedParams
. They should be functions of the parameter they operator on and include dupes = true
in their definitions.
This function must be called only after calling ret:cleanParams()
(and before ret:finish()
).
Example: grand exchange graphs do not make sense to display for untradeable items within switch infoboxes (e.g. ahrim's staff); one could use a linkParam to add a class that will display:none table row when switching to untradeable items.
In the source code of the infobox, these will be added as such:
<div class="infobox-switch-resources hidden">
<span data-attr-param="param">
<span data-attr-index="0" data-addclass="linkedParam[d]">paramName[d]</span>
<span data-attr-index="1" data-addclass="linkedParam[1]">paramName[1]</span>
<span data-attr-index="2" data-addclass="linkedParam[2]">paramName[2]</span>
</span>
</div>
From this, the switch infobox javascript will add the contents of data-addclass
to class attribute of the row of the table when the infobox is switched. You will also need to define the classes you are using in global CSS.
If the parameter is a th or td element, the class is added to the parent tr. Otherwise, it is added to the element directly (e.g. caption element).
finish
Finalises the template and adds remaining required HTML.
- Creates hidden tag for switch infobox data (if needed)
- Adds Category:Pages that contain switch infobox data if in the mainspace
- Defines Property:Version count if in the mainspace
- Adds Semantic MediaWiki Data in a hidden tag (if needed)
- This data can be viewed on the page itself by using inspect element, but it is not normally visible
- Adds infobox bottom links
param
ret:param(arg, flag)
Returns the value of the parameter named arg
. The exact format and values are determined by the flag
:
d
or empty - default value of the parameterf
orfull
- all values of the parameter as a tables
orswitches
- table of all switch values (or nil if no switches are present)s#
- switch value at index#
r
- if defined, switch value 1, otherwise the default value
Note that this function returns the actual table used by the template. If a switch value is equal to Infobox.nil_param
for flag s#
, then nil
will be returned instead; however, when calling specific indices from the tables returned by f
or r
, the value of Infobox.nil_param
will be returned without extra parsing.
paramDefined
ret:paramDefined(arg, flag)
Looks to see if the parameter named arg
is defined at any index, based on instructions from flag
:
0
or empty - default value of parameter#
- value of switch at index#
all
- true if the parameter is defined with a default or at any switch value
paramGrep
ret:paramGrep(arg, query)
Performs a function or search on every possible value of the parameter named arg
. query
can be either a function
, a string
, or a number
. If a match is found or the function query returns true, paramGrep
will end its search.
If query
is a function, that function must pass a single argument (the parameter), and return either true
or false
.
If query
is a string, then that string will be compared to each value of the parameter. If they match exactly, disregarding casing, then true
will be returned. To perform a pattern match on strings, you will need to define query
as a function that returns a boolean value based on string.find
or mw.ustring.find
.
If query
is a number (or any other type), then it will be compared to each value for a match.
Matches are only checked if the type of query
matches the value of the parameter; e.g., it is not valid to search for a number (ex: 4
) inside a string (ex: '455'
).
paramRead
Infobox.paramRead(arg, query)
Performs the same function as paramGrep
; however, instead of arg
being a name of a parameter to look for, it is the table itself. Useful for functions where only the table of parameters is passed, but not the whole infobox.
categoryData
ret:categoryData()
Returns fundamental category data collected during Infobox:cleanParams()
.
Fields in the category data include:
one_defined
-true
if at least one possible value of the parameter is definedall_defined
-false
if at least one possible value of the parameter is not defined
Rules
Defined parameters
Parameters are to be considered "defined" if they meet all of the following criteria:
- Is not
nil
- Contains at least one non-whitespace character (
string.find(param,'%S')
- Is not equal to
Infobox.nil_param
- Does not contain the string
'action=edit'
-- -- This module implements {{Infobox}} -- local p = {} local navbar = require('Module:Navbar')._navbar local args = {} local origArgs local root local function notempty( s ) return s and s:match( '%S' ) end local function fixChildBoxes(sval, tt) if notempty(sval) then local marker = '<span class=special_infobox_marker>' local s = sval s = mw.ustring.gsub(s, '(<%s*[Tt][Rr])', marker .. '%1') s = mw.ustring.gsub(s, '(</[Tt][Rr]%s*>)', '%1' .. marker) if s: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 if s:match(marker) then local subcells = mw.text.split(s, marker) s = '' for k = 1, #subcells do if k == 1 then s = s .. subcells[k] .. '</' .. tt .. '></tr>' elseif k == #subcells then local rowstyle = ' style="display:none"' if notempty(subcells[k]) then rowstyle = '' end s = s .. '<tr' .. rowstyle ..'><' .. tt .. ' colspan=2>\n' .. subcells[k] elseif notempty(subcells[k]) then if (k % 2) == 0 then s = s .. subcells[k] else s = s .. '<tr><' .. tt .. ' colspan=2>\n' .. subcells[k] .. '</' .. tt .. '></tr>' end end end end return s else return sval end end local function union(t1, t2) -- Returns the union of the values of two tables, as a sequence. local vals = {} for k, v in pairs(t1) do vals[v] = true end for k, v in pairs(t2) do vals[v] = true end local ret = {} for k, v in pairs(vals) do table.insert(ret, k) end return ret end local function getArgNums(prefix) -- 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}. local nums = {} for k, v in pairs(args) do local num = tostring(k):match('^' .. prefix .. '([1-9]%d*)$') if num then table.insert(nums, tonumber(num)) end end table.sort(nums) return nums end local function addRow(rowArgs) -- Adds a row to the infobox, with either a header cell -- or a label/data cell combination. if rowArgs.header then root :tag('tr') :addClass(rowArgs.rowclass) :cssText(rowArgs.rowstyle) :attr('id', rowArgs.rowid) :tag('th') :attr('colspan', 2) :attr('id', rowArgs.headerid) :addClass(rowArgs.class) :addClass(args.headerclass) :css('text-align', 'center') :cssText(args.headerstyle) :cssText(rowArgs.rowcellstyle) :wikitext(fixChildBoxes(rowArgs.header, 'th')) elseif rowArgs.data then local row = root:tag('tr') row:addClass(rowArgs.rowclass) row:cssText(rowArgs.rowstyle) row:attr('id', rowArgs.rowid) if rowArgs.label then row :tag('th') :attr('scope', 'row') :attr('id', rowArgs.labelid) :cssText(args.labelstyle) :cssText(rowArgs.rowcellstyle) :wikitext(rowArgs.label) :done() end local dataCell = row:tag('td') if not rowArgs.label then dataCell :attr('colspan', 2) :css('text-align', 'center') end dataCell :attr('id', rowArgs.dataid) :addClass(rowArgs.class) :cssText(rowArgs.datastyle) :cssText(rowArgs.rowcellstyle) :newline() :wikitext(fixChildBoxes(rowArgs.data, 'td')) end end local function renderTitle() if not args.title then return end root :tag('caption') :addClass(args.titleclass) :cssText(args.titlestyle) :wikitext(args.title) end local function renderAboveRow() if not args.above then return end root :tag('tr') :tag('th') :attr('colspan', 2) :addClass(args.aboveclass) :css('text-align', 'center') :css('font-size', '125%') :css('font-weight', 'bold') :cssText(args.abovestyle) :wikitext(fixChildBoxes(args.above,'th')) end local function renderBelowRow() if not args.below then return end root :tag('tr') :tag('td') :attr('colspan', '2') :addClass(args.belowclass) :css('text-align', 'center') :cssText(args.belowstyle) :newline() :wikitext(fixChildBoxes(args.below,'td')) end local function renderSubheaders() if args.subheader then args.subheader1 = args.subheader end if args.subheaderrowclass then args.subheaderrowclass1 = args.subheaderrowclass end local subheadernums = getArgNums('subheader') for k, num in ipairs(subheadernums) do addRow({ data = args['subheader' .. tostring(num)], datastyle = args.subheaderstyle or args['subheaderstyle' .. tostring(num)], class = args.subheaderclass, rowclass = args['subheaderrowclass' .. tostring(num)] }) end end local function renderImages() if args.image then args.image1 = args.image end if args.caption then args.caption1 = args.caption end local imagenums = getArgNums('image') for k, num in ipairs(imagenums) do local caption = args['caption' .. tostring(num)] local data = mw.html.create():wikitext(args['image' .. tostring(num)]) if caption then data :tag('div') :cssText(args.captionstyle) :wikitext(caption) end addRow({ data = tostring(data), datastyle = args.imagestyle, class = args.imageclass, rowclass = args['imagerowclass' .. tostring(num)] }) end end local function renderRows() -- Gets the union of the header and data argument numbers, -- and renders them all in order using addRow. local rownums = union(getArgNums('header'), getArgNums('data')) table.sort(rownums) for k, num in ipairs(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)], rowstyle = args['rowstyle' .. tostring(num)], rowcellstyle = args['rowcellstyle' .. tostring(num)], dataid = args['dataid' .. tostring(num)], labelid = args['labelid' .. tostring(num)], headerid = args['headerid' .. tostring(num)], rowid = args['rowid' .. tostring(num)] }) end end local function renderNavBar() if not args.name then return end root :tag('tr') :tag('td') :attr('colspan', '2') :css('text-align', 'right') :wikitext(navbar{ args.name, mini = 1, }) end local function renderItalicTitle() local italicTitle = args['italic title'] and mw.ustring.lower(args['italic title']) if italicTitle == '' or italicTitle == 'force' or italicTitle == 'yes' then root:wikitext(mw.getCurrentFrame():expandTemplate({title = 'italic title'})) end end local function renderTrackingCategories() if args.decat ~= 'yes' then if #(getArgNums('data')) == 0 and mw.title.getCurrentTitle().namespace == 0 then root:wikitext('[[Category:Articles which use infobox templates with no data rows]]') end if args.child == 'yes' and args.title then root:wikitext('[[Category:Pages which use embedded infobox templates with the title parameter]]') end end end local function _infobox() -- Specify the overall layout of the infobox, with special settings -- if the infobox is used as a 'child' inside another infobox. if args.child ~= 'yes' then root = mw.html.create('table') root :addClass('infobox') :addClass(args.bodyclass) if args.subbox == 'yes' then root :css('padding', '0') :css('border', 'none') :css('margin', '-3px') :css('width', 'auto') :css('min-width', '100%') :css('font-size', '100%') :css('clear', 'none') :css('float', 'none') :css('background-color', 'transparent') else root :css('width', '22em') end root :cssText(args.bodystyle) renderTitle() renderAboveRow() else root = mw.html.create() root :wikitext(args.title) end renderSubheaders() renderImages() renderRows() renderBelowRow() renderNavBar() renderItalicTitle() renderTrackingCategories() return tostring(root) end local function preprocessSingleArg(argName) -- 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. if origArgs[argName] and origArgs[argName] ~= '' then args[argName] = origArgs[argName] end end local function preprocessArgs(prefixTable, step) -- 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. if type(prefixTable) ~= 'table' then error("Non-table value detected for the prefix table", 2) end if type(step) ~= 'number' then error("Invalid step value detected", 2) end -- Get arguments without a number suffix, and check for bad input. for i,v in ipairs(prefixTable) do if type(v) ~= 'table' or type(v.prefix) ~= "string" or (v.depend and type(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. if args[v.prefix] and v.depend then for j, dependValue in ipairs(v.depend) do if type(dependValue) ~= 'string' then error('Invalid "depend" parameter value detected in preprocessArgs') end preprocessSingleArg(dependValue) end end end -- Get arguments with number suffixes. local a = 1 -- Counter variable. local moreArgumentsExist = true while moreArgumentsExist == true do moreArgumentsExist = false for i = a, a + step - 1 do for j,v in ipairs(prefixTable) do local prefixArgName = v.prefix .. tostring(i) if origArgs[prefixArgName] then moreArgumentsExist = true -- Do another loop if any arguments are found, even blank ones. 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. if v.depend and (args[prefixArgName] or (i == 1 and args[v.prefix])) then for j,dependValue in ipairs(v.depend) do local dependArgName = dependValue .. tostring(i) preprocessSingleArg(dependArgName) end end end end a = a + step end end function p.infobox(frame) -- If called via #invoke, use the args passed into the invoking template. -- Otherwise, for testing purposes, assume args are being passed directly in. if frame == mw.getCurrentFrame() then origArgs = frame:getParent().args else origArgs = frame 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. 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'}, {prefix = 'dataid'}, {prefix = 'labelid'}, {prefix = 'headerid'}, {prefix = 'rowid'} }, 50) preprocessSingleArg('headerclass') preprocessSingleArg('headerstyle') preprocessSingleArg('labelstyle') preprocessSingleArg('datastyle') preprocessSingleArg('below') preprocessSingleArg('belowclass') preprocessSingleArg('belowstyle') preprocessSingleArg('name') args['italic title'] = origArgs['italic title'] -- different behaviour if blank or absent preprocessSingleArg('decat') return _infobox() end return p