Skip to content

Commit 0b5e356

Browse files
committed
Update sorting for main/checklist with new defaults. Add new table deep merge.
Main window - Restore sensible default row order when no column sort is active (recent activity, then character name + realm, then profession), so reset/right-click matches prior “who I'm on first” behaviour. - Compare characters by UTF-8 name, then realm, when names tie across realms. Checklist - Default sort when no column is selected: progress (quests completed), then points earned, then objective label for stable ordering. - Objective column sort uses the same visible label text as the cell (item, recipe, quest title), with deterministic tie-breaks. Table / UI plumbing - Table config: Explicit WK_Table* types, CopyTable + Utils:TableMergeDeep so partial nested overrides (e.g. sorting) no longer wipe sibling defaults. - Scroll frame config uses the same deep-merge pattern. Updated changelog with v1.2.7 Fixes #144 Fixes #137 Fixes #138
1 parent 335984c commit 0b5e356

7 files changed

Lines changed: 510 additions & 179 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## v1.2.7 - 2026-04-11
4+
5+
- Updated the default sorting for the Main window to sort by last character activity (like before column sorting).
6+
- Updated the default sorting for the Checklist window to prioritize progress and points.
7+
- Updated character sorting when several characters share the same name but play on different realms.
8+
- Updated the objective sorting in the Checklist window to follow the text shown in the list.
9+
310
## v1.2.6 - 2026-03-30
411

512
- Added column sorting to the main window and checklist window.

Checklist.lua

Lines changed: 196 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,63 @@ local UI = addon.UI
1313
local Table = addon.Table
1414
local Data = addon.Data
1515

16+
---@param objectiveA table
17+
---@param objectiveB table
18+
---@return boolean
19+
local function checklistObjectiveIdentityLess(objectiveA, objectiveB)
20+
local categoryIdTextA = tostring(objectiveA.categoryID or "")
21+
local categoryIdTextB = tostring(objectiveB.categoryID or "")
22+
if categoryIdTextA ~= categoryIdTextB then return categoryIdTextA < categoryIdTextB end
23+
local questIdA = (objectiveA.quests and objectiveA.quests[1]) or 0
24+
local questIdB = (objectiveB.quests and objectiveB.quests[1]) or 0
25+
if questIdA ~= questIdB then return questIdA < questIdB end
26+
local spellIdA = objectiveA.spellID or 0
27+
local spellIdB = objectiveB.spellID or 0
28+
if spellIdA ~= spellIdB then return spellIdA < spellIdB end
29+
return (objectiveA.itemID or 0) < (objectiveB.itemID or 0)
30+
end
31+
32+
---@param data { objective: table }
33+
---@return string
34+
local function checklistObjectiveRowSortText(data)
35+
local objective = data.objective
36+
if not objective then
37+
return ""
38+
end
39+
if objective.itemID and objective.itemID > 0 then
40+
local itemName = C_Item.GetItemInfo(objective.itemID)
41+
if itemName then
42+
return itemName
43+
end
44+
return format("Error: ItemID %d not found", objective.itemID or "?")
45+
end
46+
if objective.categoryID == Enum.WK_ObjectiveCategory.FirstCraft then
47+
local recipeInfo = Data.cache.tradeSkillRecipes and Data.cache.tradeSkillRecipes[objective.spellID]
48+
if not recipeInfo then
49+
recipeInfo = C_TradeSkillUI.GetRecipeInfo(objective.spellID)
50+
if recipeInfo then
51+
if not Data.cache.tradeSkillRecipes then
52+
Data.cache.tradeSkillRecipes = {}
53+
end
54+
Data.cache.tradeSkillRecipes[objective.spellID] = recipeInfo
55+
end
56+
end
57+
if recipeInfo and recipeInfo.name then
58+
return recipeInfo.name
59+
end
60+
return format("Error: RecipeID %d not found", objective.spellID or "?")
61+
end
62+
if objective.quests and Utils:TableCount(objective.quests) > 0 then
63+
local link = format("quest:%d:-1", objective.quests[1])
64+
local questTooltipData = C_TooltipInfo.GetHyperlink(link)
65+
if questTooltipData and questTooltipData.lines and questTooltipData.lines[1] and questTooltipData.lines[1].leftText then
66+
return questTooltipData.lines[1].leftText
67+
end
68+
return format("Error: QuestID %d not found", objective.quests[1] or "?")
69+
end
70+
return "Unknown"
71+
end
72+
1673
function Checklist:ToggleWindow()
1774
if not self.window then return end
1875
if self.window:IsVisible() then
@@ -39,7 +96,7 @@ function Checklist:Render()
3996
}
4097

4198
if not self.window then
42-
local frameName = addonName .. "ChecklistWindow"
99+
local frameName = format("%sChecklistWindow", addonName)
43100
self.window = CreateFrame("Frame", frameName, UIParent)
44101
self.window:SetSize(500, 500)
45102
self.window:SetFrameStrata("MEDIUM")
@@ -421,7 +478,28 @@ function Checklist:Render()
421478
sorting = {
422479
enabled = true,
423480
defaultOrder = "desc",
424-
defaultColumn = "progress",
481+
defaultCompare = function(a, b)
482+
local rowDataA, rowDataB = a.data, b.data
483+
if not rowDataA or not rowDataB then return false end
484+
local progressA, progressB = rowDataA.progress, rowDataB.progress
485+
local questsCompletedA = progressA and (progressA.questsCompleted or 0) or 0
486+
local questsCompletedB = progressB and (progressB.questsCompleted or 0) or 0
487+
if questsCompletedA ~= questsCompletedB then
488+
return questsCompletedA > questsCompletedB
489+
end
490+
local pointsEarnedA = progressA and (progressA.pointsEarned or 0) or 0
491+
local pointsEarnedB = progressB and (progressB.pointsEarned or 0) or 0
492+
if pointsEarnedA ~= pointsEarnedB then
493+
return pointsEarnedA > pointsEarnedB
494+
end
495+
local labelCompare = strcmputf8i(checklistObjectiveRowSortText(rowDataA), checklistObjectiveRowSortText(rowDataB))
496+
if labelCompare ~= 0 then
497+
return labelCompare < 0
498+
end
499+
local objectiveA, objectiveB = rowDataA.objective, rowDataB.objective
500+
if not objectiveA or not objectiveB then return false end
501+
return checklistObjectiveIdentityLess(objectiveA, objectiveB)
502+
end,
425503
savedState = Data.db.global.checklist.tableSort,
426504
onStateChanged = function(state)
427505
if not state.columnId and not state.direction then
@@ -435,7 +513,7 @@ function Checklist:Render()
435513
self.window.table:SetParent(self.window)
436514
self.window.table:SetPoint("TOPLEFT", self.window, "TOPLEFT", 0, -Constants.TITLEBAR_HEIGHT)
437515
self.window.table:SetPoint("BOTTOMRIGHT", self.window, "BOTTOMRIGHT", 0, 0)
438-
table.insert(UISpecialFrames, self.window:GetName() or (addonName .. "ChecklistWindow"))
516+
table.insert(UISpecialFrames, self.window:GetName() or format("%sChecklistWindow", addonName))
439517
end
440518

441519
if not character then
@@ -605,6 +683,7 @@ end
605683
---@return WK_TableColumn[]
606684
function Checklist:GetColumns(unfiltered)
607685
local hidden = Data.db.global.checklist.hiddenColumns
686+
608687
---@type WK_TableColumn[]
609688
local columns = {
610689
{
@@ -733,6 +812,19 @@ function Checklist:GetColumns(unfiltered)
733812
}
734813
end
735814
end,
815+
sorting = {
816+
enabled = true,
817+
compare = function(a, b)
818+
local skillLineVariantA = a.data.skillLineVariantID or 0
819+
local skillLineVariantB = b.data.skillLineVariantID or 0
820+
if skillLineVariantA ~= skillLineVariantB then return skillLineVariantA < skillLineVariantB end
821+
local labelCompare = strcmputf8i(checklistObjectiveRowSortText(a.data), checklistObjectiveRowSortText(b.data))
822+
if labelCompare ~= 0 then return labelCompare < 0 end
823+
local objectiveA, objectiveB = a.data.objective, b.data.objective
824+
if not objectiveA or not objectiveB then return false end
825+
return checklistObjectiveIdentityLess(objectiveA, objectiveB)
826+
end,
827+
},
736828
},
737829
{
738830
id = "profession",
@@ -765,11 +857,22 @@ function Checklist:GetColumns(unfiltered)
765857
end,
766858
}
767859
end,
768-
getSortValue = function(data)
769-
local variant = Data:GetSkillLineVariantByID(data.skillLineVariantID)
770-
local skillLine = variant and Data:GetSkillLineByID(variant.skillLineID or 0)
771-
return skillLine and skillLine.name:lower() or ""
772-
end,
860+
sorting = {
861+
enabled = true,
862+
compare = function(a, b)
863+
local function skillLineNameLower(rowData)
864+
local variant = Data:GetSkillLineVariantByID(rowData.skillLineVariantID)
865+
local skillLine = variant and Data:GetSkillLineByID(variant.skillLineID or 0)
866+
return skillLine and skillLine.name:lower() or ""
867+
end
868+
local nameA, nameB = skillLineNameLower(a.data), skillLineNameLower(b.data)
869+
if nameA ~= nameB then return nameA < nameB end
870+
if a.data.skillLineVariantID ~= b.data.skillLineVariantID then
871+
return a.data.skillLineVariantID < b.data.skillLineVariantID
872+
end
873+
return Utils:CompareCharacterNameRealm(a.data.character, b.data.character) < 0
874+
end,
875+
},
773876
},
774877
{
775878
id = "expansion",
@@ -783,11 +886,22 @@ function Checklist:GetColumns(unfiltered)
783886
text = expansion and expansion.name or "",
784887
}
785888
end,
786-
getSortValue = function(data)
787-
local v = Data:GetSkillLineVariantByID(data.skillLineVariantID)
788-
local expansion = v and Data:GetExpansionByID(v.expansionID)
789-
return expansion and expansion.name:lower() or ""
790-
end,
889+
sorting = {
890+
enabled = true,
891+
compare = function(a, b)
892+
local function expansionNameLower(rowData)
893+
local variant = Data:GetSkillLineVariantByID(rowData.skillLineVariantID)
894+
local expansion = variant and Data:GetExpansionByID(variant.expansionID)
895+
return expansion and expansion.name:lower() or ""
896+
end
897+
local nameA, nameB = expansionNameLower(a.data), expansionNameLower(b.data)
898+
if nameA ~= nameB then return nameA < nameB end
899+
if a.data.skillLineVariantID ~= b.data.skillLineVariantID then
900+
return a.data.skillLineVariantID < b.data.skillLineVariantID
901+
end
902+
return Utils:CompareCharacterNameRealm(a.data.character, b.data.character) < 0
903+
end,
904+
},
791905
},
792906
{
793907
id = "category",
@@ -815,10 +929,21 @@ function Checklist:GetColumns(unfiltered)
815929
end,
816930
}
817931
end,
818-
getSortValue = function(data)
819-
local oc = Data:GetObjectiveCategoryByID(data.objective.categoryID)
820-
return oc and oc.name:lower() or ""
821-
end,
932+
sorting = {
933+
enabled = true,
934+
compare = function(a, b)
935+
local function categoryNameLower(rowData)
936+
local objectiveCategory = Data:GetObjectiveCategoryByID(rowData.objective.categoryID)
937+
return objectiveCategory and objectiveCategory.name:lower() or ""
938+
end
939+
local nameA, nameB = categoryNameLower(a.data), categoryNameLower(b.data)
940+
if nameA ~= nameB then return nameA < nameB end
941+
if a.data.skillLineVariantID ~= b.data.skillLineVariantID then
942+
return a.data.skillLineVariantID < b.data.skillLineVariantID
943+
end
944+
return Utils:CompareCharacterNameRealm(a.data.character, b.data.character) < 0
945+
end,
946+
},
822947
},
823948
{
824949
id = "location",
@@ -842,9 +967,18 @@ function Checklist:GetColumns(unfiltered)
842967
text = text
843968
}
844969
end,
845-
getSortValue = function(data)
846-
return data.objective.loc and data.objective.loc.m or 0
847-
end,
970+
sorting = {
971+
enabled = true,
972+
compare = function(a, b)
973+
local mapIdA = a.data.objective.loc and a.data.objective.loc.m or 0
974+
local mapIdB = b.data.objective.loc and b.data.objective.loc.m or 0
975+
if mapIdA ~= mapIdB then return mapIdA < mapIdB end
976+
if a.data.skillLineVariantID ~= b.data.skillLineVariantID then
977+
return a.data.skillLineVariantID < b.data.skillLineVariantID
978+
end
979+
return Utils:CompareCharacterNameRealm(a.data.character, b.data.character) < 0
980+
end,
981+
},
848982
},
849983
{
850984
id = "repeatable",
@@ -869,10 +1003,21 @@ function Checklist:GetColumns(unfiltered)
8691003
text = objectiveCategory.repeatable or "",
8701004
}
8711005
end,
872-
getSortValue = function(data)
873-
local objectiveCategory = Data:GetObjectiveCategoryByID(data.objective.categoryID)
874-
return objectiveCategory and objectiveCategory.repeatable or ""
875-
end,
1006+
sorting = {
1007+
enabled = true,
1008+
compare = function(a, b)
1009+
local function repeatableLabel(rowData)
1010+
local objectiveCategory = Data:GetObjectiveCategoryByID(rowData.objective.categoryID)
1011+
return objectiveCategory and objectiveCategory.repeatable or ""
1012+
end
1013+
local labelA, labelB = repeatableLabel(a.data), repeatableLabel(b.data)
1014+
if labelA ~= labelB then return labelA < labelB end
1015+
if a.data.skillLineVariantID ~= b.data.skillLineVariantID then
1016+
return a.data.skillLineVariantID < b.data.skillLineVariantID
1017+
end
1018+
return Utils:CompareCharacterNameRealm(a.data.character, b.data.character) < 0
1019+
end,
1020+
},
8761021
},
8771022
{
8781023
id = "progress",
@@ -890,10 +1035,18 @@ function Checklist:GetColumns(unfiltered)
8901035
text = text,
8911036
}
8921037
end,
893-
getSortValue = function(data)
894-
local p = data.progress
895-
return p and (p.questsCompleted or 0) or 0
896-
end,
1038+
sorting = {
1039+
enabled = true,
1040+
compare = function(a, b)
1041+
local questsCompletedA = a.data.progress and (a.data.progress.questsCompleted or 0) or 0
1042+
local questsCompletedB = b.data.progress and (b.data.progress.questsCompleted or 0) or 0
1043+
if questsCompletedA ~= questsCompletedB then return questsCompletedA < questsCompletedB end
1044+
if a.data.skillLineVariantID ~= b.data.skillLineVariantID then
1045+
return a.data.skillLineVariantID < b.data.skillLineVariantID
1046+
end
1047+
return Utils:CompareCharacterNameRealm(a.data.character, b.data.character) < 0
1048+
end,
1049+
},
8971050
},
8981051
{
8991052
id = "points",
@@ -912,17 +1065,27 @@ function Checklist:GetColumns(unfiltered)
9121065
text = text,
9131066
}
9141067
end,
915-
getSortValue = function(data)
916-
local p = data.progress
917-
return p and (p.pointsEarned or 0) or 0
918-
end,
1068+
sorting = {
1069+
enabled = true,
1070+
compare = function(a, b)
1071+
local pointsEarnedA = a.data.progress and (a.data.progress.pointsEarned or 0) or 0
1072+
local pointsEarnedB = b.data.progress and (b.data.progress.pointsEarned or 0) or 0
1073+
if pointsEarnedA ~= pointsEarnedB then return pointsEarnedA < pointsEarnedB end
1074+
if a.data.skillLineVariantID ~= b.data.skillLineVariantID then
1075+
return a.data.skillLineVariantID < b.data.skillLineVariantID
1076+
end
1077+
return Utils:CompareCharacterNameRealm(a.data.character, b.data.character) < 0
1078+
end,
1079+
},
9191080
},
9201081
{
9211082
id = "waypoint",
9221083
headerText = "",
9231084
width = 50,
9241085
align = "CENTER",
925-
sortable = false,
1086+
sorting = {
1087+
enabled = false,
1088+
},
9261089
renderCell = function(data)
9271090
local TomTomGlobal = _G["TomTom"]
9281091
local mapInfo = nil

Interface.lua

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ local Utils = addon.Utils
1414
function UI:CreateScrollFrame(config)
1515
local tableCount = addon.Table and addon.Table.collection and Utils:TableCount(addon.Table.collection) or 0
1616
local frame = CreateFrame("ScrollFrame", "WeeklyKnowledgeScrollFrame" .. (tableCount + 1))
17-
frame.config = CreateFromMixins(
18-
{
19-
scrollSpeedHorizontal = 20,
20-
scrollSpeedVertical = 20,
21-
},
22-
config or {}
23-
)
17+
local defaultScrollConfig = {
18+
scrollSpeedHorizontal = 20,
19+
scrollSpeedVertical = 20,
20+
}
21+
local mergedScrollConfig = CopyTable(defaultScrollConfig)
22+
Utils:TableMergeDeep(mergedScrollConfig, config or {})
23+
frame.config = mergedScrollConfig
2424

2525
frame.content = CreateFrame("Frame", "$parentContent", frame)
2626
frame.scrollbarH = CreateFrame("Slider", "$parentScrollbarH", frame, "UISliderTemplate")

0 commit comments

Comments
 (0)