Module:Comment
Jump to navigation
Jump to search
This module is invoked by templates in Category:Comment Templates.
The corresponding stylesheet for this module is Module:Comment/Styles.css.
This is the main module for the following templates: In addition, this module exports the following functions.MultiComment
{{#invoke:Comment|MultiComment|<game>|<commenter>|<commenterFileName>|<borderColor>|headingPlural=|headingSingular=}}
Invoked by comment templates which support multiple quotes per subject. Examples include Template:Fi, Template:Midna, and Template:Tingle among others.
Parameters
Parameter | Status | Description | Default value | |
---|---|---|---|---|
1 | game | required | A game code referring to the latest remake of the game in question. | |
2 | commenter | required | The name of the commenter in question. Should refer to an article name. | |
3 | commenterFileName | required | The image to display for the commenter. Icon are preferred, e.g. File:SSHD Fi Icon.png . | |
4 | borderColor | optional | An HTML color code, to use as a border color around the commenter's quote bubbles. | |
headingPlural | optional | Sets the heading text for the comment when there are two or more quotes. | commenter 's Comments | |
headingSingular | optional | Sets the heading text for the comment. | commenter 's Comment |
SingleComment
{{#invoke:Comment|SingleComment|<game>|<commenter>|<commenterFileName>|<borderColor>|headingSingular=}}
Invoked by comment templates which support only one quote per subject. Examples include Template:Fishman, Template:Happy Mask Salesman, and Template:Madame Couture among others.
Parameters
Parameter | Status | Description | Default value | |
---|---|---|---|---|
1 | game | required | A game code referring to the latest remake of the game in question. | |
2 | commenter | required | The name of the commenter in question. Should refer to an article name. | |
3 | commenterFileName | required | The image to display for the commenter. Icon are preferred, e.g. File:SSHD Fi Icon.png . | |
4 | borderColor | optional | An HTML color code, to use as a border color around the commenter's quote bubbles. | |
headingSingular | optional | Sets the heading text for the comment when there is only one quote. | commenter 's Comment |
GenerateDocumentation
{{#invoke:Comment|GenerateDocumentation|<function>|<game>|<commenter> |bosses= |characters= |dungeons= |enemies= |locations= |custom-topics= |guidelines-placement= |guidelines-formatting= }}
Auto-generates documentation for comment templates. See for example Template:Midna/Documentation, Template:Monita/Documentation, Template:Fishman/Documentation.
Parameters
Parameter | Status | Description | Accepted values | |
---|---|---|---|---|
1 | function | required | The name of the function invoked in the template. Determines whether to generate documentation for multi-comment or single-comment usage. |
|
2 | game | required | The game code of the game in question. Should be the same value as in the main template invocation, e.g. SSHD for Template:Fi. | |
3 | commenter | required | The commenter in question. This should be the same value as in the main template invocation, e.g. Fi for Template:Fi. | |
bosses | optional | Set this to true if the commenter comments on most bosses. | ||
characters | optional | Set this to true if the commenter comments on most characters. | ||
dungeons | optional | Set this to true if the commenter comments on most dungeons. | ||
enemies | optional | Set this to true if the commenter comments on most enemies. | ||
locations | optional | Set this to true if the commenter comments on most locations. | ||
custom-topics | optional | A comma-separated list of topics that the commenter comments on, in addition to or instead of the above. See Template:Tingle/Documentation and Template:Happy Mask Salesman/Documentation for example usages. | ||
guidelines-placement | optional | Custom guidelines for how the template should be placed relative to other article content, if different from the usual standard for comment templates. See Template:Tingle/Documentation for example usage. | ||
guidelines-formatting | optional | Custom guidelines for how quotes should be formatted, if different from the usual standard for comment templates. See Template:Monita/Documentation for example usage. |
local p = {}
local Cite = require("Module:Cite")
local Franchise = require("Module:Franchise")
local utilsArg = require("Module:UtilsArg")
local utilsError = require('Module:UtilsError')
local utilsMarkup = require("Module:UtilsMarkup")
local utilsString = require("Module:UtilsString")
local utilsTable = require("Module:UtilsTable")
local CAT_INVALID_ARGS = "[[Category:"..require("Module:Constants/category/invalidArgs").."]]"
local CLASS_PIXEL_ART = require("Module:Constants/class/pixelArt")
local COMMENTER_IMAGE_SIZE = "80x80px"
local MANUAL_LOGO_SIZE = "150px"
local STYLES = "Module:Comment/Styles.css"
-- [[Template:Manual]]
function p.Manual(frame)
local args, err = utilsArg.parse(frame:getParent().args, p.Templates.Manual)
local errorCategories = err and utilsMarkup.categories(err.categories) or ""
local result = p.printManualComment(args.game, args.subject, args.quote)
return result..errorCategories
end
-- [[Template:Fi]], among others
function p.MultiComment(frame)
local args, err = utilsArg.parse(frame:getParent().args, p.Templates.MultiComment)
local errorCategories = err and utilsMarkup.categories(err.categories) or ""
local result = p.printComments(frame.args[1], frame.args[2], frame.args[3], frame.args[4], args.quotes, frame.args["headingSingular"], frame.args["headingPlural"])
return result..errorCategories
end
-- [[Template:Fishman]], among others
function p.SingleComment(frame)
local args, err = utilsArg.parse(frame:getParent().args, p.Templates.SingleComment)
local errorCategories = err and utilsMarkup.categories(err.categories) or ""
local quote = {
quote = args.quote
}
local quotes = {quote}
local result = p.printComments(frame.args[1], frame.args[2], frame.args[3], frame.args[4], quotes, frame.args["headingSingular"])
return result..errorCategories
end
-- Auto-generates documentation for comment templates
-- See [[Template:Fishman/Documentation]] for example
function p.GenerateDocumentation(frame)
return p.documentation(frame)
end
function p.printManualComment(game, subject, quote)
if not game or not subject or not quote then
return ""
end
local gameArticle = Franchise.article(game)
local gameDisplay = Franchise.display(game)
local gameLogo = Franchise.logo(game)
if not gameDisplay then -- game not defined at [[Data:Franchise]]
return ""
end
gameLogo = utilsMarkup.file(gameLogo, {
size = MANUAL_LOGO_SIZE,
link = gameArticle,
caption = gameDisplay .. " logo",
})
local manualEntry = mw.html.create("div")
:addClass("comments__entry")
:tag("div")
:addClass("comments__entry-img")
:wikitext(gameLogo)
:done()
:tag("div")
:addClass("comments__entry-text")
:tag("div")
:addClass("comments__subject")
:wikitext(subject)
:done()
:tag("div")
:addClass("comments__description")
:wikitext(quote)
:done()
:done()
local quoteBubble = p.quoteBubble(manualEntry)
local heading = string.format("%s Manual Description", gameDisplay)
local modifiers = {"manual", "manual-"..utilsString.kebabCase(game)}
local html = p.commentContainer(modifiers)
:node(quoteBubble)
:done()
local collapsible = mw.getCurrentFrame():expandTemplate({
title = "Collapsible",
args = {
header = heading,
content = tostring(html)
}
})
local styles = mw.getCurrentFrame():extensionTag({
name = "templatestyles",
args = { src = STYLES }
})
return styles..collapsible
end
function p.printComments(game, commenter, commenterFileName, quoteBorderColor, quotes, headingSingular, headingPlural)
local categories = ""
if #quotes == 0 then
utilsError.warn("Please provide at least one quote.")
categories = categories..CAT_INVALID_ARGS
return categories
end
local img = utilsMarkup.file(commenterFileName, {
size = COMMENTER_IMAGE_SIZE,
link = commenter,
caption = commenter.." says:",
class = utilsString.endsWith(commenterFileName, "Sprite.png") and CLASS_PIXEL_ART or nil,
})
local commentsHeading
if #quotes == 1 then
commentsHeading = headingSingular or string.format("%s's Comment", commenter)
else
commentsHeading = headingPlural or string.format("%s's Comments", commenter)
end
local modifier = utilsString.kebabCase(commenter)
local content = p.commentContainer({modifier})
local quote = quotes[1]
local additionalQuotes = utilsTable.tail(quotes)
local firstComment = content:tag("div")
:addClass("comments__first-comment")
if quote.context then
firstComment:tag("span")
:addClass("comments__quote-context")
:wikitext(quote.context)
end
firstComment:tag("div")
:addClass("comments__commenter")
:wikitext(img)
local coloredQuote = Cite.color(quote.quote, commenter, game)
local quoteBubble = p.quoteBubble(coloredQuote, quoteBorderColor)
firstComment:node(quoteBubble)
if #additionalQuotes > 0 then
local collapsedContent = content:tag("div")
:addClass("mw-collapsible mw-collapsed comments__additional-comments")
:attr("id", "mw-customcollapsible-additionalComments"..commenter)
:tag("span")
:addClass("comments__toggle-more mw-customtoggle-additionalComments"..commenter)
:wikitext("show more...")
:done()
:tag("div")
:addClass("mw-collapsible-content comments__additional-comments-content")
for i, quote in ipairs(additionalQuotes) do
collapsedContent:tag("div")
:addClass("comments__spacer")
:attr("aria-hidden", "true")
if quote.context then
collapsedContent:tag("span")
:addClass("comments__quote-context")
:wikitext(quote.context)
elseif commenter ~= "Fi" then
-- we make an exception for Fi because for bosses she has several comments separated by "tell me more" prompts
-- It would be redundant to show "tell me more" for multiple quotes
utilsError.warn("The <code>context</code> parameter should be used when there are more than one comment.")
categories = categories .. string.format("[[Category:%s articles needing attention]]", Franchise.shortName(Franchise.baseGame(game)))
end
local coloredQuote = Cite.color(quote.quote, commenter, game)
local quoteBubble = p.quoteBubble(coloredQuote, quoteBorderColor)
collapsedContent:node(quoteBubble)
end
end
local result = tostring(content:allDone())
local collapsible = mw.getCurrentFrame():expandTemplate({
title = "Collapsible",
args = {
header = commentsHeading,
content = result,
}
})
local styles = mw.getCurrentFrame():extensionTag({
name = "templatestyles",
args = { src = STYLES }
})
return styles..collapsible..categories
end
function p.commentContainer(modifiers)
-- Custom class names use BEM syntax https://getbem.com/
local blockClasses = "comments"
for i, modifier in ipairs(modifiers) do
blockClasses = blockClasses.." comments--"..modifier -- modifier classes allow custom styling for different comment templates
end
return mw.html.create("div")
:addClass(blockClasses)
end
function p.quoteBubble(quote, borderColor)
local bubble = mw.html.create("blockquote")
:addClass("comments__quote-bubble")
-- We use an inline style here so that folks can make new comment templates
-- without having to edit two additional CSS files, which few know how to or have the rights to do
:css("border-color", borderColor)
if type(quote) == "string" then
bubble:wikitext(quote)
else -- assume the quote is an mw.html builder object
bubble:node(quote)
end
return bubble
end
function p.documentation(frame)
-- Only the documentation needs these so we require them here as an optimization
local Documentation = require("Module:Documentation")
local utilsString = require("Module:UtilsString")
local args = utilsTable.mapValues(frame.args, utilsString.trim)
args = utilsTable.mapValues(args, utilsString.nilIfEmpty)
local templateName = args[1]
local game = args[2]
local commenter = args[3]
local examples = args.examples
local baseGame = Franchise.baseGame(game)
local gameName = Franchise.shortName(baseGame)
local gameDisplay = Franchise.display(baseGame)
local topics = {
args["bosses"] == "true" and args["enemies"] ~= "true" and string.format("[[Bosses in %s|bosses]]", gameName),
args["characters"] == "true" and string.format("[[Characters in %s|characters]]", gameName),
args["dungeons"] == "true" and args["dungeons"] ~= "true" and string.format("[[Dungeons in %s|dungeons]]", gameName),
args["enemies"] == "true" and string.format("[[Enemies in %s|enemies]]", gameName),
args["locations"] == "true" and string.format("[[Locations in %s|locations]]", gameName),
}
topics = utilsTable.compact(topics)
local customTopics = args["custom-topics"]
if customTopics then
customTopics = utilsString.split(customTopics)
topics = utilsTable.concat(topics, customTopics)
end
topics = mw.text.listToText(topics)
local templatePurpose = string.format("This template displays quote bubbles containing [[%s]]'s comments on %s in %s.", commenter, topics, gameDisplay)
local templateSpec = utilsTable.merge(p.Templates[templateName], {
purpose = templatePurpose
})
local templateDoc = Documentation.printTemplateDoc("Module:Comments", templateName, templateSpec)
if examples then
templateDoc = templateDoc .. utilsMarkup.heading(3, "Examples") .. "\n"
templateDoc = templateDoc .. frame:preprocess(examples)
end
-- Guidelines
templateDoc = templateDoc .. utilsMarkup.heading(2, "Guidelines") .. "\n"
local customPlacementGuidelines = args["guidelines-placement"]
local customFormattingGuidelines = args["guidelines-formatting"]
if not utilsString.isEmpty(customPlacementGuidelines) then
templateDoc = templateDoc .. frame:preprocess(customPlacementGuidelines)
else
templateDoc = templateDoc .. string.format("This template should be placed on the line beneath the %s heading, or under the first heading if the article is about %s specifically. There should be one line of empty space between the template transclusion and the article content.", gameDisplay, gameDisplay)
end
templateDoc = templateDoc .. "\n\n"
if not utilsString.isEmpty(customFormattingGuidelines) then
templateDoc = templateDoc .. frame:preprocess(customFormattingGuidelines)
else
templateDoc = templateDoc .. frame:preprocess("Use <code><nowiki><p></nowiki></code> tags to separate blocks of dialogue. A block of dialogue consists of all the text that appears before the player must prompt the dialogue to continue using their controller.")
end
if Franchise.isRemake(game) then
templateDoc = templateDoc .. string.format("\n\nAll quotes should reference the updated remake of the game, %s. If the comment from a previous iteration of the game is notably different, it can be included as a separate quote.", Franchise.link(game))
end
return templateDoc
end
local quoteDesc = string.format("The complete description given by %s on the subject, quoted word-for-word. Use [[Template:Color]], [[Template:Icon]], [[Template:Player Name]], and [[Template:Typo]] as needed.", mw.title.getCurrentTitle().baseText)
p.Templates = {
Manual = {
format = "inline",
purpose = "This template is used to provide a text box holding the comments on various {{Plural|Series|Enemy|link}}, {{Plural|Series|Item|link}}, Locations, and Characters in {{TLoZ|Series}} that are given by game manuals.",
params = {
[1] = {
name = "game",
required = true,
type = "string",
enum = Franchise.enum({includeGroups = true}), -- includeGroups is for ALttP&FS
desc = "The abbreviation for the game the manual is associated with.",
trim = true,
nilIfEmpty = true,
},
[2] = {
name = "subject",
required = true,
type = "string",
desc = "The name of the subject being described, as it appears in the manual.",
trim = true,
nilIfEmpty = true,
},
[3] = {
name = "quote",
required = true,
type = "content",
desc = "The complete description given by the manual on the subject, quoted word-for-word. Use [[Template:Color]], [[Template:Icon]], [[Template:Player Name]], and [[Template:Typo]] as needed.",
trim = true,
nilIfEmpty = true,
},
},
examples = {
{"ALttP", "Bomb", "A bomb blast will damage enemies and knock holes in some walls, but it will also damage your character if he is too close to the blast. The bomb's fuse will burn for about two seconds, and up to two bombs can be set at a time. You can also pick up a bomb you have placed and throw it before it explodes (be careful!)."},
{"ALttP&FS", "Bomb", "You can set up to two bombs at a time. You can also pick them up and throw them."},
{"alttp", "Bomb", "Inputting the game abbreviation in lowercase still works, but the template will complain about it with a [[Template:Warn|warning]]."},
{"notAGame", "foo", "bar"},
{
desc = "All parameters are required.",
args = {},
},
},
},
SingleComment = {
format = "inline",
params = {
[1] = {
name = "quote",
required = true,
type = "content",
desc = quoteDesc,
trim = true,
nilIfEmpty = true,
},
},
},
MultiComment = {
format = "block",
repeatedGroup = {
name = "quotes",
params = {"context", "quote"},
counts = {1, 2, 3, 4, 5, 6, 7, 8},
},
params = {
quote = {
required = true,
type = "content",
desc = quoteDesc,
trim = true,
nilIfEmpty = true,
},
context = {
type = "string",
desc = "A description of where or when the quote appears. Only needed when there are multiple quotes in different contexts. Generally not needed for the first quote.",
type = "string",
trim = true,
nilIfEmpty = true,
},
},
},
}
function p.Documentation()
return {
MultiComment = {
desc = "Invoked by [[:Category:Comment Templates|comment templates]] which support multiple quotes per subject. Examples include [[Template:Fi]], [[Template:Midna]], and [[Template:Tingle]] among others.",
frameParams = {
[1] = {
name = "game",
required = true,
desc = "A [[Data:Franchise|game code]] referring to the latest remake of the game in question.",
},
[2] = {
name = "commenter",
required = true,
desc = "The name of the commenter in question. Should refer to an article name.",
},
[3] = {
name = "commenterFileName",
required = true,
desc = "The image to display for the commenter. Icon are preferred, e.g. <code>File:SSHD Fi Icon.png</code>."
},
[4] = {
name = "borderColor",
desc = "An HTML color code, to use as a border color around the commenter's quote bubbles.",
},
["headingSingular"] = {
desc = "Sets the heading text for the comment.",
default = "<code>commenter</code>'s Comment",
},
["headingPlural"] = {
desc = "Sets the heading text for the comment when there are two or more quotes.",
default = "<code>commenter</code>'s Comments",
},
},
},
SingleComment = {
desc = "Invoked by [[:Category:Comment Templates|comment templates]] which support only one quote per subject. Examples include [[Template:Fishman]], [[Template:Happy Mask Salesman]], and [[Template:Madame Couture]] among others.",
frameParams = {
[1] = {
name = "game",
required = true,
desc = "A [[Data:Franchise|game code]] referring to the latest remake of the game in question.",
},
[2] = {
name = "commenter",
required = true,
desc = "The name of the commenter in question. Should refer to an article name.",
},
[3] = {
name = "commenterFileName",
required = true,
desc = "The image to display for the commenter. Icon are preferred, e.g. <code>File:SSHD Fi Icon.png</code>."
},
[4] = {
name = "borderColor",
desc = "An HTML color code, to use as a border color around the commenter's quote bubbles.",
},
["headingSingular"] = {
desc = "Sets the heading text for the comment when there is only one quote.",
default = "<code>commenter</code>'s Comment",
},
},
},
GenerateDocumentation = {
desc = "Auto-generates documentation for comment templates. See for example [[Template:Midna/Documentation]], [[Template:Monita/Documentation]], [[Template:Fishman/Documentation]].",
frameParamsOrder = {"bosses", "characters", "dungeons", "enemies", "locations", "custom-topics", "guidelines-placement", "guidelines-formatting"},
frameParamsFormat = "multiLine",
frameParams = {
[1] = {
name = "function",
required = true,
inline = true,
enum = {"SingleComment", "MultiComment"},
desc = "The name of the function invoked in the template. Determines whether to generate documentation for multi-comment or single-comment usage.",
},
[2] = {
name = "game",
required = true,
inline = true,
desc = "The [[Data:Franchise|game code]] of the game in question. Should be the same value as in the main template invocation, e.g. <code>SSHD</code> for Template:Fi.",
},
[3] = {
name = "commenter",
required = true,
inline = true,
desc = "The commenter in question. This should be the same value as in the main template invocation, e.g. <code>Fi</code> for Template:Fi.",
},
bosses = {
desc = "Set this to <code>true</code> if the commenter comments on most bosses.",
},
characters = {
desc = "Set this to <code>true</code> if the commenter comments on most characters.",
},
dungeons = {
desc = "Set this to <code>true</code> if the commenter comments on most dungeons.",
},
enemies = {
desc = "Set this to <code>true</code> if the commenter comments on most enemies.",
},
locations = {
desc = "Set this to <code>true</code> if the commenter comments on most locations." ,
},
["custom-topics"] = {
desc = "A comma-separated list of topics that the commenter comments on, in addition to or instead of the above. See [[Template:Tingle/Documentation]] and [[Template:Happy Mask Salesman/Documentation]] for example usages.",
},
["guidelines-placement"] = {
desc = "Custom guidelines for how the template should be placed relative to other article content, if different from the usual standard for comment templates. See [[Template:Tingle/Documentation]] for example usage.",
spaceBefore = true,
},
["guidelines-formatting"] = {
desc = "Custom guidelines for how quotes should be formatted, if different from the usual standard for comment templates. See [[Template:Monita/Documentation]] for example usage.",
},
},
}
}
end
return p