Editing Module:IconGive feedback
The edit can be undone.
Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
| Latest revision | Your text | ||
| Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
-- Load language codes | |||
local lang_codes = mw.loadJsonData("Data:LangCodes.json") | local lang_codes = mw.loadJsonData("Data:LangCodes.json") | ||
local cachedLangCode | -- Cache for compiled icon data (persists during page render) | ||
local iconDataCache = nil | |||
local cachedLangCode, cachedLangData | |||
-- Cache for expensive existence checks (persists during page render) | |||
local existenceCache = {} | |||
local | |||
local | -- Heroes/Items that don't have images uploaded yet | ||
local missingImageOverrides = { | |||
-- Unreleased Heroes | |||
["boho"] = "Module-Icon missing.png", | |||
["druid"] = "Module-Icon missing.png", | |||
["fortuna"] = "Module-Icon missing.png", | |||
["graf"] = "Module-Icon missing.png", | |||
["gunslinger"] = "Module-Icon missing.png", | |||
["skyrunner"] = "Module-Icon missing.png", | |||
["swan"] = "Module-Icon missing.png", | |||
["thumper"] = "Module-Icon missing.png", | |||
-- Add any others that show red links | |||
} | |||
-- Build unified lookup table from bot-uploaded JSONs | |||
local function buildIconData() | |||
if iconDataCache then | |||
return iconDataCache | |||
-- | |||
local function | |||
if | |||
return | |||
end | end | ||
local lookup = {} | |||
-- Load bot data | |||
local heroData = mw.loadJsonData("Data:HeroData.json") | |||
local abilityData = mw.loadJsonData("Data:AbilityData.json") | |||
local itemData = mw.loadJsonData("Data:ItemData.json") | |||
-- Track which hero owns which ability (for linking) | |||
local abilityToHero = {} | |||
-- Process Heroes | |||
for heroKey, hero in pairs(heroData) do | |||
if type(hero) == "table" and hero.Name then | |||
local name = hero.Name | |||
local lowerName = name:lower() | |||
-- Check for missing image override | |||
local imageName = missingImageOverrides[lowerName] or (name .. ".png") | |||
lookup[lowerName] = { | |||
name = name, | |||
key = heroKey, | |||
link = name, | |||
image = imageName, | |||
type = "hero" | |||
} | |||
-- Map abilities to parent hero | |||
if hero.BoundAbilities then | |||
for slot, ability in pairs(hero.BoundAbilities) do | |||
if ability.Key then | |||
abilityToHero[ability.Key] = { | |||
heroName = name, | |||
abilityName = ability.Name | |||
} | |||
end | |||
end | |||
end | |||
end | |||
end | end | ||
-- Process Abilities | |||
if | for abilityKey, ability in pairs(abilityData) do | ||
if type(ability) == "table" and ability.Name then | |||
local name = ability.Name | |||
local lowerName = name:lower() | |||
local parentInfo = abilityToHero[abilityKey] | |||
-- If we already have this ability name, prefer the one linked to a hero | |||
if lookup[lowerName] and lookup[lowerName].type == "ability" then | |||
local existingHasParent = lookup[lowerName].link ~= lookup[lowerName].name | |||
local newHasParent = parentInfo ~= nil | |||
-- Skip if existing is linked to hero but this one isn't (prevents orphans from overwriting real ones) | |||
if existingHasParent and not newHasParent then | |||
-- Skip this orphan ability | |||
else | |||
-- Overwrite: new has parent and existing doesn't, or both/neither have parents | |||
local link = parentInfo and parentInfo.heroName or name | |||
lookup[lowerName] = { | |||
name = name, | |||
key = abilityKey, | |||
link = link, | |||
image = name .. ".png", | |||
type = "ability", | |||
class = "theme" | |||
} | |||
end | |||
else | |||
-- No existing entry, add normally | |||
local link = parentInfo and parentInfo.heroName or name | |||
lookup[lowerName] = { | |||
name = name, | |||
key = abilityKey, | |||
link = link, | |||
image = name .. ".png", | |||
type = "ability", | |||
class = "theme" | |||
} | |||
end | |||
end | end | ||
end | end | ||
-- | -- Process Items | ||
if | for itemKey, item in pairs(itemData) do | ||
if type(item) == "table" and item.Name then | |||
local name = item.Name | |||
local lowerName = name:lower() | |||
lookup[lowerName] = { | |||
name = name, | |||
key = itemKey, | |||
link = name, | |||
image = name .. ".png", | |||
type = "item" | |||
} | |||
end | end | ||
end | end | ||
iconDataCache = lookup | |||
return | return lookup | ||
end | end | ||
-- | -- Get icon data by name (with alias support) | ||
local function | local function getIconData(iconName) | ||
local data = buildIconData() | |||
local lowerName = iconName:lower() | |||
-- Check main lookup | |||
if data[lowerName] then | |||
return data[lowerName], nil | |||
end | |||
-- Check aliases (for edge cases like "doorman" -> "the doorman") | |||
return | local aliases = { | ||
["doorman"] = "the doorman", | |||
["mo and krill"] = "mo & krill", | |||
["mo"] = "mo & krill", | |||
["krill"] = "mo & krill", | |||
["curse"] = "cursed relic", | |||
["debuff remover"] = "dispel magic" | |||
} | |||
if aliases[lowerName] then | |||
return data[aliases[lowerName]], nil | |||
end | end | ||
return | return nil, string.format("[[:Category:Module:Icon ERROR|Icon not found]] ('%s'). [[Category:Module:Icon ERROR]]", iconName) | ||
end | end | ||
-- | -- Language handling | ||
local function getLangData() | |||
if cachedLangData then | |||
function | return cachedLangCode, cachedLangData | ||
if | |||
end | end | ||
local | local title = mw.title.getCurrentTitle().fullText | ||
local subpageLang = title:match("/([^/]+)$") | |||
local langCode = (subpageLang and lang_codes[subpageLang]) and subpageLang or "en" | |||
local langData = {} | |||
if langCode ~= "en" then | |||
local success, data = pcall(function() | |||
return mw.loadJsonData("Data:Lang " .. langCode .. ".json") | |||
end) | |||
if success and type(data) == "table" then | |||
langData = data | |||
end | |||
end | end | ||
cachedLangCode = langCode | |||
cachedLangData = langData | |||
return | return langCode, langData | ||
end | end | ||
-- Main render function | |||
local | function p.render(frame) | ||
local args = frame:getParent().args | |||
local name = args[1] or "" | |||
local customText = args.l1 or "" | |||
-- Set Defaults | |||
local | |||
local customText = args.l1 | |||
local size = args.size or "20px" | local size = args.size or "20px" | ||
local noLink = args["no-link"] == "true" | local noLink = args["no-link"] == "true" | ||
local iconOnly = args["icon-only"] == "true" | local iconOnly = args["icon-only"] == "true" | ||
-- Scan unnamed parameters | |||
for k, v in pairs(args) do | for k, v in pairs(args) do | ||
if type(k) == "number" and k > 1 then | if type(k) == "number" and k > 1 then | ||
local val = mw.text.trim(v) | local val = mw.text.trim(v) | ||
if val == "icon-only" then | if val == "icon-only" then | ||
iconOnly = true | iconOnly = true | ||
elseif val == "no-link" then | elseif val == "no-link" then | ||
noLink = true | noLink = true | ||
elseif val:match("^%d+px$") then | elseif val:match("^%d+px$") then | ||
size = val | size = val | ||
end | end | ||
| Line 170: | Line 213: | ||
end | end | ||
local | -- Get icon data automatically from JSON | ||
local iconData, err = getIconData(name) | |||
if not iconData then | |||
return "Error: " .. err | |||
end | |||
local displayName | local langCode, langData = getLangData() | ||
if customText then | |||
-- Determine display name | |||
local displayName = "" | |||
if customText ~= "" then | |||
displayName = customText | displayName = customText | ||
elseif | elseif iconData.key and langData[iconData.key] then | ||
displayName = langData[iconData.key] | |||
displayName = | |||
else | else | ||
displayName = | displayName = iconData.name | ||
end | end | ||
-- Localize link if on translated subpage | |||
local baseLink = iconData.link or "" | |||
local link = baseLink | local link = baseLink | ||
if | if langCode ~= "en" and baseLink ~= "" then | ||
link = baseLink .. "/" .. langCode | link = baseLink .. "/" .. langCode | ||
end | end | ||
-- | -- Style logic (only abilities get theme class by default) | ||
local class = iconData.class or "" | |||
local style | local style | ||
if | if class:find("theme", 1, true) then | ||
style = 'class="module-icon-ability" style="position:relative; bottom:2px;"' | style = 'class="module-icon-ability" style="position:relative; bottom:2px;"' | ||
else | else | ||
style = ' | style = 'style="position:relative; bottom:2px;"' | ||
end | end | ||
-- Generate icon HTML | |||
local imageLink = noLink and "" or link | local imageLink = noLink and "" or link | ||
local | local iconHtml = string.format('<span %s>[[File:%s|%s|link=%s]]</span>', style, iconData.image, size, imageLink) | ||
if iconOnly or displayName == "" then | if iconOnly or displayName == "" then | ||
| Line 222: | Line 257: | ||
local textHtml = (noLink or link == "") and displayName or string.format('[[%s|%s]]', link, displayName) | local textHtml = (noLink or link == "") and displayName or string.format('[[%s|%s]]', link, displayName) | ||
return '<span style="white-space:nowrap;">' .. iconHtml .. " " .. textHtml .. '</span>' | |||
end | end | ||
return p | return p | ||