(Created page with "local p = {} local args = {} local origArgs = {} local root local empty_row_categories = {} local category_in_empty_row_pattern = '%[%[%s*[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]%s*:[^]]*]]' local has_rows = false local lists = { plainlist_t = { patterns = { '^plainlist$', '%splainlist$', '^plainlist%s', '%splainlist%s' }, found = false, styles = 'Plainlist/styles.css' }, hlist_t = { patterns = { '^hlist$', '%shlist$', '^hlist%s', '%shlist%s'...") |
No edit summary |
||
(One intermediate revision by the same user not shown) | |||
Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
local | local h = {} | ||
local | |||
local | local File = require("Module:File") | ||
local | local Franchise = require("Module:Franchise") | ||
local | local Term = require("Module:Term") | ||
local | local utilsArg = require("Module:UtilsArg") | ||
local | local utilsMarkup = require("Module:UtilsMarkup") | ||
local utilsString = require("Module:UtilsString") | |||
local utilsTable = require("Module:UtilsTable") | |||
local | 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 | 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 | else | ||
args = frame:getParent().args | |||
end | end | ||
categories = err and err.categoryText or "" | |||
if args.name and args.name ~= "" then | |||
categories = categories..CATEGORY_PARAM_NAME | |||
if | |||
end | end | ||
if args.caption and args.caption ~= "" then | |||
categories = categories..CATEGORY_PARAM_CAPTION | |||
end | end | ||
local | |||
local styles = frame:extensionTag({ | |||
name = "templatestyles", | |||
args = { src = "Module:Infobox/Styles.css" } | |||
return | }) | ||
return styles, categories | |||
end | end | ||
function p.Image(frame) | |||
local file = frame.args[1] | |||
local caption = frame.args[2] | |||
if file == nil or file == "" then | |||
local | 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 | |||
-- or | mw.ext.seo.set({ | ||
image = file | |||
}) | |||
) | |||
end | end | ||
if caption and caption ~= "" then | |||
local html = mw.html.create("div") | |||
:addClass("infobox__image-caption") | |||
:wikitext(caption) | |||
image = image .. tostring(html) | |||
end | end | ||
return image | |||
end | end | ||
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 | |||
if | |||
end | end | ||
games = utilsString.split(games) | |||
local | local gameLinks = utilsTable.map(games, p.link) | ||
if | local gameLinks = utilsTable.compact(gameLinks) | ||
if #gameLinks ~= #games then | |||
categories = categories..CATEGORY_INVALID_ARGS | |||
end | end | ||
if | |||
if #gameLinks == 1 then | |||
return gameLinks[1], categories | |||
else | else | ||
local gameList = utilsMarkup.list(gameLinks) | |||
return gameList, categories | |||
end | end | ||
end | end | ||
function p.link(game) | |||
if utilsMarkup.containsLink(game) then | |||
if | return game | ||
end | 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 | end | ||
return link..notes | |||
end | end | ||
function p.GameBlocks(frame) | |||
local | local args = frame:getParent().args | ||
local blocks, categories = h.parseBlocks(args) | |||
local | local html = mw.html.create("ul"):addClass("infobox-game-blocks") | ||
for i, block in ipairs(blocks) do | |||
local gameText = html | |||
for | :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 | 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 | ||
end | end | ||
return tostring(html), categories | |||
end | end | ||
function h.parseBlocks(args) | |||
local categories = "" | |||
local | 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 | ||
end | 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, { | |||
local | 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 | 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 | |||
for | |||
end | end | ||
end | end | ||
return blocks, categories | |||
return | |||
end | end | ||
function p.Title(frame) | |||
local subpageName = mw.title.getCurrentTitle().subpageText | |||
local term = Term.fetchTerm(subpageName, "Series") | |||
return term or utilsString.stripTrailingParentheses(subpageName) | |||
end | end | ||
function h.warn(msg, ...) | |||
local utilsError = require("Module:UtilsError") | |||
local warnMessage = string.format(msg, ...) | |||
utilsError.warn(warnMessage, { | |||
includeInstance = false, | |||
}) | |||
end | end | ||
local templateSpec = function(args) | |||
local singular = args.singular | |||
local function | 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 | end | ||
for i, param in ipairs(productionParams or {}) do | |||
spec.params[param.name] = param | |||
table.insert(spec.paramOrder, param.name) | |||
for i, | |||
end | end | ||
return spec | |||
end | 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 | end | ||
return p | return p |
Latest revision as of 08:17, 6 August 2024
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