This is the main module for the following templates:
In addition, this module exports the following functions.
color
color(quote, source, game)
Given a valid game and character (source), this function applies the main color used for that character's dialogue in-game.
Parameters
quote
- The quote to color
source
- The name of the character who speaks the quote.
game
- A game code. See Module:Franchise.
Returns
- The colored text
Examples
# | Input | Output | Result | Status | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | color(
"Only the true ruler of the Twili can destroy the Mirror of Twilight.",
"Midna",
"TPHD"
)
| '<span class="colored-text" style="color:#64b1b3">Only the true ruler of the Twili can destroy the Mirror of Twilight.</span>' | Only the true ruler of the Twili can destroy the Mirror of Twilight. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Not all characters have a unique color. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 | color("Tingle, Tingle! Kooloo-Limpah!", "Tingle", "MM")
| "Tingle, Tingle! Kooloo-Limpah!" | Tingle, Tingle! Kooloo-Limpah! |
local p = {}
local Color = require("Module:Color")
local Franchise = require("Module:Franchise")
local Guide = require("Module:Guide")
local Magazine = require("Module:Magazine")
local Term = require("Module:Term")
local utilsArg = require("Module:UtilsArg")
local utilsError = require("Module:UtilsError")
local utilsLanguage = require("Module:UtilsLanguage")
local utilsMarkup = require("Module:UtilsMarkup")
local utilsString = require("Module:UtilsString")
local utilsTable = require("Module:UtilsTable")
local Constants = mw.loadData("Module:Constants/Data")
local data = mw.loadData("Module:Cite/Data")
p.Templates = mw.loadData("Module:Cite/TemplateData")
local CAT_BOOK_QUOTES = "[[Category:Book Citations Using Quotes]]"
local CAT_INVALID_ARGS = "[[Category:"..Constants.category.invalidArgs.."]]"
function p.Main(frame)
local args, err = utilsArg.parse(frame:getParent().args, p.Templates.Cite)
local categories = err and err.categoryText or ""
local gameLink = args.game and Franchise.link(args.game)
local speakerDisplay = args.source or ""
if gameLink and args.source ~= "N/A" then -- if gameLink is not null here, it means `game` should be a valid term context
speakerDisplay = Term.printTerm(args.source, args.game, {
link = true,
plural = plural,
})
end
if args.game and not gameLink and not utilsMarkup.containsLink(args.game) then
utilsError.warn(utilsMarkup.code(mw.dumpObject(args.game)) .." is neither a valid [[Data:Franchise|code]] nor an interwiki link.")
categories = CAT_INVALID_ARGS
end
if args.game and Franchise.hasRemakes(args.game) then
categories = categories .. "[[Category:Articles Citing Games with Remakes]]"
end
local gameDisplay = gameLink or utilsMarkup.italic(args.game)
local sourceDisplay = table.concat({gameDisplay, args.version}, ", ")
local quoteDisplay = args.quote and p.color(args.quote, args.source, args.game)
local result = p.printCitation(sourceDisplay, quoteDisplay, speakerDisplay)
return result
end
function p.Book(frame)
local args, err = utilsArg.parse(frame:getParent().args, p.Templates["Cite Book"])
local categories = err and err.categoryText or ""
if args.quote then
categories = categories..CAT_BOOK_QUOTES
end
-- Backcompat for deprecated parameters
if args.game and args.author then
args.book = args.game .. " ("..args.author..")"
end
local bookTitle = args.book
if args.book and not p.hasItalics(args.book) then
local bookLink = Franchise.link(args.book)
if not bookLink then
utilsError.warn(string.format("<code>%s</code> must be a code from [[Data:Franchise]] or else be written with italics.", bookTitle))
categories = categories..CAT_INVALID_ARGS
else
bookTitle = bookLink
end
end
local phraseLink = args.book and Franchise.phraseLink(args.book) -- for manga and comics and such
if phraseLink then
local byAuthor = string.find(phraseLink, " by ")
if byAuthor then
phraseLink = phraseLink.sub(phraseLink, 1, byAuthor - 1) -- strip the "by <author>" part
end
bookTitle = phraseLink
end
if not bookTitle then
bookTitle = utilsError.error("book title required", true)
categories = categories..CAT_INVALID_ARGS
end
local publisher
if args.book and args.lang then
local bookData = data.books[args.book] and data.books[args.book][args.lang]
if not bookData then
utilsEror.warn(string.format("No data exists for book %s in language %s. See [[Module:Cite/Data]].", args.book, args.lang))
categories = categories..CAT_INVALID_ARGS
end
bookTitle = string.format("''[[%s|%s]]''", Franchise.article(args.book) or bookData.display, bookData.display)
publisher = bookData.publisher
end
if not publisher then
publisher = args.publisher and p.getPublisherFromShortcut(args.publisher) or (args.book and Franchise.publisher(args.book))
end
if not publisher then -- if after all that we still didn't manage to get a publisher...
publisher = utilsError.error("publisher required", true)
categories = categories..CAT_INVALID_ARGS
end
local source = args
source.title = bookTitle
source.publisher = publisher
local citation = p.printCitation(source, args.quote, args.character)
return citation, categories
end
-- Backwards compatibility for deprecated feature
function p.getPublisherFromShortcut(publisher)
local publishers = {
["enix"] = "Enix Corporation",
["nintendo"] = "Nintendo Co., Ltd.",
["piggyback"] = "Piggyback Interactive Limited",
["prima"] = "Prima Games",
["soleil"] = "Les Éditions Soleil",
["tokuma shoten"] = "Tokuma Shoten Publishing Co., Ltd.",
}
local fullName = publishers[string.lower(publisher)]
if fullName then
utilsError.warn(string.format("Publisher shortcuts are a deprecated feature. Please enter the full publisher name <code>%s</code> instead of <code>%s</code>", fullName, publisher))
return fullName..CAT_INVALID_ARGS
else
return publisher
end
end
function p.Guide(frame)
local args, err = utilsArg.parse(frame:getParent().args, p.Templates["Cite Guide"])
local categories = err and err.categoryText or ""
if args.quote then
categories = categories..CAT_BOOK_QUOTES
end
local guideArgs = {args.game, args.guide, "-"}
local guideTitle, guideCategories, guidePublisher = Guide.guide(guideArgs, "Guide", true)
categories = categories..guideCategories
if args.year or args.edition then
local editionYear = p.concat(", ", {args.edition, args.year})
guideTitle = guideTitle.." ("..editionYear..")"
end
local source = {
title = guideTitle,
publisher = guidePublisher,
page = args.page,
}
return p.printCitation(source, args.quote)..categories
end
function p.Magazine(frame)
local args, err = utilsArg.parse(frame:getParent().args, p.Templates["Cite Magazine"])
local categories = err and err.categoryText or ""
if not args.magazine then
return utilsError.error("Magazine name required")..categories
end
-- We use italics as the cue for a custom magazine name - otherwise the magazine must be one supported by [[Template:Magazine]]
if p.hasItalics(args.magazine) then
args.title = args.magazine
else
local err = utilsArg.enum(Magazine.enum(), args.magazine, "magazine")
if err then
categories = categories.."[["..err.category.."]]"
end
args.title = "''[["..args.magazine.."]]''"
if args.date then
args.date = string.format("[[%s (%s)|%s]]", args.magazine, args.date, args.date)
end
end
return p.printCitation(args, args.quote, args.interviewee, args.url)..categories
end
function p.Manual(frame)
local args, err = utilsArg.parse(frame:getParent().args, p.Templates["Cite Manual"])
local categories = err and err.categoryText or ""
if not args.game and not args.product then
categories = categories..CAT_INVALID_ARGS
return utilsError.error("game required"), categories
end
if args.game then
local gameLink = Franchise.link(args.game)
if not gameLink then
utilsError.warn(string.format("Invalid game <code>%s</code>. See [[Data:Franchise]] for supported games.", args.game))
categories = categories..CAT_INVALID_ARGS
else
args.title = gameLink
end
end
args.title = (args.title or args.game or args.product).." manual"
if args.version then
args.title = p.concat(", ", {args.title, args.version.." version"})
end
return p.printCitation(args, args.quote), categories
end
function p.color(quote, source, game)
local colorId = data.dialogueColors[game] and data.dialogueColors[game][source or "default"]
if colorId then
local coloredText, errCategories = Color.color(colorId, quote)
return coloredText .. (errCategories or "")
else
return quote
end
end
function p.printCitation(source, quote, speaker, archive)
if type(source) == "table" then
source = p.formatCitationSource(source)
end
local citation
if not utilsString.isBlank(quote) and not utilsString.isBlank(speaker) then
citation = string.format([["''%s''" — %s (%s)]], quote, speaker, source)
elseif not utilsString.isBlank(quote) then
citation = string.format([["''%s''" (%s)]], quote, source)
elseif not utilsString.isBlank(speaker) then
citation = string.format('%s (%s)', speaker, source)
else
citation = source
end
if archive then
citation = string.format("%s ([%s archive])", citation, archive)
end
return citation
end
function p.formatCitationSource(source)
local volume, issue, page = source.volume, source.issue, source.page
if volume then
volume = "vol. "..volume
end
if issue then
issue = "no. "..issue
end
if page then
page = "pg. "..page
else
page = "<sup>[[[:Category:Pages with Vague Citations|''which page?'']]]</sup>[[Category:Pages with Vague Citations]]"
end
local title = mw.getCurrentFrame():preprocess(source.title)
local titleVolumeIssue = p.concat(" ", {title, volume, issue})
local sourceText = p.concat(", ", {titleVolumeIssue, source.publisher, source.edition, source.date, page})
return sourceText
end
function p.concat(separator, items)
items = utilsTable.compact(items)
items = utilsTable.filter(items, utilsString.notBlank)
return table.concat(items, separator)
end
function p.hasItalics(str)
return string.find(str, "''.*''")
end
function p.Data()
-- Performance optimization; importing this at the top with the others adds processing time to Template:Cite
-- these dependencies are only needed on Module:Cite/Data/Documentation
local utilsLayout = require("Module:UtilsLayout")
local utilsTable = require("Module:UtilsTable")
local tableRows = {}
for bookCode, bookData in pairs(data.books) do
table.insert(tableRows, {
{
content = string.format("<code>[[%s|%s]]</code>", Franchise.article(bookCode) or bookCode, bookCode),
rowspan = utilsTable.size(bookData) + 1,
styles = {
["text-align"] = "center",
},
},
})
for i, langCode in ipairs(utilsLanguage.enum()) do
local bookLangData = bookData[langCode]
if bookLangData then
local language, flag = utilsLanguage.printLanguage(langCode)
table.insert(tableRows, {
{
content = flag .. " " .. language,
sortValue = language,
},
string.format("''[[%s|%s]]''", Franchise.article(bookCode) or bookLangData.display, bookLangData.display),
bookLangData.publisher
})
end
end
end
local booksTable = utilsLayout.table({
headers = {"Book", "Language", "Displayed Title", "Publisher"},
rows = tableRows,
sortable = true,
})
booksTable = utilsMarkup.heading(3, utilsMarkup.anchor("books", "Books in Other Languages"))..booksTable
local tableRows = {}
for _, game in ipairs(Franchise.enumGames()) do
local gameColors = data.dialogueColors[game]
if gameColors then
local colorKeys = utilsTable.keys(gameColors)
local sortedColorKeys = utilsTable.sortBy(colorKeys, function(key)
if key == "default" then
return "0" -- show default color first
elseif key == "N/A" then
return "1" -- then show color for N/A (i.e. in-game narration)
else
return key -- then show characters in alphabetical order
end
end)
for i, colorKey in ipairs(sortedColorKeys) do
local row = {}
if i == 1 then
table.insert(row, {
rowspan = #colorKeys,
content = utilsMarkup.code(utilsMarkup.link(Franchise.article(game), game)),
})
end
if colorKey == "default" or colorKey == "N/A" then
table.insert(row, utilsMarkup.code(colorKey))
else
table.insert(row, utilsMarkup.link(colorKey))
end
local colorSample = p.color("<b>The quick brown fox jumps over the lazy dog.</b>", colorKey, game)
table.insert(row, colorSample)
table.insert(tableRows, row)
end
end
end
local colorsTable = utilsLayout.table({
headers = {"Game", "Character/Source", "Color Sample"},
rows = tableRows,
styles = {
["text-align"] = "center"
},
sortable = true,
})
colorsTable = utilsMarkup.heading(3, utilsMarkup.anchor("colors", "Text Colors"))..colorsTable
return booksTable .. "\n" .. colorsTable
end
function p.Documentation()
return {
color = {
desc = "Given a valid game and character (source), this function applies the main color used for that character's dialogue in-game.",
params = {"quote", "source", "game"},
returns = "The colored text",
cases = {
{
args = {"Only the true ruler of the Twili can destroy the Mirror of Twilight.", "Midna", "TPHD"},
expect = '<span class="colored-text" style="color:#64b1b3">Only the true ruler of the Twili can destroy the Mirror of Twilight.</span>',
},
{
desc = "Not all characters have a unique color.",
args = {"Tingle, Tingle! Kooloo-Limpah!", "Tingle", "MM"},
expect = "Tingle, Tingle! Kooloo-Limpah!"
}
}
}
}
end
function p.Schemas()
return {
Data = {
type = "record",
required = true,
properties = {
{
name = "books",
required = true,
desc = "Associates a book code from [[Data:Franchise]] to information about the publication of the book in other languages. Used by [[Template:Cite Book]].",
type = "map",
keyPlaceholder = "bookCode",
keys = { type = "string" },
values = {
type = "map",
keyPlaceholder = "langCode",
keys = {
type = "string",
enum = utilsLanguage.enum(),
desc = "A language code from [[Module:UtilsLanguage/Data]].",
},
values = {
type = "record",
properties = {
{
name = "display",
required = true,
type = "string",
desc = "The text to display when referring to the book - typically its subtitle.",
},
{
name = "publisher",
required = true,
type = "string",
desc = "The book's publisher."
},
},
},
},
},
{
name = "dialogueColors",
required = true,
desc = "Associates game characters to color IDs from [[Template:Color]]. Used by [[Template:Cite]] to determine the character's default quote text color.",
type = "map",
keyPlaceholder = "gameCode",
keys = {
type = "string",
desc = "A game code from [[Data:Franchise]].",
},
values = {
allOf = {
{
type = "map",
keyPlaceholder = "character",
keys = {
type = "string",
desc = "The name of a character in the game, or the special value <code>N/A</code>. The former should refer to a page on the wiki, using parentheses if necessary. For example, the entry for [[Wood (Character)|Wood]] in {{ST|-}} would be <code>Wood (Character)</code>.",
},
values = { type = "string" },
},
{
type = "record",
properties = {
{
name = "default",
type = "string",
desc = "Sets the default text color for quotes from the given game.",
},
},
},
},
},
},
},
},
color = {
quote = {
required = true,
type = "string",
desc = "The quote to color",
},
game = {
required = true,
type = "string",
desc = "A game code. See [[Module:Franchise]].",
},
source = {
required = true,
type = "string",
desc = "The name of the character who speaks the quote.",
},
}
}
end
return p