Module:Infobox: Difference between revisions

3,232 bytes removed ,  3 years ago
m
65 revisions imported: Importing Template:Tmbox, with templates.
(Added more options to Italic Title per discussion at Template talk:Infobox#Italics part deux)
m (65 revisions imported: Importing Template:Tmbox, with templates.)
 
(11 intermediate revisions by 4 users not shown)
Line 8:
 
local args = {}
local origArgs = {}
local root
 
Line 27:
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
Line 63:
 
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 if rowArgs.data then
root:wikitext('[[Category:Pages which use infobox templates with ignored data cells]]')
local row = root:tag('tr')
end
row:addClass(rowArgs.rowclass)
elseif row:cssText(rowArgs.rowstyle)data then
if not rowArgs.data:gsub('%[%[%s*[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]%s*:[^]]*]]', ''):match('^%S') then
row:attr('id', rowArgs.rowid)
if rowArgs.labelrowstyle = then'display:none'
end
row
local row = root:tag('thtr')
row:addClass(rowArgs.rowclass)
:attr('scope', 'row')
row:attrcssText('id', rowArgs.labelidrowstyle)
row:attr('id', rowArgs.rowid)
:cssText(args.labelstyle)
if rowArgs.label then
:cssText(rowArgs.rowcellstyle)
row
:wikitext(rowArgs.label)
:tag('th')
:done()
:attr('scope', 'row')
end
:attr('id', rowArgs.labelid)
:cssText(args.labelstyle)
local dataCell = row:tag('td')
if not :cssText(rowArgs.label then rowcellstyle)
:wikitext(rowArgs.label)
dataCell
:done()
:attr('colspan', 2)
end
:css('text-align', 'center')
 
end
local dataCell = row:tag('td')
dataCell
if :attr('id',not rowArgs.dataid)label then
dataCell
:addClass(rowArgs.class)
:attr('colspan', 2)
:cssText(rowArgs.datastyle)
:css('text-align', 'center')
:cssText(rowArgs.rowcellstyle)
end
:wikitext(fixChildBoxes(rowArgs.data, 'td'))
dataCell
end
:attr('id', rowArgs.dataid)
:addClass(rowArgs.class)
:cssText(rowArgs.datastyle)
:cssText(rowArgs.rowcellstyle)
: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)
: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,
rowcellstyle = 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
 
--[[
Function handles the page's title italicization.
-- If the value of "italic title" is set to "force" or "yes", titles with no parentheses () are fully italicised,
and titles which contain parentheses are italicised before the first opening parenthesis.
-- If the value of "italic title" is set to "all", the complete title, including the text in parentheses is italicized.
-- If the value of "italic_string" is entered, instead of italicizing the whole title, it will italicize only some specific text.
-- Note that if the specific text is in the disambiguation then both |italic title=all and |italic_string=<text> will need to be used.
--
-- Optionale combinations:
--- No italics.
--- Italicized page name without disambiguation.
--- Italicized complete page name, including parentheses.
--- Italicized part of the text, not including disambiguation.
--- Italicized part of the text, including parentheses.
--]]
local function renderItalicTitle()
local italicTitle = args['italic title'] and mw.ustring.lower(args['italic title'])
local italicTitleModule = require("Module:Italic title")._main
if italicTitle == '' or italicTitle == 'force' or italicTitle == 'yes' then
local italicTitleOption = args['italic title']
root:wikitext(mw.getCurrentFrame():expandTemplate({title = 'italic title'}))
local italicTitleString = args['italic_string']
 
local italicTitleArg = {}
 
if (italicTitleOption) then
local italicLowercase = mw.ustring.lower(italicTitleOption)
if (italicLowercase == "no") then
-- If set to "no" or any other disabling parameter, do nothing.
return
elseif (italicLowercase == '' or italicLowercase == 'force' or italicLowercase == 'yes') then
root:wikitext(italicTitleModule({}))
return
elseif (italicLowercase == 'all') then
italicTitleArg.all = "yes"
else
-- Do nothing.
return
end
end
if (italicTitleString) then
italicTitleArg.string = italicTitleString
end
 
root:wikitext(italicTitleModule(italicTitleArg))
end
 
local function renderTrackingCategories()
if args.decat ~= 'yes' then
if args.child == 'yes' then
if args.title then
root:wikitext('[[Category:Pages which use embedded infobox templates with the title parameter]]')
end
elseif #(getArgNums('data')) == 0 and mw.title.getCurrentTitle().namespace == 0 then
root:wikitext('[[Category:Articles which use infobox templates with no data rows]]')
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((args.subbox ~= 'yes') and 'infobox' or nil)
: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
 
root
renderSubheaders()
:addClass((args.subbox ~= 'yes') and 'infobox' or nil)
renderImages()
:addClass(args.bodyclass)
renderRows()
 
renderBelowRow()
if args.subbox == 'yes' then
renderNavBar()
root
renderItalicTitle()
:css('padding', '0')
renderTrackingCategories()
:css('border', 'none')
:css('margin', '-3px')
return tostring(root)
: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 withwithout a number suffixessuffix, and check for bad input.
for i,v in ipairs(prefixTable) do
local a = 1 -- Counter variable.
if type(v) ~= 'table' or type(v.prefix) ~= "string" or (v.depend and type(v.depend) ~= 'table') then
local moreArgumentsExist = true
error('Invalid input detected to preprocessArgs prefix table', 2)
while moreArgumentsExist == true do
end
moreArgumentsExist = false
preprocessSingleArg(v.prefix)
for i = a, a + step - 1 do
-- Only parse the depend parameter if the prefix parameter is present and not blank.
for j,v in ipairs(prefixTable) do
if args[v.prefix] and v.depend then
local prefixArgName = v.prefix .. tostring(i)
for j, dependValue in ipairs(v.depend) do
if origArgs[prefixArgName] then
if type(dependValue) ~= 'string' then
moreArgumentsExist = true -- Do another loop if any arguments are found, even blank ones.
error('Invalid "depend" parameter value detected in preprocessArgs')
preprocessSingleArg(prefixArgName)
end
end
preprocessSingleArg(dependValue)
-- Process the depend table if the prefix argument is present and not blank, or
end
-- we are processing "prefix1" and "prefix" is present and not blank, and
end
-- if the depend table is present.
end
if v.depend and (args[prefixArgName] or (i == 1 and args[v.prefix])) then
 
for j,dependValue in ipairs(v.depend) do
-- Get arguments with number suffixes.
local dependArgName = dependValue .. tostring(i)
local a = 1 -- Counter variable.
preprocessSingleArg(dependArgName)
local moreArgumentsExist = true
end
while moreArgumentsExist == true do
end
moreArgumentsExist = false
end
for i = a, a + step - end1 do
for j,v in ipairs(prefixTable) do
a = a + step
local prefixArgName = v.prefix .. tostring(i)
end
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
 
local function p.infoboxparseDataParameters(frame)
-- IfParse calledthe viadata #invoke,parameters usein the argssame passedorder intothat the invokingold {{infobox}} did, so template.that
-- references etc. will display in the expected places. Parameters that depend on
-- Otherwise, for testing purposes, assume args are being passed directly in.
-- another parameter are only processed if that parameter is present, to avoid
if frame == mw.getCurrentFrame() then
-- phantom references appearing in article reference lists.
origArgs = frame:getParent().args
preprocessSingleArg('autoheaders')
else
preprocessSingleArg('child')
origArgs = frame
preprocessSingleArg('bodyclass')
end
preprocessSingleArg('subbox')
preprocessSingleArg('bodystyle')
-- Parse the data parameters in the same order that the old {{infobox}} did, so that
preprocessSingleArg('title')
-- references etc. will display in the expected places. Parameters that depend on
preprocessSingleArg('titleclass')
-- another parameter are only processed if that parameter is present, to avoid
preprocessSingleArg('titlestyle')
-- phantom references appearing in article reference lists.
preprocessSingleArg('childabove')
preprocessSingleArg('bodyclassaboveclass')
preprocessSingleArg('subboxabovestyle')
preprocessArgs({
preprocessSingleArg('bodystyle')
{prefix = 'subheader', depend = {'subheaderstyle', 'subheaderrowclass'}}
preprocessSingleArg('title')
}, 10)
preprocessSingleArg('titleclass')
preprocessSingleArg('titlestylesubheaderstyle')
preprocessSingleArg('abovesubheaderclass')
preprocessArgs({
preprocessSingleArg('aboveclass')
{prefix = 'image', depend = {'caption', 'imagerowclass'}}
preprocessSingleArg('abovestyle')
}, 10)
preprocessArgs({
preprocessSingleArg('captionstyle')
{prefix = 'subheader', depend = {'subheaderstyle', 'subheaderrowclass'}}
preprocessSingleArg('imagestyle')
}, 10)
preprocessSingleArg('subheaderstyleimageclass')
preprocessArgs({
preprocessSingleArg('subheaderclass')
{prefix = 'header'},
preprocessArgs({
{prefix = 'imagedata', depend = {'caption', 'imagerowclasslabel'}},
{prefix = 'rowclass'},
}, 10)
{prefix = 'rowstyle'},
preprocessSingleArg('captionstyle')
{prefix = 'rowcellstyle'},
preprocessSingleArg('imagestyle')
{prefix = 'class'},
preprocessSingleArg('imageclass')
{prefix = 'dataid'},
preprocessArgs({
{prefix = 'headerlabelid'},
{prefix = 'data', depend = {'labelheaderid'}},
{prefix = 'rowclassrowid'},
}, 50)
{prefix = 'rowstyle'},
preprocessSingleArg('headerclass')
{prefix = 'rowcellstyle'},
preprocessSingleArg('headerstyle')
{prefix = 'class'},
preprocessSingleArg('labelstyle')
{prefix = 'dataid'},
preprocessSingleArg('datastyle')
{prefix = 'labelid'},
preprocessSingleArg('below')
{prefix = 'headerid'},
preprocessSingleArg('belowclass')
{prefix = 'rowid'}
preprocessSingleArg('belowstyle')
}, 50)
preprocessSingleArg('headerclassname')
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('italic_string')
preprocessSingleArg('decat')
return _infobox()
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
parseDataParameters()
return _infobox()
end
 
function p.infoboxTemplate(frame)
-- For calling via #invoke within a template
origArgs = {}
for k,v in pairs(frame.args) do origArgs[k] = mw.text.trim(v) end
parseDataParameters()
return _infobox()
end
 
return p