FANDOM


--------------------------------------------------------------------
-- Extended Infobox Module
--
-- * Fully CSS styled (inline styles possible but not default)
-- * Supports Multiple images (either under eachother or in a tabber)
-- * Automatically hidden sections
-- * Collapsible sections (requires JS)
-- * Alternating row styles
--
-- By User:Tjcool007
--------------------------------------------------------------------
 
local p = {}
 
local args = {} -- Arguments passed to template
local infobox -- Actual infobox
 
local sections, activeSection
local imagenums, rownums, skiprows = {}, {}, {}
local hasData, alt = false, false
local showText, hideText = 'Show', 'Hide'
 
------------------------------------------------
-- TITLE
------------------------------------------------
 
--- Processes the VDE links
local function _processVde(header)
	if not args.template then return end
 
	header
		:tag('span')
			:addClass('infobox-vde')
			:wikitext(mw.getCurrentFrame():expandTemplate({
				title = 'vdelinks',
				args = { args.template, ['type'] = 'infobox' }
			}))
end
 
--- Processes the main title row
local function processTitle()
	if not args.title then args.title = mw.title.getCurrentTitle().text end
 
	local h = infobox
		:tag('tr'):addClass('infobox-title')
			:tag('th'):attr('colspan', 2)
				:tag('div')
 
	_processVde(h)
 
	h:wikitext(args.title)
end
 
--- Adds a Gutter row
local function _addGutter(parent)
	parent:tag('tr'):addClass('infobox-gutter'):tag('td'):attr('colspan',2)	
end
 
------------------------------------------------
-- IMAGES
------------------------------------------------
 
--- Gets a single image from the arguments
--
-- @param num The number of the image. Note that this number is 1 higher than the argument
--            passed to the infobox. Eg. for "image5", num would be 6. This is because the
--            number 1 is reserved for "image" without a number.
local function _getImage(num) 
	local t = tostring(num-1)
	if t == '0' then t = '' end
 
	local i = args['image'..t]
 
	if not i:find('%[') then
		if not i:find(':') then
			i = 'File:' .. i
		end
		local imagewidth = args['imagewidth'..t] or '250px'
		if tonumber(imagewidth) then imagewidth = imagewidth .. 'px' end
		i = '[['..i..'|'..imagewidth..']]'
	end
 
	local image = mw.html.create('div'):wikitext(i)
 
	if args['caption' .. t] then
		local caption = mw.html.create('span')
			:addClass('infobox-imagecaption')
			:wikitext(args['caption' .. t])
 
		image:tag('br'):done():node(caption)
	end
 
	return image
end
 
--- Processeses the images in default mode
-- Adds images underneath eachother.
local function _processImagesDefault()
	local iclass = args.imageclass
	for i=1, #imagenums do
		local num = imagenums[i]
		local image = _getImage(num)
 
		_addGutter(infobox)
		infobox:tag('tr'):addClass('infobox-image')
			:tag('td'):attr('colspan', 2):wikitext(tostring(image))
	end
end
 
--- Processes images in tabber mode
-- Adds images in a tabber with one image per tab.
-- Tabs without a title will be automatically numbered.
local function _processImagesTabber()
	local isloaded, Tabber = pcall(require,'Module:Tabber')
	if not isloaded then
		_processImagesDefault()
		return
	end
	local tb = Tabber.new()
 
	for i=1, #imagenums do
		local num = imagenums[i]
		local image = _getImage(num)
 
		-- Get title
		local t = tostring(num-1)
		if t == '0' then t = '' end
 
		local title = args['tab'..t] or k
 
		tb:addTab( title, tostring(image) )
	end
 
 	_addGutter(infobox)
 
	infobox:tag('tr'):addClass('infobox-image')
		:tag('td'):attr('colspan', 2):wikitext(tostring(tb))
end
 
--- Dispatcher for image processing
local function processImages()
	if #imagenums == 0 then return end
	if args.imagemode == 'tabber' and #imagenums > 1 then return _processImagesTabber()
	else return _processImagesDefault() end
end
 
------------------------------------------------
-- ABOVE/BELOW
------------------------------------------------
 
--- Processeses the Above and Below rows
--
-- @param rowtype Either "above" or "below"
local function processAboveBelow(rowtype)
	if not args[rowtype] then return end
 
	_addGutter(infobox)
 
	infobox:tag('tr'):addClass('infobox-abovebelow'):addClass('infobox-' .. rowtype)
		:tag('td'):attr('colspan',2):wikitext(args[rowtype])
end
 
------------------------------------------------
-- MAIN ROWS
------------------------------------------------
 
--- Closes the currently active section, if any
-- Will add the section to the infobox if there is data or the showX parameters are used.
local function _closeCurrentSection()
	if not activeSection then return end
 
   	_addGutter(infobox)
	infobox
		:tag('tr'):addClass('infobox-sectionrow')
		:tag('td'):attr('colspan',2):node(sections[activeSection])
 
	activeSection = false
	hasData = false
end
 
--- Handles alternating rows
--
-- @return Alternatingly returns true or false. Always returns false if alternating rows
--         are disabled with "alternaterows = no"
local function _alternateRow()
	if args.alternaterows == 'no' then return false end
	if alt then	alt = false; return true
	else alt = true; return false end
end
 
--- Processes a Header row
--
-- @param num The number of the Header row (eg. "headerX")
local function _processHeader(num)
	if not args['header'..num] then return end
	-- Begin a new section
	_closeCurrentSection()
	activeSection = num
 
	local header = mw.html.create('th'):attr('colspan', 2):wikitext( args['header'..num] )
	local t = mw.html.create('table'):addClass('infobox-section')
		:tag('tr'):addClass('infobox-headerrow'):node(header):done()
 
	-- Header collapse
	local collapseme = args['state'..num] or false
	if collapseme ~= 'plain' then
		local collapseall = args.defaultstate or false
 
		if collapseall == 'plain' then collapseall = false end
 
		if collapseall or collapseme then
			t:addClass('mw-collapsible'):attr('data-expandtext',showText):attr('data-collapsetext',hideText)
			header:css('padding-left','50px')
		end
 
		if collapseme == 'collapsed' or (not collapseme and collapseall == 'collapsed') then
			t:addClass('mw-collapsed')
		end
 	end
 
	sections[num] = t
 
	_alternateRow() -- Comment this line to stop alternating on headers
end
 
--- Processes a data row
--
-- @param num The number of the data row (eg. "dataX"), as well as the label with the
--            same number (eg. "labelX")
local function _processData(num)
	local data = args['data'..num]
	if not data then return end
 
	local t = infobox
	local s = activeSection or false
	if s then
		t = sections[s] -- Open the section
		hasData = true -- This section has data!
	end
 
	local altRow = _alternateRow()
 
	local datarow = mw.html.create('tr')
		:addClass('infobox-datarow')
		:addClass((s and 'ib-section'..s) or '')
		:addClass('ib-row'..num)
 
	local datacell = mw.html.create('td')
		:addClass('infobox-rowdata')
 
	if tostring(data):sub(1,1) == '*' then
		-- Add newlines to support lists
		datacell
			:newline() 
			:wikitext(data)
			:newline()
	else
		datacell:wikitext(data)
	end
 
	if altRow then
		datarow:addClass('alt')
	end
 
 	local lbl = args['label'..num]
	if lbl then
		local label = mw.html.create('th')
			:addClass('infobox-rowlabel')
			:wikitext(lbl)
 
		datarow:node(label)
	else
		datacell:addClass('no-label'):attr('colspan',2)
	end
 
	datarow:node(datacell)
	_addGutter(t)
	t:node(datarow)
end
 
--- Processeses ONE normal row. A normal row contains a header and/or a label/data pair
--
-- @param num Number of the row to be processed.
local function processRow(num)
	_processHeader(num)
	_processData(num)
end
 
--- Processes ALL normal rows; making use of the above functions
local function processRows()
	sections = {} -- Init sections storage
	local rnum = rownums
	for i=1, #rnum do
		local num = rnum[i]
		if not skiprows[num] then
			processRow(num)
		end
	end
	_closeCurrentSection() -- Close last section if any
end
 
------------------------------------------------
-- ARGUMENTS PREPROCESSOR
-- * Extracts arguments from frame and stores them in args table
-- * At the same time, checks for valid row and image numbers
------------------------------------------------
 
--- Process Language Rows (Layton Wiki addition)
local function _preProcessLanguages(a)
	rownums[#rownums+1] = 10000
	args.header10000 = 'In other languages'
	args.state10000 = 'collapsed'
 
	local i = 10000
	local langrows = {
		{'jpname','<span title="Japanese"><span class="languageFlags JA"></span> 日本語</span>'},
		{'dename','<span title="German"><span class="languageFlags DE"></span> Deutsch</span>'},
		{'esname','<span title="Spanish"><span class="languageFlags ES"></span> Español</span>'},
		{'frname','<span title="French"><span class="languageFlags FR"></span> Français</span>'},
		{'itname','<span title="Italian"><span class="languageFlags IT"></span> Italiano</span>'},
		{'nlname','<span title="Dutch" style="font-size:90%;"><span class="languageFlags NL"></span> Nederlands</span>'},
		{'korname','<span title="Korean"><span class="languageFlags KOR"></span> 한국의</span>'}
	}
 
	for l=1,#langrows do
		local lang = langrows[l][1]
		if a[lang] and a[lang] ~= '' then
			if i > 10000 then rownums[#rownums+1] = i end
			args['label'..i] = langrows[l][2]
			args['data'..i] = a[lang]
			args[lang] = nil
		end
		i = i + 1
	end
end
 
--- Preprocessor for the arguments.
-- Will fill up the args table with the parameters from the frame grouped by their type.
--
-- @param frame The frame passed to the Module.
local function preProcessArgs(frame)
	local tmp = {}
 
	if frame == mw.getCurrentFrame() then
		tmp = frame:getParent().args
	else
		tmp = frame
	end
 
	-- Storage tables
	local nums = {}
 
	-- Loop over all the args
	for k,v in pairs(tmp) do
		-- Skip empty args, which are useless
		if v ~= '' then
			local s = tostring(k)
 
			if s == 'image' then
				imagenums[#imagenums+1] = 1
			else
				local cat,num = s:match('^(%a+)([1-9]%d*)$')
 
				if cat == 'header' or cat == 'data' then
					nums[num] = true
				elseif cat == 'image' then
					imagenums[#imagenums+1] = tonumber(num+1)
				end
			end
 
			args[k] = v -- Simple copy
		end
	end
 
	for k, v in pairs(nums) do
		rownums[#rownums+1] = tonumber(k)
	end
 
	if args.enablelanguages ~= 'no' then
		_preProcessLanguages(tmp)
	end
 
	-- Sort
	table.sort(rownums)
	table.sort(imagenums)
 
	-- Calculate skip rows
	local cSection, cSkip
	local showall = args.showall
	for i=1,#rownums do
		local num = rownums[i]
		if args['header'..num] then
			cSection = true
			cSkip = false
			local showme = args['show'..num]
			if showme == 'no' then
				cSkip = true
			elseif showme == 'auto' or (showme ~= 'yes' and showall ~= 'yes') then
				if not args['data'..num] then
					local nextNum = rownums[i+1]
					cSkip = not nextNum or args['header'..nextNum] -- If next has a header -> skip
				end
			end
		end
		if cSection and cSkip then
			skiprows[num] = true
		end
	end
end
 
------------------------------------------------
-- MAIN FUNCTIONS
------------------------------------------------
 
--- Processes the arguments to create the infobox.
--
-- @return A string with HTML that is the infobox.
local function _infobox()
	-- Create the root HTML element
	infobox = mw.html.create('table'):addClass('infobox')
 
	-- Process...
	processTitle()
	processAboveBelow('above')
	processImages()
	processRows()
	processAboveBelow('below')
 
	return tostring(infobox)
end
 
--- Main module entry point.
-- To be called with {{#invoke:infobox|main}} or directly from another module.
--
-- @param frame The frame passed to the module via the #invoke. If called from another
--              module directly, this should be a table with the parameter definition.
function p.main(frame)
	-- Save the arguments in a local variable so other functions can use them.
	preProcessArgs(frame)
 
	return _infobox()
end
 
return p
-- [[Category:Modules]]

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.