Module:Sandbox/LVL: Difference between revisions

LVL (talk | contribs)
No edit summary
LVL (talk | contribs)
No edit summary
Line 1: Line 1:
-- See /doc for docs
local p = {}
 
local iconDataRaw = mw.loadJsonData("Data:ResourceLookup.json")
local iconData2 = mw.loadJsonData("Data:ResourceLookup2.json")
local dictionary = mw.loadJsonData("Data:Dictionary")
 
local iconData = {}
 
for k, v in pairs(iconDataRaw) do
    iconData[k] = v
end
 
for k, v in pairs(iconData2) do
    iconData[k] = v
end
 
local lang_codes = mw.loadJsonData("Data:LangCodes.json")
local lang_module = require("Module:Lang")
local table_data = require("Module:Icon/data")
 
local cachedLangCode
 
local linkOverrides = table_data.linkOverrides
local legacyItems = table_data.legacyItems
local missingImageOverrides = table_data.missingImageOverrides
local aliases = table_data.aliases
local renames = table_data.renames


local p = {}
local function getLangCode()
local utils          = require "Module:Abilities/utils"
    if cachedLangCode then
local lang            = require "Module:Lang"
        return cachedLangCode
local AbilityHints    = require "Module:AbilityHints"
    end
local resource_lookup = mw.loadJsonData("Data:ResourceLookup.json")


-- Tab definitions — order here determines display order.
    local title = mw.title.getCurrentTitle().fullText
local TABS = {
     local subpageLang = title:match("/([^/]+)$")
     { key = 'notes',        label = 'Notes'        },
     local langCode = (subpageLang and lang_codes[subpageLang]) and subpageLang or "en"
     { key = 'tips',        label = 'Tips'        },
    { key = 'interactions', label = 'Interactions' },
}


local function get_hero_key(hero_name)
     cachedLangCode = langCode
    if hero_name == nil or hero_name == '' then return nil end
     return langCode
    if string.sub(hero_name, 1, 5) == "hero_" then return hero_name end
     local entry = resource_lookup[hero_name:lower()]
    if entry == nil then return nil end
     return entry.key
end
end


local function trim(s)
-- Infer image path from name, with override support for missing images
     return s:match('^%s*(.-)%s*$')
local function getImage(iconInfo, args)
     local lowerName = iconInfo.name:lower()
 
    if args.image then
        return args.image
    end
 
    return missingImageOverrides[lowerName] or (iconInfo.name .. ".png")
end
end


-- Process content in the Interactions tab to build list of icons to draw in ability hints beside ability card
-- Get the translated name (Moved up so getLink can use it)
local function process_interactions(html, ability_num)
local function getTranslatedName(iconInfo, langCode)
     local manual, idx, seen = {}, 0, {}
     if langCode == "en" then
    local out = html:gsub('(<div)([^>]*data%-iconbox%-icon="[^"]*"[^>]*)(>)', function(pre, attrs, post)
         return iconInfo.name
         local file = attrs:match('data%-iconbox%-icon="([^"]*)"')
    end
        if file and file ~= '' then
 
            local base  = mw.ustring.lower((file:gsub('%.%w+$', '')))
    -- 1. Direct key
            local entry = resource_lookup[base]
    if iconInfo.key and iconInfo.key ~= "" then
            if entry ~= nil and entry.type == 'item' and not seen[base] then
        local translated = lang_module.get_string(iconInfo.key, langCode, iconInfo.name
                seen[base] = true
        )
                idx = idx + 1
 
                local box_id = 'ai-int-' .. ability_num .. '-' .. idx
        if type(translated) == "string" then
                table.insert(manual, {
            return (translated:gsub("<[^>]+>", ""))
                    file  = file,
                    title  = attrs:match('data%-iconbox%-title="([^"]*)"') or '',
                    state  = attrs:match('data%-iconbox%-state="([^"]*)"') or 'normal',
                    anchor = box_id,
                })
                return pre .. attrs .. ' id="' .. box_id .. '"' .. post
            end
         end
         end
        return pre .. attrs .. post
    end)
    return out, manual
end


local function build_tabber(wikitext_map, tab_overrides)
        return iconInfo.name
     tab_overrides = tab_overrides or {}
     end
     local filled = {}
 
     for _, tab in ipairs(TABS) do
     -- 2. Dictionary lookup
        if wikitext_map[tab.key] ~= '' then
     if iconInfo.key_dictionary and iconInfo.key_dictionary ~= "" then
            local tab_wt = tab_overrides[tab.key]
        local entry = dictionary[iconInfo.key_dictionary]
            if tab_wt == nil or tab_wt == '' then tab_wt = wikitext_map[tab.key] end
 
            table.insert(filled, {
        if type(entry) == "table" then
                 key    = tab.key,
            return entry[langCode]
                 label  = tab.label,
                 or entry.en
                tab_wt = tab_wt,
                 or iconInfo.name
                all_wt = wikitext_map[tab.key],
            })
         end
         end
     end
     end


     if #filled == 0 then
    -- No valid key > fallback
         return ''
    return iconInfo.name
end
 
-- Infer link from type and available fields
local function getLink(iconInfo, langCode)
     if iconInfo.type == "ability" then
        local hero = iconInfo.hero_name or iconInfo.name
       
        -- Get the translated name for the specific ability
        local abilityName = getTranslatedName(iconInfo, langCode)
       
        -- Format for URL: replace spaces with underscores
        local anchor = abilityName:gsub(" ", "_")
       
         return hero .. "#" .. anchor
     end
     end


     local tabs = {}
     return linkOverrides[iconInfo.name] or iconInfo.name
    for _, section in ipairs(filled) do
end
        table.insert(tabs, {
 
            label  = section.label,
-- Returns the canonical display name for a given user input
            content = '<div class="ability-details-panel">\n' .. section.tab_wt .. '\n</div>',
-- Used by templates to store the correct casing in data attributes
         })
-- Normalizes casing so exact string matches work reliably in Lua modules
function p.getCanonicalName(frame)
    local name = frame.args[1] or ""
    local lowerName = name:lower()
 
    if renames[lowerName] then
        lowerName = renames[lowerName]
    elseif aliases[lowerName] then
         lowerName = aliases[lowerName]
     end
     end


     if #filled >= 2 then
     local iconInfo = iconData[lowerName] or legacyItems[lowerName]
        local all_parts = {}
 
        for _, section in ipairs(filled) do
    -- If unknown, return original input
            table.insert(all_parts,
    if not iconInfo then
                '<div class="ability-details-section-header">' .. section.label .. '</div>'
         return name
                .. '<div class="ability-details-section-content">\n' .. section.all_wt .. '\n</div>'
            )
        end
        table.insert(tabs, {
            label  = 'Show All',
            content = '<div class="ability-details-panel">' .. table.concat(all_parts) .. '</div>',
         })
     end
     end


     local rendered = mw.ext.tabber.render(tabs)
-- Quick hack: ability names are used by MediaWiki:Gadget-infobox-tooltip.js and expected to be localized
     if #filled == 1 then
     local langCode = getLangCode()
         return '<div class="single-tabbed">' .. rendered .. '</div>'
 
     if iconInfo.type == "ability" then
         return getTranslatedName(iconInfo, langCode)
     end
     end
     return rendered
 
     return iconInfo.name
end
end


-- Entry point. Called via {{#invoke:AbilitySection|render}}.
local function render(name, args)
function p.render(frame)
     local originalName = name
     local args       = frame.args
    local lowerName = name:lower()
     local hero_name  = trim(args.hero_name or '')
    args = args or {}
     local ability_num = trim(args.ability_num or '')
 
     local notes        = trim(args.notes or '')
    if renames[lowerName] then
     local tips        = trim(args.tips or '')
        lowerName = renames[lowerName]
     local interactions = trim(args.interactions or '')
    elseif aliases[lowerName] then
        lowerName = aliases[lowerName]
    end
 
    -- Lookup live data > legacy fallback
     local iconInfo = iconData[lowerName] or legacyItems[lowerName]
 
    -- Throw error if not found
    if not iconInfo then
        return string.format("[[:Category:Module:Icon ERROR|Icon not found]] ('%s'). [[Category:Module:Icon ERROR]]", name)
    end
 
     local customText = args.l1 ~= "" and args.l1 or nil
     local customLink = args.link ~= "" and args.link or nil
     local size = args.size or "20px"
    local noLink = args["no-link"] == "true"
    local noFile = args["no-file"] == "true"
     local iconOnly = args["icon-only"] == "true"


     local hero_key    = get_hero_key(hero_name)
     for k, v in pairs(args) do
    local heading    = ''
        if type(k) == "number" and k > 1 then
    local ability_key = nil
            local val = mw.text.trim(v)
    if hero_key ~= nil then
            if val == "icon-only" then
        local ability = utils.get_ability_card_data(hero_key, ability_num)
                iconOnly = true
        if ability ~= nil then
             elseif val == "no-link" then
            ability_key = ability.Key
                noLink = true
             local ability_name = lang.get_string(ability.Key)
             elseif val:match("^%d+px$") then
            -- Create a visually hidden H3 heading so the Table of Contents can parse
                size = val
            -- the ability name without displaying a redundant title above the card.
            end
             heading = '<h3 class="ability-name-toc">' .. ability_name .. '</h3>'
         end
         end
     end
     end


     local card = frame:expandTemplate{
     local langCode = getLangCode()
        title = 'Ability card v2',
        args  = { hero_name = hero_name, ability_num = ability_num, link_name = 'false' }
    }


     local interactions_ided, manual = interactions, {}
     local displayName
     if interactions ~= '' then
    if customText then
         interactions_ided, manual = process_interactions(interactions, ability_num)
        displayName = customText
     elseif renames[name:lower()] then
        -- Preserve original if renamed
        displayName = originalName
    else
         displayName = getTranslatedName(iconInfo, langCode)
     end
     end


     local wikitext_map = {
     local baseLink = customLink or getLink(iconInfo, langCode)
        notes        = notes,
    local fragment = ""
        tips        = tips,
        interactions = interactions,
    }


     local tabber = build_tabber(wikitext_map, { interactions = interactions_ided })
     -- Split the fragment (#Abilities) from the base link
    if baseLink:find("#") then
        local parts = mw.text.split(baseLink, "#", true)
        baseLink = parts[1]
        fragment = "#" .. (parts[2] or "")
    end


     local hints_col = ''
     local link = baseLink
     if ability_key ~= nil or #manual > 0 then
 
         hints_col = AbilityHints.get_icons(ability_key, ability_num, manual)
     if not customLink and langCode ~= "en" and baseLink ~= "" then
         link = baseLink .. "/" .. langCode
     end
     end


     local details_col = ''
    -- Reattach fragment at the end
     if tabber ~= '' then
    link = link .. fragment
         details_col = '<div class="ability-section-details">' .. tabber .. '</div>'
 
    -- Add CSS class for abilities
     local style
     if iconInfo.type == "ability" then
         style = 'class="module-icon-ability" style="position:relative; bottom:2px;"'
    else
        style = 'class="c-icon" style="position:relative; bottom:2px;"'
     end
     end


     local card_block = '<div class="ability-section-card">' .. card .. '</div>'
     local imageLink = noLink and "" or link
     local left_col
    local iconHtml = ""
     if hints_col ~= '' then
 
         left_col = '<div class="ability-section-main">' .. card_block .. hints_col .. '</div>'
    if not noFile then
        local image = getImage(iconInfo, args)
        iconHtml = string.format('<span %s>[[File:%s|%s|link=%s]]</span>', style, image, size, imageLink)
    end
 
    if iconOnly or displayName == "" then
        return iconHtml
    end
 
     local textHtml = (noLink or link == "") and displayName or string.format('[[%s|%s]]', link, displayName)
 
     if iconHtml ~= "" then
         return '<span style="white-space:nowrap;">' .. iconHtml .. " " .. textHtml .. '</span>'
     else
     else
         left_col = card_block
         return textHtml
     end
     end
end
-- Template entrypoint
function p.render(frame)
    local args = frame:getParent().args
    local name = args[1] or ""


     local ability_section = '<div class="ability-section">'
     return render(name, args)
        .. left_col
end
        .. details_col
        .. '</div>'


    return '<div class="ability-section-wrapper">'
-- Module entrypoint
        .. heading
function p._render(name, args)
        .. ability_section
    return render(name, args)
        .. '</div>'
end
end


return p
return p