ሞድዩል:Infobox
Documentation for this module may be created at ሞድዩል:Infobox/doc
--
-- This module implements {{Infobox}}
--
local p = {}
local HtmlBuilder = require('Module:HtmlBuilder')
local BadgesCategorization = require('Module:Badges categorization')
local frame = {}
local args
local root
local widthImage = '320px'
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 or args.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('image ' .. (args.bottomimageclass or '') )
.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('image ' .. (args.aboveimageclass or '') )
.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
imageS = {}
if args.rightimage ~= '' and args.rightimage ~= nil then
imageS = 'rightimage'
elseif args.leftimage ~= '' and args.leftimage ~= nil then
imageS = 'leftimage'
end
footerS = {}
if args.rightimage then
footerS = 'rightfooter'
elseif args.leftimage then
footerS = 'leftfooter'
end
root
.tag('tr')
.tag('td')
.attr('colspan', '3')
.addClass(args['class' .. imageS])
.css('text-align', 'center')
.cssText(args['style' .. imageS])
.newline()
.wikitext('[[ፋይል:' .. args[imageS] .. '|'.. args['size'..imageS] .. ']]' )
.tag('br')
.tag('div')
.css('display','inline')
.cssText(args['style' .. footerS])
.wikitext(args[footerS])
.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.imageclass,
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['last']) 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.last)
.done()
else
cell.wikitext(successionArguments.last)
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['font style'])
.wikitext(successionArguments.Next)
.done()
else
cell.wikitext(successionArguments.Next)
end
if successionArguments['next year'] then
cell
.tag('br')
.wikitext('(' .. successionArguments['next year'] .. ')')
end
end
function renderTableRows(board)
-- 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(board)
elseif row.kind == 'dropdown section' then -- MISSING
elseif row.kind == 'succession' then
addSuccession({
['last'] = debugEmpty(row[1]) or debugEmpty(row['last']),
['current'] = debugEmpty(row['current']),
['Next'] = debugEmpty(row[3]) or debugEmpty(row['Next']),
['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 board['labelstyle'],
datastyle = row['datastyle'] or board['datastyle'],
class = row['class'] or board['class'],
rowclass = row['rowclass'] or board['rowclass']
})
end
end
end
end
local function renderNavigationBar()-- Create a link to the template that is given with a name at the bottom
if not args.name then return end
root
.tag('tr')
.tag('td')
.attr('colspan', '3')
.css('text-align', 'right')
.wikitext(mw.getCurrentFrame():expandTemplate({
title = 'navbar',
args = { args.name, mini = 1 }
}))
end
local function renderBarWikidata()-- Create a link to the Wikidata item at the bottom
local pageLink = mw.title.getCurrentTitle().prefixedText
local pageLabel = mw.ustring.gsub(pageLink,'%s%(.*%)','')
local entity = args.entity or mw.wikibase.getEntityIdForCurrentPage()
local footerText = ""
if (args.child == 'yes' or args.integrated == 'yes' or args.wikidata == 'no') or (mw.title.getCurrentTitle().namespace ~= 0 and mw.title.getCurrentTitle().namespace ~= 104 and not args.entity) then
footerText = ''
elseif entity ~= "" and entity ~= nil then
footerText = '<div class="plainlinks wikidata-link" style="font-size: 0.85em">[[[d:' .. tostring(entity) .. '|ኣብ ዊኪዳታ ሓበሬታ ኣርትዕ]]]</div>'
if (entity ~= mw.wikibase.getEntityIdForCurrentPage()) and (mw.title.getCurrentTitle().namespace == 0 or mw.title.getCurrentTitle().namespace == 104) then
footerText = footerText .. '[[መደብ:ዊኪፐድያ:Articles with infoboxes that use arbitrary access]]'
end
else
footerText = "<small>'''Page not linked to [[Wikidata]]'''\n"..
"* If it does not exist in other Wikipedias: [<span class=plainlinks>[//www.wikidata.org/w/index.php?title=Special:NewItem&site=eswiki&page="..mw.uri.encode(pageLink,WIKI) .."&label="..mw.uri.encode(pageLabel,WIKI) .." create new item]]</span>\n"..
"* If it exists in other Wikipedias: [<span class=plainlinks>[[:d:Special:ItemByTitle|search ítem to link]]</span>]\n"..
"and add the link in Tigrinya: ".. pageLink ..".</small>"
end
if footerText ~= '' then
root
.tag('tr')
.tag('td')
.addClass('noprint')
.attr('colspan', '3')
.css('text-align', 'left')
.wikitext(footerText)
end
end
local function renderTrackingCategories()
if args.decat ~= 'yes' and #(getArgNums('data')) == 0 and not args[1] and mw.title.getCurrentTitle().namespace == 0 then
root.wikitext('[[መደብ:ዊኪፐድያ:Articles using infobox without data in rows]]')
end
if BadgesCategorization.hasAnyBadge() == '1' then
root.wikitext(BadgesCategorization.badgesCategories())
end
end
function _infobox()
if args.child ~= 'yes' and args.integrated ~= 'yes' then
root = HtmlBuilder.create('table')
root -- Style of the entire infobox
.addClass('infobox')
.addClass(args.class)
.cssText('width:22.7em; line-height: 1.4em; text-align:left; padding:.23em') -- Same as template:Infobox
.cssText(args.style)
if args.style and (mw.title.getCurrentTitle().namespace == 10) then -- So that it only adds it in the template namespace
root.wikitext('[[መደብ:ዊኪፐድያ:Infoboxes with the style parameter]]')
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()
renderNavigationBar()
renderBarWikidata()
renderTrackingCategories()
return mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Template:Infobox/imagelimit.css' } } .. 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