Module:Cite

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") local DocData = mw.loadData("Module:Cite/Documentation/Data")

local CAT_BOOK_QUOTES = "" local CAT_INVALID_ARGS = ""

function p.Main(frame) local args, err = utilsArg.parse(frame:getParent.args, DocData.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 code nor an interwiki link.") categories = CAT_INVALID_ARGS end if args.game and Franchise.hasRemakes(args.game) then categories = categories .. ""	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, DocData.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(" 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 " 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", 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  instead of  ", fullName, publisher)) return fullName..CAT_INVALID_ARGS else return publisher end end

function p.Guide(frame) local args, err = utilsArg.parse(frame:getParent.args, DocData.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, DocData.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", 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, DocData.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 . 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 = "&#91;which page?&#93;" 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(" ", 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", 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("The quick brown fox jumps over the lazy dog.", 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

return p