Module:Infobox: Difference between revisions

    m>Mr. Stradivarius
    m (Protected Module:Infobox: High-risk Lua module ([Edit=Block all non-admin users] (indefinite) [Move=Block all non-admin users] (indefinite)))
    m>Mr. Stradivarius
    (fix phantom reference bug)
    Line 7: Line 7:
    local HtmlBuilder = require('Module:HtmlBuilder')
    local HtmlBuilder = require('Module:HtmlBuilder')
       
       
    local args
    local args = {}
    local origArgs
    local root
    local root
       
       
    Line 263: Line 264:
    end
    end


    local function touchParameters(prefixTable, origArgs, step)
    local function preprocessSingleArg(argName)
         -- Parse the parameters with the given prefixes, in order, in batches
         -- If the argument exists and isn't blank, add it to the argument table.
        -- of the step size specified. This is to prevent references etc. from
         -- Blank arguments are treated as nil to match the behaviour of ParserFunctions.
         -- appearing in the wrong order.
         if origArgs[argName] and origArgs[argName] ~= '' then
         if type(prefixTable) ~= 'table' or type(origArgs) ~= 'table' then
             args[argName] = origArgs[argName]
             error("Invalid input to the touchParameters function detected. Both parameters must be tables.", 2)
         end
         end
         if step and type(step) ~= 'number' then
    end
             error("Non-numerical step value detected.", 2)
     
    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
         end
          
          
         step = step or 20 -- If the step size is not given, the default is 20.
         -- Get arguments without a number suffix, and check for bad input.
         local temp
        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 a = 1 -- Counter variable.
         local moreArgumentsExist = true
         local moreArgumentsExist = true
        for j,v in ipairs(prefixTable) do
            if not type(v) == "string" then
                error("Non-string value detected in the prefix table in the touchParameters function.", 2)
            end
            temp = origArgs[v]
        end
         while moreArgumentsExist == true do
         while moreArgumentsExist == true do
             moreArgumentsExist = false
             moreArgumentsExist = false
             for i = a, a + step - 1 do
             for i = a, a + step - 1 do
                 for j,v in ipairs(prefixTable) do
                 for j,v in ipairs(prefixTable) do
                     temp = origArgs[v .. tostring(i)]
                     local prefixArgName = v.prefix .. tostring(i)
                     if temp then
                     if origArgs[prefixArgName] then
                         moreArgumentsExist = true
                         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
                 end
    Line 299: Line 331:
       
       
    function p.infobox(frame)
    function p.infobox(frame)
        local origArgs
         -- If called via #invoke, use the args passed into the invoking template.
         -- If called via #invoke, use the args passed into the invoking template.
         -- Otherwise, for testing purposes, assume args are being passed directly in.
         -- Otherwise, for testing purposes, assume args are being passed directly in.
    Line 309: Line 340:
          
          
         -- Parse the data parameters in the same order that the old {{infobox}} did, so that
         -- Parse the data parameters in the same order that the old {{infobox}} did, so that
         -- references etc. will display in the expected places.
         -- references etc. will display in the expected places. Parameters that depend on
         local temp
         -- another parameter are only processed if that parameter is present, to avoid
         temp = origArgs.title
         -- phantom references appearing in article reference lists.
         temp = origArgs.above
        preprocessSingleArg('child')
         touchParameters({'subheader'}, origArgs, 5)
        preprocessSingleArg('bodyclass')
         touchParameters({'image', 'caption'}, origArgs, 5)
        preprocessSingleArg('subbox')
         touchParameters({'header', 'label', 'data'}, origArgs, 20)
        preprocessSingleArg('bodystyle')
        temp = origArgs.below
        preprocessSingleArg('title')
        preprocessSingleArg('titleclass')
         -- ParserFunctions considers whitespace to be false, so to preserve the previous
         preprocessSingleArg('titlestyle')
         -- behavior of {{infobox}}, change any whitespace arguments to nil, so Lua will consider
        preprocessSingleArg('above')
         -- them false too. (Except the 'italic title' param, which specifies different behavior
        preprocessSingleArg('aboveclass')
         -- depending on whether it's absent or empty)
        preprocessSingleArg('abovestyle')
         args = {}
         preprocessArgs({
         for k, v in pairs(origArgs) do
            {prefix = 'subheader', depend = {'subheaderstyle', 'subheaderrowclass'}}
            if mw.ustring.match(v, '%S') or k == 'italic title' then
        }, 10)
                args[k] = v
        preprocessSingleArg('subheaderstyle')
            end
        preprocessSingleArg('subheaderclass')
         end
         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()
         return _infobox()