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 = "[[Category:"..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
return 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)
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)
listItems = utilsString.split(listItems, "<br>")
listItems = utilsTable.flatMap(listItems, utilsString._split("<br/>"))
else
listItems = utilsString.split(listItems)
end
if #listItems == 1 then
return listItems[1]
else
return utilsMarkup.list(listItems)
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)
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,
}
})
}
p.Documentation = {
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 = "{{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"},
}
},
},
}
return p