Module:Keywords: Difference between revisions

From Test Wiki
Jump to navigation Jump to search
Content deleted Content added
No edit summary
No edit summary
Tag: Manual revert
 
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 ("Buffs#".. name)
return keyword and keyword["Link"] or name
end
end



Latest revision as of 23:48, 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=]]&nbsp;</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