Module:Infobox: Difference between revisions

From Xenharmonic Wiki
Jump to navigation Jump to search
Inthar (talk | contribs)
No edit summary
Sintel (talk | contribs)
Add infobox class
 
(112 intermediate revisions by 6 users not shown)
Line 1: Line 1:
-- This module follows [[User:Ganaram inukshuk/Provisional style guide for Lua]]
local getArgs = require("Module:Arguments").getArgs
local navbar  = require("Module:Navbar")._navbar
local tiu    = require("Module:Template input utils")
local yesno  = require("Module:Yesno")
local p = {}
local p = {}


local function put_adjacent_x_links(s, prev_x, next_x)
-- TODO (medium priority):
return s .. '<table style="width: 100%; margin: 0"><tr>'
-- - Use templatestyles
.. '<td style="width: 15%; text-align: left; white-space: nowrap; font-size: smaller">'
 
.. (prev_x or '')
--------------------------------------------------------------------------------
.. '</td>'
-------------------------------- MAIN FUNCTIONS --------------------------------
.. '<td style="width: 70%; padding-left: 1em; padding-right: 1em; text-align: center">'
--------------------------------------------------------------------------------
.. title
.. '</td>'
.. '<td style="width: 15%; text-align: right; white-space: nowrap; font-size: smaller">'
.. (next_x or '')
.. '</td>'
.. '</tr></table>'
end


function p.build(title, entries, prev_link, next_link)
-- Function to be called by other modules; also called by wrapper function
local s = '<div style="\n' ..
function p._infobox(args)
'border: 1px solid #999;\n' ..
local title         = args["Title"] or "Infobox Title"
'margin: 0;\n' ..
local adjacent_links = args["Adjacent Links"]
'margin-left: 1em;\n' ..
local header_row = args["Header Row"]
'margin-bottom: 0.5em;\n' ..
local rows      = args["Rows"]
'padding: 0.5em;\n' ..
local footer_row = args["Footer Row"]
'background-color: #f0f0f0;\n' ..
local name      = args["name"]
'min-width: 15em;\n' ..
'float: right;\n' ..
-- Helper function; preprocess rows
'max-width: 100%;\n' ..
function preprocess_rows()
'overflow: auto;\n' ..
-- Preproces rows
'">\n' ..
local is_jagged = true
'{| width="100%" style="border-collapse: collapse;"\n' ..
for i = 1, #rows do
'|+ style="font-weight: bold; text-align: center;" | '
local row = rows[i]
local has_adjacent = (prev_link and #prev_link > 0) or (next_link and #next_link > 0)
is_jagged = is_jagged and (#row == 1 or #row == 2)
if has_adjacent then
end
s = s .. '<table style="width: 100%; margin: 0"><tr>'
.. '<td style="width: 15%; text-align: left; white-space: nowrap; font-size: smaller">'
if is_jagged then return tiu.jagged_array_to_header_data_pairs(rows)
.. (prev_link or '')
else return rows end
.. '</td>'
end
.. '<td style="width: 70%; padding-left: 1em; padding-right: 1em; text-align: center">'
.. title
-- Preprocess rows
.. '</td>'
rows = preprocess_rows()
.. '<td style="width: 15%; text-align: right; white-space: nowrap; font-size: smaller">'
.. (next_link or '')
-- Nested helper function
.. '</td>'
-- Produces the title and, if present, prev/next links
.. '</tr></table>'
function infobox_title()
else
if adjacent_links == nil then
s = s .. title
return title
elseif #adjacent_links == 2 then
lines = {}
--table.insert(lines, "\n")
table.insert(lines, '{| style="width: 100%;"')
table.insert(lines, '|-')
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[1])
table.insert(lines, '| style="width: 50%;" | ' .. title)
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[2])
table.insert(lines, '|}')
return table.concat(lines, "\n")
elseif #adjacent_links == 8 then
lines = {}
--table.insert(lines, "\n")
table.insert(lines, '{| style="width: 100%;"')
table.insert(lines, '|-')
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[1])
table.insert(lines, '| style="font-size: 0.75em; width: 50%;" | ' .. adjacent_links[2])
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[3])
table.insert(lines, '|-')
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[4])
table.insert(lines, '| style="width: 50%;" | ' .. title)
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[5])
table.insert(lines, '|-')
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[6])
table.insert(lines, '| style="font-size: 0.75em; width: 50%;" | ' .. adjacent_links[7])
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[8])
table.insert(lines, '|}')
return table.concat(lines, "\n")
else
return title
end
end
end
s = s .. '\n'
for i, entry in ipairs(entries) do
-- Nested helper function
if #entry > 1 then
-- Produces a row in the infobox
local caption = entry[1]
function infobox_row(row_content)
local text = entry[2]
local header = row_content["Header"]
s = s .. '|-\n' ..
local data  = row_content["Data"  ]
'| style="text-align:right; padding-right: 0.25em" | ' .. caption .. '\n' ..
'| style="background-color: white; padding-left: 0.25em; font-weight: bold" | ' .. text .. '\n'
if header and data then
elseif #entry == 1 then
local lines = {}
local text = entry[1]
table.insert(lines, '|-')
s = s .. '|-\n'
table.insert(lines, '| style="text-align: right; padding-right: 0.25em;" | ' .. header)
.. '| colspan="2" style="text-align: center;" | ' .. text .. '\n'
table.insert(lines, '| style="background-color: white; padding-left: 0.25em; font-weight: bold;" | ' .. data)
return table.concat(lines, "\n")
elseif header and not data then
local lines = {}
table.insert(lines, '|-')
table.insert(lines, '| colspan="2" style="text-align: center;" | ' .. header)
return table.concat(lines, "\n")
elseif data and not header then
local lines = {}
table.insert(lines, '|-')
table.insert(lines, '| colspan="2" style="text-align: center;" | ' .. data)
return table.concat(lines, "\n")
end
end
end
end
s = s .. '|}</div>'
return s
end
function p.build(title, entries, prev_x, next_x, prev_y, next_y)
local s = '<div style="\n' ..
-- Nested helper function
'border: 1px solid #999;\n' ..
-- Produces a header or footer row
'margin: 0;\n' ..
function header_footer_row(row_content)
'margin-left: 1em;\n' ..
local lines = {}
'margin-bottom: 0.5em;\n' ..
table.insert(lines, '|-')
'padding: 0.5em;\n' ..
table.insert(lines, '| colspan="2" style="text-align: center; font-size: 0.8em;" | ' .. row_content)
'background-color: #f0f0f0;\n' ..
'min-width: 15em;\n' ..
return table.concat(lines, "\n")
'float: right;\n' ..
end
'max-width: 100%;\n' ..
'overflow: auto;\n' ..
-- Nested helper function
'">\n' ..
-- Produces the navbar, if specified
'{| width="100%" style="border-collapse: collapse;"\n' ..
function navbar_row()
'|+ style="font-weight: bold; text-align: center;" | '
local lines = {}
local has_adjacent_x = (prev_x and #prev_x > 0) or (next_x and #next_x > 0)
table.insert(lines, '|-')
local has_adjacent_y = (prev_y and #prev_y > 0) or (next_y and #next_y > 0)
table.insert(lines, '| colspan="2" style="text-align: center;" | ' .. navbar(name, "mini", ""))
return table.concat(lines, "\n")
end
-- Start of infobox; outer div and start of table
local lines = {}
-- Infobox boilerplate
table.insert(lines,
[[<div class="infobox" style="
border: 1px solid #999;  
margin: 0;  
margin-left: 1em;  
margin-bottom: 0.5em;  
padding: 0.5em;  
background-color: #f0f0f0;  
min-width: 15em;  
float: right;  
max-width: 100%;  
overflow: auto;">]]
)
table.insert(lines, '{| style="border-collapse: collapse; width: 100%;"')
table.insert(lines, '|+ style="font-size: 105%; font-weight: bold; text-align: center;" | ')
-- Title
table.insert(lines, infobox_title())
if has_adjacent_y and prev_y then
-- Header
s = s .. '\n' .. prev_y .. '\n'
if header_row then
table.insert(lines, header_footer_row(header_row))
end
-- Rows
for i = 1, #rows do
table.insert(lines, infobox_row(rows[i]))
end
end
if has_adjacent_x then
put_adjacent_x_links(s, prev_x, next_x)
-- Footer
else
if footer_row then
s = s .. title
table.insert(lines, header_footer_row(footer_row))
end
end
if has_adjacent_y and next_y then
s = s .. '\n' .. next_y .. '\n'
-- Template navbar
if name then
table.insert(lines, navbar_row())
end
end
s = s .. '\n'
for i, entry in ipairs(entries) do
-- End of infobox
if #entry > 1 then
table.insert(lines, "|}")
local caption = entry[1]
table.insert(lines, "</div>")
local text = entry[2]
 
s = s .. '|-\n' ..
return table.concat(lines, "\n")
'| style="text-align:right; padding-right: 0.25em" | ' .. caption .. '\n' ..
end
'| style="background-color: white; padding-left: 0.25em; font-weight: bold" | ' .. text .. '\n'
 
elseif #entry == 1 then
-- Function to be #invoke'd
local text = entry[1]
-- Wrapper function for template-based infoboxes
s = s .. '|-\n'
-- Modeled off of navbox
.. '| colspan="2" style="text-align: center;" | ' .. text .. '\n'
function p.infobox(frame)
local args = getArgs(frame)
-- Preprocess adjacent links
-- If there are two adjacent links (such as with edos), then links will be
-- placed on the left and right of the title:
-- [Link 1] Title [Link 2]
-- If there are eight adjacent links (such as with mosses), then links
-- surround the title in a 3x3 grid:
-- [Link 1] [Link 2] [Link 3]
-- [Link 4]  Title  [Link 5]
-- [Link 6] [Link 7] [Link 8]
local function any_keys_present(tbl, keys)
for _, key in ipairs(keys) do
if tbl[key] ~= nil then
return true
end
end
return false
end
-- Keys to links
-- Left and right are added if at least one is present -> 2-element table.
-- All three rows are added if at least one link from the upper or lower
-- rows is present, regardless of side links -> 8-element table.
-- No links are added if none of them are present -> 0-element table.
local upper_links = { "Upper Left Link", "Upper Link", "Upper Right Link" }
local side_links  = { "Left Link", "Right Link" }
local lower_links = { "Lower Left Link", "Lower Link", "Lower Right Link" }
-- Check which links are present
local is_upper_lower_links_present =
any_keys_present(args, upper_links) or any_keys_present(args, lower_links)
local is_side_links_present = any_keys_present(args, side_links)
-- Build adjacent_links
-- Links from args are removed, as they're stored in a separate table
local adjacent_links = {}
if is_upper_lower_links_present then
-- Upper row of links
for _, key in ipairs(upper_links) do
table.insert(adjacent_links, args[key] or "")
args[key] = nil
end
-- Middle row of links
for _, key in ipairs(side_links) do
table.insert(adjacent_links, args[key] or "")
args[key] = nil
end
-- Bottom row of links
for _, key in ipairs(lower_links) do
table.insert(adjacent_links, args[key] or "")
args[key] = nil
end
elseif is_side_links_present then
-- Left and right links only
for _, key in ipairs(side_links) do
table.insert(adjacent_links, args[key] or "")
args[key] = nil
end
end
end
end
s = s .. '|}</div>'
args["Adjacent Links"] = adjacent_links
return s
-- Preprocess rows
-- Set row count to 30, under the reasoning that an infobox may need more
-- rows and/or headers. This may be increased to 40 if needed.
args["Rows"] = tiu.numbered_header_data_args_to_table(args, 30)
local result = p._infobox(args)
local debugg = yesno(args["debug"])
if debugg == true then
result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>"
end
return result
end
 
--------------------------------------------------------------------------------
------------------------------- LEGACY FUNCTIONS -------------------------------
--------------------------------------------------------------------------------
 
-- These functions are kept in the meantime to support older infoboxes and WILL
-- be entirely deleted later! Please switch to the new functions!
 
-- Original function signature, kept for legacy support (for now).
function p.build(title, entries, prev_link, next_link)
local args = {
["Adjacent Links"] = { (prev_link or ""), (next_link or "") },
["Title"] = title,
["Rows"] = entries
}
 
return p._infobox(args)
end
 
-- Original 8-link function signature, pulled from infobox mos.
function p.build_multilink(title, entries, adjacent_links)
local args = {
["Adjacent Links"] = adjacent_links,
["Title"] = title,
["Rows"] = entries
}
 
return p._infobox(args)
end
end


return p
return p

Latest revision as of 11:19, 10 April 2026

Module documentation[view] [edit] [history] [purge]
This module implements a metatemplate, and may be invoked by templates using its corresponding template Template:Infobox, or used directly from other modules.

Module:Infobox is a module that implements the {{Infobox}} template. Infobox templates can be made by using the template or by calling the _sidebar function from another module.

On templates, you can create an infobox by using {{Infobox}}, which calls this module's wrapper function.

On modules, you can include local infobox= require("Module:Infobox")._infobox to create an infobox.
Introspection summary for Module:Infobox 
Functions provided (4)
Line Function Params
17 _infobox (main) (args)
182 infobox (invokable) (frame)
267 build (title, entries, prev_link, next_link)
278 build_multilink (title, entries, adjacent_links)
Lua modules required (4)
Variable Module Functions used
getArgs Module:Arguments getArgs
navbar Module:Navbar _navbar
tiu Module:Template input utils jagged_array_to_header_data_pairs
numbered_header_data_args_to_table
yesno Module:Yesno yesno

No function descriptions were provided. The Lua code may have further information.


-- This module follows [[User:Ganaram inukshuk/Provisional style guide for Lua]]
local getArgs = require("Module:Arguments").getArgs
local navbar  = require("Module:Navbar")._navbar
local tiu     = require("Module:Template input utils")
local yesno   = require("Module:Yesno")

local p = {}

-- TODO (medium priority):
-- - Use templatestyles

--------------------------------------------------------------------------------
-------------------------------- MAIN FUNCTIONS --------------------------------
--------------------------------------------------------------------------------

-- Function to be called by other modules; also called by wrapper function
function p._infobox(args)
	local title          = args["Title"] or "Infobox Title"
	local adjacent_links = args["Adjacent Links"]
	local header_row = args["Header Row"]
	local rows       = args["Rows"]
	local footer_row = args["Footer Row"]
	local name       = args["name"]
	
	-- Helper function; preprocess rows
	function preprocess_rows()
		-- Preproces rows
		local is_jagged = true
		for i = 1, #rows do
			local row = rows[i]
			is_jagged = is_jagged and (#row == 1 or #row == 2)
		end	
		
		if is_jagged then return tiu.jagged_array_to_header_data_pairs(rows)
		else return rows end
	end
	
	-- Preprocess rows
	rows = preprocess_rows()
	
	-- Nested helper function
	-- Produces the title and, if present, prev/next links
	function infobox_title()
		if adjacent_links == nil then
			return title
		elseif #adjacent_links == 2 then
			lines = {}
			--table.insert(lines, "\n")
			table.insert(lines, '{| style="width: 100%;"')
			table.insert(lines, '|-')
			table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[1])
			table.insert(lines, '| style="width: 50%;" | ' .. title)
			table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[2])
			table.insert(lines, '|}')
			
			return table.concat(lines, "\n")
		elseif #adjacent_links == 8 then
			lines = {}
			--table.insert(lines, "\n")
			table.insert(lines, '{| style="width: 100%;"')
			table.insert(lines, '|-')
			table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[1])
			table.insert(lines, '| style="font-size: 0.75em; width: 50%;" | ' .. adjacent_links[2])
			table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[3])
			table.insert(lines, '|-')
			table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[4])
			table.insert(lines, '| style="width: 50%;"  | ' .. title)
			table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[5])
			table.insert(lines, '|-')
			table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[6])
			table.insert(lines, '| style="font-size: 0.75em; width: 50%;" | ' .. adjacent_links[7])
			table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[8])
			table.insert(lines, '|}')
				
			return table.concat(lines, "\n")
		else
			return title
		end
	end
	
	-- Nested helper function
	-- Produces a row in the infobox
	function infobox_row(row_content)
		local header = row_content["Header"]
		local data   = row_content["Data"  ]
		
		if header and data then
			local lines = {}
			table.insert(lines, '|-')
			table.insert(lines, '| style="text-align: right; padding-right: 0.25em;" | ' .. header)
			table.insert(lines, '| style="background-color: white; padding-left: 0.25em; font-weight: bold;" | ' .. data)
			
			return table.concat(lines, "\n")
		elseif header and not data then
			local lines = {}
			table.insert(lines, '|-')
			table.insert(lines, '| colspan="2" style="text-align: center;" | ' .. header)
			
			return table.concat(lines, "\n")
		elseif data and not header then
			local lines = {}
			table.insert(lines, '|-')
			table.insert(lines, '| colspan="2" style="text-align: center;" | ' .. data)
			
			return table.concat(lines, "\n")
		end
	end
	
	-- Nested helper function
	-- Produces a header or footer row
	function header_footer_row(row_content)
		local lines = {}
		table.insert(lines, '|-')
		table.insert(lines, '| colspan="2" style="text-align: center; font-size: 0.8em;" | ' .. row_content)
		
		return table.concat(lines, "\n")
	end
	
	-- Nested helper function
	-- Produces the navbar, if specified
	function navbar_row()
		local lines = {}
		table.insert(lines, '|-')
		table.insert(lines, '| colspan="2" style="text-align: center;" | ' .. navbar(name, "mini", ""))
		
		return table.concat(lines, "\n")
	end
	
	-- Start of infobox; outer div and start of table
	local lines = {}
	
	-- Infobox boilerplate
	table.insert(lines, 
		[[<div class="infobox" style="
		border: 1px solid #999; 
		margin: 0; 
		margin-left: 1em; 
		margin-bottom: 0.5em; 
		padding: 0.5em; 
		background-color: #f0f0f0; 
		min-width: 15em; 
		float: right; 
		max-width: 100%; 
		overflow: auto;">]]
	)
	table.insert(lines, '{| style="border-collapse: collapse; width: 100%;"')
	table.insert(lines, '|+ style="font-size: 105%; font-weight: bold; text-align: center;" | ')
	
	-- Title
	table.insert(lines, infobox_title())
	
	-- Header
	if header_row then
		table.insert(lines, header_footer_row(header_row))
	end
		
	-- Rows
	for i = 1, #rows do
		table.insert(lines, infobox_row(rows[i]))
	end
	
	-- Footer
	if footer_row then
		table.insert(lines, header_footer_row(footer_row))
	end
	
	-- Template navbar
	if name then
		table.insert(lines, navbar_row())
	end
	
	-- End of infobox
	table.insert(lines, "|}")
	table.insert(lines, "</div>")

	return table.concat(lines, "\n")
end

-- Function to be #invoke'd
-- Wrapper function for template-based infoboxes
-- Modeled off of navbox
function p.infobox(frame)
	local args = getArgs(frame)
	
	-- Preprocess adjacent links
	-- If there are two adjacent links (such as with edos), then links will be
	-- placed on the left and right of the title:
	--		[Link 1] Title [Link 2]
	-- If there are eight adjacent links (such as with mosses), then links
	-- surround the title in a 3x3 grid:
	--		[Link 1] [Link 2] [Link 3]
	--		[Link 4]  Title   [Link 5]
	--		[Link 6] [Link 7] [Link 8]
	local function any_keys_present(tbl, keys)
		for _, key in ipairs(keys) do
			if tbl[key] ~= nil then
				return true
			end
		end
		return false
	end
	
	-- Keys to links
	-- Left and right are added if at least one is present -> 2-element table.
	-- All three rows are added if at least one link from the upper or lower
	-- rows is present, regardless of side links -> 8-element table.
	-- No links are added if none of them are present -> 0-element table.
	local upper_links = { "Upper Left Link", "Upper Link", "Upper Right Link" }
	local side_links  = { "Left Link", "Right Link" }
	local lower_links = { "Lower Left Link", "Lower Link", "Lower Right Link" }
	
	-- Check which links are present
	local is_upper_lower_links_present = 
		any_keys_present(args, upper_links) or any_keys_present(args, lower_links)
	local is_side_links_present = any_keys_present(args, side_links)
	
	-- Build adjacent_links
	-- Links from args are removed, as they're stored in a separate table
	local adjacent_links = {}
	if is_upper_lower_links_present then
		-- Upper row of links
		for _, key in ipairs(upper_links) do
			table.insert(adjacent_links, args[key] or "")
			args[key] = nil
		end
		-- Middle row of links
		for _, key in ipairs(side_links) do
			table.insert(adjacent_links, args[key] or "")
			args[key] = nil
		end
		-- Bottom row of links
		for _, key in ipairs(lower_links) do
			table.insert(adjacent_links, args[key] or "")
			args[key] = nil
		end
	elseif is_side_links_present then
		-- Left and right links only
		for _, key in ipairs(side_links) do
			table.insert(adjacent_links, args[key] or "")
			args[key] = nil
		end
	end
	args["Adjacent Links"] = adjacent_links
	
	-- Preprocess rows
	-- Set row count to 30, under the reasoning that an infobox may need more
	-- rows and/or headers. This may be increased to 40 if needed.
	args["Rows"] = tiu.numbered_header_data_args_to_table(args, 30)
	
	local result = p._infobox(args)
	local debugg = yesno(args["debug"])
	if debugg == true then
		result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>"
	end
	
	return result
end

--------------------------------------------------------------------------------
------------------------------- LEGACY FUNCTIONS -------------------------------
--------------------------------------------------------------------------------

-- These functions are kept in the meantime to support older infoboxes and WILL
-- be entirely deleted later! Please switch to the new functions!

-- Original function signature, kept for legacy support (for now).
function p.build(title, entries, prev_link, next_link)
	local args = {
		["Adjacent Links"] = { (prev_link or ""), (next_link or "") },
		["Title"] = title,
		["Rows"] = entries
	}

	return p._infobox(args)
end

-- Original 8-link function signature, pulled from infobox mos.
function p.build_multilink(title, entries, adjacent_links)
	local args = {
		["Adjacent Links"] = adjacent_links,
		["Title"] = title,
		["Rows"] = entries
	}

	return p._infobox(args)
end

return p