Leaguepedia | League of Legends Esports Wiki
Register
[checked revision][checked revision]
((via Mediawiker ST3))
([ST] categories -> args.isLowContent)
(23 intermediate revisions by the same user not shown)
Line 1: Line 1:
  +
-- <nowiki>
 
local util_args = require('Module:ArgsUtil')
 
local util_args = require('Module:ArgsUtil')
 
local util_cargo = require('Module:CargoUtil')
 
local util_cargo = require('Module:CargoUtil')
 
local util_html = require('Module:HtmlUtil')
 
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_text = require('Module:TextUtil')
  +
local util_vars = require("Module:VarsUtil")
 
local i18n = require('Module:I18nUtil')
 
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 DEFAULT_IMAGE_SIZE = '220px'
   
 
local h = {}
 
local h = {}
local p = {}
+
local p = LCS.abstract()
   
  +
p.LAYOUT = {
function p.fromPreload(frame)
 
  +
sections = { },
local args = util_args.merge(true)
 
  +
contents = {
local infoboxType = args.infoboxType
 
  +
{ },
local preload = require('Module:Infobox/' .. infoboxType)
 
  +
},
local data = preload.main(args)
 
  +
i18n = {}
return p._main(data, infoboxType)
 
  +
}
  +
  +
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
 
end
   
function p.fromArgs(frame)
+
function p:validateArgs(args) end
  +
local args = util_args.merge(true)
 
  +
function p:castArgs(args)
local data = {
 
  +
args.isLowContent = util_args.castAsBool(args.low_content)
layout = h.layoutFromArgs(args),
 
  +
args.pagename = mw.title.getCurrentTitle().text
display = args,
 
  +
args.lc = args.name and lang:lcfirst(args.name) == args.name
cargo = {},
 
  +
end
categories = {},
 
  +
settings = {},
 
  +
function p:getProcessed(args)
variables = {},
 
  +
local tbl = {
  +
pagename = mw.title.getCurrentTitle().text,
  +
lc = args.name and lang:lcfirst(args.name) == args.name,
 
}
 
}
return p._main(data)
+
return tbl
 
end
 
end
   
function p._main(data, infoboxType)
+
function p:getSettings(args, processed)
  +
local ret = {
if data.layout.i18nFile then
 
  +
lc = processed.lc,
i18n.init(data.layout.i18nFile)
 
  +
nocargo = mw.title.getCurrentTitle().nsText ~= '' or args.nocargo,
data.i18n = {}
 
  +
nocat = mw.title.getCurrentTitle().nsText ~= '' or args['no-cat'],
end
 
  +
}
h.setLC(data.settings.lc)
 
  +
return ret
h.setVariables(data.variables)
 
  +
end
h.storeCargo(data.settings.nocargo, data.cargo)
 
  +
h.mergeDynamicDisplayValuesIntoStatic(data, data.display)
 
  +
function p:getDisplay(args, processed)
h.prepDisplayDataForPrinting(data.layout, data.display, infoboxType)
 
  +
local social = social.makeSocialSection(args)
  +
local argsCopy = mw.clone(args)
  +
local tbl = {
  +
title = args.name or args.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,
  +
Display = args._display or name,
  +
IsLowercase = isLowercase,
  +
DisambigSentence = self:getDisambigSentence(args, processed),
  +
AnnounceNew = util_args.castAsBool(args.announce),
  +
DontAnnounceNew = util_args.castAsBool(args.dont_announce) or args.isLowContent,
  +
}
  +
}
  +
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 = {
  +
args.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 = {
 
local output = {
h.getTabs(data.layout.tabs),
+
h.makeTabs(self.layout.tabs),
  +
tostring(self:makeInfobox()),
h.makeAmbox(data.ambox),
 
  +
h.getCategories(self.categories, self.settings.nocat)
tostring(h.printFinalInfobox(data.display)),
 
h.setCategories(data.categories or {}, data.settings.nocat)
 
 
}
 
}
 
return table.concat(output,'')
 
return table.concat(output,'')
 
end
 
end
   
function h.layoutFromArgs(args)
+
function p:setLowercase()
  +
if not self.settings.lc then return end
local layout = {
 
  +
local title = mw.title.getCurrentTitle().text
tabs = args.tabs,
 
  +
mw.getCurrentFrame():callParserFunction{
sections = util_text.split(args.sections),
 
contents = {},
+
name = 'DISPLAYTITLE',
  +
args = h.getDisplayTitleArgs(title),
i18n = {},
 
classes = {},
 
 
}
 
}
  +
end
for k, v in ipairs(layout.sections) do
 
  +
layout.contents[k] = util_text.split(args[v] or '')
 
  +
function p:setVariables()
local section = layout.contents[k]
 
  +
if not self.variables then return end
 
  +
util_table.removeFalseEntries(self.variables)
layout.classes[v] = args[v .. '_class']
 
  +
for k, v in pairs(self.variables) do
local names = args[v .. '_names'] and util_text.split(args[v .. '_names'])
 
  +
util_vars.setVar(k, tostring(v))
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
 
end
  +
end
return layout
 
  +
  +
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
 
end
   
 
-- build infobox
 
-- build infobox
   
function h.mergeDynamicDisplayValuesIntoStatic(data, display)
+
function p:mergeDynamicDisplayValuesIntoStatic()
if not data.layout.classes then data.layout.classes = {} end
+
if not self.layout.classes then self.layout.classes = {} end
if not data.layout.i18n then data.layout.i18n = {} end
+
if not self.layout.i18n then self.layout.i18n = {} end
util_table.merge(data.layout.classes, display.classes)
+
util_table.merge(self.layout.classes, self.display.classes)
util_table.merge(data.layout.i18n, display.names)
+
util_table.merge(self.layout.i18n, self.display.names)
display.names = data.layout.i18n
+
self.display.names = self.layout.i18n
 
end
 
end
   
function h.prepDisplayDataForPrinting(layout, display, infoboxType)
+
function p:prepDisplayDataForPrinting()
  +
local serializedSections = {}
display.infoboxType = infoboxType
 
  +
for _, key in ipairs(self:getListOfNonemptySectionIndices()) do
display.lc = layout.lc
 
  +
serializedSections[#serializedSections+1] = {
for _, key in ipairs(h.getListOfNonemptySectionIndices(layout, display)) do
 
  +
name = self.layout.sections[key],
display[#display+1] = {
 
name = layout.sections[key],
+
lines = self:getSectionContentsAndValues(self.layout.contents[key]),
lines = h.getSectionContentsAndValues(layout.contents[key], display, layout.classes),
+
class = self.layout.classes[key]
class = layout.classes[key]
 
 
}
 
}
 
end
 
end
  +
return serializedSections
 
end
 
end
   
function h.getListOfNonemptySectionIndices(layout, display)
+
function p:getListOfNonemptySectionIndices()
 
local ret = {}
 
local ret = {}
for k, _ in ipairs(layout.sections) do
+
for k, _ in ipairs(self.layout.sections) do
if h.sectionIsNonempty(layout.contents[k], display) then
+
if self:doesSectionExist(self.layout.contents[k]) then
 
ret[#ret+1] = k
 
ret[#ret+1] = k
 
end
 
end
Line 111: Line 202:
 
end
 
end
   
function h.sectionIsNonempty(contents, display)
+
function p:doesSectionExist(contents)
 
for k, v in ipairs(contents) do
 
for k, v in ipairs(contents) do
if display[v] then
+
if self.display[v] then
 
return true
 
return true
 
end
 
end
Line 120: Line 211:
 
end
 
end
   
function h.getSectionContentsAndValues(contents, display, classes)
+
function p:getSectionContentsAndValues(contents)
 
local ret = {}
 
local ret = {}
 
for _, paramName in ipairs(contents) do
 
for _, paramName in ipairs(contents) do
ret[#ret+1] = h.getOneSectionContentsAndValues(contents, display, classes, paramName)
+
ret[#ret+1] = self:getOneSectionContentsAndValues(contents, paramName)
 
end
 
end
 
return ret
 
return ret
 
end
 
end
   
function h.getOneSectionContentsAndValues(contents, display, classes, paramName)
+
function p:getOneSectionContentsAndValues(contents, paramName)
if not display[paramName] then return nil end
+
if not self.display[paramName] then return nil end
 
return {
 
return {
name = display.names[paramName] or i18n.print(paramName) or paramName,
+
name = self.display.names[paramName] or i18n.print(paramName) or paramName,
value = display[paramName],
+
value = self.display[paramName],
class = classes[paramName],
+
class = self.layout.classes[paramName],
 
celltype = contents[paramName]
 
celltype = contents[paramName]
 
}
 
}
 
end
 
end
   
  +
-- print stuff
function h.printFinalInfobox(displayData)
 
  +
function h.makeTabs(tabsTemplateTitle)
local tbl = h.initializeTable(displayData)
 
  +
if not tabsTemplateTitle then return '' end
h.printHeading(tbl, displayData.notice, 'notice')
 
  +
return mw.getCurrentFrame():expandTemplate{title = tabsTemplateTitle }
h.printHeading(tbl, h.getTitleWithCasing(displayData), 'title')
 
  +
end
h.printImage(tbl, displayData)
 
  +
for k, section in ipairs(displayData) do
 
  +
function p:makeInfobox()
h.printHeading(tbl, section.name, section.class)
 
  +
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
 
for _, line in ipairs(section.lines) do
 
h.printRow(tbl, line)
 
h.printRow(tbl, line)
Line 152: Line 249:
 
end
 
end
   
function h.initializeTable(displayData)
+
function p:initializeTable()
 
local tbl = mw.html.create('table')
 
local tbl = mw.html.create('table')
 
:addClass('infobox')
 
:addClass('infobox')
:addClass(displayData.class)
+
:addClass(self.display.class)
  +
:addClass('Infobox' .. self.type)
h.addInfoboxTypeClass(tbl, displayData.infoboxType)
 
  +
:attr('id', 'infobox' .. self.type)
 
return tbl
 
return tbl
end
 
 
function h.addInfoboxTypeClass(tbl, infoboxType)
 
if not infoboxType then return end
 
tbl:addClass('Infobox' .. infoboxType)
 
:attr('id', 'infobox' .. infoboxType)
 
end
 
 
function h.getTitleWithCasing(displayData)
 
if displayData.lc then
 
return displayData.title:lower()
 
end
 
return displayData.title
 
 
end
 
end
   
Line 178: Line 263:
 
:tag('th')
 
:tag('th')
 
:attr('colspan','2')
 
:attr('colspan','2')
:addClass(class and (CLASSES[class] or class) or '')
+
:addClass(class and CLASSES[class] or class)
:wikitext(i18n.print(content) or content)
+
:wikitext(content)
  +
end
:done()
 
  +
:done()
 
  +
function h.printHeadingI18n(tbl, content, class)
return
 
  +
h.printHeading(tbl, i18n.print(content) or content, class)
 
end
 
end
   
 
function h.printImage(tbl, data)
 
function h.printImage(tbl, data)
 
if not data.image then return end
 
if not data.image then return end
local imageText = ('[[File:%s|center|%s]]'):format(data.image, data.imagesize or '220px')
+
local imageText = ('[[File:%s|center|%s]]'):format(data.image, data.imagesize)
h.printWideRow(tbl, imageText, 'infobox-image')
+
h.printWideRow(tbl:tag('tr'), imageText, 'infobox-image')
h.printWideRow(tbl, data.imagecaption, 'infobox-image-caption')
+
h.printWideRow(tbl:tag('tr'), data.imagecaption, 'infobox-image-caption')
 
end
 
end
   
Line 196: Line 282:
 
:addClass(line.class)
 
:addClass(line.class)
 
if line.celltype == 'wide' then
 
if line.celltype == 'wide' then
h.printWideRow(tr, line.value)
+
h.printWideCell(tr, line.value)
 
else
 
else
h.printNormalRow(tr, line.name, line.value)
+
h.printNormalCell(tr, line.name, line.value)
 
end
 
end
 
end
 
end
   
 
function h.printWideRow(tbl, content)
 
function h.printWideRow(tbl, content)
if not content then return end
 
 
local tr = tbl:tag('tr')
 
local tr = tbl:tag('tr')
  +
h.printWideCell(tr, content)
  +
end
  +
  +
function h.printWideCell(tr, content)
  +
if not content then return end
 
tr:tag('td')
 
tr:tag('td')
 
:attr('colspan','2')
 
:attr('colspan','2')
Line 212: Line 302:
 
end
 
end
   
function h.printNormalRow(tr, label, content)
+
function h.printNormalCell(tr, label, content)
 
if not content then return end
 
if not content then return end
 
tr:tag('td')
 
tr:tag('td')
Line 232: Line 322:
 
end
 
end
   
function h.storeCargo(nocargo, data)
+
function h.getDisplayTitleArgs(title)
  +
if mw.title.getCurrentTitle().nsText ~= '' then
if nocargo or not data then return end
 
  +
return ('%s:%s'):format(
for _, tbl in ipairs(data) do
 
  +
mw.title.getCurrentTitle().nsText,
util_cargo.store(tbl)
 
  +
lang:lcfirst(title)
  +
)
 
end
 
end
return
+
return lang:lcfirst(title)
 
end
 
end
   
function h.getTabs(tabsTemplateTitle)
+
function h.getCategories(categories, nocat)
if tabsTemplateTitle then
+
if nocat then return '' end
  +
if not categories then return '' end
local frame = mw.getCurrentFrame()
 
return frame:expandTemplate{title = tabsTemplateTitle }
 
end
 
return ''
 
end
 
 
function h.makeAmbox(ambox)
 
if not ambox then return '' end
 
return mw.getCurrentFrame():expandTemplate{
 
title = ambox,
 
args = {}
 
}
 
end
 
 
function h.setLC(lc)
 
if not lc then return end
 
local title = mw.title.getCurrentTitle().text
 
local frame = mw.getCurrentFrame()
 
frame:callParserFunction{ name = 'DISPLAYTITLE', args = lang:lcfirst(title) }
 
return
 
end
 
 
function h.setVariables(data)
 
if not data then return end
 
util_table.removeFalseEntries(data)
 
for k, v in pairs(data) do
 
mw.getCurrentFrame():callParserFunction{
 
name = '#vardefine:' .. k,
 
args = { v }
 
}
 
end
 
return
 
end
 
 
function h.setCategories(data, nocat)
 
if nocat then
 
return ''
 
end
 
 
local tbl = {}
 
local tbl = {}
for _, v in pairs(data) do
+
for _, v in pairs(categories) do
 
if v then
 
if v then
 
tbl[#tbl+1] = ("[[Category:%s]]"):format(v)
 
tbl[#tbl+1] = ("[[Category:%s]]"):format(v)
Line 290: Line 345:
   
 
return p
 
return p
  +
-- </nowiki>

Revision as of 22:53, 29 October 2021

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)
	args.isLowContent = util_args.castAsBool(args.low_content)
	args.pagename = mw.title.getCurrentTitle().text
	args.lc = args.name and lang:lcfirst(args.name) == args.name
end

function p:getProcessed(args)
	local tbl = {
		pagename = mw.title.getCurrentTitle().text,
		lc = args.name and lang:lcfirst(args.name) == args.name,
	}
	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 args.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,
			Display = args._display or name,
			IsLowercase = isLowercase,
			DisambigSentence = self:getDisambigSentence(args, processed),
			AnnounceNew = util_args.castAsBool(args.announce),
			DontAnnounceNew = util_args.castAsBool(args.dont_announce) or args.isLowContent,
		}
	}
	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 = {
		args.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>