From 5f761e76ff38d1cc9b1359a15c69c39bd373b32e Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 11 Oct 2025 10:59:35 +0900 Subject: [PATCH 01/57] use anyOf --- lua/wikis/commons/MatchTable.lua | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 91ed9378b7e..e4a65eb2ac4 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -43,6 +43,7 @@ local ConditionNode = Condition.Node local Comparator = Condition.Comparator local BooleanOperator = Condition.BooleanOperator local ColumnName = Condition.ColumnName +local ConditionUtil = Condition.Util local DRAW_WINNER = 0 local INVALID_TIER_DISPLAY = 'Undefined' @@ -392,10 +393,7 @@ function MatchTable:buildAdditionalConditions() local getOrCondition = function(lpdbKey, input) if Logic.isEmpty(input) then return end - local orConditions = ConditionTree(BooleanOperator.any) - Array.forEach(mw.text.split(input, ','), function(value) - orConditions:add{ConditionNode(ColumnName(lpdbKey), Comparator.eq, String.trim(value))} - end) + local orConditions = ConditionUtil.anyOf(ColumnName(lpdbKey), Array.parseCommaSeparatedString(input, ',')) conditions:add(orConditions) end From eddce8b28486d5d16636b534bb308b230c4a4e66 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 11 Oct 2025 11:07:06 +0900 Subject: [PATCH 02/57] parseCommaSeparatedString --- lua/wikis/commons/MatchTable.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index e4a65eb2ac4..10e5be19602 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -203,7 +203,7 @@ function MatchTable:_readOpponentInputsFromBase(base) if Logic.isNotEmpty(inputs) or Logic.isEmpty(self.args[base .. 's']) then return inputs end - return Array.map(mw.text.split(self.args[base .. 's'], ',', true), String.trim) + return Array.parseCommaSeparatedString(self.args[base .. 's']) end ---@param mode MatchTableMode @@ -225,7 +225,7 @@ function MatchTable:readAliases(mode) local aliases = {} if String.isEmpty(self.args.aliases) then return aliases end - local aliasInput = Array.map(mw.text.split(self.args.aliases, ','), String.trim) + local aliasInput = Array.parseCommaSeparatedString(self.args.aliases) Array.forEach(aliasInput, function(alias) alias = alias:gsub(' ', '_') From 6f5bb239a7a5753f859005dceda2a7de7096a501 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 11 Oct 2025 16:14:10 +0900 Subject: [PATCH 03/57] code conciseness Co-authored-by: hjpalpha <75081997+hjpalpha@users.noreply.github.com> --- lua/wikis/commons/MatchTable.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 10e5be19602..db8575b31fd 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -393,8 +393,7 @@ function MatchTable:buildAdditionalConditions() local getOrCondition = function(lpdbKey, input) if Logic.isEmpty(input) then return end - local orConditions = ConditionUtil.anyOf(ColumnName(lpdbKey), Array.parseCommaSeparatedString(input, ',')) - conditions:add(orConditions) + conditions:add(ConditionUtil.anyOf(ColumnName(lpdbKey), Array.parseCommaSeparatedString(input, ','))) end getOrCondition('liquipediatier', args.tier) From 096186124087d07ab708bbe969c806e6fcf803f6 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:38:37 +0900 Subject: [PATCH 04/57] remove redundant comma --- lua/wikis/commons/MatchTable.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index db8575b31fd..00dc856d3f7 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -393,7 +393,7 @@ function MatchTable:buildAdditionalConditions() local getOrCondition = function(lpdbKey, input) if Logic.isEmpty(input) then return end - conditions:add(ConditionUtil.anyOf(ColumnName(lpdbKey), Array.parseCommaSeparatedString(input, ','))) + conditions:add(ConditionUtil.anyOf(ColumnName(lpdbKey), Array.parseCommaSeparatedString(input))) end getOrCondition('liquipediatier', args.tier) From e0dd11adb2459d25584c89dda8947140e9fcfd49 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:41:13 +0900 Subject: [PATCH 05/57] commaSeparatedString --- lua/wikis/commons/MatchTable.lua | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 00dc856d3f7..4c0c9e98f6c 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -284,10 +284,10 @@ function MatchTable:readTimeRange() end --build year range from subpage name (or input) - local yearRange = Array.map(mw.text.split(yearsString, '-'), String.trim) - yearRange = { - tonumber(yearRange[1]), - tonumber(yearRange[2] or yearRange[1]), + local yearInput = Array.parseCommaSeparatedString(yearsString, '-') + local yearRange = { + tonumber(yearInput[1]), + tonumber(yearInput[2] or yearInput[1]), } --sort @@ -387,8 +387,9 @@ end ---@return ConditionTree? function MatchTable:buildAdditionalConditions() local args = self.args - local conditions = ConditionTree(BooleanOperator.all) - :add{ConditionNode(ColumnName('status'), Comparator.neq, 'notplayed')} + local conditions = ConditionTree(BooleanOperator.all):add( + ConditionNode(ColumnName('status'), Comparator.neq, 'notplayed') + ) local getOrCondition = function(lpdbKey, input) if Logic.isEmpty(input) then return end From 0dcacef4b2833e4d83e1b5b6a7d243e0f16b45cd Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:42:48 +0900 Subject: [PATCH 06/57] clean up condition building --- lua/wikis/commons/MatchTable.lua | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 4c0c9e98f6c..4cecda8219a 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -306,7 +306,7 @@ function MatchTable:query() self.matches = {} Lpdb.executeMassQuery('match2', { - conditions = self:buildConditions(), + conditions = tostring(self:buildConditions()), order = 'date desc', query = 'match2id, match2opponents, match2games, date, dateexact, icon, icondark, liquipediatier, game, type,' .. 'liquipediatiertype, tournament, pagename, parent, section, tickername, vod, winner, match2bracketdata,' @@ -328,14 +328,13 @@ function MatchTable:query() return self end ----@return string +---@return ConditionTree function MatchTable:buildConditions() return ConditionTree(BooleanOperator.all) - :add{ConditionNode(ColumnName('finished'), Comparator.eq, 1)} - :add{self:buildDateConditions()} - :add{self:buildOpponentConditions()} - :add{self:buildAdditionalConditions()} - :toString() + :add(ConditionNode(ColumnName('finished'), Comparator.eq, 1)) + :add(self:buildDateConditions()) + :add(self:buildOpponentConditions()) + :add(self:buildAdditionalConditions()) end ---@return ConditionTree? From 85533eb96e145c6fe0a28f68ab8a115af174e6f9 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 16:02:19 +0900 Subject: [PATCH 07/57] use MGUMatch for processing --- lua/wikis/commons/MatchTable.lua | 54 ++++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 4cecda8219a..5aa1f9278e9 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -89,11 +89,11 @@ local SECONDS_ONE_DAY = 3600 * 24 ---@field result MatchTableMatchResult ---@class MatchTableMatchResult ----@field opponent match2opponent +---@field opponent standardOpponent ---@field gameOpponents table[] ----@field vs match2opponent +---@field vs standardOpponent ---@field gameVsOpponents table[] ----@field winner number +---@field winner number? ---@field countGames boolean ---@field countRounds boolean @@ -410,21 +410,17 @@ function MatchTable:buildAdditionalConditions() return conditions end ----@param record table +---@param record match2 ---@return MatchTableMatch? function MatchTable:matchFromRecord(record) - local result = self:resultFromRecord(record) + local match = MatchGroupUtil.matchFromRecord(record) --[[@as MatchTableMatch]] + local result = self:resultFromRecord(match) if not result then return end - record.extradata = record.extradata or {} - - ---@type MatchTableMatch - local match = Table.merge({ - vods = self:vodsFromRecord(record), - result = result, - }, MatchGroupUtil.matchFromRecord(record)) + match.result = result + match.vods = self:vodsFromRecord(match) local tournament = Tournament.partialTournamentFromMatch(match) @@ -438,16 +434,16 @@ function MatchTable:matchFromRecord(record) return match end ----@param record table +---@param record MatchGroupUtilMatch ---@return {index: number, link: string}[] function MatchTable:vodsFromRecord(record) local vods = {} if String.nilIfEmpty(record.vod) then - vods = {{index = 0, link = record.vod}} + vods[1] = {index = 0, link = record.vod} end - Array.forEach(record.match2games, function(game, gameIndex) - if String.nilIfEmpty(game.vod) then + Array.forEach(record.games, function(game, gameIndex) + if String.isNotEmpty(game.vod) then table.insert(vods, {link = game.vod, index = gameIndex}) end end) @@ -455,10 +451,10 @@ function MatchTable:vodsFromRecord(record) return vods end ----@param record table +---@param record MatchGroupUtilMatch ---@return MatchTableMatchResult? function MatchTable:resultFromRecord(record) - if #record.match2opponents ~= 2 then + if #record.opponents ~= 2 then return self:resultFromNonStandardRecord(record) end @@ -466,22 +462,24 @@ function MatchTable:resultFromRecord(record) local countGames = false local countRounds = false + ---@param opponentRecord standardOpponent + ---@return boolean local foundInAlias = function(opponentRecord) if aliases[opponentRecord.name] then countGames = true countRounds = self.config.showRoundStats return true end - return self.config.mode == Opponent.solo and Array.any(opponentRecord.match2players, function(player) - return aliases[player.name] or false + return self.config.mode == Opponent.solo and Array.any(opponentRecord.players, function(player) + return aliases[player.pageName] or false end) end - local winner = tonumber(record.winner) + local winner = record.winner local indexes - if foundInAlias(record.match2opponents[1]) then + if foundInAlias(record.opponents[1]) then indexes = {1, 2} - elseif foundInAlias(record.match2opponents[2]) then + elseif foundInAlias(record.opponents[2]) then indexes = {2, 1} winner = winner == 2 and 1 or winner == 1 and 2 or winner else @@ -490,10 +488,12 @@ function MatchTable:resultFromRecord(record) return end - local gameOpponents = Array.map(record.match2games, Operator.property('opponents')) + local gameOpponents = Array.map(record.games, Operator.property('opponents')) + + ---@type MatchTableMatchResult local result = { - opponent = record.match2opponents[indexes[1]], - vs = record.match2opponents[indexes[2]], + opponent = record.opponents[indexes[1]], + vs = record.opponents[indexes[2]], winner = winner, countGames = countGames, countRounds = countRounds, @@ -505,7 +505,7 @@ function MatchTable:resultFromRecord(record) end ---overwritable for wikis that have BR/FFA matches ----@param record table +---@param record MatchGroupUtilMatch ---@return table? function MatchTable:resultFromNonStandardRecord(record) end From 6788ea49fd2221ea04a44431ba74980d194e20d5 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 16:05:30 +0900 Subject: [PATCH 08/57] type conciseness --- lua/wikis/commons/MatchTable.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 5aa1f9278e9..2baf72c3cc1 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -54,6 +54,7 @@ local BO1_SCORE_CONCAT = ' - ' local SECONDS_ONE_DAY = 3600 * 24 ---@alias MatchTableMode `Opponent.solo` | `Opponent.team` +---@alias WDLCount {w: number, d: number, l: number} ---@class MatchTableConfig ---@field mode MatchTableMode @@ -510,7 +511,7 @@ end function MatchTable:resultFromNonStandardRecord(record) end ----@return {matches: {w: number, d: number, l: number}, games: {w: number, d: number, l: number}} +---@return {matches: WDLCount, games: WDLCount, rounds: WDLCount} function MatchTable:statsFromMatches() local totalMatches = {w = 0, d = 0, l = 0} local totalGames = {w = 0, d = 0, l = 0} From 5a8be95a15a1785ecf65d9920a6570249e16b43b Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 16:05:40 +0900 Subject: [PATCH 09/57] type annotation --- lua/wikis/commons/MatchTable.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 2baf72c3cc1..d1e78e9e74e 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -521,6 +521,8 @@ function MatchTable:statsFromMatches() return math.max(tonumber(value) or 0, 0) end + ---@param opponent standardOpponent + ---@return boolean local hasWalkoverStatus = function(opponent) return Logic.isNotEmpty(opponent.status) and opponent.status ~= 'S' end From 54a3e6405479448a2ee983b68478433fc897c5ed Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 16:10:57 +0900 Subject: [PATCH 10/57] use standardOpponent --- lua/wikis/commons/MatchTable.lua | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index d1e78e9e74e..b46e9b8a646 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -798,12 +798,11 @@ function MatchTable:nonStandardMatch(match) :wikitext('') end ----@param opponentRecord match2opponent +---@param opponent standardOpponent ---@param flipped boolean? ---@return Html -function MatchTable:_displayOpponent(opponentRecord, flipped) +function MatchTable:_displayOpponent(opponent, flipped) local cell = mw.html.create('td') - local opponent = Opponent.fromMatch2Record(opponentRecord) if Logic.isEmpty(opponent) then return cell:wikitext('Unknown') end return cell @@ -824,13 +823,13 @@ function MatchTable:_displayScore(match) return opponent.status == 'S' end) local bestof1Score = match.bestof == 1 and Info.config.match2.gameScoresIfBo1 and hasOnlyScores - ---@param opponentRecord match2opponent + ---@param opponent standardOpponent ---@param gameOpponents table[] ---@return Html|string - local toScore = function(opponentRecord, gameOpponents) - if Table.isEmpty(opponentRecord) or not opponentRecord.status then return 'Unkn' end - local score = OpponentDisplay.InlineScore(opponentRecord) - local status = opponentRecord.status + local toScore = function(opponent, gameOpponents) + if Table.isEmpty(opponent) or not opponent.status then return 'Unkn' end + local score = OpponentDisplay.InlineScore(opponent) + local status = opponent.status local game1Opponent = gameOpponents[1] if bestof1Score and game1Opponent then @@ -838,7 +837,7 @@ function MatchTable:_displayScore(match) status = game1Opponent.status end - return mw.html.create(tonumber(opponentRecord.placement) == 1 and 'b' or nil) + return mw.html.create(tonumber(opponent.placement) == 1 and 'b' or nil) :wikitext(status == SCORE_STATUS and (score or '–') or status) end From af0145fde5e095c0431fd2bea7f4d163d30d96ae Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 16:53:42 +0900 Subject: [PATCH 11/57] extract matchtable style to separate file --- stylesheets/Main.scss | 1 + stylesheets/commons/MatchTable.scss | 14 ++++++++++++++ stylesheets/commons/Miscellaneous.scss | 16 ---------------- 3 files changed, 15 insertions(+), 16 deletions(-) create mode 100644 stylesheets/commons/MatchTable.scss diff --git a/stylesheets/Main.scss b/stylesheets/Main.scss index b5f39d63f02..91b2d1400b9 100644 --- a/stylesheets/Main.scss +++ b/stylesheets/Main.scss @@ -26,6 +26,7 @@ @use "commons/Infobox"; @use "commons/Mainpage"; @use "commons/Matchseries"; +@use "commons/MatchTable"; @use "commons/NavigationCard"; @use "commons/Miscellaneous"; @use "commons/BigMatch"; diff --git a/stylesheets/commons/MatchTable.scss b/stylesheets/commons/MatchTable.scss new file mode 100644 index 00000000000..97a238c7a8f --- /dev/null +++ b/stylesheets/commons/MatchTable.scss @@ -0,0 +1,14 @@ +/******************************************************************************* +Template(s): MatchTable +*******************************************************************************/ +.recent-matches-bg-win { + background-color: var( --table-green-background-color, #f0fff0 ) !important; +} + +.recent-matches-bg-tie { + background-color: var( --table-yellow-background-color, #f9f9c7 ) !important; +} + +.recent-matches-bg-lose { + background-color: var( --table-red-background-color, #f9f0f2 ) !important; +} diff --git a/stylesheets/commons/Miscellaneous.scss b/stylesheets/commons/Miscellaneous.scss index 2369d5af2a7..682381c8da0 100644 --- a/stylesheets/commons/Miscellaneous.scss +++ b/stylesheets/commons/Miscellaneous.scss @@ -2318,22 +2318,6 @@ Author(s): iMarbot color: #8b0000; } -/******************************************************************************* -Template(s): Template:Team matches table -Author(s): iMarbot via ??? -*******************************************************************************/ -.recent-matches-bg-win { - background-color: var( --table-green-background-color, #f0fff0 ) !important; -} - -.recent-matches-bg-tie { - background-color: var( --table-yellow-background-color, #f9f9c7 ) !important; -} - -.recent-matches-bg-lose { - background-color: var( --table-red-background-color, #f9f0f2 ) !important; -} - /******************************************************************************* Template(s): white-space as classes Author(s): iMarbot From 1c7ef27b197bfdf8a0fd45379485217066618ade Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 17:22:57 +0900 Subject: [PATCH 12/57] use new table --- lua/wikis/commons/MatchTable.lua | 377 +++++++++++++++++++------------ 1 file changed, 234 insertions(+), 143 deletions(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index b46e9b8a646..8c9bb1b91b9 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -36,6 +36,8 @@ local OpponentDisplay = Lua.import('Module:OpponentDisplay/Custom') local Link = Lua.import('Module:Widget/Basic/Link') local MatchPageButton = Lua.import('Module:Widget/Match/PageButton') local HtmlWidgets = Lua.import('Module:Widget/Html/All') +local TableWidgets = Lua.import('Module:Widget/Table2/All') +local WidgetUtil = Lua.import('Module:Widget/Util') local Condition = Lua.import('Module:Condition') local ConditionTree = Condition.Tree @@ -568,34 +570,6 @@ function MatchTable:buildDisplay() :node(self:_titleRow(self.config.title)) :node(self:headerRow()) - if Table.isEmpty(self.matches) then - ---@return string - local function getNoResultText() - local isH2H = Logic.isNotEmpty(self.config.vs) - if isH2H then - return I18n.translate( - 'matchtable-no-h2h-match-results', - { - mode = self.config.mode == Opponent.solo and 'players' or 'teams', - } - ) - end - return I18n.translate( - 'matchtable-no-match-results', - { - mode = self.config.mode == Opponent.solo and 'player' or 'team', - } - ) - end - - return display:tag('tr') - :tag('td') - :attr('colspan', '100') - :css('font-style', 'italic') - :wikitext(getNoResultText()) - :allDone() - end - local currentYear Array.forEach(self.matches, function(match) local year = tonumber(match.date:sub(1, 4)) @@ -606,16 +580,16 @@ function MatchTable:buildDisplay() display:node(self:matchRow(match)) end) - if self.config.linkSubPage then - local pagename = self.title.text .. '/Matches' - display:tag('tr') - :tag('th') - :attr('colspan', 42) - :css('font-style', 'italic') - :wikitext('[[' .. pagename .. '|Extended list of matches]]') - end - - return display + return TableWidgets.Table{ + sortable = true, + columns = self:_buildColumnDefinitions(), + title = String.nilIfEmpty(self.config.title), + children = WidgetUtil.collect( + self:headerRow(), + TableWidgets.TableBody{children = self:buildBody()} + ), + footer = self:buildFooter() + } end ---@return Html @@ -641,79 +615,193 @@ function MatchTable:_titleRow(title) :done() end +---@private +---@return table[] +function MatchTable:_buildColumnDefinitions() + local config = self.config + return WidgetUtil.collect( + { + -- Date column + align = 'left', + sortType = 'number', + }, + config.showTier and {align = 'left'} or nil, + config.showType and {align = 'center'} or nil, + config.displayGameIcons and {align = 'center'} or nil, + config.showIcon and { + align = 'center', + unsortable = true, + } or nil, + { + -- Tournament column + align = 'left', + }, + config.showResult and WidgetUtil.collect( + config.showOpponent and {align = 'center'} or nil, + { + -- Score column + align = 'center', + }, + { + -- vs Opponent column + align = 'left' + } + ) or nil, + config.showVod and { + align = 'left', + unsortable = true, + } or nil, + config.showMatchPage and { + align = 'center', + unsortable = true, + } or nil + ) +end + ---@param year number? ----@return Html? +---@return Widget? function MatchTable:_yearRow(year) if not year then return end - return mw.html.create('tr') - :addClass('sortbottom') - :tag('td') - :attr('colspan', '100') - :addClass('match-table-year-header') - :wikitext(year) - :done() + return TableWidgets.Row{ + section = 'subhead', + classes = {'sortbottom'}, + css = {['font-weight'] = 'bold'}, + children = TableWidgets.CellHeader{ + align = 'center', + colspan = 100, + children = year + } + } end ---@return Html function MatchTable:headerRow() - local makeHeaderCell = function(text, width) - return mw.html.create('th'):css('max-width', width):node(text) + ---@param text string? + ---@return Widget + local makeHeaderCell = function(text) + return TableWidgets.CellHeader{children = text} end local config = self.config - return mw.html.create('tr') - :node(makeHeaderCell('Date', '100px')) - :node(config.showTier and makeHeaderCell('Tier', '70px') or nil) - :node(config.showType and makeHeaderCell('Type', '70px') or nil) - :node(config.displayGameIcons and makeHeaderCell(nil, '25px') or nil) - :node(config.showIcon and makeHeaderCell(nil, '25px'):addClass('unsortable') or nil) - :node(makeHeaderCell('Tournament')) - :node(config.showResult and config.showOpponent and makeHeaderCell('Participant', '120px') or nil) - :node(config.showResult and makeHeaderCell('Score', '68px'):addClass('unsortable') or nil) - :node(config.showResult and makeHeaderCell('vs. Opponent', '120px') or nil) - :node(config.showVod and makeHeaderCell('VOD(s)', '80px'):addClass('unsortable') or nil) - :node(config.showMatchPage and makeHeaderCell(''):addClass('unsortable') or nil) + return TableWidgets.TableHeader{children = { + TableWidgets.Row{children = WidgetUtil.collect( + makeHeaderCell('Date'), + config.showTier and makeHeaderCell('Tier') or nil, + config.showType and makeHeaderCell('Type') or nil, + config.displayGameIcons and makeHeaderCell() or nil, + config.showIcon and makeHeaderCell() or nil, + makeHeaderCell('Tournament'), + config.showResult and WidgetUtil.collect( + config.showOpponent and makeHeaderCell('Participant') or nil, + makeHeaderCell('Score'), + TableWidgets.CellHeader{ + align = 'center', + children = 'vs. Opponent' + } + ) or nil, + config.showVod and TableWidgets.CellHeader{ + align = 'center', + children = 'VOD(s)' + } or nil, + config.showMatchPage and makeHeaderCell() or nil + )} + }} +end + +---@return Widget[] +function MatchTable:buildBody() + if Table.isEmpty(self.matches) then + ---@return string + local function getNoResultText() + local isH2H = Logic.isNotEmpty(self.config.vs) + if isH2H then + return I18n.translate( + 'matchtable-no-h2h-match-results', + { + mode = self.config.mode == Opponent.solo and 'players' or 'teams', + } + ) + end + return I18n.translate( + 'matchtable-no-match-results', + { + mode = self.config.mode == Opponent.solo and 'player' or 'team', + } + ) + end + + return {TableWidgets.Row{ + css = {['font-style'] = 'italic'}, + children = TableWidgets.Cell{ + colspan = 100, + children = getNoResultText(), + } + }} + end + + ---@type Widget[] + local rows = {} + + local currentYear = math.huge + Array.forEach(self.matches, function(match) + local year = DateExt.getYearOf(match.date) + if self.config.showYearHeaders and year ~= currentYear then + currentYear = year + table.insert(rows, self:_yearRow(year)) + end + table.insert(rows, self:matchRow(match)) + end) + + return rows +end + +---@return Widget? +function MatchTable:buildFooter() + if not self.config.linkSubPage then + return + end + return Link{ + link = self.title.text .. '/Matches', + children = 'Extended list of matches' + } end ---@param match MatchTableMatch ----@return Html? +---@return Widget function MatchTable:matchRow(match) - return mw.html.create('tr') - :addClass(self:_getBackgroundClass(match.result.winner)) - :node(self:_displayDate(match)) - :node(self:_displayTier(match)) - :node(self:_displayType(match)) - :node(self:_displayGameIcon(match)) - :node(self:_displayIcon(match)) - :node(self:_displayTournament(match)) - :node(self:_displayMatch(match)) - :node(self:_displayVods(match)) - :node(self:_displayMatchPage(match)) + return TableWidgets.Row{ + classes = {self:_getBackgroundClass(match.result.winner)}, + children = WidgetUtil.collect( + self:_displayDate(match), + self:_displayTier(match), + self:_displayType(match), + self:_displayGameIcon(match), + self:_displayIcon(match), + self:_displayTournament(match), + self:_displayMatch(match), + self:_displayVods(match), + self:_displayMatchPage(match) + ) + } end ---@param match MatchTableMatch ----@return Html +---@return Widget function MatchTable:_displayDate(match) - local cell = mw.html.create('td') - :css('text-align', 'left') - :css('min-width', '5rem') - :attr('data-sort-value', match.timestamp) - - if match.timestamp == DateExt.defaultTimestamp then - return cell - end - - return cell:node(Countdown.create{ - finished = match.finished, - date = DateExt.toCountdownArg(match.timestamp, match.timezoneId, match.dateIsExact), - rawdatetime = true, - format = self.config.dateFormat - } or nil) + return TableWidgets.Cell{ + attributes = {['data-sort-value'] = match.timestamp}, + children = not DateExt.isDefaultTimestamp(match.timestamp) and Countdown.create{ + finished = match.finished, + date = DateExt.toCountdownArg(match.timestamp, match.timezoneId, match.dateIsExact), + rawdatetime = true, + format = self.config.dateFormat + } or nil + } end ---@param match MatchTableMatch ----@return Html? +---@return Widget? function MatchTable:_displayTier(match) if not self.config.showTier then return end @@ -722,60 +810,64 @@ function MatchTable:_displayTier(match) options.onlyTierTypeIfBoth = true if not Tier.isValid(tier, tierType) then - return mw.html.create('td') - :attr('data-sort-value', INVALID_TIER_SORT) - :wikitext(INVALID_TIER_DISPLAY) + return TableWidgets.Cell{ + attributes = {['data-sort-value'] = INVALID_TIER_SORT}, + children = INVALID_TIER_DISPLAY + } end - return mw.html.create('td') - :attr('data-sort-value', Tier.toSortValue(tier, tierType)) - :wikitext(Tier.display(tier, tierType, options)) + return TableWidgets.Cell{ + attributes = {['data-sort-value'] = Tier.toSortValue(tier, tierType)}, + children = Tier.display(tier, tierType, options) + } end ---@param match MatchTableMatch ----@return Html? +---@return Widget? function MatchTable:_displayType(match) if not self.config.showType then return end - return mw.html.create('td') - :wikitext(match.type and mw.getContentLanguage():ucfirst(match.type) or nil) + return TableWidgets.Cell{ + children = match.type and String.upperCaseFirst(match.type) or nil + } end ---@param match MatchTableMatch ----@return Html? +---@return Widget? function MatchTable:_displayGameIcon(match) if not self.config.displayGameIcons then return end - return mw.html.create('td') - :node(Game.icon{game = match.game}) + return TableWidgets.Cell{ + children = Game.icon{game = match.game} + } end ---@param match MatchTableMatch ----@return Html? +---@return Widget? function MatchTable:_displayIcon(match) if not self.config.showIcon then return end - return mw.html.create('td') - :node(LeagueIcon.display{ + return TableWidgets.Cell{ + children = LeagueIcon.display{ icon = match.icon, iconDark = match.iconDark, link = match.pageName, name = match.displayName, options = {noTemplate = true}, - }) + } + } end ---@param match MatchTableMatch ---@return Widget function MatchTable:_displayTournament(match) - return HtmlWidgets.Td{ - css = {['text-align'] = 'left'}, + return TableWidgets.Cell{ children = Link{children = match.displayName, link = match.pageName} } end ---@param match MatchTableMatch ----@return Html? +---@return Widget|Widget[]? function MatchTable:_displayMatch(match) if not self.config.showResult then return @@ -783,36 +875,36 @@ function MatchTable:_displayMatch(match) return self:nonStandardMatch(match) end - return mw.html.create() - :node(self.config.showOpponent and self:_displayOpponent(match.result.opponent, true) or nil) - :node(self:_displayScore(match)) - :node(self:_displayOpponent(match.result.vs):css('text-align', 'left')) + return WidgetUtil.collect( + self.config.showOpponent and self:_displayOpponent(match.result.opponent, true) or nil, + self:_displayScore(match), + self:_displayOpponent(match.result.vs) + ) end ---overwritable for wikis that have BR/FFA matches ---@param match MatchTableMatch ----@return Html +---@return Widget function MatchTable:nonStandardMatch(match) - return mw.html.create('td') - :attr('colspan', self.config.showOpponent and 3 or 2) - :wikitext('') + return TableWidgets.Cell{ + colspan = self.config.showOpponent and 3 or 2, + children = '', + } end ---@param opponent standardOpponent ---@param flipped boolean? ----@return Html +---@return Widget function MatchTable:_displayOpponent(opponent, flipped) - local cell = mw.html.create('td') - if Logic.isEmpty(opponent) then return cell:wikitext('Unknown') end - - return cell - :node(OpponentDisplay.BlockOpponent{ + return TableWidgets.Cell{ + attributes = {['data-sort-value'] = Opponent.toName(opponent)}, + children = OpponentDisplay.BlockOpponent{ opponent = opponent, flip = flipped, overflow = 'wrap', teamStyle = self.config.teamStyle, - }) - :attr('data-sort-value', opponent.name) + } + } end ---@param match MatchTableMatch @@ -825,7 +917,7 @@ function MatchTable:_displayScore(match) ---@param opponent standardOpponent ---@param gameOpponents table[] - ---@return Html|string + ---@return string|Widget local toScore = function(opponent, gameOpponents) if Table.isEmpty(opponent) or not opponent.status then return 'Unkn' end local score = OpponentDisplay.InlineScore(opponent) @@ -837,16 +929,17 @@ function MatchTable:_displayScore(match) status = game1Opponent.status end - return mw.html.create(tonumber(opponent.placement) == 1 and 'b' or nil) - :wikitext(status == SCORE_STATUS and (score or '–') or status) + return HtmlWidgets.Span{ + css = {['font-weight'] = tonumber(opponent.placement) == 1 and 'bold' or nil}, + children = status == SCORE_STATUS and (score or '–') or status, + } end - return mw.html.create('td') - :addClass('match-table-score') - :css('white-space', 'nowrap') - :node(toScore(result.opponent, result.gameOpponents)) - :node(bestof1Score and BO1_SCORE_CONCAT or SCORE_CONCAT) - :node(toScore(result.vs, result.gameVsOpponents)) + return TableWidgets.Cell{children = { + toScore(result.opponent, result.gameOpponents), + bestof1Score and BO1_SCORE_CONCAT or SCORE_CONCAT, + toScore(result.vs, result.gameVsOpponents) + }} end ---@param match MatchTableMatch @@ -854,15 +947,11 @@ end function MatchTable:_displayVods(match) if not self.config.showVod then return end - local vodsNode = mw.html.create('td'):css('text-align', 'left') - Array.forEach(match.vods, function(vod, vodIndex) - if vodIndex ~= 1 then - vodsNode:node(' ') - end - vodsNode:node(VodLink.display{vod = vod.link, gamenum = vod.index ~= 0 and vod.index or nil}) - end) - - return vodsNode + return TableWidgets.Cell{ + children = Array.interleave(Array.map(match.vods, function (vod) + return VodLink.display{vod = vod.link, gamenum = vod.index ~= 0 and vod.index or nil} + end), ' ') + } end ---@param match MatchTableMatch @@ -870,7 +959,9 @@ end function MatchTable:_displayMatchPage(match) if not self.config.showMatchPage then return end - return mw.html.create('td'):node(MatchPageButton{match = match, buttonText = self.config.matchPageButtonText}) + return TableWidgets.Cell{ + children = MatchPageButton{match = match, buttonText = self.config.matchPageButtonText} + } end ---@param winner any From 9aee5269506edae06ad3afb9f5ce03100d7ddb3c Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 17:24:51 +0900 Subject: [PATCH 13/57] use formatPercentage --- lua/wikis/commons/MatchTable.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 8c9bb1b91b9..88ffc86414c 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -993,11 +993,11 @@ function MatchTable:displayStats() data.l .. 'L' ), ' : ') - local percentage = Math.round((data.w + 0.5 * data.d) / sum, 4) * 100 + local percentage = Math.formatPercentage((data.w + 0.5 * data.d) / sum, 2) local parts = { scoreText, - '(' .. percentage .. '%)', + '(' .. percentage .. ')', 'in', statsType, } From 4b72bed886ba1bb956f3c914ce56805a59bdc083 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 17:25:38 +0900 Subject: [PATCH 14/57] isDefaultTimestamp --- lua/wikis/commons/MatchTable.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 88ffc86414c..137a5804ee5 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -1006,9 +1006,9 @@ function MatchTable:displayStats() end local makeStatsTitle = function() - if startTimeStamp == DateExt.defaultTimestamp and endTimeStamp == DateExt.defaultTimestamp then + if DateExt.isDefaultTimestamp(startTimeStamp) and DateExt.isDefaultTimestamp(endTimeStamp) then return 'For all matches:' - elseif startTimeStamp == DateExt.defaultTimestamp then + elseif DateExt.isDefaultTimestamp(startTimeStamp) then return 'For all matches before '.. DateExt.formatTimestamp('M d, Y', endTimeStamp) .. ':' end From c32b5e9fca4fbce55f46990b6de5c45b48ed75e5 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 17:36:31 +0900 Subject: [PATCH 15/57] clean up stats --- lua/wikis/commons/MatchTable.lua | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 137a5804ee5..7a2e7a554cd 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -973,7 +973,7 @@ function MatchTable:_getBackgroundClass(winner) nil end ----@return Html? +---@return Widget? function MatchTable:displayStats() if not self.config.showStats or Table.isEmpty(self.matches) then return end @@ -1017,9 +1017,10 @@ function MatchTable:displayStats() return 'For matches between ' .. startDate .. ' and ' .. endDate .. ':' end - local titleNode = mw.html.create('div') - :css('font-weight', 'bold') - :wikitext(makeStatsTitle()) + local titleNode = HtmlWidgets.Div{ + css = {['font-weight'] = 'bold'}, + children = makeStatsTitle(), + } local stats = Array.append({}, self.config.showOnlyGameStats and '' or displayScores(self.stats.matches, 'matches'), @@ -1027,12 +1028,10 @@ function MatchTable:displayStats() self.config.showOnlyGameStats and '' or displayScores(self.stats.rounds, 'rounds') ) - return mw.html.create('div') - :node(titleNode) - :tag('div') - :wikitext(table.concat(stats, self.config.showOnlyGameStats and '' or ' and ')) - :wikitext() - :done() + return HtmlWidgets.Div{children = { + titleNode, + HtmlWidgets.Div{children = Array.interleave(stats, self.config.showOnlyGameStats and '' or ' and ')} + }} end return MatchTable From f205f9177280f6ab8e1cfad4cef60d43fa2135d3 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 17:38:13 +0900 Subject: [PATCH 16/57] clean up build --- lua/wikis/commons/MatchTable.lua | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 7a2e7a554cd..6f2fb8f5333 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -562,7 +562,7 @@ function MatchTable:statsFromMatches() } end ----@return Html +---@return Widget function MatchTable:buildDisplay() local display = mw.html.create('table') :addClass('wikitable wikitable-striped sortable') @@ -592,16 +592,12 @@ function MatchTable:buildDisplay() } end ----@return Html +---@return Widget function MatchTable:build() - local wrappedTableNode = mw.html.create('div') - :addClass('match-table-wrapper') - :addClass('table-responsive') - :node(self:buildDisplay()) - - return mw.html.create('div') - :node(self:displayStats()) - :node(wrappedTableNode) + return HtmlWidgets.Fragment{children = WidgetUtil.collect( + self:displayStats(), + self:buildDisplay() + )} end ---@param title string From 583b0dd626afeb36a50335b8ab1b724b72993477 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 17:41:39 +0900 Subject: [PATCH 17/57] update custom --- lua/wikis/commons/MatchTable/Custom.lua | 2 +- lua/wikis/counterstrike/MatchTable/Custom.lua | 29 ++++++++++--------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/lua/wikis/commons/MatchTable/Custom.lua b/lua/wikis/commons/MatchTable/Custom.lua index 9e38bd4a7d2..787c8a33d2e 100644 --- a/lua/wikis/commons/MatchTable/Custom.lua +++ b/lua/wikis/commons/MatchTable/Custom.lua @@ -14,7 +14,7 @@ local MatchTable = Lua.import('Module:MatchTable') local CustomMatchTable = {} ---@param args table ----@return Html +---@return Widget function CustomMatchTable.results(args) return MatchTable(args):readConfig():query():build() end diff --git a/lua/wikis/counterstrike/MatchTable/Custom.lua b/lua/wikis/counterstrike/MatchTable/Custom.lua index 72216c89bac..94922c169fe 100644 --- a/lua/wikis/counterstrike/MatchTable/Custom.lua +++ b/lua/wikis/counterstrike/MatchTable/Custom.lua @@ -13,27 +13,28 @@ local Tier = Lua.import('Module:Tier/Custom') local MatchTable = Lua.import('Module:MatchTable') +local TableWidgets = Lua.import('Module:Widget/Table2/All') + local INVALID_TIER_DISPLAY = 'Undefined' local INVALID_TIER_SORT = 'ZZ' -local CustomMatchTable = {} +---@class CounterstrikeMatchTable: MatchTable +---@operator call(table): CounterstrikeMatchTable +local CustomMatchTable = Class.new(MatchTable) ---@param args table ----@return Html +---@return Widget function CustomMatchTable.results(args) args.showRoundStats = Logic.nilOr(Logic.readBoolOrNil(args.showRoundStats), true) args.gameIcons = Logic.nilOr(Logic.readBoolOrNil(args.gameIcons), true) args.vod = Logic.nilOr(Logic.readBoolOrNil(args.vod), true) args.showType = Logic.nilOr(Logic.readBoolOrNil(args.showType), true) - local matchtable = MatchTable(args) - matchtable._displayTier = CustomMatchTable._displayTier - - return matchtable:readConfig():query():build() + return CustomMatchTable(args):readConfig():query():build() end ---@param match MatchTableMatch ----@return Html? +---@return Widget? function CustomMatchTable:_displayTier(match) if not self.config.showTier then return end @@ -42,14 +43,16 @@ function CustomMatchTable:_displayTier(match) options.onlyDisplayPrioritized = true if not Tier.isValid(tier, tierType) then - return mw.html.create('td') - :attr('data-sort-value', INVALID_TIER_DISPLAY) - :wikitext(INVALID_TIER_SORT) + return TableWidgets.Cell{ + attributes = {['data-sort-value'] = INVALID_TIER_SORT}, + children = INVALID_TIER_DISPLAY + } end - return mw.html.create('td') - :attr('data-sort-value', Tier.toSortValue(tier, tierType)) - :wikitext(Tier.display(tier, tierType, options)) + return TableWidgets.Cell{ + attributes = {['data-sort-value'] = Tier.toSortValue(tier, tierType)}, + children = Tier.display(tier, tierType, options) + } end return Class.export(CustomMatchTable, {exports = {'results'}}) From 29b75d2c20308d8b6d552c1c7169619221f8f27a Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 17:45:05 +0900 Subject: [PATCH 18/57] adjust access modifier --- lua/wikis/commons/GameTable.lua | 2 +- lua/wikis/commons/GameTable/Character.lua | 2 +- lua/wikis/commons/MatchTable.lua | 5 +++-- lua/wikis/counterstrike/MatchTable/Custom.lua | 3 ++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lua/wikis/commons/GameTable.lua b/lua/wikis/commons/GameTable.lua index e7965d09614..406c1e6de94 100644 --- a/lua/wikis/commons/GameTable.lua +++ b/lua/wikis/commons/GameTable.lua @@ -126,7 +126,7 @@ function GameTable:gameRow(match, game) return mw.html.create('tr') :addClass(self:_getBackgroundClass(winner)) :node(self:_displayDate(match)) - :node(self:_displayTier(match)) + :node(self:displayTier(match)) :node(self:_displayType(match)) :node(self:_displayGameIconForGame(game)) :node(self:_displayIcon(match)) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index f09268f9f78..f1bac3241a8 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -422,7 +422,7 @@ function CharacterGameTable:gameRow(match, game) return mw.html.create('tr') :addClass(self:_getBackgroundClass(winner)) :node(self:_displayDate(match)) - :node(self:_displayTier(match)) + :node(self:displayTier(match)) :node(self:_displayType(match)) :node(self:_displayGameIconForGame(game)) :node(self:_displayIcon(match)) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 6f2fb8f5333..b39109edb54 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -770,7 +770,7 @@ function MatchTable:matchRow(match) classes = {self:_getBackgroundClass(match.result.winner)}, children = WidgetUtil.collect( self:_displayDate(match), - self:_displayTier(match), + self:displayTier(match), self:_displayType(match), self:_displayGameIcon(match), self:_displayIcon(match), @@ -796,9 +796,10 @@ function MatchTable:_displayDate(match) } end +---@protected ---@param match MatchTableMatch ---@return Widget? -function MatchTable:_displayTier(match) +function MatchTable:displayTier(match) if not self.config.showTier then return end local tier, tierType, options = Tier.parseFromQueryData(match) diff --git a/lua/wikis/counterstrike/MatchTable/Custom.lua b/lua/wikis/counterstrike/MatchTable/Custom.lua index 94922c169fe..66fe317e612 100644 --- a/lua/wikis/counterstrike/MatchTable/Custom.lua +++ b/lua/wikis/counterstrike/MatchTable/Custom.lua @@ -33,9 +33,10 @@ function CustomMatchTable.results(args) return CustomMatchTable(args):readConfig():query():build() end +---@protected ---@param match MatchTableMatch ---@return Widget? -function CustomMatchTable:_displayTier(match) +function CustomMatchTable:displayTier(match) if not self.config.showTier then return end local tier, tierType, options = Tier.parseFromQueryData(match) From cdbd0f37a14dcd28131f40a5abc335004ca58b37 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 17:48:19 +0900 Subject: [PATCH 19/57] use html entity over code --- lua/wikis/commons/GameTable.lua | 8 ++------ lua/wikis/commons/GameTable/Character.lua | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/lua/wikis/commons/GameTable.lua b/lua/wikis/commons/GameTable.lua index 406c1e6de94..dd37889842d 100644 --- a/lua/wikis/commons/GameTable.lua +++ b/lua/wikis/commons/GameTable.lua @@ -17,10 +17,7 @@ local VodLink = Lua.import('Module:VodLink') local MatchTable = Lua.import('Module:MatchTable') local NOT_PLAYED = 'notplayed' -local SCORE_CONCAT = ' : ' - ----@class GameTableMatch: MatchTableMatch ----@field games match2game[] +local SCORE_CONCAT = ' : ' ---@class GameTable: MatchTable ---@field countGames number @@ -40,11 +37,10 @@ function GameTable:gameFromRecord(game) end ---@param record table ----@return GameTableMatch? +---@return MatchTableMatch? function GameTable:matchFromRecord(record) if self.countGames == self.config.limit then return nil end local matchRecord = MatchTable.matchFromRecord(self, record) - ---@cast matchRecord GameTableMatch if Logic.isEmpty(record.match2games) then return nil end diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index f1bac3241a8..e0cedf79499 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -26,7 +26,7 @@ local ColumnName = Condition.ColumnName local DRAW_WINNER = 0 local CHARACTER_MODE = 'character' -local SCORE_CONCAT = ' : ' +local SCORE_CONCAT = ' : ' ---@class CharacterGameTableConfig: MatchTableConfig ---@field showGameWithoutCharacters boolean From e798df42c19811ad7d9da7060389a0f688ec19be Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 18:33:48 +0900 Subject: [PATCH 20/57] slice buildRows --- lua/wikis/commons/MatchTable.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index b39109edb54..d2b7d367743 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -736,6 +736,11 @@ function MatchTable:buildBody() }} end + return self:buildRows() +end + +---@return Widget[] +function MatchTable:buildRows() ---@type Widget[] local rows = {} From 975e459280edbcc25ee9361503cbe2c95fbb2149 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 19:28:04 +0900 Subject: [PATCH 21/57] clean up GameTable --- lua/wikis/commons/GameTable.lua | 168 +++++++++++++++++-------------- lua/wikis/commons/MatchTable.lua | 4 + 2 files changed, 98 insertions(+), 74 deletions(-) diff --git a/lua/wikis/commons/GameTable.lua b/lua/wikis/commons/GameTable.lua index dd37889842d..afaf40aa660 100644 --- a/lua/wikis/commons/GameTable.lua +++ b/lua/wikis/commons/GameTable.lua @@ -9,6 +9,7 @@ local Lua = require('Module:Lua') local Array = Lua.import('Module:Array') local Class = Lua.import('Module:Class') +local DateExt = Lua.import('Module:Date/Ext') local Game = Lua.import('Module:Game') local Logic = Lua.import('Module:Logic') local Operator = Lua.import('Module:Operator') @@ -16,90 +17,94 @@ local VodLink = Lua.import('Module:VodLink') local MatchTable = Lua.import('Module:MatchTable') +local HtmlWidgets = Lua.import('Module:Widget/Html/All') +local TableWidgets = Lua.import('Module:Widget/Table2/All') +local WidgetUtil = Lua.import('Module:Widget/Util') + local NOT_PLAYED = 'notplayed' local SCORE_CONCAT = ' : ' ---@class GameTable: MatchTable ----@field countGames number +---@operator call(table): GameTable +---@field countGames integer local GameTable = Class.new(MatchTable, function (self) self.countGames = 0 end) ----@param game match2game ----@return match2game? -function GameTable:gameFromRecord(game) - if self.countGames == self.config.limit then return nil end - if game.status == NOT_PLAYED or Logic.isEmpty(game.winner) then - return nil - end - - return game -end - ----@param record table +---@param record match2 ---@return MatchTableMatch? function GameTable:matchFromRecord(record) - if self.countGames == self.config.limit then return nil end + if self.countGames >= self.config.limit then return nil end local matchRecord = MatchTable.matchFromRecord(self, record) - if Logic.isEmpty(record.match2games) then + if not matchRecord then + return + elseif Logic.isEmpty(record.match2games) then return nil end - matchRecord.games = {} - --order games from last played to first - Array.forEach(Array.reverse(record.match2games), function (game) - local gameRecord = self:gameFromRecord(game) - if gameRecord then self.countGames = self.countGames + 1 end - table.insert(matchRecord.games, gameRecord) - end) + ---@param game MatchGroupUtilGame + ---@return boolean + local function gameIsFinished(game) + return game.status ~= NOT_PLAYED and Logic.isNotEmpty(game.winner) + end + + matchRecord.games = Array.filter(matchRecord.games, gameIsFinished) + + self.countGames = self.countGames + #matchRecord.games return matchRecord end ---@param vod string? ----@return Html? +---@return Widget? function GameTable:_displayGameVod(vod) - if not self.config.showVod then return end - - local vodNode = mw.html.create('td') - if Logic.isEmpty(vod) then - return vodNode:wikitext('') + if not self.config.showVod then + return + elseif Logic.isEmpty(vod) then + return TableWidgets.Cell{} end ---@cast vod -nil - return vodNode:node(VodLink.display{vod = vod}) + return TableWidgets.Cell{children = VodLink.display{vod = vod}} end ---@param result MatchTableMatchResult ----@param game match2game +---@param game MatchGroupUtilGame ---@return Html? function GameTable:_displayGameScore(result, game) local scores = Array.map(game.opponents, Operator.property('score')) - local toScore = function(opponentRecord) - local isWinner = opponentRecord.id == tonumber(game.winner) - local score = scores[opponentRecord.id] or (isWinner and 1) or 0 - return mw.html.create(isWinner and 'b' or nil) - :wikitext(score) + local indexes = result.flipped and {2, 1} or {1, 2} + + ---@param opponentIndex integer + ---@return Widget + local toScore = function(opponentIndex) + local isWinner = opponentIndex == tonumber(game.winner) + local score = scores[opponentIndex] or (isWinner and 1) or 0 + return HtmlWidgets.Span{ + css = {['font-weight'] = isWinner and 'bold' or nil}, + children = score + } end - return mw.html.create('td') - :addClass('match-table-score') - :node(toScore(result.opponent)) - :node(SCORE_CONCAT) - :node(toScore(result.vs)) + return TableWidgets.Cell{children = { + toScore(indexes[1]), + SCORE_CONCAT, + toScore(indexes[2]), + }} end ----@param game match2game +---@param game MatchGroupUtilGame ---@return Html? function GameTable:_displayGameIconForGame(game) if not self.config.displayGameIcons then return end - return mw.html.create('td') - :node(Game.icon{game = game.game}) + return TableWidgets.Cell{ + children = Game.icon{game = game.game} + } end ----@param match GameTableMatch ----@param game match2game ----@return Html? +---@param match MatchTableMatch +---@param game MatchGroupUtilGame +---@return Widget|Widget[]? function GameTable:displayGame(match, game) if not self.config.showResult then return @@ -107,41 +112,56 @@ function GameTable:displayGame(match, game) return self:nonStandardMatch(match) end - return mw.html.create() - :node(self.config.showOpponent and self:_displayOpponent(match.result.opponent, true) or nil) - :node(self:_displayGameScore(match.result, game)) - :node(self:_displayOpponent(match.result.vs):css('text-align', 'left')) + return WidgetUtil.collect( + self.config.showOpponent and self:_displayOpponent(match.result.opponent, true) or nil, + self:_displayGameScore(match.result, game), + self:_displayOpponent(match.result.vs) + ) end ----@param match GameTableMatch ----@param game match2game ----@return Html? +---@param match MatchTableMatch +---@param game MatchGroupUtilGame +---@return Widget function GameTable:gameRow(match, game) - local winner = match.result.opponent.id == tonumber(game.winner) and 1 or 2 - - return mw.html.create('tr') - :addClass(self:_getBackgroundClass(winner)) - :node(self:_displayDate(match)) - :node(self:displayTier(match)) - :node(self:_displayType(match)) - :node(self:_displayGameIconForGame(game)) - :node(self:_displayIcon(match)) - :node(self:_displayTournament(match)) - :node(self:displayGame(match, game)) - :node(self:_displayGameVod(game.vod)) - :node(self:_displayMatchPage(match)) + local indexes = match.result.flipped and {2, 1} or {1, 2} + local winner = game.winner == indexes[1] + + return TableWidgets.Row{ + classes = {self:_getBackgroundClass(winner)}, + children = WidgetUtil.collect( + self:_displayDate(match), + self:displayTier(match), + self:_displayType(match), + self:_displayGameIconForGame(game), + self:_displayIcon(match), + self:_displayTournament(match), + self:displayGame(match, game), + self:_displayGameVod(game.vod), + self:_displayMatchPage(match) + ) + } end ----@param match GameTableMatch ----@return Html? -function GameTable:matchRow(match) - local display = mw.html.create() - - Array.forEach(match.games, function(game) - display:node(self:gameRow(match, game)) +---@return Widget[] +function GameTable:buildRows() + ---@type Widget[] + local rows = {} + + local currentYear = math.huge + Array.forEach(self.matches, function(match) + local year = DateExt.getYearOf(match.date) + if self.config.showYearHeaders and year ~= currentYear then + currentYear = year + table.insert(rows, self:_yearRow(year)) + end + Array.extendWith(rows, Array.reverse( + Array.map(match.games, function (game) + self:gameRow(match, game) + end) + )) end) - return display + return rows end return GameTable diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index d2b7d367743..df83befe1aa 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -97,6 +97,7 @@ local SECONDS_ONE_DAY = 3600 * 24 ---@field vs standardOpponent ---@field gameVsOpponents table[] ---@field winner number? +---@field flipped boolean ---@field countGames boolean ---@field countRounds boolean @@ -479,11 +480,13 @@ function MatchTable:resultFromRecord(record) end local winner = record.winner + local flipped = false local indexes if foundInAlias(record.opponents[1]) then indexes = {1, 2} elseif foundInAlias(record.opponents[2]) then indexes = {2, 1} + flipped = true winner = winner == 2 and 1 or winner == 1 and 2 or winner else mw.ext.TeamLiquidIntegration.add_category('MatchesTables with invalid matches') @@ -498,6 +501,7 @@ function MatchTable:resultFromRecord(record) opponent = record.opponents[indexes[1]], vs = record.opponents[indexes[2]], winner = winner, + flipped = flipped, countGames = countGames, countRounds = countRounds, gameOpponents = Array.map(gameOpponents, Operator.property(indexes[1])), From 65962e1a69d9038d3b7a35af2e42489b61cae969 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 19:29:07 +0900 Subject: [PATCH 22/57] type anno --- lua/wikis/commons/GameTable/Character.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index e0cedf79499..127ca255103 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -45,6 +45,7 @@ local SCORE_CONCAT = ' : ' ---@field pickedByplayer number? ---@class CharacterGameTable: GameTable +---@operator call(table): CharacterGameTable ---@field character string ---@field isCharacterTable boolean ---@field isPickedByRequired boolean From 4e9b5db79b255ae90adcb10d5679c5dddd455ce9 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 19:30:43 +0900 Subject: [PATCH 23/57] use isMain --- lua/wikis/commons/GameTable/Character.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index 127ca255103..b2138ab1d18 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -12,6 +12,7 @@ local Array = Lua.import('Module:Array') local CharacterIcon = Lua.import('Module:CharacterIcon') local Class = Lua.import('Module:Class') local Logic = Lua.import('Module:Logic') +local Namespace = Lua.import('Module:Namespace') local Operator = Lua.import('Module:Operator') local Table = Lua.import('Module:Table') @@ -76,7 +77,7 @@ function CharacterGameTable:readCharacter() if Logic.isNotEmpty(self.args.character) then self.character = self.args.character else - assert(self.title.namespace == 0, 'Lua.importd character= argument') + assert(Namespace.isMain(self.title), 'Lua.importd character= argument') self.character = self.title.rootText end From 73eb2fabc10ecf8094783ab8ee0b2eb41df54d69 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 22:58:44 +0900 Subject: [PATCH 24/57] rewrite charactergametable --- lua/wikis/commons/GameTable.lua | 16 +- lua/wikis/commons/GameTable/Character.lua | 287 +++++++++++++--------- lua/wikis/commons/MatchTable.lua | 6 +- 3 files changed, 186 insertions(+), 123 deletions(-) diff --git a/lua/wikis/commons/GameTable.lua b/lua/wikis/commons/GameTable.lua index afaf40aa660..2e6fc5bf3f2 100644 --- a/lua/wikis/commons/GameTable.lua +++ b/lua/wikis/commons/GameTable.lua @@ -42,19 +42,21 @@ function GameTable:matchFromRecord(record) return nil end - ---@param game MatchGroupUtilGame - ---@return boolean - local function gameIsFinished(game) - return game.status ~= NOT_PLAYED and Logic.isNotEmpty(game.winner) - end - - matchRecord.games = Array.filter(matchRecord.games, gameIsFinished) + matchRecord.games = Array.filter(matchRecord.games, function (game) + return self:filterGame(game) + end) self.countGames = self.countGames + #matchRecord.games return matchRecord end +---@param game MatchGroupUtilGame +---@return boolean +function GameTable:filterGame(game) + return game.status ~= NOT_PLAYED and Logic.isNotEmpty(game.winner) +end + ---@param vod string? ---@return Widget? function GameTable:_displayGameVod(vod) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index b2138ab1d18..2a14f79ff5f 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -25,6 +25,11 @@ local Comparator = Condition.Comparator local BooleanOperator = Condition.BooleanOperator local ColumnName = Condition.ColumnName +local HtmlWidgets = Lua.import('Module:Widget/Html/All') +local MatchSummaryCharacters = Lua.import('Module:Widget/Match/Summary/Characters') +local TableWidgets = Lua.import('Module:Widget/Table2/All') +local WidgetUtil = Lua.import('Module:Widget/Util') + local DRAW_WINNER = 0 local CHARACTER_MODE = 'character' local SCORE_CONCAT = ' : ' @@ -39,18 +44,22 @@ local SCORE_CONCAT = ' : ' ---@field iconSize string ---@field iconSeparator string ----@class CharacterGameTableGame: match2game +---@class CharacterGameTableGame: MatchGroupUtilGame ---@field picks string[][] ---@field bans string[][]? ---@field pickedBy number? ---@field pickedByplayer number? +---@class CharacterGameTableMatch: MatchTableMatch +---@field games CharacterGameTableGame[] + ---@class CharacterGameTable: GameTable ---@operator call(table): CharacterGameTable ---@field character string ---@field isCharacterTable boolean ---@field isPickedByRequired boolean ---@field config CharacterGameTableConfig +---@field matches CharacterGameTableMatch[] local CharacterGameTable = Class.new(GameTable, function (self) self.isCharacterTable = self.args.tableMode == CHARACTER_MODE self.isPickedByRequired = self.isCharacterTable @@ -221,26 +230,21 @@ function CharacterGameTable:getCharacterPick(game) return findCharacter(1) or findCharacter(2) end ----@param game match2game ----@return match2game? -function CharacterGameTable:gameFromRecord(game) - local gameRecord = GameTable.gameFromRecord(self, game) - if not gameRecord then - return nil - end - - ---@cast gameRecord CharacterGameTableGame - gameRecord.picks = self:getCharacters(gameRecord, self.config.numPicks, self.getCharacterKey) - gameRecord.bans = self.config.showBans and - self:getCharacters(gameRecord, self.config.numBans,self.getCharacterBanKey) or nil - gameRecord.pickedBy = self.isPickedByRequired and self:getCharacterPick(gameRecord) or nil +---@param game MatchGroupUtilGame +---@return boolean +function CharacterGameTable:filterGame(game) + ---@cast game CharacterGameTableGame + game.picks = self:getCharacters(game, self.config.numPicks, self.getCharacterKey) + game.bans = self.config.showBans and + self:getCharacters(game, self.config.numBans,self.getCharacterBanKey) or nil + game.pickedBy = self.isPickedByRequired and self:getCharacterPick(game) or nil if self.isPickedByRequired then - return Logic.isNotEmpty(gameRecord.pickedBy) and gameRecord or nil + return Logic.isNotEmpty(game.pickedBy) end - local foundPicks = Table.isNotEmpty(gameRecord.picks[1]) or Table.isNotEmpty(gameRecord.picks[2]) - return (foundPicks or self.config.showGameWithoutCharacters) and gameRecord or nil + local foundPicks = Table.isNotEmpty(game.picks[1]) or Table.isNotEmpty(game.picks[2]) + return foundPicks or self.config.showGameWithoutCharacters end ---@param record table @@ -259,7 +263,6 @@ function CharacterGameTable:statsFromMatches() local totalGames = {w = 0, d = 0, l = 0} Array.forEach(self.matches, function(match) - ---@cast match GameTableMatch Array.forEach(match.games, function (game, index) local winner = tonumber(game.winner) @@ -278,71 +281,125 @@ function CharacterGameTable:statsFromMatches() } end ----@return Html -function CharacterGameTable:headerRow() - local makeHeaderCell = function(text, width) - return mw.html.create('th'):css('max-width', width):node(text) - end - +---@protected +---@return table[] +function CharacterGameTable:buildColumnDefinitions() local config = self.config - - local nodes = Array.append({}, - makeHeaderCell('Date', '100px'), - config.showTier and makeHeaderCell('Tier', '70px') or nil, - config.showType and makeHeaderCell('Type', '70px') or nil, - config.displayGameIcons and makeHeaderCell(nil, '25px') or nil, - config.showIcon and makeHeaderCell(nil, '25px'):addClass('unsortable') or nil, - makeHeaderCell('Tournament') + local isCharTable = self.isCharacterTable + return WidgetUtil.collect( + { + -- Date column + align = 'left', + sortType = 'number', + }, + config.showTier and {align = 'left'} or nil, + config.showType and {align = 'center'} or nil, + config.displayGameIcons and {align = 'center'} or nil, + config.showIcon and { + align = 'center', + unsortable = true, + } or nil, + { + -- Tournament column + align = 'left', + }, + config.showResult and WidgetUtil.collect( + not isCharTable and {align = 'center'} or nil, + { + align = 'center', + unsortable = true, + }, + config.showBans and { + align = 'center', + unsortable = true + } or nil, + isCharTable and { + {align = 'center'}, + {align = 'center'}, + {align = 'center'}, + } or nil, + { + align = 'center', + unsortable = true, + }, + config.showBans and { + align = 'center', + unsortable = true + } or nil + ) or nil, + config.showLength and { + align = 'left', + unsortable = true, + } or nil, + config.showVod and { + align = 'left', + unsortable = true, + } or nil, + config.showMatchPage and { + align = 'center', + unsortable = true, + } or nil ) +end - if config.showResult then - local isCharTable = self.isCharacterTable - nodes = Array.appendWith(nodes, - not isCharTable and makeHeaderCell('vs.', '80px') or nil, - makeHeaderCell('Picks'):addClass('unsortable'), - config.showBans and makeHeaderCell('Bans'):addClass('unsortable') or nil, - isCharTable and makeHeaderCell(nil, '80px') or nil, - isCharTable and makeHeaderCell('Score') or nil, - isCharTable and makeHeaderCell(nil, '80px') or nil, - makeHeaderCell('vs. Picks'):addClass('unsortable'), - config.showBans and makeHeaderCell('vs. Bans'):addClass('unsortable') or nil - ) +---@return Widget +function CharacterGameTable:headerRow() + ---@param text string? + ---@return Widget + local makeHeaderCell = function(text) + return TableWidgets.CellHeader{children = text} end - nodes = Array.append(nodes, - config.showLength and makeHeaderCell('Length') or nil, - config.showVod and makeHeaderCell('VOD', '60px') or nil, - config.showMatchPage and makeHeaderCell('') or nil - ) - - local header = mw.html.create('tr') - Array.forEach(nodes, function (node) - header:node(node) - end) + local config = self.config + local isCharTable = self.isCharacterTable - return header + return TableWidgets.TableHeader{children = { + TableWidgets.Row{children = WidgetUtil.collect( + makeHeaderCell('Date'), + config.showTier and makeHeaderCell('Tier') or nil, + config.showType and makeHeaderCell('Type') or nil, + config.displayGameIcons and makeHeaderCell() or nil, + config.showIcon and makeHeaderCell() or nil, + makeHeaderCell('Tournament'), + config.showResult and WidgetUtil.collect( + not isCharTable and makeHeaderCell('vs.') or nil, + makeHeaderCell('Picks'), + config.showBans and makeHeaderCell('Bans') or nil, + isCharTable and { + makeHeaderCell(), + makeHeaderCell('Score'), + makeHeaderCell(), + } or nil, + makeHeaderCell('vs. Picks'), + config.showBans and makeHeaderCell('vs. Bans') or nil + ) or nil, + config.showLength and makeHeaderCell('Length') or nil, + config.showVod and TableWidgets.CellHeader{ + align = 'center', + children = 'VOD' + } or nil, + config.showMatchPage and makeHeaderCell() or nil + )} + }} end ---@param game CharacterGameTableGame ---@param opponentIndex number ---@param key string ----@return Html? +---@return Widget? function CharacterGameTable:_displayCharacters(game, opponentIndex, key) local config = self.config - local makeIcon = function(character) - return CharacterIcon.Icon{character = character, size = config.iconSize, date = game.date} - end - local icons = Array.map(game[key][opponentIndex] or {}, makeIcon) - - return mw.html.create('td') - :addClass(config.showSideClass and self:getSideClass(game.extradata, opponentIndex) or nil) - :node(#icons > 0 and table.concat(icons, config.iconSeparator) or nil) + return TableWidgets.Cell{children = MatchSummaryCharacters{ + bg = config.showSideClass and self:getSideClass(game.extradata, opponentIndex) or nil, + characters = game[key][opponentIndex] or {}, + date = game.date, + }} end ----@param match GameTableMatch +---@param match CharacterGameTableMatch ---@param game CharacterGameTableGame ----@return Html? +---@return Widget[]? function CharacterGameTable:displayGame(match, game) if not self.config.showResult then return @@ -353,35 +410,36 @@ function CharacterGameTable:displayGame(match, game) ---@cast pickedBy -nil local pickedVs = pickedBy == 1 and 2 or 1 local opponentRecords = {match.result.opponent, match.result.vs} - return mw.html.create() - :node(self:_displayDraft(game, opponentRecords[pickedBy], false)) - :node(self:_displayScore(game, pickedBy, pickedVs)) - :node(self:_displayDraft(game, opponentRecords[pickedVs], true)) + return WidgetUtil.collect( + self:_displayDraft(game, opponentRecords[pickedBy], pickedBy, false), + self:_displayScore(game, pickedBy, pickedVs), + self:_displayDraft(game, opponentRecords[pickedVs], pickedVs, true) + ) else - return mw.html.create() - :node(self:_displayOpponent(match.result.vs):css('text-align', 'left')) - :node(self:_displayDraft(game, match.result.opponent)) - :node(self:_displayDraft(game, match.result.vs)) + local indexes = match.result.flipped and {2, 1} or {1, 2} + return WidgetUtil.collect( + self:_displayOpponent(match.result.vs), + self:_displayDraft(game, match.result.opponent, indexes[1]), + self:_displayDraft(game, match.result.vs, indexes[2]) + ) end end ---@param game CharacterGameTableGame ----@param opponentRecord match2opponent +---@param opponentRecord standardOpponent +---@param opponentIndex integer ---@param flipped boolean? ----@return Html? -function CharacterGameTable:_displayDraft(game, opponentRecord, flipped) - local opponentIndex = opponentRecord.id - +---@return Widget[]? +function CharacterGameTable:_displayDraft(game, opponentRecord, opponentIndex, flipped) local isCharTable = self.isCharacterTable local opponent = self:_displayOpponent(opponentRecord, flipped) - return mw.html.create() - :node((flipped and isCharTable) and opponent or nil) - :node(self:_displayCharacters(game, opponentIndex, 'picks')) - :node(self.config.showBans and - self:_displayCharacters(game, opponentIndex, 'bans'):addClass('lor-graycard') or nil - ) - :node((not flipped and isCharTable) and opponent or nil) + return WidgetUtil.collect( + (flipped and isCharTable) and opponent or nil, + self:_displayCharacters(game, opponentIndex, 'picks'), + self.config.showBans and self:_displayCharacters(game, opponentIndex, 'bans') or nil, + (not flipped and isCharTable) and opponent or nil + ) end ---@param game CharacterGameTableGame @@ -394,15 +452,17 @@ function CharacterGameTable:_displayScore(game, pickedBy, pickedVs) local toScore = function(opponentId) local isWinner = winner == opponentId - return mw.html.create(isWinner and 'b' or nil) - :wikitext(scores[opponentId] or (isWinner and 'W' or 'L')) + return HtmlWidgets.Span{ + css = {['font-weight'] = isWinner and 'bold' or nil}, + children = scores[opponentId] or (isWinner and 'W' or 'L') + } end - return mw.html.create('td') - :addClass('match-table-score') - :node(toScore(pickedBy)) - :node(SCORE_CONCAT) - :node(toScore(pickedVs)) + return TableWidgets.Cell{children = { + toScore(pickedBy), + SCORE_CONCAT, + toScore(pickedVs), + }} end ---@param game CharacterGameTableGame @@ -410,33 +470,34 @@ end function CharacterGameTable:_displayLength(game) if not self.config.showLength then return end - return mw.html.create('td') - :node(game.length) + return TableWidgets.Cell{children = game.length} end ----@param match GameTableMatch +---@param match CharacterGameTableMatch ---@param game CharacterGameTableGame ----@return Html? +---@return Widget function CharacterGameTable:gameRow(match, game) - local winner = (self.isCharacterTable and game.pickedBy or - match.result.opponent.id) == tonumber(game.winner) and 1 or 2 - - return mw.html.create('tr') - :addClass(self:_getBackgroundClass(winner)) - :node(self:_displayDate(match)) - :node(self:displayTier(match)) - :node(self:_displayType(match)) - :node(self:_displayGameIconForGame(game)) - :node(self:_displayIcon(match)) - :node(self:_displayTournament(match)) - :node(self:displayGame(match, game)) - :node(self:_displayLength(game)) - :node(self:_displayGameVod(game.vod)) - :node(self:_displayMatchPage(match)) + local indexes = ((self.isCharacterTable and game.pickedBy == game.winner) or match.result.flipped) and {2, 1} or {1, 2} + local winner = game.winner == indexes[1] + + return TableWidgets.Row{ + classes = {self:_getBackgroundClass(winner)}, + children = WidgetUtil.collect( + self:_displayDate(match), + self:displayTier(match), + self:_displayType(match), + self:_displayGameIconForGame(game), + self:_displayIcon(match), + self:_displayTournament(match), + self:displayGame(match, game), + self:_displayGameVod(game.vod), + self:_displayMatchPage(match) + ) + } end ---@param frame Frame ----@return Html +---@return Widget function CharacterGameTable.results(frame) local args = Arguments.getArgs(frame) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index df83befe1aa..e0f9173c414 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -586,7 +586,7 @@ function MatchTable:buildDisplay() return TableWidgets.Table{ sortable = true, - columns = self:_buildColumnDefinitions(), + columns = self:buildColumnDefinitions(), title = String.nilIfEmpty(self.config.title), children = WidgetUtil.collect( self:headerRow(), @@ -615,9 +615,9 @@ function MatchTable:_titleRow(title) :done() end ----@private +---@protected ---@return table[] -function MatchTable:_buildColumnDefinitions() +function MatchTable:buildColumnDefinitions() local config = self.config return WidgetUtil.collect( { From b4172203c3ebb9567b433512ee718ac338a1f17b Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Feb 2026 23:00:52 +0900 Subject: [PATCH 25/57] lint --- lua/wikis/commons/GameTable/Character.lua | 1 - lua/wikis/commons/MatchTable.lua | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index 2a14f79ff5f..292f1aefd1a 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -9,7 +9,6 @@ local Lua = require('Module:Lua') local Arguments = Lua.import('Module:Arguments') local Array = Lua.import('Module:Array') -local CharacterIcon = Lua.import('Module:CharacterIcon') local Class = Lua.import('Module:Class') local Logic = Lua.import('Module:Logic') local Namespace = Lua.import('Module:Namespace') diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index e0f9173c414..fe45c31d33f 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -699,7 +699,7 @@ function MatchTable:headerRow() align = 'center', children = 'vs. Opponent' } - ) or nil, + ) or nil, config.showVod and TableWidgets.CellHeader{ align = 'center', children = 'VOD(s)' From a791e1656668f87fcd8fcac662fb235d58409766 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Fri, 27 Feb 2026 19:09:52 +0900 Subject: [PATCH 26/57] adjust matchpage usage --- lua/wikis/commons/MatchPage/Base.lua | 8 +++----- lua/wikis/commons/MatchTable.lua | 1 + stylesheets/commons/BigMatch.scss | 15 ++++----------- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/lua/wikis/commons/MatchPage/Base.lua b/lua/wikis/commons/MatchPage/Base.lua index ea89d10156b..9f5e3b65fb8 100644 --- a/lua/wikis/commons/MatchPage/Base.lua +++ b/lua/wikis/commons/MatchPage/Base.lua @@ -510,14 +510,12 @@ function BaseMatchPage:previousMatches() headToHead and AdditionalSection{ css = {flex = '2 0 100%'}, header = 'Head to Head', - bodyClasses = {'match-table-wrapper'}, children = headToHead, } or nil, Array.map(self.opponents, function (opponent) local matchTable = self:_buildMatchTable(opponent) return AdditionalSection{ header = OpponentDisplay.InlineOpponent{opponent = opponent, teamStyle = 'hybrid'}, - bodyClasses = matchTable and {'match-table-wrapper'} or nil, children = matchTable or self:getTournamentIcon() } end) @@ -535,7 +533,7 @@ end ---@private ---@param props table ----@return Html +---@return Widget function BaseMatchPage:_createMatchTable(props) return MatchTable(Table.mergeInto({ addCategory = false, @@ -552,7 +550,7 @@ end ---@private ---@param opponent standardOpponent ----@return Html? +---@return Widget? function BaseMatchPage:_buildMatchTable(opponent) if not BaseMatchPage._isTeamOpponent(opponent) then return @@ -568,7 +566,7 @@ function BaseMatchPage:_buildMatchTable(opponent) end ---@private ----@return Html? +---@return Widget? function BaseMatchPage:_buildHeadToHeadMatchTable() if not Array.all(self.opponents, BaseMatchPage._isTeamOpponent) then return diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index fe45c31d33f..5dc41616f5b 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -585,6 +585,7 @@ function MatchTable:buildDisplay() end) return TableWidgets.Table{ + classes = {'match-table-wrapper'}, sortable = true, columns = self:buildColumnDefinitions(), title = String.nilIfEmpty(self.config.title), diff --git a/stylesheets/commons/BigMatch.scss b/stylesheets/commons/BigMatch.scss index b204146fad8..20d68292b44 100644 --- a/stylesheets/commons/BigMatch.scss +++ b/stylesheets/commons/BigMatch.scss @@ -1106,19 +1106,12 @@ span.slash { border-color: var( --clr-on-surface-dark-primary-8 ); } - &.match-table-wrapper { - display: block; + &:has( > .match-table-wrapper ) { + display: contents; padding: unset; - @media ( max-width: 767px ) { - overflow-x: auto; - } - - & > table.wikitable { - border-radius: 0.5rem; - overflow: hidden; - height: 100%; - width: 100%; + > .match-table-wrapper { + width: unset; } } } From 78606f2bfaaad0a795936d31a0d1e2ae34071b21 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 14:47:26 +0900 Subject: [PATCH 27/57] missing return --- lua/wikis/commons/GameTable.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/wikis/commons/GameTable.lua b/lua/wikis/commons/GameTable.lua index 2e6fc5bf3f2..d67d471bef3 100644 --- a/lua/wikis/commons/GameTable.lua +++ b/lua/wikis/commons/GameTable.lua @@ -158,7 +158,7 @@ function GameTable:buildRows() end Array.extendWith(rows, Array.reverse( Array.map(match.games, function (game) - self:gameRow(match, game) + return self:gameRow(match, game) end) )) end) From ba449669f207da20c429cd56854b10a6674ffef3 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 14:52:26 +0900 Subject: [PATCH 28/57] indentation --- lua/wikis/commons/GameTable/Character.lua | 24 +++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index 292f1aefd1a..a92e32ab312 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -361,18 +361,18 @@ function CharacterGameTable:headerRow() config.showIcon and makeHeaderCell() or nil, makeHeaderCell('Tournament'), config.showResult and WidgetUtil.collect( - not isCharTable and makeHeaderCell('vs.') or nil, - makeHeaderCell('Picks'), - config.showBans and makeHeaderCell('Bans') or nil, - isCharTable and { - makeHeaderCell(), - makeHeaderCell('Score'), - makeHeaderCell(), - } or nil, - makeHeaderCell('vs. Picks'), - config.showBans and makeHeaderCell('vs. Bans') or nil - ) or nil, - config.showLength and makeHeaderCell('Length') or nil, + not isCharTable and makeHeaderCell('vs.') or nil, + makeHeaderCell('Picks'), + config.showBans and makeHeaderCell('Bans') or nil, + isCharTable and { + makeHeaderCell(), + makeHeaderCell('Score'), + makeHeaderCell(), + } or nil, + makeHeaderCell('vs. Picks'), + config.showBans and makeHeaderCell('vs. Bans') or nil + ) or nil, + config.showLength and makeHeaderCell('Length') or nil, config.showVod and TableWidgets.CellHeader{ align = 'center', children = 'VOD' From fdd1c5f1f9660a30f56b9fbeb53fa09a8068bc27 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 14:52:58 +0900 Subject: [PATCH 29/57] add missing length display --- lua/wikis/commons/GameTable/Character.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index a92e32ab312..45e4d08244d 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -489,6 +489,7 @@ function CharacterGameTable:gameRow(match, game) self:_displayIcon(match), self:_displayTournament(match), self:displayGame(match, game), + self:_displayLength(game), self:_displayGameVod(game.vod), self:_displayMatchPage(match) ) From b7f519c4a65025a752067b4a3d7fcf11f4bda3bb Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 14:55:02 +0900 Subject: [PATCH 30/57] restore notplayed filter --- lua/wikis/commons/GameTable/Character.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index 45e4d08244d..114a19fe5d1 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -31,6 +31,7 @@ local WidgetUtil = Lua.import('Module:Widget/Util') local DRAW_WINNER = 0 local CHARACTER_MODE = 'character' +local NOT_PLAYED = 'notplayed' local SCORE_CONCAT = ' : ' ---@class CharacterGameTableConfig: MatchTableConfig @@ -232,6 +233,9 @@ end ---@param game MatchGroupUtilGame ---@return boolean function CharacterGameTable:filterGame(game) + if game.status == NOT_PLAYED or Logic.isEmpty(game.winner) then + return false + end ---@cast game CharacterGameTableGame game.picks = self:getCharacters(game, self.config.numPicks, self.getCharacterKey) game.bans = self.config.showBans and From 7fadf23da5aedbf9edb0d5c626ede9cac01cf69a Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:01:39 +0900 Subject: [PATCH 31/57] use compact date as default --- lua/wikis/commons/GameTable/Character.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index 114a19fe5d1..375024316da 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -504,6 +504,7 @@ end ---@return Widget function CharacterGameTable.results(frame) local args = Arguments.getArgs(frame) + args.dateFormat = Logic.emptyOr(args.dateFormat, 'compact') return CharacterGameTable(args):readConfig():query():build() end From 4ea8e6aecde286b5980afbeb025baa88bd411c61 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:04:13 +0900 Subject: [PATCH 32/57] make length sortable --- lua/wikis/commons/GameTable/Character.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index 375024316da..5e7362182ed 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -332,7 +332,6 @@ function CharacterGameTable:buildColumnDefinitions() ) or nil, config.showLength and { align = 'left', - unsortable = true, } or nil, config.showVod and { align = 'left', From 571ba4f4c0c5e0e88ba78b1caf967ef7fb93ac8b Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:15:20 +0900 Subject: [PATCH 33/57] add patch display --- lua/wikis/commons/GameTable/Character.lua | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index 5e7362182ed..2b512cf52e5 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -25,6 +25,7 @@ local BooleanOperator = Condition.BooleanOperator local ColumnName = Condition.ColumnName local HtmlWidgets = Lua.import('Module:Widget/Html/All') +local Link = Lua.import('Module:Widget/Basic/Link') local MatchSummaryCharacters = Lua.import('Module:Widget/Match/Summary/Characters') local TableWidgets = Lua.import('Module:Widget/Table2/All') local WidgetUtil = Lua.import('Module:Widget/Util') @@ -39,6 +40,7 @@ local SCORE_CONCAT = ' : ' ---@field showSideClass boolean ---@field showBans boolean ---@field showLength boolean +---@field showPatch boolean ---@field numPicks number ---@field numBans number ---@field iconSize string @@ -109,6 +111,7 @@ function CharacterGameTable:readConfig() showSideClass = Logic.nilOr(Logic.readBoolOrNil(args.showSideClass), true), showBans = Logic.nilOr(Logic.readBoolOrNil(args.showBans), true), showLength = Logic.readBool(args.length), + showPatch = Logic.nilOr(Logic.readBoolOrNil(args.showPatch), true), numPicks = self:getNumberOfPicks(), numBans = self:getNumberOfBans(), iconSize = Logic.nilIfEmpty(self.args.iconSize) or '27px', @@ -333,6 +336,9 @@ function CharacterGameTable:buildColumnDefinitions() config.showLength and { align = 'left', } or nil, + config.showPatch and { + align = 'left', + } or nil, config.showVod and { align = 'left', unsortable = true, @@ -376,6 +382,7 @@ function CharacterGameTable:headerRow() config.showBans and makeHeaderCell('vs. Bans') or nil ) or nil, config.showLength and makeHeaderCell('Length') or nil, + config.showPatch and makeHeaderCell('Patch') or nil, config.showVod and TableWidgets.CellHeader{ align = 'center', children = 'VOD' @@ -475,6 +482,26 @@ function CharacterGameTable:_displayLength(game) return TableWidgets.Cell{children = game.length} end +---@private +---@param game CharacterGameTableGame +---@return Widget? +function CharacterGameTable:_displayPatch(game) + if not self.config.showPatch then return end + + if Logic.isEmpty(game.patch) then + return TableWidgets.Cell{} + end + + return TableWidgets.Cell{children = self:getPatchLink(game)} +end + +---@protected +---@param game CharacterGameTableGame +---@return Widget? +function CharacterGameTable:getPatchLink(game) + return Link{link = 'Patch ' .. game.patch, children = game.patch} +end + ---@param match CharacterGameTableMatch ---@param game CharacterGameTableGame ---@return Widget @@ -493,6 +520,7 @@ function CharacterGameTable:gameRow(match, game) self:_displayTournament(match), self:displayGame(match, game), self:_displayLength(game), + self:_displayPatch(game), self:_displayGameVod(game.vod), self:_displayMatchPage(match) ) From 75d02d810b40a4aac47ba40f37a7746b5daf2616 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:20:35 +0900 Subject: [PATCH 34/57] adjust background setting --- lua/wikis/commons/GameTable.lua | 4 ++-- lua/wikis/commons/GameTable/Character.lua | 4 ++-- lua/wikis/commons/MatchTable.lua | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lua/wikis/commons/GameTable.lua b/lua/wikis/commons/GameTable.lua index d67d471bef3..ad76250de0c 100644 --- a/lua/wikis/commons/GameTable.lua +++ b/lua/wikis/commons/GameTable.lua @@ -126,10 +126,10 @@ end ---@return Widget function GameTable:gameRow(match, game) local indexes = match.result.flipped and {2, 1} or {1, 2} - local winner = game.winner == indexes[1] + local winner = indexes[game.winner] return TableWidgets.Row{ - classes = {self:_getBackgroundClass(winner)}, + classes = {self:getBackgroundClass(winner)}, children = WidgetUtil.collect( self:_displayDate(match), self:displayTier(match), diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index 2b512cf52e5..5b09bed21aa 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -507,10 +507,10 @@ end ---@return Widget function CharacterGameTable:gameRow(match, game) local indexes = ((self.isCharacterTable and game.pickedBy == game.winner) or match.result.flipped) and {2, 1} or {1, 2} - local winner = game.winner == indexes[1] + local winner = indexes[game.winner] return TableWidgets.Row{ - classes = {self:_getBackgroundClass(winner)}, + classes = {self:getBackgroundClass(winner)}, children = WidgetUtil.collect( self:_displayDate(match), self:displayTier(match), diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 5dc41616f5b..3d27e19d3d5 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -777,7 +777,7 @@ end ---@return Widget function MatchTable:matchRow(match) return TableWidgets.Row{ - classes = {self:_getBackgroundClass(match.result.winner)}, + classes = {self:getBackgroundClass(match.result.winner)}, children = WidgetUtil.collect( self:_displayDate(match), self:displayTier(match), @@ -971,9 +971,10 @@ function MatchTable:_displayMatchPage(match) } end ----@param winner any +---@protected +---@param winner integer ---@return string? -function MatchTable:_getBackgroundClass(winner) +function MatchTable:getBackgroundClass(winner) return winner == 1 and 'recent-matches-bg-win' or winner == 0 and 'recent-matches-bg-tie' or winner == 2 and 'recent-matches-bg-lose' or From 71519060f76fef371ff91137d633ec2ef03f32c3 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:24:53 +0900 Subject: [PATCH 35/57] fix character table mode --- lua/wikis/commons/GameTable/Character.lua | 33 ++++++++++++----------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index 5b09bed21aa..fdaba3ecdf2 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -65,12 +65,6 @@ local SCORE_CONCAT = ' : ' local CharacterGameTable = Class.new(GameTable, function (self) self.isCharacterTable = self.args.tableMode == CHARACTER_MODE self.isPickedByRequired = self.isCharacterTable - - if not self.isCharacterTable then - self.resultFromRecord = GameTable.resultFromRecord - self.buildConditions = GameTable.buildConditions - self.statsFromMatches = GameTable.statsFromMatches - end end) ---@return integer @@ -175,8 +169,11 @@ function CharacterGameTable:_buildCharacterConditions() return characterConditions end ----@return string +---@return ConditionTree function CharacterGameTable:buildConditions() + if not self.isCharacterTable then + return GameTable.buildConditions(self) + end local lpdbData = mw.ext.LiquipediaDB.lpdb('match2game', { conditions = self:_buildMatchConditions(), query = 'match2id', @@ -190,7 +187,7 @@ function CharacterGameTable:buildConditions() conditions:add(ConditionNode(ColumnName('match2id'), Comparator.eq, game.match2id)) end) - return conditions:toString() + return conditions end ---@param game CharacterGameTableGame @@ -253,19 +250,25 @@ function CharacterGameTable:filterGame(game) return foundPicks or self.config.showGameWithoutCharacters end ----@param record table +---@param record MatchGroupUtilMatch ---@return MatchTableMatchResult? function CharacterGameTable:resultFromRecord(record) - return { - opponent = record.match2opponents[1], - vs = record.match2opponents[2], - winner = tonumber(record.winner), - countGames = true, - } + if self.isCharacterTable then + return { + opponent = record.opponents[1], + vs = record.opponents[2], + winner = tonumber(record.winner), + countGames = true, + } + end + return GameTable.resultFromRecord(self, record) end ---@return {games: {w: number, d: number, l: number}} function CharacterGameTable:statsFromMatches() + if not self.isCharacterTable then + return GameTable.statsFromMatches(self) + end local totalGames = {w = 0, d = 0, l = 0} Array.forEach(self.matches, function(match) From f8dd786df24ba7a9cad56e476fb8f86e626583d4 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:27:04 +0900 Subject: [PATCH 36/57] adjust deadlock custom --- lua/wikis/deadlock/GameTable/Character/Custom.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/wikis/deadlock/GameTable/Character/Custom.lua b/lua/wikis/deadlock/GameTable/Character/Custom.lua index b976950ee86..ad429e1972b 100644 --- a/lua/wikis/deadlock/GameTable/Character/Custom.lua +++ b/lua/wikis/deadlock/GameTable/Character/Custom.lua @@ -12,6 +12,8 @@ local Class = Lua.import('Module:Class') local GameTableCharacter = Lua.import('Module:GameTable/Character') +---@class DeadlockCharacterGameTable: CharacterGameTable +---@operator call(table): CharacterGameTable local CustomGameTableCharacter = Class.new(GameTableCharacter) ---@return integer @@ -27,7 +29,7 @@ function CustomGameTableCharacter:getCharacterKey(opponentIndex, playerIndex) end ---@param frame Frame ----@return Html +---@return Widget function CustomGameTableCharacter.results(frame) local args = Arguments.getArgs(frame) From 18232dd4953ef4c60bff7670e4ce8f819ec0965a Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:27:59 +0900 Subject: [PATCH 37/57] adjust dota2 custom --- lua/wikis/dota2/GameTable/Character/Custom.lua | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lua/wikis/dota2/GameTable/Character/Custom.lua b/lua/wikis/dota2/GameTable/Character/Custom.lua index c9d71ef36a0..3a2ff227373 100644 --- a/lua/wikis/dota2/GameTable/Character/Custom.lua +++ b/lua/wikis/dota2/GameTable/Character/Custom.lua @@ -12,7 +12,10 @@ local Class = Lua.import('Module:Class') local GameTableCharacter = Lua.import('Module:GameTable/Character') +local Link = Lua.import('Module:Widget/Basic/Link') + ---@class Dota2CharacterGameTable: CharacterGameTable +---@operator call(table): Dota2CharacterGameTable local CustomCharacterGameTable = Class.new(GameTableCharacter) ---@return integer @@ -27,8 +30,15 @@ function CustomCharacterGameTable:getCharacterKey(opponentIndex, playerIndex) return 'team' .. opponentIndex .. 'hero' .. playerIndex end +---@protected +---@param game CharacterGameTableGame +---@return Widget? +function CustomCharacterGameTable:getPatchLink(game) + return Link{link = 'Version ' .. game.patch, children = game.patch} +end + ---@param frame Frame ----@return Html +---@return Widget function CustomCharacterGameTable.results(frame) local args = Arguments.getArgs(frame) From a26efe2e527395026de90a95e9ae2077dc51493b Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:30:07 +0900 Subject: [PATCH 38/57] add character table custom to commons --- lua/wikis/commons/GameTable/Character/Custom.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 lua/wikis/commons/GameTable/Character/Custom.lua diff --git a/lua/wikis/commons/GameTable/Character/Custom.lua b/lua/wikis/commons/GameTable/Character/Custom.lua new file mode 100644 index 00000000000..d10d0bb72c4 --- /dev/null +++ b/lua/wikis/commons/GameTable/Character/Custom.lua @@ -0,0 +1,12 @@ +--- +-- @Liquipedia +-- page=Module:GameTable/Character/Custom +-- +-- Please see https://github.com/Liquipedia/Lua-Modules to contribute +-- + +local Lua = require('Module:Lua') + +local CharacterGameTable = Lua.import('Module:GameTable/Character') + +return CharacterGameTable From 0c6946962081a2f3350f1d0dc2c097c1c800b1f7 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:30:28 +0900 Subject: [PATCH 39/57] type annotation --- lua/wikis/commons/GameTable/Custom.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/wikis/commons/GameTable/Custom.lua b/lua/wikis/commons/GameTable/Custom.lua index 4a27cd360b0..6a02e0b214e 100644 --- a/lua/wikis/commons/GameTable/Custom.lua +++ b/lua/wikis/commons/GameTable/Custom.lua @@ -14,7 +14,7 @@ local GameTable = Lua.import('Module:GameTable') local CustomGameTable = {} ---@param args table ----@return Html +---@return Widget function CustomGameTable.results(args) return GameTable(args):readConfig():query():build() end From 9a7eaff1c78e7ed4d01574c2cab6323895e69433 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:33:26 +0900 Subject: [PATCH 40/57] update val custom type annotations --- lua/wikis/valorant/GameTable/Character/Custom.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lua/wikis/valorant/GameTable/Character/Custom.lua b/lua/wikis/valorant/GameTable/Character/Custom.lua index 1f876f3521a..09ee8bdaa99 100644 --- a/lua/wikis/valorant/GameTable/Character/Custom.lua +++ b/lua/wikis/valorant/GameTable/Character/Custom.lua @@ -19,6 +19,7 @@ local Opponent = Lua.import('Module:Opponent/Custom') local CharacterGameTable = Lua.import('Module:GameTable/Character') ---@class ValorantCharacterGameTable: CharacterGameTable +---@operator call(table): ValorantCharacterGameTable local CustomCharacterGameTable = Class.new(CharacterGameTable, function (self) self.args.showBans = false @@ -115,7 +116,7 @@ function CustomCharacterGameTable:_getRatio(participant) return MathUtil.round(kills / deaths, 1) end ----@param match GameTableMatch +---@param match CharacterGameTableMatch ---@param game CharacterGameTableGame ---@return Html? function CustomCharacterGameTable:displayGame(match, game) @@ -166,7 +167,7 @@ function CustomCharacterGameTable:displayGame(match, game) end ---@param frame Frame ----@return Html +---@return Widget function CustomCharacterGameTable.results(frame) local args = Arguments.getArgs(frame) From b3d58312133ca11add297d77664624526a379ae6 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:35:02 +0900 Subject: [PATCH 41/57] organize imports --- lua/wikis/valorant/GameTable/Character/Custom.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lua/wikis/valorant/GameTable/Character/Custom.lua b/lua/wikis/valorant/GameTable/Character/Custom.lua index 09ee8bdaa99..200a97b721e 100644 --- a/lua/wikis/valorant/GameTable/Character/Custom.lua +++ b/lua/wikis/valorant/GameTable/Character/Custom.lua @@ -12,9 +12,8 @@ local Array = Lua.import('Module:Array') local CharacterIcon = Lua.import('Module:CharacterIcon') local Class = Lua.import('Module:Class') local MathUtil = Lua.import('Module:MathUtil') -local Page = Lua.import('Module:Page') - local Opponent = Lua.import('Module:Opponent/Custom') +local Page = Lua.import('Module:Page') local CharacterGameTable = Lua.import('Module:GameTable/Character') From 7928d96633c378aa73ac0ee57344e0a819d1db78 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 16:53:49 +0900 Subject: [PATCH 42/57] type anno --- lua/wikis/commons/GameTable/Character.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index fdaba3ecdf2..7d1e1aae22a 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -398,7 +398,7 @@ end ---@param game CharacterGameTableGame ---@param opponentIndex number ---@param key string ----@return Widget? +---@return Widget function CharacterGameTable:_displayCharacters(game, opponentIndex, key) local config = self.config @@ -457,7 +457,7 @@ end ---@param game CharacterGameTableGame ---@param pickedBy number ---@param pickedVs number ----@return Html +---@return Widget function CharacterGameTable:_displayScore(game, pickedBy, pickedVs) local winner = tonumber(game.winner) local scores = Array.map(game.opponents, Operator.property('score')) @@ -478,7 +478,7 @@ function CharacterGameTable:_displayScore(game, pickedBy, pickedVs) end ---@param game CharacterGameTableGame ----@return Html? +---@return Widget? function CharacterGameTable:_displayLength(game) if not self.config.showLength then return end From c1f298a9405576ffd4643fd394f8d0a9992e4e7e Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 17:05:43 +0900 Subject: [PATCH 43/57] update val custom impl --- .../valorant/GameTable/Character/Custom.lua | 201 ++++++++++++------ 1 file changed, 140 insertions(+), 61 deletions(-) diff --git a/lua/wikis/valorant/GameTable/Character/Custom.lua b/lua/wikis/valorant/GameTable/Character/Custom.lua index 200a97b721e..b009adf6fcb 100644 --- a/lua/wikis/valorant/GameTable/Character/Custom.lua +++ b/lua/wikis/valorant/GameTable/Character/Custom.lua @@ -17,6 +17,11 @@ local Page = Lua.import('Module:Page') local CharacterGameTable = Lua.import('Module:GameTable/Character') +local LinkWidget = Lua.import('Module:Widget/Basic/Link') +local MatchSummaryCharacters = Lua.import('Module:Widget/Match/Summary/Characters') +local TableWidgets = Lua.import('Module:Widget/Table2/All') +local WidgetUtil = Lua.import('Module:Widget/Util') + ---@class ValorantCharacterGameTable: CharacterGameTable ---@operator call(table): ValorantCharacterGameTable local CustomCharacterGameTable = Class.new(CharacterGameTable, function (self) @@ -65,42 +70,118 @@ function CustomCharacterGameTable:getCharacterKey(opponentIndex, playerIndex) return 't' .. opponentIndex .. 'p' .. playerIndex .. 'agent' end +---@protected +---@return table[] +function CustomCharacterGameTable:buildColumnDefinitions() + local config = self.config + return WidgetUtil.collect( + { + -- Date column + align = 'left', + sortType = 'number', + }, + config.showTier and {align = 'left'} or nil, + config.showType and {align = 'center'} or nil, + config.showIcon and { + align = 'center', + unsortable = true, + } or nil, + { + -- Tournament column + align = 'left', + }, + { + -- Map column + align = 'left', + }, + config.showResult and WidgetUtil.collect( + config.mode == Opponent.solo and {align = 'center'} or nil, + config.mode ~= Opponent.team and { + {align = 'right'}, -- Kills + {align = 'right'}, -- Deaths + {align = 'right'}, -- Assists + {align = 'right'} -- Ratio + } or nil, + { + -- Picks column + align = 'center', + unsortable = true, + }, + { + -- Team column + align = 'center', + }, + { + -- Score column + align = 'center', + }, + { + -- vs. Team column + align = 'center', + }, + { + -- vs. Picks column + align = 'center', + } + ) or nil, + config.showLength and { + align = 'left', + } or nil, + config.showPatch and { + align = 'left', + } or nil, + config.showVod and { + align = 'left', + unsortable = true, + } or nil, + config.showMatchPage and { + align = 'center', + unsortable = true, + } or nil + ) +end + ---@return Html function CustomCharacterGameTable:headerRow() - local makeHeaderCell = function(text, width) - return mw.html.create('th'):css('max-width', width):node(text) + ---@param text string? + ---@return Widget + local makeHeaderCell = function(text) + return TableWidgets.CellHeader{children = text} end local config = self.config - local nodes = Array.append({}, - makeHeaderCell('Date', '100px'), - config.showTier and makeHeaderCell('Tier', '70px') or nil, - config.showType and makeHeaderCell('Type', '70px') or nil, - config.showIcon and makeHeaderCell(nil, '25px'):addClass('unsortable') or nil, - makeHeaderCell('Tournament'), - makeHeaderCell('Map'), - (config.showResult and config.mode == Opponent.solo) and makeHeaderCell('') or nil, - (config.showResult and config.mode ~= Opponent.team) and makeHeaderCell('K') or nil, - (config.showResult and config.mode ~= Opponent.team) and makeHeaderCell('D') or nil, - (config.showResult and config.mode ~= Opponent.team) and makeHeaderCell('A') or nil, - (config.showResult and config.mode ~= Opponent.team) and makeHeaderCell('Ratio') or nil, - config.showResult and makeHeaderCell('Picks'):addClass('unsortable') or nil, - config.showResult and makeHeaderCell(nil, '80px') or nil, - config.showResult and makeHeaderCell('Score') or nil, - config.showResult and makeHeaderCell(nil, '80px') or nil, - config.showResult and makeHeaderCell('vs. Picks'):addClass('unsortable') or nil, - config.showLength and makeHeaderCell('Length') or nil, - config.showVod and makeHeaderCell('VOD', '60px') or nil, - config.showMatchPage and makeHeaderCell('') or nil - ) - - local header = mw.html.create('tr') - Array.forEach(nodes, function (node) - header:node(node) - end) - - return header + return TableWidgets.TableHeader{children = { + TableWidgets.Row{children = WidgetUtil.collect( + makeHeaderCell('Date'), + config.showTier and makeHeaderCell('Tier') or nil, + config.showType and makeHeaderCell('Type') or nil, + config.showIcon and makeHeaderCell() or nil, + makeHeaderCell('Tournament'), + makeHeaderCell('Map'), + config.showResult and WidgetUtil.collect( + config.mode == Opponent.solo and makeHeaderCell() or nil, + config.mode ~= Opponent.team and { + makeHeaderCell('K'), + makeHeaderCell('D'), + makeHeaderCell('A'), + makeHeaderCell('Ratio'), + } or nil, + makeHeaderCell('Picks'), + makeHeaderCell(), + makeHeaderCell('Score'), + makeHeaderCell(), + makeHeaderCell('vs. Picks') + ) or nil, + config.showLength and makeHeaderCell('Length') or nil, + config.showPatch and makeHeaderCell('Patch') or nil, + config.showVod and TableWidgets.CellHeader{ + align = 'center', + children = 'VOD' + } or nil, + config.showMatchPage and makeHeaderCell() or nil + )} + }} end ---@param participant table @@ -117,30 +198,26 @@ end ---@param match CharacterGameTableMatch ---@param game CharacterGameTableGame ----@return Html? +---@return Widget[]? function CustomCharacterGameTable:displayGame(match, game) - local makeCell = function (text) - return mw.html.create('td'):node(text) + ---@param children Renderable|Renderable[]? + ---@return Table2Cell + local makeCell = function (children) + return TableWidgets.Cell{children = children} end - local makeIcon = function (character) - if not character then return nil end - return mw.html.create('td') - :node(CharacterIcon.Icon{character = character, size = self.config.iconSize, date = game.date}) - end + local indexes = ((self.isCharacterTable and game.pickedBy == game.winner) or match.result.flipped) and {2, 1} or {1, 2} - local opponent = match.result.opponent - local opponentVs = match.result.vs - if self.isCharacterTable then - local pickedBy = game.pickedBy - ---@cast pickedBy -nil - if pickedBy == 2 then - opponent, opponentVs = opponentVs, opponent - end - end + local opponent = match.opponents[indexes[1]] + local opponentVs = match.opponents[indexes[2]] - local node = mw.html.create() - :node(makeCell(Page.makeInternalLink(game.map))) + ---@type Widget[] + local cells = {makeCell(LinkWidget{link = game.map})} + + ---@param cell Widget + local function addCell(cell) + table.insert(cells, cell) + end if self.config.mode ~= Opponent.team then local participant = game.opponents[game.pickedBy].players[game.pickedByplayer] @@ -148,21 +225,23 @@ function CustomCharacterGameTable:displayGame(match, game) local index = Array.indexOf(game.picks[game.pickedBy], function (pick) return participant.agent == pick end) - node:node(index > 0 and makeIcon(table.remove(game.picks[game.pickedBy], index)) or makeCell()) + addCell(makeCell(index > 0 and MatchSummaryCharacters{ + characters = {table.remove(game.picks[game.pickedBy], index)} + } or nil)) end - node - :node(makeCell(participant and participant.kills or nil)) - :node(makeCell(participant and participant.deaths or nil)) - :node(makeCell(participant and participant.assists or nil)) - :node(makeCell(participant and self:_getRatio(participant) or nil)) + addCell(makeCell(participant and participant.kills or nil)) + addCell(makeCell(participant and participant.deaths or nil)) + addCell(makeCell(participant and participant.assists or nil)) + addCell(makeCell(participant and self:_getRatio(participant) or nil)) end - return node - :node(self:_displayCharacters(game, opponent.id, 'picks')) - :node(self:_displayOpponent(opponent, false)) - :node(self:_displayScore(game, opponent.id, opponentVs.id)) - :node(self:_displayOpponent(opponentVs, true)) - :node(self:_displayCharacters(game, opponentVs.id, 'picks')) + addCell(self:_displayCharacters(game, indexes[1], 'picks')) + addCell(self:_displayOpponent(opponent, false)) + addCell(self:_displayScore(game, indexes[1], indexes[2])) + addCell(self:_displayOpponent(opponentVs, true)) + addCell(self:_displayCharacters(game, indexes[2], 'picks')) + + return cells end ---@param frame Frame From c83510f72873efa290f954d8662982357bce79b7 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 17:09:24 +0900 Subject: [PATCH 44/57] adjust column config --- lua/wikis/valorant/GameTable/Character/Custom.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/wikis/valorant/GameTable/Character/Custom.lua b/lua/wikis/valorant/GameTable/Character/Custom.lua index b009adf6fcb..903997ee34c 100644 --- a/lua/wikis/valorant/GameTable/Character/Custom.lua +++ b/lua/wikis/valorant/GameTable/Character/Custom.lua @@ -95,7 +95,7 @@ function CustomCharacterGameTable:buildColumnDefinitions() align = 'left', }, config.showResult and WidgetUtil.collect( - config.mode == Opponent.solo and {align = 'center'} or nil, + config.mode == Opponent.solo and {align = 'left'} or nil, config.mode ~= Opponent.team and { {align = 'right'}, -- Kills {align = 'right'}, -- Deaths @@ -160,14 +160,14 @@ function CustomCharacterGameTable:headerRow() makeHeaderCell('Tournament'), makeHeaderCell('Map'), config.showResult and WidgetUtil.collect( - config.mode == Opponent.solo and makeHeaderCell() or nil, + config.mode == Opponent.solo and makeHeaderCell('Pick') or nil, config.mode ~= Opponent.team and { makeHeaderCell('K'), makeHeaderCell('D'), makeHeaderCell('A'), makeHeaderCell('Ratio'), } or nil, - makeHeaderCell('Picks'), + makeHeaderCell(config.mode == Opponent.solo and 'Team Picks' or 'Picks'), makeHeaderCell(), makeHeaderCell('Score'), makeHeaderCell(), From b1519944c71c25c0b6fca5159770d8b813e30e93 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 17:09:49 +0900 Subject: [PATCH 45/57] move date default to constructor --- lua/wikis/commons/GameTable/Character.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index 7d1e1aae22a..e1eb94e1f54 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -63,6 +63,7 @@ local SCORE_CONCAT = ' : ' ---@field config CharacterGameTableConfig ---@field matches CharacterGameTableMatch[] local CharacterGameTable = Class.new(GameTable, function (self) + self.args.dateFormat = Logic.emptyOr(self.args.dateFormat, 'compact') self.isCharacterTable = self.args.tableMode == CHARACTER_MODE self.isPickedByRequired = self.isCharacterTable end) @@ -534,7 +535,6 @@ end ---@return Widget function CharacterGameTable.results(frame) local args = Arguments.getArgs(frame) - args.dateFormat = Logic.emptyOr(args.dateFormat, 'compact') return CharacterGameTable(args):readConfig():query():build() end From b47e4fe177e9c71ad5cba88f4eef8afe58d93ac2 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 17:14:17 +0900 Subject: [PATCH 46/57] formatRounded --- lua/wikis/valorant/GameTable/Character/Custom.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/wikis/valorant/GameTable/Character/Custom.lua b/lua/wikis/valorant/GameTable/Character/Custom.lua index 903997ee34c..64db3cd4194 100644 --- a/lua/wikis/valorant/GameTable/Character/Custom.lua +++ b/lua/wikis/valorant/GameTable/Character/Custom.lua @@ -185,7 +185,7 @@ function CustomCharacterGameTable:headerRow() end ---@param participant table ----@return number? +---@return string? function CustomCharacterGameTable:_getRatio(participant) local kills = tonumber(participant.kills) or 0 local deaths = tonumber(participant.deaths) or 0 @@ -193,7 +193,7 @@ function CustomCharacterGameTable:_getRatio(participant) return nil end - return MathUtil.round(kills / deaths, 1) + return MathUtil.formatRounded{value = kills / deaths, precision = 1} end ---@param match CharacterGameTableMatch From 85d432bac6a5e3568c91187689812b4308b13a55 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 17:16:23 +0900 Subject: [PATCH 47/57] remove unused import --- lua/wikis/valorant/GameTable/Character/Custom.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/lua/wikis/valorant/GameTable/Character/Custom.lua b/lua/wikis/valorant/GameTable/Character/Custom.lua index 64db3cd4194..192fe2dc56b 100644 --- a/lua/wikis/valorant/GameTable/Character/Custom.lua +++ b/lua/wikis/valorant/GameTable/Character/Custom.lua @@ -9,11 +9,9 @@ local Lua = require('Module:Lua') local Arguments = Lua.import('Module:Arguments') local Array = Lua.import('Module:Array') -local CharacterIcon = Lua.import('Module:CharacterIcon') local Class = Lua.import('Module:Class') local MathUtil = Lua.import('Module:MathUtil') local Opponent = Lua.import('Module:Opponent/Custom') -local Page = Lua.import('Module:Page') local CharacterGameTable = Lua.import('Module:GameTable/Character') From a13b17485659b7d7347347d901426b80bcf6547a Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 17:41:48 +0900 Subject: [PATCH 48/57] add hover support --- lua/wikis/commons/MatchTable.lua | 6 ++-- stylesheets/commons/MatchTable.scss | 50 +++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 3d27e19d3d5..d320dd54daf 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -975,9 +975,9 @@ end ---@param winner integer ---@return string? function MatchTable:getBackgroundClass(winner) - return winner == 1 and 'recent-matches-bg-win' or - winner == 0 and 'recent-matches-bg-tie' or - winner == 2 and 'recent-matches-bg-lose' or + return winner == 1 and 'match-table-row__win' or + winner == 0 and 'match-table-row__draw' or + winner == 2 and 'match-table-row__loss' or nil end diff --git a/stylesheets/commons/MatchTable.scss b/stylesheets/commons/MatchTable.scss index 97a238c7a8f..c4464280feb 100644 --- a/stylesheets/commons/MatchTable.scss +++ b/stylesheets/commons/MatchTable.scss @@ -12,3 +12,53 @@ Template(s): MatchTable .recent-matches-bg-lose { background-color: var( --table-red-background-color, #f9f0f2 ) !important; } + +.match-table-wrapper table.table2__table tr.table2__row--body { + &.match-table-row__win { + background-color: var( --clr-semantic-positive-90 ); + + &:hover { + background-color: var( --clr-semantic-positive-80 ); + } + + .theme--dark & { + background-color: var( --clr-semantic-positive-10 ); + + &:hover { + background-color: var( --clr-semantic-positive-20 ); + } + } + } + + &.match-table-row__draw { + background-color: var( --clr-semantic-gold-90 ); + + &:hover { + background-color: var( --clr-semantic-gold-80 ); + } + + .theme--dark & { + background-color: var( --clr-semantic-gold-10 ); + + &:hover { + background-color: var( --clr-semantic-gold-20 ); + } + } + } + + &.match-table-row__loss { + background-color: var( --clr-semantic-negative-90 ); + + &:hover { + background-color: var( --clr-semantic-negative-80 ); + } + + .theme--dark & { + background-color: var( --clr-semantic-negative-10 ); + + &:hover { + background-color: var( --clr-semantic-negative-20 ); + } + } + } +} From d427677de96092625b5cceeb9d43eba8e58651a7 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 17:42:31 +0900 Subject: [PATCH 49/57] short button in character table --- lua/wikis/commons/GameTable/Character.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index e1eb94e1f54..2749f21044a 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -64,6 +64,7 @@ local SCORE_CONCAT = ' : ' ---@field matches CharacterGameTableMatch[] local CharacterGameTable = Class.new(GameTable, function (self) self.args.dateFormat = Logic.emptyOr(self.args.dateFormat, 'compact') + self.args.matchPageButtonText = Logic.emptyOr(self.args.matchPageButtonText, 'short') self.isCharacterTable = self.args.tableMode == CHARACTER_MODE self.isPickedByRequired = self.isCharacterTable end) From 3f175ac46e7e339d5b4fe382415ce804b3a20707 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sat, 28 Feb 2026 17:48:35 +0900 Subject: [PATCH 50/57] grayscale for bans --- lua/wikis/commons/GameTable/Character.lua | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index 2749f21044a..0bdc700e462 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -404,11 +404,14 @@ end function CharacterGameTable:_displayCharacters(game, opponentIndex, key) local config = self.config - return TableWidgets.Cell{children = MatchSummaryCharacters{ - bg = config.showSideClass and self:getSideClass(game.extradata, opponentIndex) or nil, - characters = game[key][opponentIndex] or {}, - date = game.date, - }} + return TableWidgets.Cell{ + classes = key == 'bans' and {'lor-graycard'} or nil, + children = MatchSummaryCharacters{ + bg = config.showSideClass and self:getSideClass(game.extradata, opponentIndex) or nil, + characters = game[key][opponentIndex] or {}, + date = game.date, + } + } end ---@param match CharacterGameTableMatch From 30f3472971581fdad6803593221759b6bb243e2e Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sun, 1 Mar 2026 12:21:57 +0900 Subject: [PATCH 51/57] use mixin --- stylesheets/commons/MatchTable.scss | 48 +++++++---------------------- 1 file changed, 11 insertions(+), 37 deletions(-) diff --git a/stylesheets/commons/MatchTable.scss b/stylesheets/commons/MatchTable.scss index c4464280feb..86b979e783f 100644 --- a/stylesheets/commons/MatchTable.scss +++ b/stylesheets/commons/MatchTable.scss @@ -13,52 +13,26 @@ Template(s): MatchTable background-color: var( --table-red-background-color, #f9f0f2 ) !important; } -.match-table-wrapper table.table2__table tr.table2__row--body { - &.match-table-row__win { - background-color: var( --clr-semantic-positive-90 ); - - &:hover { - background-color: var( --clr-semantic-positive-80 ); - } - - .theme--dark & { - background-color: var( --clr-semantic-positive-10 ); - - &:hover { - background-color: var( --clr-semantic-positive-20 ); - } - } - } - - &.match-table-row__draw { - background-color: var( --clr-semantic-gold-90 ); +@mixin match-table-colors($row-type, $color-type) { + &.match-table-row__#{$row-type} { + background-color: var( --clr-#{$color-type}-90 ); &:hover { - background-color: var( --clr-semantic-gold-80 ); + background-color: var( --clr-#{$color-type}-80 ); } .theme--dark & { - background-color: var( --clr-semantic-gold-10 ); + background-color: var( --clr-#{$color-type}-10 ); &:hover { - background-color: var( --clr-semantic-gold-20 ); + background-color: var( --clr-#{$color-type}-20 ); } } } +} - &.match-table-row__loss { - background-color: var( --clr-semantic-negative-90 ); - - &:hover { - background-color: var( --clr-semantic-negative-80 ); - } - - .theme--dark & { - background-color: var( --clr-semantic-negative-10 ); - - &:hover { - background-color: var( --clr-semantic-negative-20 ); - } - } - } +.match-table-wrapper table.table2__table tr.table2__row--body { + @include match-table-colors( win, semantic-positive ); + @include match-table-colors( draw, semantic-gold ); + @include match-table-colors( loss, semantic-negative ); } From 885b3899986cd5e2f53d21fa10171520aef41e13 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sun, 1 Mar 2026 16:17:36 +0900 Subject: [PATCH 52/57] remove unused args --- lua/wikis/commons/GameTable/Character.lua | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index 0bdc700e462..de1b77d5a99 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -43,8 +43,6 @@ local SCORE_CONCAT = ' : ' ---@field showPatch boolean ---@field numPicks number ---@field numBans number ----@field iconSize string ----@field iconSeparator string ---@class CharacterGameTableGame: MatchGroupUtilGame ---@field picks string[][] @@ -110,8 +108,6 @@ function CharacterGameTable:readConfig() showPatch = Logic.nilOr(Logic.readBoolOrNil(args.showPatch), true), numPicks = self:getNumberOfPicks(), numBans = self:getNumberOfBans(), - iconSize = Logic.nilIfEmpty(self.args.iconSize) or '27px', - iconSeparator = Logic.nilIfEmpty(args.iconSeparator) or '' }) return self From de7207c9508d26359c6a68220bc24009de5afcef Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Wed, 11 Mar 2026 20:19:37 +0900 Subject: [PATCH 53/57] cleanup --- lua/wikis/commons/MatchTable.lua | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index d320dd54daf..4c325adc7bb 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -568,27 +568,11 @@ end ---@return Widget function MatchTable:buildDisplay() - local display = mw.html.create('table') - :addClass('wikitable wikitable-striped sortable') - :css('text-align', 'center') - :node(self:_titleRow(self.config.title)) - :node(self:headerRow()) - - local currentYear - Array.forEach(self.matches, function(match) - local year = tonumber(match.date:sub(1, 4)) - if self.config.showYearHeaders and year ~= currentYear then - currentYear = year - display:node(self:_yearRow(year)) - end - display:node(self:matchRow(match)) - end) - return TableWidgets.Table{ classes = {'match-table-wrapper'}, sortable = true, columns = self:buildColumnDefinitions(), - title = String.nilIfEmpty(self.config.title), + title = Logic.nilIfEmpty(self.config.title), children = WidgetUtil.collect( self:headerRow(), TableWidgets.TableBody{children = self:buildBody()} @@ -605,17 +589,6 @@ function MatchTable:build() )} end ----@param title string ----@return Html? -function MatchTable:_titleRow(title) - if not title then return end - return mw.html.create('tr') - :tag('th') - :attr('colspan', '100') - :wikitext(title) - :done() -end - ---@protected ---@return table[] function MatchTable:buildColumnDefinitions() From e857c7afe2606b49926d0b0636f1c5424f3a8851 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Wed, 11 Mar 2026 22:29:50 +0900 Subject: [PATCH 54/57] suppress sorting in matchpage --- lua/wikis/commons/MatchPage/Base.lua | 1 + lua/wikis/commons/MatchTable.lua | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lua/wikis/commons/MatchPage/Base.lua b/lua/wikis/commons/MatchPage/Base.lua index 9f5e3b65fb8..02f5a521bff 100644 --- a/lua/wikis/commons/MatchPage/Base.lua +++ b/lua/wikis/commons/MatchPage/Base.lua @@ -542,6 +542,7 @@ function BaseMatchPage:_createMatchTable(props) inclusive, and we don't want that here ]], limit = 5, stats = false, + sortableResults = false, tableMode = Opponent.team, vod = false, matchPageButtonText = 'short', diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 4c325adc7bb..3d7c3f65e30 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -81,6 +81,7 @@ local SECONDS_ONE_DAY = 3600 * 24 ---@field queryHistoricalAliases boolean ---@field showType boolean ---@field showYearHeaders boolean +---@field sortableResults boolean ---@field useTickerName boolean ---@field teamStyle teamStyle ---@field linkSubPage boolean @@ -168,6 +169,7 @@ function MatchTable:_readDefaultConfig() showRoundStats = Logic.readBool(args.showRoundStats), showType = Logic.readBool(args.showType), showYearHeaders = Logic.readBool(args.showYearHeaders), + sortableResults = Logic.nilOr(Logic.readBoolOrNil(args.sortableResults), true), useTickerName = Logic.readBool(args.useTickerName), teamStyle = String.nilIfEmpty(args.teamStyle) or 'short', linkSubPage = Logic.readBool(args.linkSubPage), @@ -570,7 +572,7 @@ end function MatchTable:buildDisplay() return TableWidgets.Table{ classes = {'match-table-wrapper'}, - sortable = true, + sortable = self.config.sortableResults, columns = self:buildColumnDefinitions(), title = Logic.nilIfEmpty(self.config.title), children = WidgetUtil.collect( From 03947b15dcf8f00ce72fd9e9dff3a37604764484 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Wed, 11 Mar 2026 23:38:32 +0900 Subject: [PATCH 55/57] remove row bg --- stylesheets/commons/MatchTable.scss | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/stylesheets/commons/MatchTable.scss b/stylesheets/commons/MatchTable.scss index 86b979e783f..97a238c7a8f 100644 --- a/stylesheets/commons/MatchTable.scss +++ b/stylesheets/commons/MatchTable.scss @@ -12,27 +12,3 @@ Template(s): MatchTable .recent-matches-bg-lose { background-color: var( --table-red-background-color, #f9f0f2 ) !important; } - -@mixin match-table-colors($row-type, $color-type) { - &.match-table-row__#{$row-type} { - background-color: var( --clr-#{$color-type}-90 ); - - &:hover { - background-color: var( --clr-#{$color-type}-80 ); - } - - .theme--dark & { - background-color: var( --clr-#{$color-type}-10 ); - - &:hover { - background-color: var( --clr-#{$color-type}-20 ); - } - } - } -} - -.match-table-wrapper table.table2__table tr.table2__row--body { - @include match-table-colors( win, semantic-positive ); - @include match-table-colors( draw, semantic-gold ); - @include match-table-colors( loss, semantic-negative ); -} From 88a555f3bcb16310a190699d0404990eb31098f8 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 12 Mar 2026 18:16:01 +0900 Subject: [PATCH 56/57] use result indicator --- lua/wikis/commons/GameTable.lua | 16 ++++++---- lua/wikis/commons/GameTable/Character.lua | 22 ++++++++----- lua/wikis/commons/MatchTable.lua | 39 +++++++++++++++-------- 3 files changed, 48 insertions(+), 29 deletions(-) diff --git a/lua/wikis/commons/GameTable.lua b/lua/wikis/commons/GameTable.lua index ad76250de0c..050241bbd9d 100644 --- a/lua/wikis/commons/GameTable.lua +++ b/lua/wikis/commons/GameTable.lua @@ -71,7 +71,7 @@ end ---@param result MatchTableMatchResult ---@param game MatchGroupUtilGame ----@return Html? +---@return Widget[] function GameTable:_displayGameScore(result, game) local scores = Array.map(game.opponents, Operator.property('score')) local indexes = result.flipped and {2, 1} or {1, 2} @@ -87,11 +87,14 @@ function GameTable:_displayGameScore(result, game) } end - return TableWidgets.Cell{children = { - toScore(indexes[1]), - SCORE_CONCAT, - toScore(indexes[2]), - }} + return { + TableWidgets.Cell{children = MatchTable.getResultIndicator(indexes[game.winner])}, + TableWidgets.Cell{children = { + toScore(indexes[1]), + SCORE_CONCAT, + toScore(indexes[2]), + }} + } end ---@param game MatchGroupUtilGame @@ -129,7 +132,6 @@ function GameTable:gameRow(match, game) local winner = indexes[game.winner] return TableWidgets.Row{ - classes = {self:getBackgroundClass(winner)}, children = WidgetUtil.collect( self:_displayDate(match), self:displayTier(match), diff --git a/lua/wikis/commons/GameTable/Character.lua b/lua/wikis/commons/GameTable/Character.lua index de1b77d5a99..7056a6975b4 100644 --- a/lua/wikis/commons/GameTable/Character.lua +++ b/lua/wikis/commons/GameTable/Character.lua @@ -324,6 +324,7 @@ function CharacterGameTable:buildColumnDefinitions() {align = 'center'}, {align = 'center'}, {align = 'center'}, + {align = 'center'}, } or nil, { align = 'center', @@ -376,7 +377,10 @@ function CharacterGameTable:headerRow() config.showBans and makeHeaderCell('Bans') or nil, isCharTable and { makeHeaderCell(), - makeHeaderCell('Score'), + TableWidgets.CellHeader{ + colspan = 2, + children = 'Score' + }, makeHeaderCell(), } or nil, makeHeaderCell('vs. Picks'), @@ -458,7 +462,7 @@ end ---@param game CharacterGameTableGame ---@param pickedBy number ---@param pickedVs number ----@return Widget +---@return Widget[] function CharacterGameTable:_displayScore(game, pickedBy, pickedVs) local winner = tonumber(game.winner) local scores = Array.map(game.opponents, Operator.property('score')) @@ -471,11 +475,14 @@ function CharacterGameTable:_displayScore(game, pickedBy, pickedVs) } end - return TableWidgets.Cell{children = { - toScore(pickedBy), - SCORE_CONCAT, - toScore(pickedVs), - }} + return { + TableWidgets.Cell{children = CharacterGameTable.getResultIndicator((winner == pickedBy) and 1 or 2)}, + TableWidgets.Cell{children = { + toScore(pickedBy), + SCORE_CONCAT, + toScore(pickedVs), + }} + } end ---@param game CharacterGameTableGame @@ -514,7 +521,6 @@ function CharacterGameTable:gameRow(match, game) local winner = indexes[game.winner] return TableWidgets.Row{ - classes = {self:getBackgroundClass(winner)}, children = WidgetUtil.collect( self:_displayDate(match), self:displayTier(match), diff --git a/lua/wikis/commons/MatchTable.lua b/lua/wikis/commons/MatchTable.lua index 3d7c3f65e30..5474333bab9 100644 --- a/lua/wikis/commons/MatchTable.lua +++ b/lua/wikis/commons/MatchTable.lua @@ -11,6 +11,7 @@ local Array = Lua.import('Module:Array') local Class = Lua.import('Module:Class') local Countdown = Lua.import('Module:Countdown') local DateExt = Lua.import('Module:Date/Ext') +local FnUtil = Lua.import('Module:FnUtil') local Game = Lua.import('Module:Game') local I18n = Lua.import('Module:I18n') local Info = Lua.import('Module:Info', {loadData = true}) @@ -37,6 +38,7 @@ local Link = Lua.import('Module:Widget/Basic/Link') local MatchPageButton = Lua.import('Module:Widget/Match/PageButton') local HtmlWidgets = Lua.import('Module:Widget/Html/All') local TableWidgets = Lua.import('Module:Widget/Table2/All') +local WinLossIndicator = Lua.import('Module:Widget/Match/Summary/GameWinLossIndicator') local WidgetUtil = Lua.import('Module:Widget/Util') local Condition = Lua.import('Module:Condition') @@ -614,6 +616,10 @@ function MatchTable:buildColumnDefinitions() }, config.showResult and WidgetUtil.collect( config.showOpponent and {align = 'center'} or nil, + { + -- Result indicator column + align = 'center', + }, { -- Score column align = 'center', @@ -670,7 +676,10 @@ function MatchTable:headerRow() makeHeaderCell('Tournament'), config.showResult and WidgetUtil.collect( config.showOpponent and makeHeaderCell('Participant') or nil, - makeHeaderCell('Score'), + TableWidgets.CellHeader{ + colspan = 2, + children = 'Score' + }, TableWidgets.CellHeader{ align = 'center', children = 'vs. Opponent' @@ -752,7 +761,6 @@ end ---@return Widget function MatchTable:matchRow(match) return TableWidgets.Row{ - classes = {self:getBackgroundClass(match.result.winner)}, children = WidgetUtil.collect( self:_displayDate(match), self:displayTier(match), @@ -917,11 +925,14 @@ function MatchTable:_displayScore(match) } end - return TableWidgets.Cell{children = { - toScore(result.opponent, result.gameOpponents), - bestof1Score and BO1_SCORE_CONCAT or SCORE_CONCAT, - toScore(result.vs, result.gameVsOpponents) - }} + return { + TableWidgets.Cell{children = MatchTable.getResultIndicator(match.result.winner)}, + TableWidgets.Cell{children = { + toScore(result.opponent, result.gameOpponents), + bestof1Score and BO1_SCORE_CONCAT or SCORE_CONCAT, + toScore(result.vs, result.gameVsOpponents) + }} + } end ---@param match MatchTableMatch @@ -948,13 +959,13 @@ end ---@protected ---@param winner integer ----@return string? -function MatchTable:getBackgroundClass(winner) - return winner == 1 and 'match-table-row__win' or - winner == 0 and 'match-table-row__draw' or - winner == 2 and 'match-table-row__loss' or - nil -end +---@return Widget? +MatchTable.getResultIndicator = FnUtil.memoize(function (winner) + return WinLossIndicator{ + opponentIndex = 1, + winner = winner, + } +end) ---@return Widget? function MatchTable:displayStats() From 058e3c86f37e10ec8f57af807cf4e0daf3487cae Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 12 Mar 2026 18:31:34 +0900 Subject: [PATCH 57/57] update valorant custom --- lua/wikis/valorant/GameTable/Character/Custom.lua | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lua/wikis/valorant/GameTable/Character/Custom.lua b/lua/wikis/valorant/GameTable/Character/Custom.lua index 192fe2dc56b..41a15630b02 100644 --- a/lua/wikis/valorant/GameTable/Character/Custom.lua +++ b/lua/wikis/valorant/GameTable/Character/Custom.lua @@ -109,6 +109,10 @@ function CustomCharacterGameTable:buildColumnDefinitions() -- Team column align = 'center', }, + { + -- Result indicator column + align = 'center', + }, { -- Score column align = 'center', @@ -167,7 +171,10 @@ function CustomCharacterGameTable:headerRow() } or nil, makeHeaderCell(config.mode == Opponent.solo and 'Team Picks' or 'Picks'), makeHeaderCell(), - makeHeaderCell('Score'), + TableWidgets.CellHeader{ + colspan = 2, + children = 'Score' + }, makeHeaderCell(), makeHeaderCell('vs. Picks') ) or nil, @@ -235,7 +242,7 @@ function CustomCharacterGameTable:displayGame(match, game) addCell(self:_displayCharacters(game, indexes[1], 'picks')) addCell(self:_displayOpponent(opponent, false)) - addCell(self:_displayScore(game, indexes[1], indexes[2])) + Array.forEach(self:_displayScore(game, indexes[1], indexes[2]), addCell) addCell(self:_displayOpponent(opponentVs, true)) addCell(self:_displayCharacters(game, indexes[2], 'picks'))