Module:Infobox : Différence entre versions

De Lagny-sur-Marne Wiki
Aller à : navigation, rechercher
(+ support Wikidata expérimental)
Ligne 1 : Ligne 1 :
local Infobox = {}
+
--
 
+
-- This module implements {{Infobox}}
function Infobox:new( args )
+
--
    --Object initialisation
+
    local object = {
+
local p = {}
        text = "",
+
        isPart = false,
+
local HtmlBuilder = require('Module:HtmlBuilder')
        entity = nil --Lazy loading of the related Wikidata item
+
     }
+
local args = {}
     setmetatable(object, {
+
local origArgs
        __index = Infobox,
+
local root
        __tostring = function( self ) return self:tostring() end
+
    })
+
function union(t1, t2)
 
+
    -- Returns the union of the values of two tables, as a sequence.
    if args.isPart then
+
     local vals = {}
         object.isPart = true
+
     for k, v in pairs(t1) do
 +
         vals[v] = true
 
     end
 
     end
 
+
     for k, v in pairs(t2) do
    --Open main div
+
         vals[v] = true
     if object.isPart then
 
         return object --On retourne si on construit seulement un module
 
 
     end
 
     end
 
+
     local ret = {}
     local str = '<div class="infobox_v3 '
+
     for k, v in pairs(vals) do
     if args.class then
+
         table.insert(ret, k)
         str = str .. args.class
 
 
     end
 
     end
     str = str ..'"'
+
     return ret
     if args.width then
+
end
         str = str .. ' style="width: ' .. args.width .. 'em"'
+
 +
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')
 +
                .tag('th')
 +
                    .attr('colspan', 2)
 +
                    .addClass(rowArgs.class)
 +
                    .css('text-align', 'center')
 +
                    .cssText(args.headerstyle)
 +
                    .wikitext(rowArgs.header)
 +
    elseif rowArgs.data then
 +
         local row = root.tag('tr')
 +
        row.addClass(rowArgs.rowclass)
 +
        if rowArgs.label then
 +
            row
 +
                .tag('th')
 +
                    .attr('scope', 'row')
 +
                    .css('text-align', 'left')
 +
                    .cssText(args.labelstyle)
 +
                    .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
 +
            .addClass(rowArgs.class)
 +
            .cssText(rowArgs.datastyle)
 +
            .newline()
 +
            .wikitext(rowArgs.data)
 
     end
 
     end
    object.text = str .. '>'
 
    return object
 
 
end
 
end
 
+
function Infobox:addText( args )
+
local function renderTitle()
    self.text = self.text .. args.text
+
    if not args.title then return end
 +
 +
    root
 +
        .tag('caption')
 +
            .addClass(args.titleclass)
 +
            .cssText(args.titlestyle)
 +
            .wikitext(args.title)
 
end
 
end
 
+
function Infobox:getEntity()
+
local function renderAboveRow()
     if self.entity == nil then
+
     if not args.above then return end
         self.entity = mw.wikibase.getEntity()
+
     end
+
    root
     return self.entity
+
         .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(args.above)
 +
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(args.below)
 
end
 
end
 
+
function Infobox:addTitle( args )
+
local function renderSubheaders()
    local str = '<p class="entete'
+
     if args.subheader then
     if args.icon then
+
         args.subheader1 = args.subheader
         str = str .. ' icon ' .. args.icon
 
 
     end
 
     end
     if args.class then
+
     if args.subheaderrowclass then
         str = str .. ' ' .. args.class
+
         args.subheaderrowclass1 = args.subheaderrowclass
    end
 
    str = str .. '"'
 
    if args.background then
 
        local style = {}
 
        style['background-color'] = args.background
 
        if args['border-color'] then
 
            style['border-color'] = args['border-color']
 
        else
 
            style['border-color'] = args.background
 
        end
 
        if args.color then
 
            style['color'] = args.color
 
        end
 
        str = str .. ' style="' .. formatStyle( style ) .. '"'
 
 
     end
 
     end
     str = str .. '>'
+
     local subheadernums = getArgNums('subheader')
     if args.text and args.text ~= '' then
+
     for k, num in ipairs(subheadernums) do
        str = str .. args.text
+
        addRow({
    else
+
            data = args['subheader' .. tostring(num)],
        str = str .. mw.title.getCurrentTitle().text
+
            datastyle = args.subheaderstyle or args['subheaderstyle' .. tostring(num)],
 +
            class = args.subheaderclass,
 +
            rowclass = args['subheaderrowclass' .. tostring(num)]
 +
        })
 
     end
 
     end
    self.text = self.text .. str .. '</p>'
 
 
end
 
end
 
+
function Infobox:openTable( args )
+
local function renderImages()
    local str = '<table'
+
     if args.image then
    str = str .. '><caption'
+
         args.image1 = args.image
     if args.class then
 
         str = str .. ' class="' .. args.class .. '"'
 
 
     end
 
     end
 
+
     if args.caption then
    --Style of the caption
+
         args.caption1 = args.caption
    local style = {}
 
     if args.border then
 
         style['border-color'] = args.border
 
 
     end
 
     end
     if args.background then
+
     local imagenums = getArgNums('image')
         style['background'] = args.background
+
    for k, num in ipairs(imagenums) do
         if args.color then
+
         local caption = args['caption' .. tostring(num)]
             style['color'] = args.color
+
        local data = HtmlBuilder.create().wikitext(args['image' .. tostring(num)])
 +
         if caption then
 +
             data
 +
                .tag('br', {selfClosing = true})
 +
                    .done()
 +
                .tag('div')
 +
                    .cssText(args.captionstyle)
 +
                    .wikitext(caption)
 
         end
 
         end
 +
        addRow({
 +
            data = tostring(data),
 +
            datastyle = args.imagestyle,
 +
            class = args.imageclass,
 +
            rowclass = args['imagerowclass' .. tostring(num)]
 +
        })
 
     end
 
     end
     if next( style ) then
+
end
         str = str .. ' style="' .. formatStyle( style ) .. '"'
+
 +
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)]
 +
        })
 
     end
 
     end
 
+
end
     str = str .. '>'
+
    if args.text and args.text ~= '' then
+
local function renderNavBar()
        str = str .. args.text
+
    if not args.name then return end
     else
+
         str = str .. 'Données clés'
+
     root
 +
        .tag('tr')
 +
            .tag('td')
 +
                .attr('colspan', '2')
 +
                .css('text-align', 'right')
 +
                .wikitext(mw.getCurrentFrame():expandTemplate({
 +
                    title = 'navbar',
 +
                    args = { 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
 
    self.text = self.text .. str .. '</caption>'
 
 
end
 
end
 
+
function Infobox:closeTable( args )
+
local function renderTrackingCategories()
     self.text = self.text .. '</table>'
+
     if args.decat ~= 'yes' then
end
+
        if #(getArgNums('data')) == 0 and mw.title.getCurrentTitle().namespace == 0 then
 
+
            root.wikitext('[[Category:Articles which use infobox templates with no data rows]]')
function Infobox:addMixedRow( args )
+
         end
 
+
         if args.child == 'yes' and args.title then
    --Get value from Wikidata if needed
+
            root.wikitext('[[Category:Articles which use embedded infobox templates with the title parameter]]')
    if args.property and ( not args.value or args.value == '' ) then
 
         local entity = self:getEntity()
 
         if entity then
 
            local Wikidata = require 'Module:Wikidata'
 
            args.value = Wikidata.formatStatementsFromLua( {
 
                entity = entity,
 
                property = args.property,
 
                rank = args.rank
 
            } )
 
 
         end
 
         end
 
     end
 
     end
 
+
end
     if not args.value or args.value == '' then
+
         return
+
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 = HtmlBuilder.create('table')
 +
 +
        root
 +
            .addClass('infobox')
 +
            .addClass(args.bodyclass)
 +
            .attr('cellspacing', 3)
 +
            .css('border-spacing', '3px')
 +
 +
            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 = HtmlBuilder.create()
 +
 +
         root
 +
            .wikitext(args.title)
 
     end
 
     end
     if not args.label then
+
        self.text = self.text .. '<tr><td class="error">Le paramètre label n\'est pas renseigné.</td></tr>'
+
    renderSubheaders()
         return
+
    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 str = '<tr><th scope="row"'
+
end
     if args.class then
+
        str = str .. ' class="' .. args.class .. '"'
+
local function preprocessArgs(prefixTable, step)
     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
     local style = {}
+
    -- wrong order. The prefixTable should be an array containing tables, each of which has
     if args.width then
+
     -- two possible fields, a "prefix" string and a "depend" table. The function always parses
        style['width'] =  args.width .. 'em'
+
     -- parameters containing the "prefix" string, but only parses parameters in the "depend"
    end
+
     -- table if the prefix parameter is present and non-blank.
     if next( style ) then
+
     if type(prefixTable) ~= 'table' then
         str = str .. ' style="' .. formatStyle( style ) .. '"'
+
         error("Non-table value detected for the prefix table", 2)
 
     end
 
     end
 
+
     if type(step) ~= 'number' then
     self.text = self.text .. str .. '>' .. args.label .. '</th><td>' .. args.value .. '</td></tr>'
+
        error("Invalid step value detected", 2)
end
 
 
 
function Infobox:addImages( args )
 
    --Get images
 
    local images = {}
 
    if not args.images then
 
        return
 
 
     end
 
     end
     for i,conf in pairs( args.images ) do
+
         if conf.name and conf.name ~= '' then
+
    -- Get arguments without a number suffix, and check for bad input.
             table.insert( images, conf )
+
     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
 
         end
    end
+
        preprocessSingleArg(v.prefix)
 
+
         -- Only parse the depend parameter if the prefix parameter is present and not blank.
    if not next( images ) then
+
        if args[v.prefix] and v.depend then
         return --Pas d'images
+
            for j, dependValue in ipairs(v.depend) do
    end
+
                if type(dependValue) ~= 'string' then
    local imagesCount = table.maxn( images )
+
                    error('Invalid "depend" parameter value detected in preprocessArgs')
 
+
                end
    local str = ''
+
                preprocessSingleArg(dependValue)
    if imagesCount == 2 then
+
             end
        str = '<div class="image2"'
 
        if args.background then
 
             str = str .. ' style="background: ' .. args.background .. ';"'
 
 
         end
 
         end
        str = str .. '>'
 
 
     end
 
     end
 
+
     for i,image in pairs( images ) do
+
     -- Get arguments with number suffixes.
        str = str .. '[[Fichier:' .. image.name .. '|thumb'
+
    local a = 1 -- Counter variable.
        if imagesCount == 1 then
+
    local moreArgumentsExist = true
            str = str .. '|center'
+
    while moreArgumentsExist == true do
         end
+
         moreArgumentsExist = false
         if image.upright then
+
         for i = a, a + step - 1 do
             str = str .. '|upright=' .. image.upright
+
             for j,v in ipairs(prefixTable) do
        else
+
                local prefixArgName = v.prefix .. tostring(i)
            str = str .. '|upright=' .. ( 1 / imagesCount )
+
                if origArgs[prefixArgName] then
        end
+
                    moreArgumentsExist = true -- Do another loop if any arguments are found, even blank ones.
        if image.alt then
+
                    preprocessSingleArg(prefixArgName)
            str = str .. '|alt=' .. image.alt
+
                end
        else
+
                -- Process the depend table if the prefix argument is present and not blank, or
            str = str .. '|alt=Description de '
+
                -- we are processing "prefix1" and "prefix" is present and not blank, and
            if args.legend then
+
                -- if the depend table is present.
                str = str .. 'cette image, également commentée ci-après'
+
                if v.depend and (args[prefixArgName] or (i == 1 and args[v.prefix])) then
            else
+
                    for j,dependValue in ipairs(v.depend) do
                 str = str .. 'l\'image ' .. image.name
+
                        local dependArgName = dependValue .. tostring(i)
 +
                        preprocessSingleArg(dependArgName)
 +
                    end
 +
                 end
 
             end
 
             end
 
         end
 
         end
         str = str .. ']]'
+
         a = a + step
    end
 
 
 
    if imagesCount == 2 then
 
        str = str .. '</div>'
 
    end
 
 
 
    if args.legend then
 
        str = str .. '<p class="legend">' .. args.legend .. '</p>'
 
 
     end
 
     end
   
 
    self.text = self.text .. str
 
 
end
 
end
 
+
function Infobox:tostring()
+
function p.infobox(frame)
     if self.isPart then
+
    -- If called via #invoke, use the args passed into the invoking template.
         return self.text
+
    -- Otherwise, for testing purposes, assume args are being passed directly in.
 +
     if frame == mw.getCurrentFrame() then
 +
         origArgs = frame:getParent().args
 
     else
 
     else
         return self.text .. '</div>'
+
         origArgs = frame
    end
 
end
 
 
 
--Create a style property value from an array CSS property = CSS value
 
function formatStyle( args )
 
    local elems = {}
 
    for key, val in pairs( args ) do
 
        table.insert( elems, key .. ':' .. val )
 
 
     end
 
     end
     return table.concat( elems, '; ' )
+
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
local p = {}
+
    -- another parameter are only processed if that parameter is present, to avoid
function p.new( args )
+
     -- phantom references appearing in article reference lists.
     return Infobox:new( args )
+
    preprocessSingleArg('child')
end
+
    preprocessSingleArg('bodyclass')
function p.test()
+
    preprocessSingleArg('subbox')
     local a = Infobox:new( {} )
+
    preprocessSingleArg('bodystyle')
     a:addTitle( {} )
+
    preprocessSingleArg('title')
     a:addImages( {
+
     preprocessSingleArg('titleclass')
         images = {
+
    preprocessSingleArg('titlestyle')
            {
+
    preprocessSingleArg('above')
                name = 'Pellicule.jpg'
+
     preprocessSingleArg('aboveclass')
            },
+
     preprocessSingleArg('abovestyle')
            {
+
     preprocessArgs({
                name = 'Pellicule.jpg'
+
         {prefix = 'subheader', depend = {'subheaderstyle', 'subheaderrowclass'}}
            }
+
    }, 10)
         },
+
    preprocessSingleArg('subheaderstyle')
         legend = 'legend'
+
    preprocessSingleArg('subheaderclass')
     } )
+
    preprocessArgs({
     a:openTable( {} )
+
        {prefix = 'image', depend = {'caption', 'imagerowclass'}}
     a:addMixedRow( {
+
    }, 10)
        label = 'Test',
+
    preprocessSingleArg('captionstyle')
        value = 'test'
+
    preprocessSingleArg('imagestyle')
     } )
+
    preprocessSingleArg('imageclass')
     a:closeTable( {} )
+
    preprocessArgs({
     return tostring(a)
+
        {prefix = 'header'},
 +
         {prefix = 'data', depend = {'label', 'rowclass'}},
 +
         {prefix = 'class'}
 +
     }, 50)
 +
    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
 
end
 +
 
return p
 
return p

Version du 29 juillet 2013 à 11:27

La documentation pour ce module peut être créée à Module:Infobox/doc

--
-- This module implements {{Infobox}}
--
 
local p = {}
 
local HtmlBuilder = require('Module:HtmlBuilder')
 
local args = {}
local origArgs
local root
 
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')
                .tag('th')
                    .attr('colspan', 2)
                    .addClass(rowArgs.class)
                    .css('text-align', 'center')
                    .cssText(args.headerstyle)
                    .wikitext(rowArgs.header)
    elseif rowArgs.data then
        local row = root.tag('tr')
        row.addClass(rowArgs.rowclass)
        if rowArgs.label then
            row
                .tag('th')
                    .attr('scope', 'row')
                    .css('text-align', 'left')
                    .cssText(args.labelstyle)
                    .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
            .addClass(rowArgs.class)
            .cssText(rowArgs.datastyle)
            .newline()
            .wikitext(rowArgs.data)
    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(args.above)
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(args.below)
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 = HtmlBuilder.create().wikitext(args['image' .. tostring(num)])
        if caption then
            data
                .tag('br', {selfClosing = true})
                    .done()
                .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)]
        })
    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(mw.getCurrentFrame():expandTemplate({ 
                    title = 'navbar', 
                    args = { 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:Articles 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 = HtmlBuilder.create('table')
 
        root
            .addClass('infobox')
            .addClass(args.bodyclass)
            .attr('cellspacing', 3)
            .css('border-spacing', '3px')
 
            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 = HtmlBuilder.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', 'rowclass'}},
        {prefix = 'class'}
    }, 50)
    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