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:
@@ -7,6 +7,7 @@
|
||||
|
||||
Core.lua
|
||||
Util\Json.lua
|
||||
Util\TalentEncoder.lua
|
||||
UI\ExportFrame.lua
|
||||
Collectors\Talents.lua
|
||||
Collectors\Gear.lua
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user