Module:ItemsNav

local p = {} local h = {}

local data = mw.loadData("Module:Imagenav/Data") local tab2 = require("Module:Tab2") local terminology = require("Module:Term") local utilsError = require("Module:UtilsError") local utilsTable = require("Module:UtilsTable") local validate = require("Module:ArgsUtil").validate

local classes = { stateContainer = "state-container", state = "state-container__state", defaultState = "state-container__state state-container__state--active", stateControlForward = "state-control state-control-forward", stateControlBack = "state-control state-control-back", stateControlDisabled = "state-control--disabled" } local rowSpacing = "16px"

local currentPage = mw.title.getCurrentTitle.text

function p.Main(frame) local args = frame:getParent.args return p.main({		game = args[1],		type = args[2],	}) end

local validators = { type = { required = true, values = utilsTable.keys(data) },	game = { required = true, values = function(args) return utilsTable.keys(data[args.type]) end } }

function p.main(args) local err = validate(args, validators) if err then utilsError.logWarnings(err) return utilsError.printErrorCategories(utilsError.INVALID_TEMPLATE_ARGUMENTS) end local config = data[args.type][args.game] return h.createTabbedNav(config, args.game) end

function h.createTabbedNav(config, game) if #config == 1 and not tabs[1].tabName then return h.createNav(config[1], game) end local tabs = {} local defaultTab for i, v in pairs(config) do		local tab, terms = h.createNav(v, game) table.insert(tabs, {			tabName = v.tab,			tabContent = tab,		}) if not defaultTab then defaultTab = utilsTable.hash(terms)[currentPage] and i		end end defaultTab = defaultTab or 1 return tab2.Main(tabs, defaultTab, "top", nil, nil, nil, nil, "center") end

function h.createNav(config, game) if config.imagemap then return h.createMapNav(config.imagemap, game) end if config.row then return h.createRowNav(config.row, game) end end

function h.createRowNav(data, game) local pages = {} local row = mw.html.create("div") :css({			["display"] = "flex",			["justify-content"] = "center",			["align-items"] = "flex-end",			["margin-top"] = "-"..rowSpacing,			["margin-left"] = "-"..rowSpacing,		}) for _, item in ipairs(data.items) do		table.insert(pages, item) local fileName = data.filePattern:format(item) local rowItem = ("link=%s|%s"):format(fileName, h.getLinkParts(game, item)) row :tag("div") :wikitext(rowItem) :css({				["margin-top"] = rowSpacing,				["margin-left"] = rowSpacing,			}) :done end return tostring(row), pages end function h.createMapNav(config, game) local baseImageMap, pages = h.createImageMap(game, {		image = config.image,		areas = config.areas,	}) if not config.upgrades then return baseImageMap, pages end local states = { baseImageMap } local defaultState = 1 local initialAreas = utilsTable.shallowClone(config.areas) for i, upgradeData in pairs(config.upgrades) do		local addedPages = {} local changedAreas = utilsTable.mapInPlace(initialAreas, function(area)			local change = upgradeData.changes[area.page]			if not change then				return area			end			if change == "" then				return nil			end			if type(change) == "string" then				change = { page = change }			end			table.insert(addedPages, change.page)			return {				area = change.area or area.area,				page = change.page or area.page,				display = change.display,			}		end) changedAreas = utilsTable.removeFalseEntries(changedAreas) local newAreas = utilsTable.shallowClone(upgradeData.areas or {}) local upgradeAreas = utilsTable.mergeArrays(newAreas, changedAreas) local imageMap, mapPages = h.createImageMap(game, {			image = upgradeData.image,			areas = upgradeAreas,		}) table.insert(states, imageMap)

pages = utilsTable.mergeArrays(pages, addedPages) defaultState = (utilsTable.hash(addedPages)[currentPage] and i) or defaultState initialAreas = upgradeAreas end return h.createStatefulMenuMap(states, defaultState), pages end

function h.createStatefulMenuMap(states, defaultState) local stateContainer = mw.html.create("div") for i, state in ipairs(states) do 		local default = i == defaultState stateContainer :tag("div") :addClass(default and classes.defaultState or classes.state) :wikitext(state) :done end local stateControls = mw.html.create("div") :css({			["display"] = "flex",			["flex-direction"] = "column",		}) :tag("div") :addClass(classes.stateControlForward) :addClass(defaultState == #states and classes.stateControlDisabled or nil) :wikitext("") :done :tag("div") :addClass(classes.stateControlBack) :addClass(defaultState == 1 and classes.stateControlDisabled or nil) :wikitext("") :done stateContainer :addClass(classes.stateContainer) :node(stateControls) :css({			["display"] = "flex",			["justify-content"] = "center",			["align-items"] = "center",		}) return tostring(stateContainer) end

function h.createImageMap(game, data) local lines = { data.image } local pages = {} for _, area in ipairs(data.areas) do		local link = ("[%s %s]"):format(h.getLinkParts(game, area.page, area.display)) table.insert(pages, area.page) table.insert(lines, area.area .. link) end table.insert(lines, " desc none") local imagemap = mw.getCurrentFrame:extensionTag("imagemap", table.concat(lines, "\n")) return imagemap, pages end

-- For rendering a page link as an external link, so as to not spam Special:WhatLinksHere function h.getLinkParts(game, page, display) local url = mw.title.new(page):fullUrl if display then return url, display end local row = terminology.fetchRow({ term = page, game = game }) local alt = row and row.term or page return url, alt end

return p