Module:Infobox

local p = {} local h = {}

local Constants = mw.loadData("Module:Constants/Data")

local File = require("Module:File") local Franchise = require("Module:Franchise") local utilsArg = require("Module:UtilsArg") local utilsMarkup = require("Module:UtilsMarkup") local utilsPackage = require("Module:UtilsPackage") local utilsString = require("Module:UtilsString") local utilsTable = require("Module:UtilsTable") local _utilsError = utilsPackage.lazyLoad("Module:UtilsError")

local DEFAULT_IMG_SIZE = "320px" local CATEGORY_INVALID_ARGS = "" local CATEGORY_PARAM_CAPTION = "" local CATEGORY_PARAM_NAME = "" local CATEGORY_BR_TAGS = "" local BR_TAGS_MSG = "Using  tags to create lists is discouraged. See Category:Infoboxes Using br Tags for more information."

function p.Main(frame) local templateName = "Infobox "..frame:getParent:getTitle local args, err, categories local templateSpec = p.Templates[templateName] if templateSpec then args, err = utilsArg.parse(frame:getParent.args, templateSpec) else args = frame:getParent.args end categories = err and err.categoryText or "" if args.name and args.name ~= "" then categories = categories..CATEGORY_PARAM_NAME end if args.caption and args.caption ~= "" then categories = categories..CATEGORY_PARAM_CAPTION end local styles = frame:extensionTag({		name = "templatestyles",		args = { src = "Module:Infobox/Styles.css" }	}) return styles, categories end

function p.Image(frame) local file = frame.args[1] local caption = frame.args[2] if file == nil or file == "" then return nil elseif not utilsString.startsWith(file, "File:") then return file else local image = File.image(file, {			size = frame.args.size or DEFAULT_IMG_SIZE, -- unclear whether we should even support custom sizing or force them all to 320x320px.			scale = 10,		}) if caption and caption ~= "" then local html = mw.html.create("div") :addClass("infobox__image-caption") :wikitext(caption) image = image .. tostring(html) end return image end end

function p.List(frame) local categories = "" listItems = frame.args[1] listItems = listItems and utilsString.trim(listItems) if listItems == nil or listItems == "" then return nil end

if string.find(listItems, "<br") then h.warn(BR_TAGS_MSG) categories = categories..CATEGORY_BR_TAGS listItems = utilsString.split(listItems, " ") listItems = utilsTable.flatMap(listItems, utilsString._split(" ")) else listItems = utilsString.split(listItems, '%s*,[%D+|%s*]') -- %D ensures that we don't split large numbers (e.g. 1,500) end if #listItems == 1 then return listItems[1], categories else return utilsMarkup.list(listItems), categories end end

function p.Games(frame) local games = frame.args[1] local categories = ""

games = games and utilsString.trim(games) if games == nil or games == "" then return nil end

if string.find(games, "<br") then h.warn(BR_TAGS_MSG) categories = categories..CATEGORY_BR_TAGS games = utilsString.split(games, " ") games = utilsTable.flatMap(games, utilsString._split(" ")) else games = utilsString.split(games) end

local gameLinks = utilsTable.map(games, p.link) local gameLinks = utilsTable.compact(gameLinks) if #gameLinks ~= #games then categories = categories..CATEGORY_INVALID_ARGS end if #gameLinks == 1 then return gameLinks[1], categories else local gameList = utilsMarkup.list(gameLinks) return gameList, categories end end function p.link(game) if utilsMarkup.containsLink(game) then return game end local link = Franchise.link(game) local properCode = Franchise.code(game) if not link then h.warn(string.format("Invalid entry . See Data:Franchise for a list of valid entries.", game)) return nil elseif properCode and properCode ~= game then h.warn(string.format(" should be written as  ", game, properCode)) end return link end

function p.GameBlocks(frame) local args = frame:getParent.args local categories = ""

local seenParams = {} local blocks = {} for i, game in ipairs(Franchise.enum({ includeSeries = true })) do		seenParams[game] = true local listItems = args[game] listItems = listItems and utilsString.trim(listItems) listItems = listItems and utilsString.nilIfEmpty(listItems) if listItems then table.insert(blocks, {				game = Franchise.display(game), 				listItems = args[game],			}) end end

for k, v in pairs(args) do		if not seenParams[k] then local errorMessage = string.format("Invalid game ", k)			h.warn(errorMessage) categories = categories..CATEGORY_INVALID_ARGS end end local html = mw.html.create("ul") :addClass("infobox-game-blocks") for i, block in ipairs(blocks) do		local gameList = html :tag("li") :addClass("infobox-game-blocks__block") :tag("span") :addClass("infobox-game-blocks__game") :wikitext(block.game) :done :tag("ul") :addClass("infobox-game-blocks__game-list") local listItems = block.listItems local hasBrTags = string.find(listItems, "<br") if hasBrTags then h.warn(BR_TAGS_MSG) categories = categories..CATEGORY_BR_TAGS listItems = utilsString.split(listItems, " ") listItems = utilsTable.flatMap(listItems, utilsString._split(" ")) else listItems = utilsString.split(listItems, '%s*,[%D+|%s*]') end for j, listItem in ipairs(listItems) do			gameList:tag("li") :wikitext(listItem) end end return tostring(html), categories end

function h.warn(msg) _utilsError.warn(msg, {		includeInstance = false,	}) end

local templateSpec = function(args) local singular = args.singular local plural = args.plural local params = args.params local productionParams = args.productionParams local imageSuchAs = args.imageSuchAs

local spec = { format = "block", purpose = string.format("Infobox for %s.", plural, string.lower(plural)), categories = {"Infobox Templates"}, boilerplate = { separateRequiredParams = false, },		paramOrder = {"name", "image", "caption"}, params = { name = { desc = " Name to use in the infobox header. Defaults to . In general, this parameter should be omitted unless the title requires italics. ", type = "content", },			image = { desc = string.format("An image to represent the %s, such as %s.", singular, imageSuchAs), type = "wiki-file-name", },			caption = { desc = "A caption for the image.", type = "content", }		},	}	for i, param in ipairs(params or {}) do		spec.params[param.name] = param table.insert(spec.paramOrder, param.name) end for i, param in ipairs(productionParams or {}) do		spec.params[param.name] = param table.insert(spec.paramOrder, param.name) end return spec end

local released = { name = "released", desc = "Release date(s) of the film. Use Template:Release.", type = "content", }

p.Templates = { ["Infobox Game Blocks"] = {}, ["Infobox Film"] = templateSpec({		singular = "film",		plural = "films",		imageSuchAs = "a release poster or a DVD cover",		params = {			{				name = "director",				desc = "The director(s) of the film.",				type = "content",			},			{				name = "producer",				desc = "The producer(s) of the film.",				type = "content",			},			{				name = "country",				desc = "Country or countries of production.",				},			released,		}	}), ["Infobox Television"] = templateSpec({		singular = "television",		plural = "television",		imageSuchAs = "the series' logo or title card",		params = {			{				name = "basedOn",				type = "string",				desc = "Comma separated list of games that the series is based on.",				enum = Franchise.enum,				trim = true,				split = true,			},			{				name = "seasons",				type = "content",				desc = "Number of seasons.",			},			{				name = "episodes",				type = "content",				desc = "Number of total episodes.",			},			{				name = "company",				type = "content",				desc = "Production comapany or companies.",			},			{				name = "distributor",				type = "content",				desc = "Distributor(s) of the television series.",			},			released,		}	}) }

function p.Documentation return { Games = { desc = "Used by infobox templates to turn comma-separated game codes into lists of games.", frameParams = { [1] = {					name = "param", desc = "The infobox parameter, usually  or  .", },			},			cases = { {					args = {"TLoZ, TAoL, ALttP"}, },				{					args = {"TLoZ (Ran), BoMC, TLoZ (Susumu)"}, },				{					args = {""}, },				{					args = {}, },				{					args = {"invalid game"}, },				{					args = {"OoT, invalid game, TP"}, },				{					desc = "br tags are discouraged due to the poor HTML semantics.", args = {" "}, },			}		},		Image = { desc = "Used by infobox templates to generate an image when Template:Media is not used.", frameParams = { [1] = {					name = "file", desc = "The image parameter - a file name.", },				[2] = {					name = "caption", desc = "The caption parameter.", },				size = { desc = "Image size in pixels. Sprites are scaled to a maximum of 10 times their original size.", default = DEFAULT_IMG_SIZE, },			},			cases = { {					args = {"File:TWW Great Fairy Figurine Model.png"}, },				{					args = {"File:TWW Great Fairy Figurine Model.png", "Great Fairy Figurine", size = "250px"} },				{					desc = "Sprites are scaled to a maximum of 10 times their original size.", args = {"File:ALttP Apple Sprite.png"}, },				{					desc = "Template:Media output is rendered as-is", args = {""} },				{					desc = "Anything other than a file name starting with  is rendered as-is", args = {"NaN Cyber Pico Blooms are never seen in-game"}, },			},		},		List = { desc = "Used by infobox templates to turn comma-separated input into lists.", frameParams = { [1] = {					name = "param", desc = "The infobox parameter", },			},			cases = { {					args = {"A, B, C"} },				{					desc = "Digit separators don't count.", args = {"1,500 Rupees"}, },				{					desc = " can be used to escape commas when an item itself contains a comma.", args = {"The Way of Sumo, Part I, The Way of Sumo, Part II, The Way of Sumo, Part III"}, },				{					args = {"A"}, },				{					args = {""}, },				{					args = {}, },				{					desc = "br tags are discouraged due to the poor HTML semantics.", args = {"A B C"}, }			},		},	} end

return p