Module:Descriptions

From Zelda Wiki, the Zelda encyclopedia
Revision as of 14:40, 5 November 2023 by PhantomCaleb (talk | contribs)
This is the main module for the following templates:
local p = {}
local h = {}
local Data = mw.loadData("Module:Descriptions/Data")

local Franchise = require("Module:Franchise")
local utilsArg = require("Module:UtilsArg")
local utilsCargo = require("Module:UtilsCargo")
local utilsTable = require("Module:UtilsTable")

local CATEGORY_INVALID_ARGS = "[[Category:"..require("Module:Constants/category/invalidArgs").."]]"

function h.warn(warnMsg, ...)
	local utilsError = require("Module:UtilsError")
	utilsError.warn(string.format(warnMsg, ...))
end

function p.Main(frame)
	local args, err = utilsArg.parse(frame:getParent().args, p.Templates["Descriptions"])
	local categories = err and err.categoryText or ""
	if not args.game then
		return categories
	end
	
	local page = args.page or mw.title.getCurrentTitle().subpageText -- subpageText for the benefit of sandboxes
	
	local descriptions = p.query(args.game, page)
	local formattedDescriptions = p.format(args.game, descriptions)
	
	if not formattedDescriptions then
		return "", categories
	end
	-- if not formattedDescriptions then
	-- 	h.warn("No descriptions found for <code>%s</code> in <code>%s</code>", page, args.game)
	-- 	categories = categories..CATEGORY_INVALID_ARGS
	-- end
	
	local printedDescriptions = p.print(args.game, formattedDescriptions)

	local hasMultipleDescriptions = not (#formattedDescriptions == 1 and #formattedDescriptions[1].descriptions == 1)
	local collapsible =  mw.getCurrentFrame():expandTemplate({
		title = "Collapsible",
		args = {
			header = "Descriptions",
			content = printedDescriptions,
			collapse = hasMultipleDescriptions and "true" or "false"
		}
	})
	
	return collapsible, categories
end

function p.query(game, page)
	local synonyms = utilsCargo.query("Terminologies", "_pageName", {
		where = utilsCargo.allOf({
			redirectTarget = page
		})
	})
	local synonymClauses = utilsTable.map(synonyms, function (synonym)
		return {
			subject = synonym._pageName
		}
	end)
	local subjectClause = utilsCargo.anyOf({ subject = page }, unpack(synonymClauses))
	
	return utilsCargo.query("Descriptions", "subjectDisplayName, description, descriptionType, context, subjectDisplayName", {
		where = utilsCargo.allOf(subjectClause, {
			game = game
		})
	})
end

function p.format(game, descriptions)
	local descriptionTypes = Data.descriptionTypes[game] or {}
	local descriptionsByType = utilsTable.groupBy(descriptions, "descriptionType")

	local descriptionGroups = {}
	for i, descriptionType in ipairs(descriptionTypes) do
		local descriptionsOfType = descriptionsByType[descriptionType.type]
		if descriptionsOfType then
			table.insert(descriptionGroups, {
				type = descriptionType.type,
				header = descriptionType.header,
				descriptions = descriptionsOfType,
			})
		end
	end
	if #descriptionGroups == 0 then
		return nil
	else
		return descriptionGroups
	end
end

function p.print(game, descriptionGroups)
	if not descriptionGroups then
		return ""
	end
	
	local html = mw.html.create("div")
		:addClass("zw-descriptions")
	
	for i, descriptionGroup in ipairs(descriptionGroups) do
		local group = html:tag("div")
				:addClass("zw-descriptions__group zw-descriptions__group--"..game.."-"..descriptionGroup.type)
				:tag("div")
					:addClass("zw-descriptions__group-header")
					:wikitext(mw.getCurrentFrame():preprocess(descriptionGroup.header))
					:done()
				:tag("div")
					:addClass("zw-descriptions__group-descriptions")
		
		for i, description in pairs(descriptionGroup.descriptions) do
			group:tag("div")
				:addClass("zw-descriptions__description")
				:tag("div")
					:addClass("zw-descriptions__description-subject")
					:wikitext(description.subjectDisplayName)
					:done()
				:tag("div")
					:addClass("zw-descriptions__description-body")
					:wikitext(description.description)
					:done()
		end
	end
	
	return tostring(html)
end

p.Templates = {
	["Descriptions"] = {
		params = {
			[1] = {
				name = "game",
				required = true,
				enum = Franchise.enum(),
				type = "string",
				desc = "A game code from [[Data:Franchise]]",
				trim = true,
				nilIfEmpty = true,
			},
			[2] = {
				name = "page",
				hidden = true,
				type = "wiki-page-name",
				desc = "A wiki page name. For testing purposes only—defaults to the current page.",
				trim = true,
				nilIfEmpty = true,
			},
		},
	},
}

return p