Editing Module:Infobox

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. Read the Privacy Policy to learn what information we collect about you and how we use it.

If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.

Latest revision Your text
Line 1: Line 1:
--
--
-- This module implements {{Infobox}}
-- This module will implement {{Infobox}}
--
--
 
local p = {}
local p = {}
 
local navbar = require('Module:Navbar')._navbar
local HtmlBuilder = require('Module:HtmlBuilder')
 
local args = {}
local args
local origArgs
local root
local root
 
   
local function notempty( s ) return s and s:match( '%S' ) end
function union(t1, t2)
 
     -- return the union of the values of two tables, as a sequence
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
-- the next two lines add a newline at the end of lists for the PHP parser
-- https://en.wikipedia.org/w/index.php?title=Template_talk:Infobox_musical_artist&oldid=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')
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 = {}
     local vals = {}
     for k, v in pairs(t1) do
     for k, v in pairs(t1) do
Line 77: Line 27:


local function getArgNums(prefix)
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 = {}
     local nums = {}
     for k, v in pairs(args) do
     for k, v in pairs(args) do
         local num = tostring(k):match('^' .. prefix .. '([1-9]%d*)$')
         local num = ('' .. k):match('^' .. prefix .. '(%d+)$')
         if num then table.insert(nums, tonumber(num)) end
         if num then table.insert(nums, tonumber(num)) end
     end
     end
Line 90: Line 37:


local function addRow(rowArgs)
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
     if rowArgs.header then
         root
         root
             :tag('tr')
             .tag('tr')
                 :addClass(rowArgs.rowclass)
                 .tag('th')
                :cssText(rowArgs.rowstyle)
                     .attr('colspan', 2)
                :attr('id', rowArgs.rowid)
                     .addClass(rowArgs.class)
                :tag('th')
                     .css('text-align', 'center')
                     :attr('colspan', 2)
                     .cssText(args.headerstyle)
                     :attr('id', rowArgs.headerid)
                     .wikitext(rowArgs.header)
                    :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
     elseif rowArgs.data then
         local row = root:tag('tr')
         local row = root.tag('tr')
         row:addClass(rowArgs.rowclass)
         row.addClass(rowArgs.rowclass)
        row:cssText(rowArgs.rowstyle)
        row:attr('id', rowArgs.rowid)
         if rowArgs.label then
         if rowArgs.label then
             row
             row
                 :tag('th')
                 .tag('th')
                     :attr('scope', 'row')
                     .attr('scope', 'row')
                     :attr('id', rowArgs.labelid)
                     .css('text-align', 'left')
                     :cssText(args.labelstyle)
                     .cssText(args.labelstyle)
                     :cssText(rowArgs.rowcellstyle)
                     .wikitext(rowArgs.label)
                    :wikitext(rowArgs.label)
                     .done()
                     :done()
         end
         end
          
          
         local dataCell = row:tag('td')
         local dataCell = row.tag('td')
         if not rowArgs.label then  
         if not rowArgs.label then  
             dataCell
             dataCell
                 :attr('colspan', 2)
                 .attr('colspan', 2)
                 :css('text-align', 'center')  
                 .css('text-align', 'center')  
         end
         end
         dataCell
         dataCell
             :attr('id', rowArgs.dataid)
             .addClass(rowArgs.class)
            :addClass(rowArgs.class)
             .cssText(rowArgs.datastyle)
             :cssText(rowArgs.datastyle)
             .wikitext(rowArgs.data)
             :cssText(rowArgs.rowcellstyle)
            :newline()
            :wikitext(fixChildBoxes(rowArgs.data, 'td'))
     end
     end
end
end
Line 143: Line 76:


     root
     root
         :tag('caption')
         .tag('caption')
             :addClass(args.titleclass)
             .addClass(args.titleclass)
             :cssText(args.titlestyle)
             .cssText(args.titlestyle)
             :wikitext(args.title)
             .wikitext(args.title)
end
end


Line 153: Line 86:
      
      
     root
     root
         :tag('tr')
         .tag('tr')
             :tag('th')
             .tag('th')
                 :attr('colspan', 2)
                 .attr('colspan', 2)
                 :addClass(args.aboveclass)
                 .addClass(args.aboveclass)
                 :css('text-align', 'center')
                 .css('text-align', 'center')
                 :css('font-size', '125%')
                 .css('font-size', '125%')
                 :css('font-weight', 'bold')
                 .css('font-weight', 'bold')
                 :cssText(args.abovestyle)
                 .cssText(args.abovestyle)
                 :wikitext(fixChildBoxes(args.above,'th'))
                 .wikitext(args.above)
end
end


Line 168: Line 101:
      
      
     root
     root
         :tag('tr')
         .tag('tr')
             :tag('td')
             .tag('td')
                 :attr('colspan', '2')
                 .attr('colspan', '2')
                 :addClass(args.belowclass)
                 .addClass(args.belowclass)
                 :css('text-align', 'center')
                 .css('text-align', 'center')
                 :cssText(args.belowstyle)
                 .cssText(args.belowstyle)
                 :newline()
                 .newline()
                 :wikitext(fixChildBoxes(args.below,'td'))
                 .wikitext(args.below)
                .newline()
end
end


Line 188: Line 122:
     for k, num in ipairs(subheadernums) do
     for k, num in ipairs(subheadernums) do
         addRow({
         addRow({
             data = args['subheader' .. tostring(num)],
             data = args['subheader' .. num],
             datastyle = args.subheaderstyle or args['subheaderstyle' .. tostring(num)],
             datastyle = args.subheaderstyle or args['subheaderstyle' .. num],
             class = args.subheaderclass,
             class = args.subheaderclass,
             rowclass = args['subheaderrowclass' .. tostring(num)]
             rowclass = args['subheaderrowclass' .. num]
         })
         })
     end
     end
Line 205: Line 139:
     local imagenums = getArgNums('image')
     local imagenums = getArgNums('image')
     for k, num in ipairs(imagenums) do
     for k, num in ipairs(imagenums) do
         local caption = args['caption' .. tostring(num)]
         local caption = args['caption' .. num]
         local data = mw.html.create():wikitext(args['image' .. tostring(num)])
         local data = HtmlBuilder.create().wikitext(args['image' .. num])
         if caption then
         if caption then
             data
             data
                 :tag('div')
                 .tag('br', {selfClosing = true})
                     :cssText(args.captionstyle)
                     .done()
                     :wikitext(caption)
                .tag('span')
                    .cssText(args.captionstyle)
                     .wikitext(caption)
         end
         end
         addRow({
         addRow({
Line 217: Line 153:
             datastyle = args.imagestyle,
             datastyle = args.imagestyle,
             class = args.imageclass,
             class = args.imageclass,
             rowclass = args['imagerowclass' .. tostring(num)]
             rowclass = args['imagerowclass' .. num]
         })
         })
     end
     end
Line 223: Line 159:


local function renderRows()
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'))
     local rownums = union(getArgNums('header'), getArgNums('data'))
     table.sort(rownums)
     table.sort(rownums)
     for k, num in ipairs(rownums) do
     for k, num in ipairs(rownums) do
         addRow({
         addRow({
             header = args['header' .. tostring(num)],
             header = args['header' .. num],
             label = args['label' .. tostring(num)],
             label = args['label' .. num],
             data = args['data' .. tostring(num)],
             data = args['data' .. num],
             datastyle = args.datastyle,
             datastyle = args.datastyle,
             class = args['class' .. tostring(num)],
             class = args['class' .. num],
             rowclass = args['rowclass' .. tostring(num)],
             rowclass = args['rowclass' .. 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
Line 249: Line 177:
      
      
     root
     root
         :tag('tr')
         .tag('tr')
             :tag('td')
             .tag('td')
                 :attr('colspan', '2')
                 .attr('colspan', '2')
                 :css('text-align', 'right')
                 .css('text-align', 'right')
                 :wikitext(navbar{
                 .wikitext(mw.getCurrentFrame():expandTemplate({
                     args.name,
                    title = 'navbar',
                    mini = 1,
                     args = { args.name, mini = 1 }
                 })
                 }))
end
end


Line 262: Line 190:
     local italicTitle = args['italic title'] and mw.ustring.lower(args['italic title'])
     local italicTitle = args['italic title'] and mw.ustring.lower(args['italic title'])
     if italicTitle == '' or italicTitle == 'force' or italicTitle == 'yes' then
     if italicTitle == '' or italicTitle == 'force' or italicTitle == 'yes' then
         root:wikitext(mw.getCurrentFrame():expandTemplate({title = 'italic title'}))
         root.wikitext(mw.getCurrentFrame():expandTemplate({title = 'italic title'}))
     end
     end
end
end
Line 268: Line 196:
local function renderTrackingCategories()
local function renderTrackingCategories()
     if args.decat ~= 'yes' then
     if args.decat ~= 'yes' then
    if args.child == 'yes' then
        if #(getArgNums('data')) == 0 and mw.title.getCurrentTitle().namespace == 0 then
        if args.title then
            root.wikitext('[[Category:Articles which use infobox templates with no data rows]]')
            root:wikitext('[[Category:Pages which use embedded infobox templates with the title parameter]]')
        end
        end
         if args.child == 'yes' and args.title then
         elseif #(getArgNums('data')) == 0 and mw.title.getCurrentTitle().namespace == 0 then
             root.wikitext('[[Category:Articles which use embedded infobox templates with the title parameter]]')
             root:wikitext('[[Category:Articles which use infobox templates with no data rows]]')
         end
         end
     end
     end
Line 279: Line 206:


local function _infobox()
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
     if args.child ~= 'yes' then
         root = mw.html.create('table')
         root = HtmlBuilder.create('table')
          
          
         root
         root
             :addClass((args.subbox ~= 'yes') and 'infobox' or nil)
             .addClass('infobox')
             :addClass(args.bodyclass)
            .addClass(args.bodyclass)
            .attr('cellspacing', 3)
            .css('border-spacing', '3px')
             .cssText(args.bodystyle)
              
              
             if args.subbox == 'yes' then
             if args.subbox == 'yes' then
                 root
                 root
                     :css('padding', '0')
                     .css('padding', '0')
                     :css('border', 'none')
                     .css('border', 'none')
                     :css('margin', '-3px')
                     .css('margin', '-3px')
                     :css('width', 'auto')
                     .css('width', 'auto')
                     :css('min-width', '100%')
                     .css('min-width', '100%')
                     :css('font-size', '100%')
                     .css('font-size', '100%')
                     :css('clear', 'none')
                     .css('clear', 'none')
                     :css('float', 'none')
                     .css('float', 'none')
                     :css('background-color', 'transparent')
                     .css('background-color', 'transparent')
             else
             else
                 root
                 root
                     :css('width', '22em')
                     .css('width', '22em')
             end
             end
        root
            :cssText(args.bodystyle)
      
      
         renderTitle()
         renderTitle()
         renderAboveRow()
         renderAboveRow()
     else
     else
         root = mw.html.create()
         root = HtmlBuilder.create()
       
        root
            :wikitext(args.title)
     end
     end


Line 324: Line 247:
      
      
     return tostring(root)
     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
end
   
   
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 400: Line 258:
         origArgs = frame
         origArgs = frame
     end
     end
   
     -- Parse the data parameters in the same order that the old {{infobox}} did, so that
     -- ParserFunctions considers the empty string to be false, so to preserve the previous
    -- references etc. will display in the expected places. Parameters that depend on
    -- behavior of {{infobox}}, change any empty arguments to nil, so Lua will consider
    -- another parameter are only processed if that parameter is present, to avoid
     -- them false too. (Except the 'italic title' param, which specifies different behavior
     -- phantom references appearing in article reference lists.
     -- depending on whether it's absent or empty)
    preprocessSingleArg('child')
     args = {}
    preprocessSingleArg('bodyclass')
     for k, v in pairs(origArgs) do
    preprocessSingleArg('subbox')
         if v ~= '' or k == 'italic title' then
    preprocessSingleArg('bodystyle')
            args[k] = v
    preprocessSingleArg('title')
        end
    preprocessSingleArg('titleclass')
     end
    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()
     return _infobox()
Please note that all contributions to Nonbinary Wiki are considered to be released under the Creative Commons Attribution-ShareAlike (see Nonbinary Wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!
Cancel Editing help (opens in new window)

Template used on this page: