Module:Infobox

From Zelda Wiki, the Zelda encyclopedia
Jump to navigation Jump to search
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

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
6
{{#invoke:Infobox|Games|TLoZ, TAoL, ALttP}}
7
{{#invoke:Infobox|Games|TLoZ (Ran), BoMC, TLoZ (Susumu)}}
8
{{#invoke:Infobox|Games|}}
9
{{#invoke:Infobox|Games}}
10
{{#invoke:Infobox|Games|invalid game}}
11
{{#invoke:Infobox|Games|OoT, invalid game, TP}}
br tags are discouraged due to the poor HTML semantics.
12
{{#invoke:Infobox|Games|{{OoT}}<br>{{TP}}<br/>{{TotK}}}}

local p = {}
local h = {}

local File = require("Module:File")
local Franchise = require("Module:Franchise")
local Term = require("Module:Term")
local utilsArg = require("Module:UtilsArg")
local utilsMarkup = require("Module:UtilsMarkup")
local utilsString = require("Module:UtilsString")
local utilsTable = require("Module:UtilsTable")
local utilsVar = require("Module:UtilsVar")

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 CATEGORY_BR_TAGS_GAME = "[[Category:Infoboxes using br tags in game fields]]"
local CLASS_TOOLTIP = require("Module:Constants/class/tooltip")
local DEFAULT_IMG_SIZE = "320x320px"
local VAR_IS_AFTER_INFOBOX = require("Module:Constants/var/isAfterInfobox")

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
	
	for k, v in pairs(args) do
		if string.find(v, "<br") then
			h.warn("It appears the <code>%s</code> field may be using <code><nowiki><br></nowiki></code> tags to create a list. If so, please use [[Template:List]] or [[Template:Infobox Game Blocks]] instead. See [[:Category:Infoboxes using br tags]] for more information.", k)
			categories = categories..CATEGORY_BR_TAGS
		end
	end
	
	local styles = frame:extensionTag({
		name = "templatestyles",
		args = { src = "Module:Infobox/Styles.css" }
	})

	utilsVar.set(VAR_IS_AFTER_INFOBOX, true)
	
	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, exists = 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 exists then
			-- Set this image as the article's representative image for things like page previews
			mw.ext.seo.set({
				image = file
			})
		end
		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.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
		categories = categories..CATEGORY_BR_TAGS_GAME
		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 game, notes = utilsMarkup.separateMarkup(game)
	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..notes
end

function p.GameBlocks(frame)
	local args = frame:getParent().args
	local blocks, categories = h.parseBlocks(args)
	
	local html = mw.html.create("ul"):addClass("infobox-game-blocks")
	for i, block in ipairs(blocks) do
		local gameText = html
			:tag("li")
			:addClass("infobox-game-blocks__game")
			:tag("span")
				:addClass("infobox-game-blocks__game-text")
		local game = gameText:done()
	
		if blocks.compact then
			gameText:wikitext(Franchise.display(block.game))
			local gameList = game
				:tag("ul")
				:addClass("infobox-game-blocks__game-list")
			for j, listItem in ipairs(block.listItems) do
				gameList
					:tag("li")
					:addClass("infobox-game-blocks__game-list-item")
					:wikitext(listItem)
			end
		else
			html:addClass("infobox-game-blocks--compact")
			gameText
				:tag("span")
					:addClass(CLASS_TOOLTIP)
					:attr("title", Franchise.shortName(block.game))
					:wikitext(block.game)
					:done()
				:wikitext(": ")
			game:wikitext(block.listItems[1])
		end
	end

	return tostring(html), categories
end
function h.parseBlocks(args)
	local categories = ""

	local seenParams = {}
	local blocks = {}
	blocks.compact = false
	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 and string.find(listItems, ", %l") then
			h.warn("Lowercase character detected following comma. Within <code>Template:Infobox Game Blocks</code>, commas are used to separate list items. All list items should be in sentence case. Literal commas can be escaped using {{Template|,}}.")
			categories = categories..CATEGORY_INVALID_ARGS
		end
		if listItems and string.find(listItems, "<br") then
			h.warn("Using <code><nowiki><br></nowiki></code> tags to create lists is discouraged. Use commas instead, as this template treats them as delimiters. See [[Template:Infobox Game Blocks]] for more information.")
			categories = categories..CATEGORY_BR_TAGS
			listItems = utilsString.split(listItems, "<br>")
			listItems = utilsTable.flatMap(listItems, utilsString._split("<br/>"))
		elseif listItems then
			listItems = utilsString.split(listItems, '%s*,%f[^,%d]%s*') -- %f[^,%d] is so we don't split numbers on their thousands separator (e.g., 1,500)
		end
		if listItems then
			table.insert(blocks, {
				game = game, 
				listItems = listItems,
			})
		end
		local hasDiv = listItems and listItems[1] and string.find(listItems[1], "<div") -- See [[Minuet of Forest]] "Notes" field, for example
		if listItems and #listItems > 1 or hasDiv then
			blocks.compact = true
		end
		if listItems and listItems[1] and string.find(listItems[1], "plainlist") then
			blocks.compact = true
		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
	
	return blocks, categories
end

function p.Title(frame)
	local subpageName = mw.title.getCurrentTitle().subpageText
	local term = Term.fetchTerm(subpageName, "Series")
	return term or utilsString.stripTrailingParentheses(subpageName)
end

function h.warn(msg, ...)
	local utilsError = require("Module:UtilsError")
	local warnMessage = string.format(msg, ...)
	utilsError.warn(warnMessage, {
		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 = "writer",
				desc = "The writer(s) of the film.",
				type = "content",
			},
			{
				name = "production",
				desc = "The companies producing the film.",
				type = "content",
			},
			{
				name = "distributor",
				desc = "The companies distributing 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"},
				},
			},
		},
	}
end

return p