Module:Keywords: Difference between revisions
Jump to navigation
Jump to search
Content deleted Content added
No edit summary |
No edit summary |
||
| Line 200: | Line 200: | ||
local name = frame.args[1] |
local name = frame.args[1] |
||
local keyword = data.Keywords and data.Keywords[name] |
local keyword = data.Keywords and data.Keywords[name] |
||
return keyword and keyword["Link"] or |
return keyword and keyword["Link"] or name |
||
end |
end |
||
Revision as of 23:43, 1 February 2026
Documentation for this module may be created at Module:Keywords/doc
local data = mw.loadData("Module:Keywords/data")
local vars = mw.ext.VariablesLua
local p = {}
local default_kw_size = "24px"
local default_icon_size = "20px"
---------------------------------------------------
-- get keyword/icon info and store in variables
---------------------------------------------------
function p.getData(frame)
local name = frame.args[1] or frame:getParent().args[1]
name = mw.text.trim(tostring(name))
local info = (data.Keywords and data.Keywords[name]) or (data.Icons and data.Icons[name]) or {}
vars.vardefine("keywords_info_name", name)
vars.vardefine("keywords_info_image", info["Image"] or "")
vars.vardefine("keywords_info_description", frame:preprocess("{{Infobox Styling|" .. (info["Text"] or "") .. "}}"))
end
---------------------------------------------------
-- escape special chars in lua patterns
---------------------------------------------------
local function escape_pattern(s)
return mw.ustring.gsub(s, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1")
end
---------------------------------------------------
-- replace codes like #Vulnerable or @PO in text
-- Supports multi-word keyword codes (e.g. "#Orb Slot") and resolves overlaps by replacing longer codes first.
---------------------------------------------------
function p.replace(text, hide_icon, label_override, size_override)
local target_text = ""
if type(text) == "string" then --type() in Lua returns a string
target_text = text
else
if text.args then
target_text = text.args[1]
else
target_text = ""
end
end
local keywords_to_replace = {}
local replacements = {}
---------------------------------------------------
-- icons (@) - build replacements
---------------------------------------------------
for iconName, icon in pairs(data.Icons or {}) do
if icon.Code and mw.ustring.find(target_text, icon.Code, 1, true) then
local pattern = escape_pattern(icon.Code)
table.insert(keywords_to_replace, pattern)
local size = (size_override and size_override ~= "")
and size_override
or default_icon_size
local replacement = string.format(
"<span class='keyword-trigger' data-name='%s'>[[File:%s|%s|middle|link=]]</span>",
icon.Code,
icon.Image or "",
size
)
table.insert(replacements, replacement)
end
end
---------------------------------------------------
-- keywords (#) - sorted longest-first to avoid conflicts
---------------------------------------------------
local keywordEntries = {}
for keywordName, keyword in pairs(data.Keywords or {}) do
table.insert(keywordEntries, { name = keywordName, kw = keyword })
end
table.sort(keywordEntries, function(a, b)
return #(a.kw.Code or "") > #(b.kw.Code or "")
end)
for _, entry in ipairs(keywordEntries) do
local keywordName, keyword = entry.name, entry.kw
for _, code in ipairs(keyword.Codes) do
if keyword and code then
local has_found = mw.ustring.find(target_text, code, 1, true) -- literal find
if has_found then
local prev = (has_found > 1) and mw.ustring.sub(target_text, has_found - 1, has_found - 1) or ""
if prev == "" or not mw.ustring.match(prev, "[%w_]") then
-- capture trailing "suffix" chars that directly follow the code (e.g. "Vulnerable2" -> suffix "2")
local pattern = escape_pattern(code) .. "([%w%-_]*)"
table.insert(keywords_to_replace, pattern)
local size = (size_override and size_override ~= "") and size_override or default_kw_size
local base_label = (label_override and label_override ~= "") and label_override or code:sub(2)
local link = keyword.Link or ("Buffs#" .. keywordName)
local imagePart = ""
if keyword.Image and keyword.Image ~= "" then
imagePart = string.format("[[File:%s|%s|middle|link=%s]] ", keyword.Image, size, link)
end
-- replacement as a FUNCTION so the suffix goes INSIDE the span
local function replacement_fn(suffix)
local label = base_label .. (suffix or "")
return string.format(
"<span class='keyword-trigger inline-trigger' data-name='%s'>%s[[%s|%s]]</span>",
keywordName, -- strip leading '#'
imagePart,
link,
label
)
end
table.insert(replacements, replacement_fn)
break
end
end
end
end
end
---------------------------------------------------
-- Replace everything (in insertion order)
-- Keywords already ordered long -> short, so overlaps are handled.
---------------------------------------------------
for index, target in ipairs(keywords_to_replace) do
local repl = replacements[index]
if type(repl) == "function" then
target_text = mw.ustring.gsub(target_text, target, repl)
else
target_text = mw.ustring.gsub(target_text, target, repl)
end
end
return target_text
end
---------------------------------------------------
-- Process a single keyword/icon by exact name
---------------------------------------------------
function p.process(frame)
local args = frame.args[1] and frame.args or frame:getParent().args
local input = args[1] or ""
local label_override = args[2]
local size_override = args[3]
local keyword = (data.Keywords and data.Keywords[input]) or (data.Icons and data.Icons[input])
if keyword then
local size = (size_override and size_override ~= "") and size_override or default_kw_size
local label = (label_override and label_override ~= "") and label_override or input
local link = keyword.Link or ("Buffs#" .. input)
local imagePart = ""
if keyword.Image and keyword.Image ~= "" then
imagePart = string.format("[[File:%s|%s|baseline|link=]]", keyword.Image, size)
end
return string.format(
"<span class='keyword-trigger inline-trigger' data-name='%s'>%s [[%s|%s]]</span>",
input,
imagePart,
link,
label
)
end
return input
end
---------------------------------------------------
-- Used for the Icon template: replaces @codes in a string
---------------------------------------------------
function p.getIcon(frame)
local args = frame.args[1] and frame.args or frame:getParent().args
local text = args[1] or ""
local size_override = args[2]
for iconName, icon in pairs(data.Icons or {}) do
if icon.Code and icon.Image and mw.ustring.sub(icon.Code, 1, 1) == "@" then
local pattern = escape_pattern(icon.Code)
local size = (size_override and size_override ~= "")
and size_override
or (mw.ustring.find(icon.Code, "E", 1, true) and default_kw_size or default_icon_size)
local replacement = string.format(
"<span class='keyword-trigger inline-trigger' data-name='%s'>[[File:%s|%s|middle|link=]] </span>",
icon.Code,
icon.Image,
size
)
text = mw.ustring.gsub(text, pattern, replacement)
end
end
return text
end
---------------------------------------------------
-- Gets the corresponding link for a keyword
---------------------------------------------------
function p.getLink(frame)
local name = frame.args[1]
local keyword = data.Keywords and data.Keywords[name]
return keyword and keyword["Link"] or name
end
return p