Module:Categories

local p = {} local h = {} local cargo = mw.ext.cargo local utilsArg = require("Module:UtilsArg") local utilsCode = require("Module:UtilsCode") local utilsGame = require("Module:UtilsGame") local utilsLayout = require("Module:UtilsLayout") local utilsMarkup = require("Module:UtilsMarkup") local utilsTable = require("Module:UtilsTable")

-- See the module for documentation about subcategories. local SUBCATEGORIES = require("Module:Categories/Subcategories") local PER_GAME_CATEGORIES = { {parameter = "bosses", category = "Bosses"}, {parameter = "characters", category = "Characters"}, {parameter = "dungeons", category = "Dungeons"}, {parameter = "enemies", category = "Enemies"}, {parameter = "items", category = "Items"}, {parameter = "levels", category = "Levels"}, {parameter = "objects", category = "Objects"}, {parameter = "places", category = "Places"}, {parameter = "playable", category = "Playable Characters"}, {parameter = "songs", category = "Songs"}, {parameter = "stages", category = "Stages"}, {parameter = "sub-bosses", category = "Sub-Bosses"}, } local MAX_NAV_LINKS = 100

function p.Main(frame) local args, err = utilsArg.parse(frame:getParent.args, p.Templates.Categories) local result = p.printNavboxes(args.categories) .. p.printCategories(args) if err then result = result .. utilsMarkup.categories(err.categories) end return result end

function p._CategorizeEntries(frame) local args = frame:getParent.args return p.CategorizeEntries(frame.args["plain"], args) end

function p.CategorizeEntries(plain, lists) local result = "" result = result .. p.PlainToNavboxes(plain) result = result .. p.PlainToCategories(plain) result = result .. p.GamesToCategories(lists) return result end

function p.PlainToNavboxes(plain) result = "" local plaintable = mw.text.split(plain, '%s*,%s*') local navboxTitle = "" local rows = {} local rowDisplayName = "" local notCategories = "" local notParentCategories = "" local dplQuery = "" local dplParameters = '|namespace=|includesubpages=false|skipthispage=no|mode=userformat|format=,%PAGE%,;,|ordermethod=titlewithoutnamespace|noresultsheader=emptyCategory}}' -- For every category entered in the template for key, category in ipairs(plaintable) do		rows = {} if not utilsCode.IsEmpty(category) then if tonumber(mw.getCurrentFrame:callParserFunction{name = 'PAGESINCATEGORY', args = {category, "R", "pages"}}) <= MAX_NAV_LINKS then -- Sets the title, which is "X in " navboxTitle = "" .. category .. " in " .. mw.getCurrentFrame:expandTemplate{ title = "TLoZ", args = { "Series" } } -- If subcategories exist, handles that if not utilsCode.IsEmpty(SUBCATEGORIES[category]) then notCategories = "" for key2, subCategory in ipairs(SUBCATEGORIES[category]) do						notParentCategories = "" notCategories = notCategories .. "|notcategory=" .. subCategory["category"] if not utilsCode.IsEmpty(subCategory["parents"]) then for key3, parentCategory in ipairs(subCategory["parents"]) do notParentCategories = notParentCategories .. "|notcategory=" .. parentCategory end end dplQuery = h.dplToExternalLinks(mw.getCurrentFrame:preprocess("{{#dpl:|category=" .. category .. "|category=" .. subCategory["category"] .. notParentCategories .. dplParameters)) if not (dplQuery == "emptyCategory") then if utilsCode.IsEmpty(subCategory["display"]) then rowDisplayName = subCategory["category"] else rowDisplayName = subCategory["display"] end table.insert(rows, {title = rowDisplayName, content = dplQuery}) end end -- Other(s) row dplQuery = h.dplToExternalLinks(mw.getCurrentFrame:preprocess("{{#dpl:|category=" .. category .. notCategories .. dplParameters)) if not (dplQuery == "emptyCategory") then table.insert(rows, {title = "Other(s)", content = dplQuery}) end result = result .. utilsLayout.CreateRowNavbox(rows, navboxTitle) -- else just outputs everything else dplQuery = h.dplToExternalLinks(mw.getCurrentFrame:preprocess("{{#dpl:|category=" .. category .. dplParameters)) if not (dplQuery == "emptyCategory") then table.insert(rows, {title = "All", content = dplQuery}) result = result .. utilsLayout.CreateRowNavbox(rows, navboxTitle) end end end end end return tostring(result) end

function h.dplToExternalLinks(dplResult) local result = "" local firstLink = true dplResult = mw.text.split(dplResult, '%s*;%s*') -- Removing the last entry in the table since it's "empty" due to how DPL -- adds a ";" at the end of each entry instead of just in-between entries table.remove(dplResult) for key, link in ipairs(dplResult) do		if firstLink == true then firstLink = false else result = result .. ' · '		end result = result .. ' [https://zelda.gamepedia.com/' .. mw.getCurrentFrame:callParserFunction{name = 'urlencode', args = {link, "WIKI"}} .. ' ' .. link .. '] '	end return result end

function p.PlainToCategories(plain) result = "" local plaintable = mw.text.split(plain, '%s*,%s*') for key, category in ipairs(plaintable) do		if not utilsCode.IsEmpty(category) then result = result .. ""		end end return result end

function p.GamesToCategories(lists) local result = "" local categories = {}

for key, list in ipairs(PER_GAME_CATEGORIES) do		if not (utilsCode.IsEmpty(lists[list["parameter"]])) then for key2, entry in ipairs(mw.text.split(lists[list["parameter"]], '%s*,%s*')) do				table.insert(categories, {list.category, entry}) end end end for _, game in ipairs(utilsGame.GetSortOrder("canon")) do		for _2, category in ipairs(categories) do			if game == category[2] then result = result .. ""			end end end return result end

local params = {} local paramOrder = {} for _, perGameCategory in ipairs(PER_GAME_CATEGORIES) do	params[perGameCategory.parameter] = { type = "string", desc = string.format("Comma-separated list of codes representing the games or other titles in which the given article subject is one of the %s.", perGameCategory.category, perGameCategory.category), split = true, trim = true, nilIfEmpty = true, }	table.insert(paramOrder, perGameCategory.parameter) end

p.Templates = { Categories = { purpose = "Adding categories to pages. For each category, a navbox is generated with links between the pages in the category.", format = "block", paramOrder = utilsTable.concat({1}, paramOrder), params = utilsTable.merge(params, {			[1] = {				name = "categories",				type = "string",				desc = "Comma separated list of categories which are not subcategorized by game. Examples of these include Animals, Forests, Fire-Related Enemies, and so on.",				split = true,				trim = true,				nilIfEmpty = true,			}		}), examples = { vertical = true, {				desc = "Ice Keese", args = { [1] = "Keese, Ice-Related Enemies", ["enemies"] = "OoT, OoT3D, MM, MM3D, TP, TPHD, PH, ST, TFH, BotW", ["sub-bosses"] = "ST", }			},			{				desc = "Yuga", args = { [1] = "Demons, Loruleans, Sorcerers", ["bosses"] = "TLoZ, ALttP, OoT, OoT3D, OoS, OoA, FSA, TP, TPHD, TFoE, TWoG, ZA, BSTLoZ, AST, HW, HWL, HWDE", ["characters"] = "ALBW, HW", ["playable"] = "HW", },			},			{				desc = "Blue Fire", args = { [1] = "Ancient Technology", ["items"] = "OoT, OoT3D", ["objects"] = "BotW" }			},			{				desc = "Desert Temple", args = { ["dungeons"] = "OoT, OoT3D", ["levels"] = "TFH", ["places"] = "OoT, OoT3D", },			},			{				desc = "Eldin Caves", args = { ["stages"] = "HW, HWL, HWDE", },			},			{				desc = "Song of Healing", args = { ["songs"] = "MM, MM3D, TP, TPHD, ST", },			},			{				desc = string.format("Navboxes are not generated for categories with %s+ links.", MAX_NAV_LINKS), args = { [1] = "Hylians, Swords", },			},			{				desc = "Invalid codes, duplicate cods, and improperly ordered codes are handled appropriately.", args = { characters = "TP, TP, fakeGame, OoT, OoT", },			},		},	}, }

return p