Module:Infobox

From Zelda Wiki, the Zelda encyclopedia
Revision as of 02:37, 8 November 2022 by PhantomCaleb (talk | contribs) (storing with Template:Categories instead)
This is the main module for the following templates: In addition, this module exports the following functions.

Image

{{#invoke:Infobox|Image|<file>||size=}}

Used by infobox templates to generate an image when Template:Media is not used.

Parameters

ParameterStatusDescriptionDefault value
1fileoptionalThe image parameter - a file name.
2captionoptionalThe caption parameter.
sizeoptionalImage size in pixels. Sprites are scaled to a maximum of 10 times their original size.320x320px

Examples

#InputOutputResult
1
{{#invoke:Infobox|Image|File:TWW Great Fairy Figurine Model.png}}
TWW Great Fairy Figurine Model.png
2
{{#invoke:Infobox|Image|File:TWW Great Fairy Figurine Model.png|Great Fairy Figurine|size= 250px}}
TWW Great Fairy Figurine Model.png
Great Fairy Figurine
Sprites are scaled to a maximum of 10 times their original size.
3
{{#invoke:Infobox|Image|File:ALttP Apple Sprite.png}}
ALttP Apple Sprite.png
Template:Media output is rendered as-is
4
{{#invoke:Infobox|Image|{{Media|Model TWW= TWW Great Fairy Figurine Model.png}}}}
TWW Great Fairy Figurine Model.png
Anything other than a file name starting with File: is rendered as-is
5
{{#invoke:Infobox|Image|{{Plural|Series|Cyber Pico Bloom}} are never seen in-game}}
Cyber Pico Blooms are never seen in-game

List

{{#invoke:Infobox|List|<param>}}

Used by infobox templates to turn comma-separated input into lists.

Parameters

ParameterStatusDescription
1paramoptionalThe infobox parameter

Examples

#InputOutputResult
6
{{#invoke:Infobox|List|A, B, C}}
  • A
  • B
  • C
Digit separators don't count.
7
{{#invoke:Infobox|List|1,500 Rupees}}
1,500 Rupees
{{,}} can be used to escape commas when an item itself contains a comma.
8
{{#invoke:Infobox|List|[[The Way of Sumo{{,}} Part I]], [[The Way of Sumo{{,}} Part II]], [[The Way of Sumo{{,}} Part III]]}}
9
{{#invoke:Infobox|List|A}}
A
10
{{#invoke:Infobox|List|}}
11
{{#invoke:Infobox|List}}
br tags are discouraged due to the poor HTML semantics.
12
{{#invoke:Infobox|List|A<br>B<br>C}}
  • A
  • B
  • C

Games

{{#invoke:Infobox|Games|<param>}}

Used by infobox templates to turn comma-separated game codes into lists of games.

Parameters

ParameterStatusDescription
1paramoptionalThe infobox parameter, usually {{{game|}}} or {{{other|}}}.

Examples

#InputOutputResult
13
{{#invoke:Infobox|Games|TLoZ, TAoL, ALttP}}
14
{{#invoke:Infobox|Games|TLoZ (Ran), BoMC, TLoZ (Susumu)}}
15
{{#invoke:Infobox|Games|}}
16
{{#invoke:Infobox|Games}}
17
{{#invoke:Infobox|Games|invalid game}}
18
{{#invoke:Infobox|Games|OoT, invalid game, TP}}
br tags are discouraged due to the poor HTML semantics.
19
{{#invoke:Infobox|Games|{{OoT}}<br>{{TP}}<br/>{{TotK}}}}

local p = {}
local h = {}

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 = "320x320px"
local CATEGORY_INVALID_ARGS = "[[Category:"..require("Module:Constants/category/invalidArgs").."]]"
local CATEGORY_PARAM_CAPTION = "[[Category:Infoboxes Using Captions]]"
local CATEGORY_PARAM_NAME = "[[Category:Infoboxes Using the Name Parameter]]"
local CATEGORY_BR_TAGS = "[[Category:Infoboxes Using br Tags]]"
local BR_TAGS_MSG = "Using <code><nowiki><br></nowiki></code> 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, "<br/?>")
	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, "<br>")
		games = utilsTable.flatMap(games, utilsString._split("<br/>"))
	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 <code>%s</code>. See [[Data:Franchise]] for a list of valid entries.", game))
		return nil
	elseif properCode and properCode ~= game then
		h.warn(string.format("<code>%s</code> should be written as <code>%s</code>", 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 <code>%s</code>", 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, "<br>")
			listItems = utilsTable.flatMap(listItems, utilsString._split("<br/>"))
		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("[[Guidelines:Articles#Infobox|Infobox]] for [[:Category:%s|%s]].", plural, string.lower(plural)),
		categories = {"Infobox Templates"},
		boilerplate = {
			separateRequiredParams = false,	
		},
		paramOrder = {"name", "image", "caption"},
		params = {
			name = {
				desc = "<p>Name to use in the infobox header. Defaults to {{Template|Page Name}}.</p><p>In general, this parameter should be omitted unless the title requires italics.</p>",
				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 [[Data:Franchise|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 [[:Category:Infobox Templates|infobox templates]] to turn comma-separated [[Data:Franchise|game codes]] into lists of games.",
			frameParams = {
				[1] = {
					name = "param",
					desc = "The infobox parameter, usually <code><nowiki>{{{game|}}}</nowiki></code> or <code><nowiki>{{{other|}}}</nowiki></code>.",
				},
			},
			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 = {"{{OoT}}<br>{{TP}}<br/>{{TotK}}"},
				},
			}
		},
		Image = {
			desc = "Used by [[:Category:Infobox Templates|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 = {"{{Media|Model TWW= TWW Great Fairy Figurine Model.png}}"}
				},
				{
					desc = "Anything other than a file name starting with <code>File:</code> is rendered as-is",
					args = {"{{Plural|Series|Cyber Pico Bloom}} are never seen in-game"},
				},
			},
		},
		List = {
			desc = "Used by [[:Category:Infobox Templates|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 = "{{Template|,}} 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<br>B<br>C"},
				}
			},
		},
	}
end

return p