ሞድዩል:Infobox
Documentation for this module may be created at ሞድዩል:Infobox/doc
--
-- This module implements {{Infobox}}
--
local p = {}
local HtmlBuilder = require('Module:HtmlBuilder')
local frame = {}
local args
local root
local widthImage = '245px'
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 debugEmpty(content)
if content and content ~= '' then
return content
end
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.section then
root
.tag('tr')
.tag('th')
.attr('colspan', 3)
.addClass(rowArgs.rowclass)
.css('text-align', 'center')
.cssText(rowArgs.sectionstyle or args.sectionstyle)
.wikitext(rowArgs.section)
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')
.addClass(rowArgs.rowclass)
.cssText(rowArgs.labelstyle or args.labelstyle)
.wikitext(rowArgs.label)
.done()
end
local dataCell = row.tag('td')
if rowArgs.label then
dataCell
.attr('colspan', 2)
else
dataCell
.attr('colspan', 3)
.css('text-align', 'center')
end
dataCell
.addClass(rowArgs.class)
.cssText(rowArgs.datastyle)
.wikitext('\n' .. rowArgs.data)
--.newline()
end
end
local function renderTitle()
if not args.title then return end
local header = {}
if args.media == 'yes' and args.classtitle then
header = 'media ' .. args['classtitle']
elseif args.media == 'yes' then
header = 'media '
elseif args.headertype then
header = 'header ' .. args.headertype
elseif args.classtitle then
header = 'header ' .. args.classtitle
else
header = 'header '
end
root
.tag('tr')
.tag('th')
.attr('colspan', 3)
.addClass(header)
.css('text-align', 'center')
.css('background-color', args.backgroundcolor or args.colorbackgroundtitle or 'transparent')
.css('color', args.textcolor or 'black')
.cssText(args.titlestyle)
.wikitext(args.title)
end
local function renderAboveRow()
if not args.above and not args.title2 then return end
root
.tag('tr')
.tag('th')
.attr('colspan', 3)
.addClass(args.aboveclass or args.titleclass2)
.css('text-align', 'center')
.css('font-size', '125%')
.css('font-weight', 'bold')
.cssText(args.abovestyle)
.wikitext(args.above)
end
local function renderTableFooter()-- Table footer, it will appear at the bottom of the table
if not args.tablefooter then return end
root
.tag('tr')
.tag('td')
.attr('colspan', '3')
.addClass(args.tablefooterclass)
.css('text-align', 'center')
.cssText(args.tablefooterstyle)
.wikitext(args.tablefooter)
end
local function renderBottomImage()-- Image that will appear at the bottom of the table
if not args.bottomimage then return end
bottomimage = {}
if args['bottomimagesize'] == nil or args['bottomimagesize'] == '' then
args['bottomimagesize'] = widthImage
end
if string.find(args.bottomimage, '[{[]') == nil then
bottomimage = ('[[ፋይል:' .. args.bottomimage .. '|'.. args['bottomimagesize'] .. ']]' )
else
bottomimage = args.bottomimage
end
root
.tag('tr')
.tag('td')
.attr('colspan', '3')
.addClass(args.bottomimageclass)
.css('text-align', 'center')
.cssText(args.bottomimagestyle)
.newline()
.wikitext(bottomimage)
.tag('br', {selfClosing = true})
.done()
.tag('div')
.css('display','inline')
.cssText(args.bottomfooterstyle)
.wikitext(args.bottomfooter)
.done()
.newline()
end
local function renderAboveImage()-- Image that will appear at the top of the table
if not args.aboveimage then return end
if args['aboveimagesize'] == nil or args['aboveimagesize'] == '' then
args['aboveimagesize'] = widthImage
end
aboveimage = {}
if string.find(args.aboveimage, '[{[]') == nil then
aboveimage = ('[[ፋይል:' .. args.aboveimage .. '|'.. args['aboveimagesize'] .. ']]' )
else
aboveimage = args.aboveimage
end
root
.tag('tr')
.tag('td')
.attr('colspan', '3')
.addClass(args.aboveimageclass)
.css('text-align', 'center')
.cssText(args.aboveimagestyle)
.newline()
.wikitext(aboveimage)
.tag('br', {selfClosing = true})
.done()
.tag('div')
.css('display','inline')
.cssText(args.abovefooterstyle)
.wikitext(args.abovefooter)
.done()
.newline()
end
local function renderSubtitles()-- Subtitles of the infobox
if args.subtitle then
args.subtitle1 = args.subtitle
end
if args.subtitleclass then
args.subtitleclass1 = args.subtitleclass
end
local subtitlenumber = getArgNums('subtitle')
for k, num in ipairs(subtitlenumber) do
addrow({
data = args['subtitle' .. num],
datastyle = args['subtitlestyle' .. num] or args.subtitlestyle,
class = args.subtitleclass,
rowclass = args['subtitleclass' .. num]
})
end
end
local function renderaboverows()-- rows above side images
if args.abovedata then
args.abovedata1 = args.abovedata
end
if args.abovedataclass then
args.abovedataclass1 = args.abovedataclass
end
if args.abovedatastyle then
args.abovedatastyle1 = args.abovedatastyle
end
local abovedatanumber = getArgNums('abovedata')
for k, num in ipairs(abovedatanumber) do
addrow({
data = args['abovedata' .. num],
datastyle = args['abovedatastyle' .. num],
class = args.abovedataclass,
rowclass = args['abovedataclass' .. num]
})
end
end
local function renderSideimages()
-- Images that will appear above in a geminate way for example shields and flags
if args['leftimagesize'] == "" or args['leftimagesize'] == nil then
args['leftimagesize'] = '100px'
end
if args['rightimagesize'] == "" or args['rightimagesize'] == nil then
args['rightimagesize'] = '100px'
end
if args.rightimage and args.leftimage then
if args.leftfooter then leftbrconditional = 'br' end
if args.rightfooter then rightbrconditional = 'br' end
root
.tag('tr')
.tag('td')
--.attr('cellspacing', '0em')
--.attr('padding','0em')
.attr('colspan', '3')
.css('align', 'center')
.tag('table') -- it has to go inside a table so that the rows don't deform it
.css('width', '100%')
.addClass('mergedrow')
.tag('tr')
.tag('td')
.css('text-align', 'center')
.css('background-color', 'transparent')
.addClass(args.leftimageclass)
.css('align', 'center')-- It aligns in the horizontal center
.css('text-align', 'center') -- It aligns in the horizontal center
.css('vertical-align', 'middle')-- It aligns in the vertical center
.cssText(args.leftimagestyle)
.wikitext('[[ፋይል:' .. args.leftimage .. '|' .. args['leftimagesize'] .. ']]' )
.tag(leftbrconditional)
.tag('div')
.css('display','inline')
.cssText(args.leftfooterstyle)
.wikitext(args.leftfooter)
.done()
.tag('td')
.css('text-align', 'center')-- It aligns in the horizontal center
.css('align', 'center')-- It aligns in the horizontal center
.css('vertical-align', 'middle')-- It aligns in the vertical center
.css('background-color', 'transparent')
.addClass(args.rightimageclass)
.cssText(args.rightimagestyle)
.wikitext('[[ፋይል:' .. args.rightimage .. '|' .. args['rightimagesize'] .. ']]' )
.tag(rightbrconditional)
.tag('div')
.css('display','inline')
.cssText(args.rightfootersyle)
.wikitext(args.rightfooter)
.done()
.newline()
elseif args.rightimage or args.leftimage then
-- If only one of the two, the image that appears will be in the center
imageSide = {}
if args.rightimage ~= '' and args.rightimage ~= nil then
imageSide = 'rightimage'
elseif args.leftimage ~= '' and args.leftimage ~= nil then
imageSide = 'leftimage'
end
footerSide = {}
if args.rightimage then
footerSide = 'rightfooter'
elseif args.leftimage then
footerSide = 'leftfooter'
end
root
.tag('tr')
.tag('td')
.attr('colspan', '3')
.addClass(args['class' .. imageSide])
.css('text-align', 'center')
.cssText(args['style' .. imageSide])
.newline()
.wikitext('[[ፋይል:' .. args[imageSide] .. '|'.. args['size'..imageSide] .. ']]' )
.tag('br')
.tag('div')
.css('display','inline')
.cssText(args['style' .. footerSide])
.wikitext(args[footerSide])
.done()
end
end
local function renderImages() -- Can create infinite number of images
if args.image then
args.image1 = args.image
end
if args['imagesize'] then
args['imagesize1'] = args['imagesize']
end
if args.footer then
args.footer1 = args.footer
end
local imagenums = getArgNums('image')
for k, num in ipairs(imagenums) do
local footer = args['footer' .. num]
local floating = args['floatingimage' .. num] or false
if args['imagesize'..num] == nil then
args['imagesize'..num] = widthImage
end
image = {}
local searchString = mw.ustring.gsub(args['image'..num],'UNIQ','[') -- So that this does not cause problems with certain templates
if mw.ustring.find(searchString, '[{[|]') == nil then -- Check if there is [ or { to not add prefix
image = ('[[ፋይል:' .. args['image' .. num] .. '|'.. args['imagesize' ..num] .. ']]' )
else
image = args['image'..num]
end
local data = HtmlBuilder.create().wikitext(image)
if footer and not floating then
data
.tag('br', {selfClosing = true})
.done()
end
if footer then
data
.tag('div')
.css('display','inline')
.cssText(args.footerstyle)
.wikitext(footer)
.done()
end
addrow({
data = tostring(data),
datastyle = args.imagestyle,
class = args.claseimagen,
rowclass = args['imageclass' .. 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('section'), getArgNums('data'))
table.sort(rownums)
for k, num in ipairs(rownums) do
addrow({
subtitlestyle = debugEmpty(args['subtitlestyle' .. num]),
section = debugEmpty(args['section' .. num]),
sectionstyle = debugEmpty(args['sectionstyle' .. num]),
label = debugEmpty(args['label' .. num]),
data = debugEmpty(args['data' .. num]),
labelstyle = debugEmpty(args['labelstyle' .. num]),
datastyle = debugEmpty(args['datastyle' .. num]),
class = debugEmpty(args['class' .. num]),
rowclass = debugEmpty(args['rowclass' .. num])
})
end
end
function hasDataRow(row)
-- Function that returns true if the row or group of rows (in the case of
-- sections) has data.
if row.kind == 'section' then
for k, rowSection in ipairs(row) do
if hasDataRow(rowSection) then
return true
end
end
elseif row.kind == 'succession' then
if debugEmpty(row[1]) or debugEmpty(row['previous']) or
debugEmpty(row[3]) or debugEmpty(row['next']) then
return true
end
else
if debugEmpty(row[2]) or debugEmpty(row['data']) then
return true
end
end
return false
end
function addSuccession(successionArguments)
local row = root.tag('tr')
row.css('font-size', '88%')
row.css('text-align', 'center')
local cell
local width
width = '33%'
cell = row.tag('td')
cell
.css('width', width)
.css('padding', '0.2em 0.1em 0.2em 0')
.css('vertical-align', 'middle')
if successionArguments['font style'] then
cell
.tag('div')
.css('display','inline')
.css('font-style', successionArguments['font style'])
.wikitext(successionArguments.previous)
.done()
else
cell.wikitext(successionArguments.previous)
end
if successionArguments['last year'] then
cell
.tag('br')
.wikitext('(' .. successionArguments['last year'] .. ')')
end
cell = row.tag('td')
cell
.css('width', width)
.css('padding', '0.2em 0.1em')
.css('vertical-align', 'middle')
.css('background-color', successionArguments.color or '#E6E8FA')
cell
.tag('div')
.css('display','inline')
.css('font-weight', 'bold')
.css('font-style', successionArguments['font style'] or '')
.wikitext(successionArguments.current or args.title)
.done()
if successionArguments['year'] then
cell
.tag('br')
.wikitext('(' .. successionArguments['year'] .. ')')
end
cell = row.tag('td')
cell
.css('width', width)
.css('padding', '0.2em 0 0.2em 0.1em')
.css('vertical-align', 'middle')
if successionArguments['font style'] then
cell
.tag('div')
.css('display','inline')
.css('font-style', successionArguments['estilo fuente'])
.wikitext(successionArguments.following)
.done()
else
cell.wikitext(successionArguments.following)
end
if successionArguments['next year'] then
cell
.tag('br')
.wikitext('(' .. successionArguments['next year'] .. ')')
end
end
function renderTableRows(Table)
-- Function that makes up the rows of a table, either the file or a section of it.
local addedSectionTitle = false
for k, row in ipairs(Table) do
if hasDataRow(row) then
if row.kind == 'section' then
-- Add the title of the section (if you are informed)
local sectiontitle = debugEmpty(row.title) or debugEmpty(row['title'])
if sectiontitle then
addrow({
sectionstyle = row['titlestyle'],
section = sectiontitle
})
end
renderTableRows(Table)
elseif row.kind == 'dropdown section' then -- MISSING
elseif row.kind == 'succession' then
addSuccession({
['previous'] = debugEmpty(row[1]) or debugEmpty(row['previous']),
['current'] = debugEmpty(row['current']),
['following'] = debugEmpty(row[3]) or debugEmpty(row['following']),
['last year'] = debugEmpty(row['last year']),
['year'] = debugEmpty(row['year']),
['next year'] = debugEmpty(row['next year']),
['font style'] = debugEmpty(row['font style']),
['color'] = debugEmpty(row['color'])
})
elseif row.kind == 'two columns' then -- MISSING
elseif row.kind == 'three columns' then -- MISSING
else -- Label + Data or just Data
addrow({
label = debugEmpty(row[1]) or debugEmpty(row['label']),
data = debugEmpty(row[2]) or debugEmpty(row['data']),
labelstyle = row['labelstyle'] or Table['labelstyle'],
datastyle = row['datastyle'] or Table['datastyle'],
class = row['class'] or Table['class'],
rowclass = row['rowclass'] or Table['rowclass']
})
end
end
end
end
function _infobox()
if args.child ~= 'yes' and args.integrated ~= 'yes' then
root = HtmlBuilder.create('table')
root
.addClass('infobox')
.addClass(args.class)
.cssText('width:22.7em; line-height: 1.4em; text-align:left; padding:.23em')
.cssText(args.style)
if args.style and (mw.title.getCurrentTitle().namespace == 10) then
end
renderTitle()
renderAboveRow()
else
root = HtmlBuilder.create()
if args.title then
root.wikitext("'''" .. args.title .. "'''")
end
end
renderSubtitles()
renderAboveImage()
renderSideimages()
renderaboverows()
renderImages()
if not args[1] then
renderRows()
else
renderTableRows(args)
end
renderBottomImage()
renderTableFooter()
return tostring(root)
end
local function touchParameters(prefixTable, origArgs, step)
-- 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 type(prefixTable) ~= 'table' or type(origArgs) ~= 'table' then
error("Invalid input detected for the touchParameters function. Both parameters must be tables.", 2)
end
if step and type(step) ~= 'number' then
error("Invalid step value detected", 2)
end
step = step or 20
local temp
local a = 1
local moreArgumentsExist = true
for j,v in ipairs(prefixTable) do
if not type(v) == "string" then
error("Non-string value detected in table prefix by touchParameters function.", 2)
end
temp = origArgs[v]
end
while moreArgumentsExist == true do
moreArgumentsExist = false
for i = a, a + step - 1 do
for j,v in ipairs(prefixTable) do
temp = origArgs[v .. tostring(i)]
if temp then
moreArgumentsExist = true
end
end
end
a = a + step
end
end
function p.infobox(frame)
local origArgs
frame = 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.
local temp
temp = origArgs.title
temp = origArgs.above
touchParameters({'subtitle'}, origArgs, 5)
touchParameters({'image', 'footer'}, origArgs, 5)
touchParameters({'section', 'label', 'data'}, origArgs, 20)
temp = origArgs.tablefooter
-- The function parser considers an empty string to be false, so to preserve the previous
-- behavior of {{Infobox}}, you must change the empty arguments to zero, so Lua will consider them
-- which are false too (except for 'title italic' parameters, which specifies different behavior
-- depending on whether it is absent or empty)
args = {}
for k, v in pairs(origArgs) do
if v ~= '' then
args[k] = v
end
end
return _infobox()
end
return p