Module:Infobox

Documentation for this module may be created at Module:Infobox/doc

-- Load necessary modules.
require('Module:No globals')
local getArgs
local yesno = require('Module:Yesno')

local p = { }

--------------------------------------------------------------------------------
-- Helper functions
--------------------------------------------------------------------------------

local function union(t1, t2)
	local temp = {}
	for _, v in pairs(t1) do
		temp[v] = true
	end
	for _, v in pairs(t2) do
		temp[v] = true
	end
	local ret = {}
	for k in pairs(temp) do
		table.insert(ret, k)
	end
	table.sort(ret)
	return ret
end

local function getArgNums(args, prefix)
	local ret = { }
	for k in pairs(args) do
		local num = string.match(k, "^" .. prefix .. "(%d*)$")
		if num then
			table.insert(ret, tonumber(num))
		end
	end
	table.sort(ret)
	return ret
end

--------------------------------------------------------------------------------
-- Box class definition
--------------------------------------------------------------------------------

local Infobox = {}
Infobox.__index = Infobox

function Infobox.new(args)
	args = args or {}
	local obj = {}

	-- Set the arguments
	obj.args = args
	
	mw.logObject(obj)

	return setmetatable(obj, Infobox)
end

function Infobox:setParameters()
	local args = self.args
	
	self.child = yesno(args.child)
	
	self.title = args.title
	self.above = args.above
	
	self.autoheaders = yesno(args.autoheaders)
	if self.autoheaders then
		self:removeLoneHeaders()
	end
	
	self.subheaders = self:setSubheaders()
	self.images = self:setImages()
	self.rows = self:setRows()
	
	self.below = args.below
end

function Infobox:setSubheaders()
	local args = self.args
	local nums = getArgNums(args, 'subheader')
	local t = { }
	
	if args.subheader then
		table.insert(t, args.subheader)
	end
	
	for _,v in pairs(nums) do
		table.insert(t, args['subheader' .. v])
	end
	
	return t
end

function Infobox:setImages()
	local args = self.args
	local nums = union(getArgNums(args, 'image'), getArgNums(args, 'caption'))
	local t = { }
	
	if args.image or args.caption then
		table.insert(t, 
			{
				image = args.image,
				caption = args.caption
			})
	end
	
	for _,v in pairs(nums) do
		table.insert(t, 
			{
				image = args['image' .. v], 
				caption = args['caption' .. v]
			})
	end
	
	return t
end

function Infobox:removeLoneHeaders()
	local args = self.args
	
	local nums = union(getArgNums(args, 'header'), getArgNums(args, 'data'))
	table.sort(nums)
	
	local lastHeader
	
	for _, v in pairs(nums) do
		if args['header' .. v] then
			if lastHeader then
				args['header' .. lastHeader] = nil
			end
			lastHeader = v
		else
			lastHeader = nil
		end
	end

	if lastHeader then
		args['header' .. lastHeader] = nil
	end
end

function Infobox:setRows()
	local args = self.args
	
	local nums = { }
	nums = union(nums, getArgNums(args, 'header'))
	nums = union(nums, getArgNums(args, 'label'))
	nums = union(nums, getArgNums(args, 'data'))
	
	local t = { }
	
	for _,v in pairs(nums) do
		table.insert(t, 
			{
				header = args['header' .. v],
				label = args['label' .. v],
				data = args['data' .. v]
			})
	end
	
	return t
end

function Infobox:export()
	local root = mw.html.create()
	
	if not self.child then
		root = root:tag('table')
		root:addClass('infobox')
	end
	
	if self.title then
		local title = root:tag('caption')
		title
			:addClass('ib-title')
			:wikitext(self.title)
	end
	
	if self.above then
		local above = root:tag('tr'):tag('td')
		above
			:attr('colspan', 2)
			:addClass('ib-above')
			:wikitext(self.above)
	end
	
	for _,v in ipairs(self.subheaders) do
		local subheader = root:tag('tr'):tag('td')
		subheader
			:attr('colspan', 2)
			:addClass('ib-subheader')
			:wikitext(v)
	end
	
	for _,v in ipairs(self.images) do
		if v.image then
			local cell = root:tag('tr'):tag('td')
				:attr('colspan', 2)
				:addClass('ib-image')
				:wikitext(v.image)
				
			if v.caption then
				cell
					:tag('div')
					:addClass('ib-image-caption')
					:wikitext(v.caption)
			end
		end
	end
	
	for _,v in ipairs(self.rows) do
		if v.header then
			if v.header ~= '_BLANK_' then 
				local header = root:tag('tr'):tag('th')
				header:attr('colspan', 2)
				header:addClass('ib-header')
				header:wikitext(v.header)
			end
		else
			if v.label and v.data then
				local row = root:tag('tr')
				
				local label = row:tag('th')
				label:addClass('ib-label')
				label:wikitext(v.label)
				
				local data = row:tag('td')
				data:addClass('ib-data')
				data:wikitext(v.data)
			end
			
			if v.data and not v.label then
				local data = root:tag('tr'):tag('td')
				data:attr('colspan', 2)
				data:addClass('ib-data')
				data:wikitext(v.data)
			end
		end
	end
	
	if self.below then
		local below = root:tag('tr'):tag('td')
		below
			:attr('colspan', 2)
			:addClass('ib-below')
			:wikitext(self.below)
	end
	
	local templateStyle = mw.getCurrentFrame():extensionTag( 'templatestyles', '', { src = 'Template:Infobox/styles.css' } );

	return templateStyle .. tostring(root)
end

--------------------------------------------------------------------------------
-- Exports
--------------------------------------------------------------------------------

function p.infobox(frame)
	if not getArgs then
		getArgs = require('Module:Arguments').getArgs
	end
		
	local box = Infobox.new(getArgs(frame))
	box:setParameters()
	return box:export()
end

return p