Documentation for this module may be created at Module:Infobox/doc
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 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 CLASS_TOOLTIP = require("Module:Constants/class/tooltip") local DEFAULT_IMG_SIZE = "320x320px" 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, 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 games = utilsString.split(games) 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 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) 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"}, }, } }, 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