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", states = "state-container__states", state = "state-container__state", defaultState = "state-container__state state-container__state--active", controls = "state-container__controls state-container__controls--vertical", stateControlForward = "state-control state-control-forward", stateControlBack = "state-control state-control-back", stateControlDisabled = "state-control--disabled", } local defaultSpacing = "16px"

local currentPage = mw.title.getCurrentTitle.text

function p.Main(frame) local args = frame:getParent.args local output = p.main({		game = args[1],		type = args[2],	}) return output 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 not config[1].tab 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",			["flex-wrap"] = "wrap",			["justify-content"] = "center",			["align-items"] = "flex-end",			["margin-top"] = "-" .. defaultSpacing,			["margin-left"] = "-" .. (data.spacing or defaultSpacing),		}) 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"] = defaultSpacing,				["margin-left"] = (data.spacing or defaultSpacing),			}) :done end return tostring(row), pages end function h.createMapNav(config, game) local baseImageMap, pages = h.createImageMap(game, config) 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,			maxWidth = config.maxWidth,		}) 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, config.maxWidth), pages end

function h.createStatefulMenuMap(states, defaultState, maxWidth) local statesNode = mw.html.create("div") :addClass(classes.states) :css({				["display"] = "flex",				["align-items"] = "center",				["justify-content"] = "center",				["flex"] = "1",				["max-width"] = maxWidth and maxWidth .. "px",		}) for i, state in ipairs(states) do 		local default = i == defaultState statesNode :tag("div") :addClass(default and classes.defaultState or classes.state) :css("flex", "1") :wikitext(state) :done end local controlCss = { ["height"] = "12%", ["min-height"] = "32px", ["margin-left"] = "15%", }	local controlsNode = mw.html.create("div") :addClass(classes.controls) :tag("div") :addClass(classes.stateControlForward) :addClass(defaultState == #states and classes.stateControlDisabled or nil) :css(controlCss) :wikitext("") :done :tag("div") :addClass(classes.stateControlBack) :addClass(defaultState == 1 and classes.stateControlDisabled or nil) :css(controlCss) :wikitext("") :done local stateContainer = mw.html.create("div") :addClass(classes.stateContainer) :node(mw.clone(controlsNode):css("visibility", "hidden")) --Hack to "balance" the left side and keep the content centered :node(statesNode) :node(controlsNode) :css({			["display"] = "flex",			["justify-content"] = "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")) local responsiveImageMap = mw.html.create("div") :addClass("resizable-image-map") :css({			["max-width"] = data.maxWidth and data.maxWidth .. "px",			["margin"] = "0 auto",		}) :wikitext(imagemap) return tostring(responsiveImageMap), 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