Fortnite Esports Wiki
Register
No edit summary
Ispoonz (talk | contribs)
No edit summary
 
(4 intermediate revisions by 2 users not shown)
Line 1: Line 1:
  +
-- <nowiki>
 
local util_args = require('Module:ArgsUtil')
 
local util_args = require('Module:ArgsUtil')
local util_html = require('Module:HTMLUtil')
 
local util_text = require('Module:TextUtil')
 
 
local util_cargo = require('Module:CargoUtil')
 
local util_cargo = require('Module:CargoUtil')
  +
local util_html = require('Module:HtmlUtil')
  +
local util_map = require("Module:MapUtil")
 
local util_table = require('Module:TableUtil')
 
local util_table = require('Module:TableUtil')
  +
local util_text = require('Module:TextUtil')
  +
local util_vars = require("Module:VarsUtil")
  +
local i18n = require('Module:I18nUtil')
 
local lang = mw.getLanguage('en')
 
local lang = mw.getLanguage('en')
  +
local social = require('Module:Infobox/Social')
  +
local LCS = require('Module:LuaClassSystem').class
 
local CLASSES = {
 
local CLASSES = {
 
title = 'infobox-title',
 
title = 'infobox-title',
 
notice = 'infobox-notice'
 
notice = 'infobox-notice'
 
}
 
}
  +
local sep = '%s*,%s*'
 
  +
local DEFAULT_IMAGE_SIZE = '220px'
   
 
local h = {}
 
local h = {}
  +
local p = LCS.abstract()
   
  +
p.LAYOUT = {
function h.layoutFromArgs(args)
 
local layout = {
+
sections = { },
  +
contents = {
tabs = args.tabs,
 
  +
{ },
sections = util_text.split(args.sections,sep),
 
  +
},
contents = {},
 
i18n = {},
+
i18n = {}
  +
}
classes = {},
 
  +
  +
p.NOIMAGE = 'Unknown Infobox Image - Player.png'
  +
  +
function p:init(args)
  +
i18n.init('Infobox/' .. self.type)
  +
self:validateArgs(args)
  +
self:castArgs(args)
  +
local processed = self:getProcessed(args)
  +
  +
self.display = self:getDisplay(args, processed)
  +
self.serializedSections = {}
  +
self.cargo = self:getCargo(args, processed)
  +
self.settings = self:getSettings(args, processed)
  +
self.categories = self:getCategories(args, processed)
  +
self.variables = self:getVariables(args, processed)
  +
self.layout = self.LAYOUT -- hmm.....
  +
end
  +
  +
function p:validateArgs(args) end
  +
  +
function p:castArgs(args) end
  +
  +
function p:getProcessed(args)
  +
local tbl = {
  +
pagename = mw.title.getCurrentTitle().text,
  +
lc = args.name and lang:lcfirst(args.name) == args.name,
  +
isLowContent = util_args.castAsBool(args.low_content),
 
}
 
}
  +
return tbl
for k, v in ipairs(layout.sections) do
 
layout.contents[k] = util_text.split(args[v],sep)
 
local section = layout.contents[k]
 
 
layout.classes[v] = args[v .. '_class']
 
local names = args[v .. '_names'] and util_text.split(args[v .. '_names'],sep)
 
for i, field in ipairs(section) do
 
layout.i18n[field] = args[field .. '_name'] or names and names[i]
 
layout.classes[field] = args[field .. '_class']
 
if args[field .. '_style'] then
 
section[field] = args[field .. '_style']
 
end
 
end
 
end
 
return layout
 
 
end
 
end
   
  +
function p:getSettings(args, processed)
-- build infobox
 
  +
local ret = {
  +
lc = processed.lc,
  +
nocargo = mw.title.getCurrentTitle().nsText ~= '' or args.nocargo,
  +
nocat = mw.title.getCurrentTitle().nsText ~= '' or args['no-cat'],
  +
}
  +
return ret
  +
end
   
function h.addHeading(tbl, content, class)
+
function p:getDisplay(args, processed)
  +
local social = social.makeSocialSection(args)
tbl:tag('tr')
 
  +
local argsCopy = mw.clone(args)
:tag('th')
 
  +
local tbl = {
:attr('colspan','2')
 
  +
title = args.name or processed.pagename,
:addClass(class and (CLASSES[class] or class) or '')
 
  +
social = next(social) and tostring(util_html.blockBox(social)),
:wikitext(content)
 
  +
imagesize = DEFAULT_IMAGE_SIZE,
:done()
 
  +
}
:done()
 
  +
return util_table.merge(argsCopy, tbl)
return
 
 
end
 
end
   
function h.addNormalRow(tbl, label, content, class)
+
function p:getCargo(args, processed)
  +
local name = args._title or processed.title or mw.title.getCurrentTitle().text
tbl:tag('tr')
 
  +
local page = mw.title.getCurrentTitle().text
:addClass(class or '')
 
  +
local isLowercase = lang:lcfirst(name) == name
:tag('td')
 
  +
local entity = isLowercase and page or util_text.lcfirst(page)
:addClass('infobox-label')
 
  +
local tbl = {
:wikitext(label)
 
:done()
+
{
  +
_table = 'Entities',
:tag('td')
 
  +
Entity = entity,
:wikitext(content)
 
  +
EntityName = name,
:done()
 
  +
EntityPage = page,
:done()
 
  +
EntityType = self.type,
return
 
  +
IsLowercase = isLowercase,
  +
DisambigSentence = self:getDisambigSentence(args, processed),
  +
}
  +
}
  +
return tbl
 
end
 
end
  +
 
function h.addWideRow(tbl, content, class)
+
function p:getDisambigSentence(args, processed)
  +
return ('%s (%s)'):format(
tbl:tag('tr')
 
  +
util_text.intLinkOrText(mw.title.getCurrentTitle().text, args._title or processed.title),
:addClass(class or '')
 
  +
self.type
:tag('td')
 
  +
)
:attr('colspan','2')
 
:addClass('infobox-wide')
 
:wikitext(content)
 
:done()
 
:done()
 
return
 
 
end
 
end
   
function h.printFinalInfobox(infoboxType, layout, display)
+
function p:getCategories(args, processed)
  +
local tbl = {
local classes = util_table.merge(layout.classes, display.classes)
 
  +
processed.isLowContent and 'LowContent',
local names = util_table.merge(layout.i18n, display.names)
 
  +
}
local tbl = mw.html.create('table')
 
  +
return tbl
:addClass('infobox')
 
  +
end
:addClass(display.class)
 
  +
if infoboxType then
 
  +
function p:getVariables(args, processed)
tbl:addClass('Infobox' .. infoboxType)
 
  +
local tbl = {
:attr('id','infobox' .. infoboxType)
 
  +
isLowContent = args.low_content,
  +
hasInfobox = 'Yes',
  +
}
  +
return tbl
  +
end
  +
  +
-- @staticmethod
  +
function p.mergeDisplay(display, tbl)
  +
tbl.names = util_table.merge(display.names, tbl.names)
  +
tbl.footnotes = util_table.merge(display.footnotes, tbl.footnotes)
  +
util_table.merge(display, tbl)
  +
return display
  +
end
  +
  +
function p:run()
  +
self:setLowercase()
  +
self:setVariables()
  +
self:storeCargo()
  +
self:mergeDynamicDisplayValuesIntoStatic()
  +
self.serializedSections = self:prepDisplayDataForPrinting()
  +
local output = {
  +
h.makeTabs(self.layout.tabs),
  +
tostring(self:makeInfobox()),
  +
h.getCategories(self.categories, self.settings.nocat)
  +
}
  +
return table.concat(output,'')
  +
end
  +
  +
function p:setLowercase()
  +
if not self.settings.lc then return end
  +
local title = mw.title.getCurrentTitle().text
  +
mw.getCurrentFrame():callParserFunction{
  +
name = 'DISPLAYTITLE',
  +
args = h.getDisplayTitleArgs(title),
  +
}
  +
end
  +
  +
function p:setVariables()
  +
if not self.variables then return end
  +
util_table.removeFalseEntries(self.variables)
  +
for k, v in pairs(self.variables) do
  +
util_vars.setVar(k, tostring(v))
 
end
 
end
  +
end
if display.notice then
 
  +
h.addHeading(tbl, display.notice,'notice')
 
  +
function p:storeCargo(nocargo, data)
  +
if self.settings.nocargo or not self.cargo then return end
  +
util_map.rowsInPlace(self.cargo, util_cargo.store)
  +
end
  +
  +
-- build infobox
  +
  +
function p:mergeDynamicDisplayValuesIntoStatic()
  +
if not self.layout.classes then self.layout.classes = {} end
  +
if not self.layout.i18n then self.layout.i18n = {} end
  +
util_table.merge(self.layout.classes, self.display.classes)
  +
util_table.merge(self.layout.i18n, self.display.names)
  +
self.display.names = self.layout.i18n
  +
end
  +
  +
function p:prepDisplayDataForPrinting()
  +
local serializedSections = {}
  +
for _, key in ipairs(self:getListOfNonemptySectionIndices()) do
  +
serializedSections[#serializedSections+1] = {
  +
name = self.layout.sections[key],
  +
lines = self:getSectionContentsAndValues(self.layout.contents[key]),
  +
class = self.layout.classes[key]
  +
}
 
end
 
end
  +
return serializedSections
h.addHeading(tbl,layout.lc and lang:lcfirst(display.title) or display.title, 'title')
 
  +
end
if display.image then
 
  +
h.addWideRow(tbl, string.format('[[File:%s|center|%s]]', display.image, display.imagesize or '220px'))
 
  +
function p:getListOfNonemptySectionIndices()
if display.imagecaption then
 
  +
local ret = {}
h.addWideRow(tbl, display.imagecaption, 'infobox-image-caption')
 
  +
for k, _ in ipairs(self.layout.sections) do
  +
if self:doesSectionExist(self.layout.contents[k]) then
  +
ret[#ret+1] = k
 
end
 
end
 
end
 
end
  +
return ret
for k, v in ipairs(layout.sections) do
 
  +
end
heading_already = false
 
  +
for _, v2 in ipairs(layout.contents[k]) do
 
  +
function p:doesSectionExist(contents)
if display[v2] then
 
  +
for k, v in ipairs(contents) do
if not heading_already then
 
  +
if self.display[v] then
h.addHeading(tbl, v, classes[v2])
 
heading_already = true
+
return true
end
 
if layout.contents[k][v2] == 'wide' then
 
h.addWideRow(tbl, display[v2], classes[v2])
 
else
 
h.addNormalRow(tbl, names[v2] or v2, display[v2], classes[v2])
 
end
 
end
 
 
end
 
end
 
end
 
end
return tbl
+
return false
 
end
 
end
   
  +
function p:getSectionContentsAndValues(contents)
function h.storeCargo(frame, nocargo, data)
 
  +
local ret = {}
if nocargo then return end
 
for _, tbl in ipairs(data) do
+
for _, paramName in ipairs(contents) do
  +
ret[#ret+1] = self:getOneSectionContentsAndValues(contents, paramName)
util_cargo.store(tbl, frame)
 
 
end
 
end
return
+
return ret
 
end
 
end
   
function h.setLC(frame, lc)
+
function p:getOneSectionContentsAndValues(contents, paramName)
if not lc then
+
if not self.display[paramName] then return nil end
return
+
return {
  +
name = self.display.names[paramName] or i18n.print(paramName) or paramName,
end
 
  +
value = self.display[paramName],
local title = mw.title.getCurrentTitle().text
 
  +
class = self.layout.classes[paramName],
frame:callParserFunction{ name = 'DISPLAYTITLE', args = lang:lcfirst(title) }
 
  +
celltype = contents[paramName]
return
 
  +
}
 
end
 
end
   
  +
-- print stuff
function h.setVariables(frame, data)
 
  +
function h.makeTabs(tabsTemplateTitle)
util_table.removeFalseEntries(data)
 
  +
if not tabsTemplateTitle then return '' end
for k, v in pairs(data) do
 
  +
return mw.getCurrentFrame():expandTemplate{title = tabsTemplateTitle }
-- table may have entries that are false
 
  +
end
if v then
 
  +
frame:callParserFunction{
 
  +
function p:makeInfobox()
name = '#vardefine:' .. k,
 
  +
local tbl = self:initializeTable()
args = { v }
 
  +
h.printHeadingI18n(tbl, self.display.notice, 'notice')
}
 
  +
h.printHeading(tbl, self.display.title, 'title')
  +
h.printImage(tbl, self.display)
  +
for k, section in ipairs(self.serializedSections) do
  +
h.printHeadingI18n(tbl, section.name, section.class)
  +
for _, line in ipairs(section.lines) do
  +
h.printRow(tbl, line)
 
end
 
end
 
end
 
end
return
+
return tbl
 
end
 
end
   
function h.setCategories(data, nocat)
+
function p:initializeTable()
  +
local tbl = mw.html.create('table')
if nocat then
 
  +
:addClass('infobox')
return ''
 
  +
:addClass(self.display.class)
end
 
  +
:addClass('Infobox' .. self.type)
util_table.removeFalseEntries(data)
 
  +
:attr('id', 'infobox' .. self.type)
local tbl = {}
 
  +
return tbl
for _, v in ipairs(data) do
 
  +
end
tbl[#tbl+1] = ("[[Category:%s]]"):format(v)
 
  +
end
 
  +
function h.printHeading(tbl, content, class)
return table.concat(tbl, '')
 
  +
if not content then return end
  +
tbl:tag('tr')
  +
:tag('th')
  +
:attr('colspan','2')
  +
:addClass(class and CLASSES[class] or class)
  +
:wikitext(content)
  +
end
  +
  +
function h.printHeadingI18n(tbl, content, class)
  +
h.printHeading(tbl, i18n.print(content) or content, class)
  +
end
  +
  +
function h.printImage(tbl, data)
  +
if not data.image then return end
  +
local imageText = ('[[File:%s|center|%s]]'):format(data.image, data.imagesize)
  +
h.printWideRow(tbl:tag('tr'), imageText, 'infobox-image')
  +
h.printWideRow(tbl:tag('tr'), data.imagecaption, 'infobox-image-caption')
 
end
 
end
   
  +
function h.printRow(tbl, line)
local p = {}
 
  +
local tr = tbl:tag('tr')
function p.fromPreload(frame)
 
  +
:addClass(line.class)
local args = frame
 
if frame == mw.getCurrentFrame() then
+
if line.celltype == 'wide' then
  +
h.printWideCell(tr, line.value)
args = util_args.merge(true)
 
 
else
 
else
  +
h.printNormalCell(tr, line.name, line.value)
frame = mw.getCurrentFrame()
 
 
end
 
end
local infoboxType = args.infoboxType
 
local preload = require('Module:Infobox/' .. infoboxType)
 
local data = preload.main(args)
 
return p.main(frame, data, infoboxType)
 
 
end
 
end
   
function p.fromArgs(frame)
+
function h.printWideRow(tbl, content)
local args = frame
+
local tr = tbl:tag('tr')
  +
h.printWideCell(tr, content)
if frame == mw.getCurrentFrame() then
 
  +
end
args = util_args.overwrite(true)
 
  +
else
 
  +
function h.printWideCell(tr, content)
frame = mw.getCurrentFrame()
 
  +
if not content then return end
  +
tr:tag('td')
  +
:attr('colspan','2')
  +
:addClass('infobox-wide')
  +
:wikitext(content)
  +
return
  +
end
  +
  +
function h.printNormalCell(tr, label, content)
  +
if not content then return end
  +
tr:tag('td')
  +
:addClass('infobox-label')
  +
:wikitext(label)
  +
:done()
  +
:tag('td')
  +
:wikitext(content)
  +
:done()
  +
return
  +
end
  +
  +
function h.getKeyForHeading(contents, display)
  +
for k, v in ipairs(contents) do
  +
if display[v] then
  +
return k
  +
end
 
end
 
end
local data = {
 
layout = h.layoutFromArgs(args),
 
display = args,
 
cargo = {},
 
categories = {},
 
settings = {},
 
variables = {},
 
}
 
return p.main(frame, data)
 
 
end
 
end
   
function p.main(frame, data, infoboxType)
+
function h.getDisplayTitleArgs(title)
  +
if mw.title.getCurrentTitle().nsText ~= '' then
h.setLC(frame, data.settings.lc)
 
  +
return ('%s:%s'):format(
h.setVariables(frame, data.variables or {})
 
  +
mw.title.getCurrentTitle().nsText,
h.storeCargo(frame, data.settings.nocargo, data.cargo or {})
 
  +
lang:lcfirst(title)
local output = {
 
  +
)
data.layout.tabs and frame:expandTemplate{title = data.layout.tabs} or '',
 
  +
end
tostring(h.printFinalInfobox(infoboxType, data.layout, data.display)),
 
  +
return lang:lcfirst(title)
h.setCategories(data.categories or {}, data.settings.nocat)
 
}
 
return table.concat(output,'')
 
 
end
 
end
  +
  +
function h.getCategories(categories, nocat)
  +
if nocat then return '' end
  +
if not categories then return '' end
  +
local tbl = {}
  +
for _, v in pairs(categories) do
  +
if v then
  +
tbl[#tbl+1] = ("[[Category:%s]]"):format(v)
  +
end
  +
end
  +
return table.concat(tbl, '')
  +
end
  +
 
return p
 
return p
  +
-- </nowiki>

Latest revision as of 17:12, 27 December 2020

Edit the documentation or categories for this module.

To make a new infobox module, subclass this.


-- <nowiki>
local util_args = require('Module:ArgsUtil')
local util_cargo = require('Module:CargoUtil')
local util_html = require('Module:HtmlUtil')
local util_map = require("Module:MapUtil")
local util_table = require('Module:TableUtil')
local util_text = require('Module:TextUtil')
local util_vars = require("Module:VarsUtil")
local i18n = require('Module:I18nUtil')
local lang = mw.getLanguage('en')
local social = require('Module:Infobox/Social')
local LCS = require('Module:LuaClassSystem').class
local CLASSES = {
	title = 'infobox-title',
	notice = 'infobox-notice'
}

local DEFAULT_IMAGE_SIZE = '220px'

local h = {}
local p = LCS.abstract()

p.LAYOUT = {
	sections = {  },
	contents = {
		{  },
	},
	i18n = {}
}

p.NOIMAGE = 'Unknown Infobox Image - Player.png'

function p:init(args)
	i18n.init('Infobox/' .. self.type)
	self:validateArgs(args)
	self:castArgs(args)
	local processed = self:getProcessed(args)
	
	self.display = self:getDisplay(args, processed)
	self.serializedSections = {}
	self.cargo = self:getCargo(args, processed)
	self.settings = self:getSettings(args, processed)
	self.categories = self:getCategories(args, processed)
	self.variables = self:getVariables(args, processed)
	self.layout = self.LAYOUT -- hmm.....
end

function p:validateArgs(args) end

function p:castArgs(args) end

function p:getProcessed(args)
	local tbl = {
		pagename = mw.title.getCurrentTitle().text,
		lc = args.name and lang:lcfirst(args.name) == args.name,
		isLowContent = util_args.castAsBool(args.low_content),
	}
	return tbl
end

function p:getSettings(args, processed)
	local ret = {
		lc = processed.lc,
		nocargo = mw.title.getCurrentTitle().nsText ~= '' or args.nocargo,
		nocat = mw.title.getCurrentTitle().nsText ~= '' or args['no-cat'],
	}
	return ret
end

function p:getDisplay(args, processed)
	local social = social.makeSocialSection(args)
	local argsCopy = mw.clone(args)
	local tbl = {
		title = args.name or processed.pagename,
		social = next(social) and tostring(util_html.blockBox(social)),
		imagesize = DEFAULT_IMAGE_SIZE,
	}
	return util_table.merge(argsCopy, tbl)
end

function p:getCargo(args, processed)
	local name = args._title or processed.title or mw.title.getCurrentTitle().text
	local page = mw.title.getCurrentTitle().text
	local isLowercase = lang:lcfirst(name) == name
	local entity = isLowercase and page or util_text.lcfirst(page)
	local tbl = {
		{
			_table = 'Entities',
			Entity = entity,
			EntityName = name,
			EntityPage = page,
			EntityType = self.type,
			IsLowercase = isLowercase,
			DisambigSentence = self:getDisambigSentence(args, processed),
		}
	}
	return tbl
end

function p:getDisambigSentence(args, processed)
	return ('%s (%s)'):format(
		util_text.intLinkOrText(mw.title.getCurrentTitle().text, args._title or processed.title),
		self.type
	)
end

function p:getCategories(args, processed)
	local tbl = {
		processed.isLowContent and 'LowContent',
	}
	return tbl
end

function p:getVariables(args, processed)
	local tbl = {
		isLowContent = args.low_content,
		hasInfobox = 'Yes',
	}
	return tbl
end

-- @staticmethod
function p.mergeDisplay(display, tbl)
	tbl.names = util_table.merge(display.names, tbl.names)
	tbl.footnotes = util_table.merge(display.footnotes, tbl.footnotes)
	util_table.merge(display, tbl)
	return display
end

function p:run()
	self:setLowercase()
	self:setVariables()
	self:storeCargo()
	self:mergeDynamicDisplayValuesIntoStatic()
	self.serializedSections = self:prepDisplayDataForPrinting()
	local output = {
		h.makeTabs(self.layout.tabs),
		tostring(self:makeInfobox()),
		h.getCategories(self.categories, self.settings.nocat)
	}
	return table.concat(output,'')
end

function p:setLowercase()
	if not self.settings.lc then return end
	local title = mw.title.getCurrentTitle().text
	mw.getCurrentFrame():callParserFunction{
		name = 'DISPLAYTITLE',
		args = h.getDisplayTitleArgs(title),
	}
end

function p:setVariables()
	if not self.variables then return end
	util_table.removeFalseEntries(self.variables)
	for k, v in pairs(self.variables) do
		util_vars.setVar(k, tostring(v))
	end
end

function p:storeCargo(nocargo, data)
	if self.settings.nocargo or not self.cargo then return end
	util_map.rowsInPlace(self.cargo, util_cargo.store)
end

-- build infobox

function p:mergeDynamicDisplayValuesIntoStatic()
	if not self.layout.classes then self.layout.classes = {} end
	if not self.layout.i18n then self.layout.i18n = {} end
	util_table.merge(self.layout.classes, self.display.classes)
	util_table.merge(self.layout.i18n, self.display.names)
	self.display.names = self.layout.i18n
end

function p:prepDisplayDataForPrinting()
	local serializedSections = {}
	for _, key in ipairs(self:getListOfNonemptySectionIndices()) do
		serializedSections[#serializedSections+1] = {
			name = self.layout.sections[key],
			lines = self:getSectionContentsAndValues(self.layout.contents[key]),
			class = self.layout.classes[key]
		}
	end
	return serializedSections
end

function p:getListOfNonemptySectionIndices()
	local ret = {}
	for k, _ in ipairs(self.layout.sections) do
		if self:doesSectionExist(self.layout.contents[k]) then
			ret[#ret+1] = k
		end
	end
	return ret
end

function p:doesSectionExist(contents)
	for k, v in ipairs(contents) do
		if self.display[v] then
			return true
		end
	end
	return false
end

function p:getSectionContentsAndValues(contents)
	local ret = {}
	for _, paramName in ipairs(contents) do
		ret[#ret+1] = self:getOneSectionContentsAndValues(contents, paramName)
	end
	return ret
end

function p:getOneSectionContentsAndValues(contents, paramName)
	if not self.display[paramName] then return nil end
	return {
		name = self.display.names[paramName] or i18n.print(paramName) or paramName,
		value = self.display[paramName],
		class = self.layout.classes[paramName],
		celltype = contents[paramName]
	}
end

-- print stuff
function h.makeTabs(tabsTemplateTitle)
	if not tabsTemplateTitle then return '' end
	return mw.getCurrentFrame():expandTemplate{title = tabsTemplateTitle }
end

function p:makeInfobox()
	local tbl = self:initializeTable()
	h.printHeadingI18n(tbl, self.display.notice, 'notice')
	h.printHeading(tbl, self.display.title, 'title')
	h.printImage(tbl, self.display)
	for k, section in ipairs(self.serializedSections) do
		h.printHeadingI18n(tbl, section.name, section.class)
		for _, line in ipairs(section.lines) do
			h.printRow(tbl, line)
		end
	end
	return tbl
end

function p:initializeTable()
	local tbl = mw.html.create('table')
		:addClass('infobox')
		:addClass(self.display.class)
		:addClass('Infobox' .. self.type)
		:attr('id', 'infobox' .. self.type)
	return tbl
end

function h.printHeading(tbl, content, class)
	if not content then return end
	tbl:tag('tr')
		:tag('th')
			:attr('colspan','2')
			:addClass(class and CLASSES[class] or class)
			:wikitext(content)
end

function h.printHeadingI18n(tbl, content, class)
	h.printHeading(tbl, i18n.print(content) or content, class)
end

function h.printImage(tbl, data)
	if not data.image then return end
	local imageText = ('[[File:%s|center|%s]]'):format(data.image, data.imagesize)
	h.printWideRow(tbl:tag('tr'), imageText, 'infobox-image')
	h.printWideRow(tbl:tag('tr'), data.imagecaption, 'infobox-image-caption')
end

function h.printRow(tbl, line)
	local tr = tbl:tag('tr')
		:addClass(line.class)
	if line.celltype == 'wide' then
		h.printWideCell(tr, line.value)
	else
		h.printNormalCell(tr, line.name, line.value)
	end
end

function h.printWideRow(tbl, content)
	local tr = tbl:tag('tr')
	h.printWideCell(tr, content)
end

function h.printWideCell(tr, content)
	if not content then return end
	tr:tag('td')
		:attr('colspan','2')
		:addClass('infobox-wide')
		:wikitext(content)
	return
end

function h.printNormalCell(tr, label, content)
	if not content then return end
	tr:tag('td')
		:addClass('infobox-label')
		:wikitext(label)
	:done()
	:tag('td')
		:wikitext(content)
	:done()
	return
end

function h.getKeyForHeading(contents, display)
	for k, v in ipairs(contents) do
		if display[v] then
			return k
		end
	end
end

function h.getDisplayTitleArgs(title)
	if mw.title.getCurrentTitle().nsText ~= '' then
		return ('%s:%s'):format(
			mw.title.getCurrentTitle().nsText,
			lang:lcfirst(title)
		)
	end
	return lang:lcfirst(title)
end

function h.getCategories(categories, nocat)
	if nocat then return '' end
	if not categories then return '' end
	local tbl = {}
	for _, v in pairs(categories) do
		if v then
			tbl[#tbl+1] = ("[[Category:%s]]"):format(v)
		end
	end
	return table.concat(tbl, '')
end

return p
-- </nowiki>