Module:GameInfo: Difference between revisions
From SpiritVale Wiki
More actions
m Protected "Module:GameInfo" ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite)) |
No edit summary |
||
| Line 1: | Line 1: | ||
-- Module:GameInfo | -- Module:GameInfo | ||
-- Base container + shared scaffolding for all GameInfo.* renderers (Phase 4.1). | -- Base container + shared scaffolding for all GameInfo.* renderers (Phase 4.1). | ||
-- | |||
-- Routing: | |||
-- Skill pages (recommended): | |||
-- {{#invoke:GameInfo|Skills|notes=...|data=...}} | |||
-- | |||
-- Category pages (generic): | |||
-- {{#invoke:GameInfo|Category|name=Skills|...}} -> Module:GameInfo/Skills | |||
-- {{#invoke:GameInfo|Category|name=Monsters|...}} -> Module:GameInfo/Monsters (future) | |||
-- | |||
-- Notes: | |||
-- - This module is the stable entrypoint. Render logic lives in submodules. | |||
-- - Submodules are expected to return a string of wikitext/HTML. | |||
local p = {} | local p = {} | ||
| Line 13: | Line 25: | ||
n = math.floor(n + 0.0) | n = math.floor(n + 0.0) | ||
return n | return n | ||
end | |||
local function _trim(v) | |||
if v == nil then return nil end | |||
local s = tostring(v) | |||
return mw.text and mw.text.trim(s) or s:match("^%s*(.-)%s*$") | |||
end | end | ||
| Line 27: | Line 45: | ||
end | end | ||
container:wikitext(tostring(content)) | container:wikitext(tostring(content)) | ||
end | |||
local function _error_box(msg) | |||
-- Keep this simple and obvious on-wiki while troubleshooting. | |||
local div = mw.html.create("div") | |||
:addClass("error") | |||
:wikitext(tostring(msg)) | |||
return tostring(div) | |||
end | end | ||
| Line 81: | Line 107: | ||
_add_content(box.bottom, opts and opts.bottom) | _add_content(box.bottom, opts and opts.bottom) | ||
return tostring(box.root) | return tostring(box.root) | ||
end | |||
-- ----------------------------------------------------------------------------- | |||
-- Routing / Dispatch | |||
-- ----------------------------------------------------------------------------- | |||
local ROUTES = { | |||
-- Canonical category -> submodule | |||
["Skills"] = "Module:GameInfo/Skills", | |||
-- Future: | |||
-- ["Monsters"] = "Module:GameInfo/Monsters", | |||
-- ["Equips"] = "Module:GameInfo/Equips", | |||
} | |||
local function _pick_entry(mod) | |||
-- Support a few common entrypoint names. | |||
if type(mod) ~= "table" then return nil end | |||
if type(mod.main) == "function" then return mod.main end | |||
if type(mod.render) == "function" then return mod.render end | |||
if type(mod.Skills) == "function" then return mod.Skills end | |||
return nil | |||
end | |||
local function _invoke_submodule(frame, module_title) | |||
local ok_mod, mod = pcall(require, module_title) | |||
if not ok_mod then | |||
return _error_box("GameInfo: failed to require " .. module_title) | |||
end | |||
local fn = _pick_entry(mod) | |||
if type(fn) ~= "function" then | |||
return _error_box("GameInfo: " .. module_title .. " has no entry function (main/render).") | |||
end | |||
local ok_call, out = pcall(fn, frame) | |||
if not ok_call then | |||
return _error_box("GameInfo: error inside " .. module_title) | |||
end | |||
return out | |||
end | |||
-- Explicit entrypoint for skill pages. | |||
function p.Skills(frame) | |||
frame = frame or mw.getCurrentFrame() | |||
return _invoke_submodule(frame, "Module:GameInfo/Skills") | |||
end | |||
-- Generic entrypoint for category pages (not limited to Skills). | |||
-- Usage: | |||
-- {{#invoke:GameInfo|Category|name=Skills|...}} | |||
-- If name matches ROUTES, we use that mapping. | |||
-- Otherwise, we attempt Module:GameInfo/<name> (safe, limited characters). | |||
function p.Category(frame) | |||
frame = frame or mw.getCurrentFrame() | |||
local args = frame.args or {} | |||
local name = _trim(args.name or args.category or args[1]) | |||
if not name or name == "" then | |||
return _error_box("GameInfo.Category: missing |name=CategoryName") | |||
end | |||
-- First: known route table. | |||
local module_title = ROUTES[name] | |||
-- Second: case-insensitive match on known routes. | |||
if not module_title and mw.ustring then | |||
local want = mw.ustring.lower(name) | |||
for k, v in pairs(ROUTES) do | |||
if mw.ustring.lower(k) == want then | |||
module_title = v | |||
break | |||
end | |||
end | |||
end | |||
-- Third: dynamic fallback to Module:GameInfo/<name> | |||
if not module_title then | |||
-- Allow letters, numbers, spaces, underscores, hyphens, and slashes. | |||
-- (Spaces are fine in page titles; MediaWiki normalizes.) | |||
if not name:match("^[%w %_%-/]+$") then | |||
return _error_box("GameInfo.Category: invalid name=" .. tostring(name)) | |||
end | |||
module_title = "Module:GameInfo/" .. name | |||
end | |||
return _invoke_submodule(frame, module_title) | |||
end | end | ||