Add Talent URL encoding and Markdown export

- Introduced `TalentEncoder.lua` to encode talents into URL format for easier sharing via talent calculator links.
- Implemented `GenerateMarkdownTalents()` for Markdown-based talent exports, including embedded iframe support.
- Enhanced slash command to support `mdtalents` for talent Markdown export.
- Updated UI with "MD Talents" button to trigger talent Markdown exports.
- Adjusted TOC and UI layout to integrate the new functionality.
This commit is contained in:
2025-12-08 17:23:36 +01:00
parent 03c369e10e
commit 4f81bd94fa
4 changed files with 140 additions and 2 deletions
+1
View File
@@ -7,6 +7,7 @@
Core.lua
Util\Json.lua
Util\TalentEncoder.lua
UI\ExportFrame.lua
Collectors\Talents.lua
Collectors\Gear.lua
+32 -1
View File
@@ -337,6 +337,34 @@ function AE:GenerateMarkdownEnchants()
return table.concat(lines, "\n")
end
-- Markdown talents export generator
function AE:GenerateMarkdownTalents()
local talents = self.CollectTalents and self.CollectTalents() or { selected = {} }
local _, class = UnitClass("player")
local lines = {}
table.insert(lines, "## Talents\n")
if #(talents.selected or {}) == 0 then
table.insert(lines, "*No talents selected.*\n")
return table.concat(lines, "\n")
end
-- Generate the talent calc URL
local url = self.GenerateTalentCalcURL and self.GenerateTalentCalcURL(talents, class)
if url then
table.insert(lines, string.format("[View in Talent Calculator](%s)\n", url))
end
-- Optional: embed iframe for Wiki.js
local build = self.EncodeTalentsToURL and self.EncodeTalentsToURL(talents, class)
if build then
table.insert(lines, string.format('<iframe src="/static/talents/?build=%s&embed=true" width="100%%" height="840" style="border: 0px solid #333; border-radius: 8px;"></iframe>\n', build))
end
return table.concat(lines, "\n")
end
-- Slash command handling
SLASH_ASCX1 = "/ascx"
SLASH_ASCX2 = "/asxc" -- alias: both map to the same handler key "ASCX"
@@ -348,7 +376,7 @@ SlashCmdList["ASCX"] = function(msg)
-- avoid referencing buttons that won't be present in the fallback window.
local hasButtons = type(_G.AscensionExporter_ShowExportFrame) == "function"
local prefix = hasButtons and "Use the buttons above or type:" or "Type one of the commands:"
local help = prefix .. "\n/ascx export all|talents|gear|enchants|mdgear\n/ascx sv on|off (SavedVariables is currently " .. (AscensionExporterConfig.enableSavedVariables and "ON" or "OFF") .. ")\n/ascx debug (show collector status)\n"
local help = prefix .. "\n/ascx export all|talents|gear|enchants|mdgear|mdtalents\n/ascx sv on|off (SavedVariables is currently " .. (AscensionExporterConfig.enableSavedVariables and "ON" or "OFF") .. ")\n/ascx debug (show collector status)\n"
AE:ShowExport(help, "Ascension Export - Tools & Help")
return
end
@@ -359,6 +387,9 @@ SlashCmdList["ASCX"] = function(msg)
if rest == "mdgear" or rest == "md" then
local md = AE:GenerateMarkdownGear()
AE:ShowExport(md, "Ascension Export - Markdown Gear - Copy All (Ctrl+C)")
elseif rest == "mdtalents" then
local md = AE:GenerateMarkdownTalents()
AE:ShowExport(md, "Ascension Export - Markdown Talents - Copy All (Ctrl+C)")
elseif rest == "all" or rest == "talents" or rest == "gear" or rest == "enchants" then
AE:Export(rest)
else
+14 -1
View File
@@ -66,9 +66,22 @@ local function CreateOrGetFrame()
end
end)
-- Second row for additional buttons
local x2 = 0
makeBtn("MD Talents", x2, function()
if AscensionExporter and AscensionExporter.GenerateMarkdownTalents then
local md = AscensionExporter:GenerateMarkdownTalents() or ""
if AscensionExporter.ShowExport then
AscensionExporter:ShowExport(md, "Ascension Export - Markdown Talents - Copy All (Ctrl+C)")
else
AscensionExporter_ShowExportFrame(md, "Ascension Export - Markdown Talents - Copy All (Ctrl+C)")
end
end
end):SetPoint("TOPLEFT", 16 + x2, -62)
-- ScrollFrame + EditBox
local scrollFrame = CreateFrame("ScrollFrame", "AscensionExporterScrollFrame", frame, "UIPanelScrollFrameTemplate")
scrollFrame:SetPoint("TOPLEFT", 16, -64)
scrollFrame:SetPoint("TOPLEFT", 16, -90)
scrollFrame:SetPoint("BOTTOMRIGHT", -32, 16)
local editBox = CreateFrame("EditBox", "AscensionExporterEditBox", scrollFrame)
+93
View File
@@ -0,0 +1,93 @@
-- AscensionExporter - Talent URL Encoder
-- Encodes talents into URL format for https://exil.es/en/wow/talent-calc?build=...
AscensionExporter = _G.AscensionExporter or {}
_G.AscensionExporter = AscensionExporter
local AE = AscensionExporter
local BASE36_CHARS = "0123456789abcdefghijklmnopqrstuvwxyz"
local function encodeRank(rank)
if rank < 10 then
return tostring(rank)
end
-- For ranks >= 10, use base36 (a=10, b=11, etc)
if rank <= 35 then
return BASE36_CHARS:sub(rank + 1, rank + 1)
end
return "0"
end
local function toBase36(num)
if num == 0 then return "0" end
local result = ""
while num > 0 do
local remainder = num % 36
result = BASE36_CHARS:sub(remainder + 1, remainder + 1) .. result
num = math.floor(num / 36)
end
return result
end
-- Encode talents to URL format
-- Format: `${class}.${tree0}.${tree1}.${tree2}`
-- Each tree is encoded as "index_rank" pairs separated by underscores
-- Example: "0_3_b_5" means slot 0 has rank 3, slot 11 (b in base36) has rank 5
function AE.EncodeTalentsToURL(talentsData, className)
if not talentsData or not className then
return nil
end
-- Normalize class name to lowercase
className = className:lower()
-- Build a structure: 3 talent trees with slots
-- Each WoW class has 3 talent trees
local trees = {{}, {}, {}}
-- Group talents by their tabIndex (1-based in Lua, but we want 0-based for array)
for _, t in ipairs(talentsData.selected or {}) do
local tabIndex = t.tabIndex or 1
local talentIndex = (t.talentIndex or 1) - 1 -- Convert to 0-based index
local rank = t.rank or 0
if rank > 0 and tabIndex >= 1 and tabIndex <= 3 then
table.insert(trees[tabIndex], {
index = talentIndex,
rank = rank
})
end
end
-- Sort each tree by index for consistent encoding
for _, tree in ipairs(trees) do
table.sort(tree, function(a, b) return a.index < b.index end)
end
-- Encode each tree
local treeParts = {}
for _, tree in ipairs(trees) do
local pairs = {}
for _, talent in ipairs(tree) do
local idxStr = toBase36(talent.index)
local rankStr = encodeRank(talent.rank)
table.insert(pairs, idxStr .. rankStr)
end
table.insert(treeParts, table.concat(pairs, "_"))
end
-- Build final URL format: class.tree0.tree1.tree2
return className .. "." .. table.concat(treeParts, ".")
end
-- Generate full talent calc URL
function AE.GenerateTalentCalcURL(talentsData, className)
local build = AE.EncodeTalentsToURL(talentsData, className)
if not build then
return nil
end
return "https://exil.es/en/wow/talent-calc?build=" .. build
end
-- Mark module as loaded
AE._loadedTalentEncoder = true