Module:Gallery List

local p = {} local Data = mw.loadData("Module:Gallery List/Data")

local Franchise = require("Module:Franchise") local Term = require("Module:Term") local TermList = require("Module:Term List") local utilsArg = require("Module:UtilsArg") local utilsLayout = require("Module:UtilsLayout") local utilsPackage = require("Module:UtilsPackage") local utilsString = require("Module:UtilsString") local utilsTable = require("Module:UtilsTable") local _utilsError = utilsPackage.lazyLoad("Module:UtilsError")

local CATEGORY_INVALID_ARGS = ""

-- Generally the latest remake is the default tab but some remakes don't have enough high quality images uploaded yet local DEFAULT_TAB_DENYLIST = { ["OoT3D"] = true, ["MM3D"] = true, ["TPHD"] = true, ["SSHD"] = true, }

-- Enhanced ports may have the same assets as the original game -- There's no need to show a separate tab in those cases local ENHANCED_PORTS = { --["FSAE"] = true -- turns out FSAE does have its own sprites }

function p.Main(frame) local args, err = utilsArg.parse(frame:getParent.args, p.Templates["Gallery List"]) local categories = err and err.categoryText or "" local subjectType = args.subjectType local pagename = mw.title.getCurrentTitle.text

local tabData = {} local defaultTab = 1 for i, game in ipairs(Franchise.enumGames) do		local isListing = utilsString.endsWith(pagename, " in "..Franchise.shortName(game)) local subjects = args[game] subjects = subjects and utilsTable.filter(subjects, utilsString.notEmpty) if subjects and #subjects > 0 then local gallery, subjectTerms = p.printGallery(subjectType, game, subjects, args) table.insert(tabData, {				label = Franchise.display(game),				content = gallery			}) if not DEFAULT_TAB_DENYLIST[game] then defaultTab = #tabData end if not isListing then frame:expandTemplate({					title = "Location Features/Store",					args = {						feature = subjectType,						game = game,						subjects = table.concat(subjectTerms, ", ")					}				}) for j, remake in ipairs(Franchise.remakes(game)) do					if not args[remake] and not ENHANCED_PORTS[remake] then local gallery, subjectTerms = p.printGallery(subjectType, remake, subjects, args) table.insert(tabData, {							label = Franchise.display(remake),							content = gallery,						}) if not DEFAULT_TAB_DENYLIST[remake] then defaultTab = #tabData end frame:expandTemplate({							title = "Location Features/Store",							args = {								feature = subjectType,								game = remake,								subjects = table.concat(subjectTerms, ", ")							}						}) end end end end end local tabs = utilsLayout.tabs(tabData, {		default = defaultTab,		tabOptions = {			collapse = true,		},	}) local html = mw.html.create("div") :addClass("zw-gallery-list") :wikitext(tabs) return tostring(html), categories end

function p.printGallery(subjectType, game, subjects, options) local entries = p.parseEntries(subjectType, game, subjects, options)

local galleryContent = "" for i, galleryEntry in ipairs(entries) do		galleryContent = galleryContent..galleryEntry.file.."|"..galleryEntry.link.."\n" end local size = Data.sizes[game] and Data.sizes[game][subjectType] or {} local gallery = mw.getCurrentFrame:extensionTag({		name = "gallery",		content = galleryContent,		args = {			caption = options.caption,			widths = options.widths or size.widths,			heights = options.heights or size.heights,			perrow = options.perrow,		}	}) local terms = utilsTable.map(entries, "term") terms = utilsTable.unique(terms)

return gallery, terms end

local VARIANT_REGEX = "%s*%[([^%]]+)%]$" function p.parseEntries(subjectType, game, subjects, options) local options = options or {} local fileType = options.fileType local useTerms = options.useTerms if not fileType then local graphics = Franchise.graphics(game) if subjectType == "Locations" then fileType = "" elseif graphics == "2D" then fileType = "Sprite" elseif subjectType == "Items" then fileType = "Icon" else fileType = "Model" end end

local galleryEntries = {} for i, subject in ipairs(subjects) do		local subject, info = TermList.separateAdditionalInfo(subjects[i]) local link local term if useTerms then local links, terms = TermList.termList(game, {subject}, options) link = links[1]..info term = terms[1] else link = string.format("%s", subject)..info term = subject end

local suffix = fileType == "" and "" or " "..fileType local variant = string.match(link, VARIANT_REGEX) if variant then link = p.stripVariantSyntax(link, "") if tonumber(variant) and tonumber(variant) < 10 then -- Why < 10 ? See Items in Phantom Hourglass suffix = suffix .. " " .. variant else suffix = " " .. variant .. " " .. suffix end end local entry = { link = link, term = term, subject = subject, }		if variant == "No Image" then entry.file = "File:No Image.png" elseif variant and string.find(variant, "^File:") then entry.file = variant elseif useTerms == false then entry.file = string.format("File:%s %s%s.png", game, subject, suffix) else local term = string.gsub(term, "#", "") -- filenames can't have # so we strip them from the terms entry.file = string.format("File:%s %s%s.png", game, term, suffix) end table.insert(galleryEntries, entry) end return galleryEntries end

function p.stripVariantSyntax(str) return string.gsub(str, VARIANT_REGEX, "") end

function p.Schemas return { Data = { type = "record", required = true, properties = { {					name = "sizes", desc = "Sets the size of gallery thumbnails based on the  and   parameters of Template:Gallery List.", required = true, type = "map", keyPlaceholder = "game", keys = { type = "string" }, values = { type = "map", keyPlaceholder = "subjectType", keys = { type = "string" }, values = { type = "record", properties = { {									name = "widths", type = "string", required = true, desc = "A value in pixels corresponding to the  ." },								{									name = "heights", type = "string", required = true, desc = "A value in pixels corresponding to the  ." },							},						},					},				},			},		}	} end

function p.templateData local paramOrder = {1, "fileType", "storeAs", "caption", "perrow", "widths", "heights"} local params = { [1] = {			name = "subjectType", required = true, type = "string", enum = {"Characters", "Creatures", "Enemies", "Locations", "Items", "Materials", "Objects"}, desc = "The type of subject being listed.", trim = true, nilIfEmpty = true, },		fileType = { type = "string", desc = "Sets a custom filename suffix for gallery entries", trim = true, },		storeAs = { type = "string", desc = "Stores the list in the Sequences Cargo table for use by Template:Sort Value and Module:Sequences.", canOmit = true, trim = true, nilIfEmpty = true, },		caption = { type = "string", desc = "Caption text for the gallery.", trim = true, nilIfEmpty = true, canOmit= true, },		perrow = { type = "number", desc = "Maximum number of thumbnails to show per row in the gallery.", trim = true, nilIfEmpty = true, canOmit = true, },		widths = { type = "string", desc = "A value in pixels. Sets the width of gallery entries, overriding any default set in Module:Gallery List/Data", trim = true, nilIfEmpty = true, canOmit = true, },		heights = { type = "string", desc = "A value in pixels. Sets the heights of gallery entries, overriding any default set in Module:Gallery List/Data", trim = true, nilIfEmpty = true, canOmit = true, }	}	for i, game in ipairs(Franchise.enumGames) do		if Franchise.isCanon(game) or Franchise.family(game) ~= "" then -- only games featured on the main page for now table.insert(paramOrder, game) params[game] = { type = "string", desc = "Comma-separated list of wiki page names referring to subjects in "..Franchise.display(game), trim = true, split = true, }		end end return { format = "block", params = params, paramOrder = paramOrder, } end

p.Templates = { ["Gallery List"] = p.templateData }

return p