Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
66a3e28
use anyOf
ElectricalBoy Oct 11, 2025
acc2f48
parseCommaSeparatedString
ElectricalBoy Oct 11, 2025
5fb3e95
code conciseness
ElectricalBoy Oct 11, 2025
49ffcbb
remove redundant comma
ElectricalBoy Feb 26, 2026
78219f8
commaSeparatedString
ElectricalBoy Feb 26, 2026
a228469
clean up condition building
ElectricalBoy Feb 26, 2026
8e160d5
use MGUMatch for processing
ElectricalBoy Feb 26, 2026
3076162
type conciseness
ElectricalBoy Feb 26, 2026
0c69d0f
type annotation
ElectricalBoy Feb 26, 2026
6367a16
use standardOpponent
ElectricalBoy Feb 26, 2026
8d41a9d
extract matchtable style to separate file
ElectricalBoy Feb 26, 2026
220cb3d
use new table
ElectricalBoy Feb 26, 2026
2377374
use formatPercentage
ElectricalBoy Feb 26, 2026
ee69938
isDefaultTimestamp
ElectricalBoy Feb 26, 2026
1273755
clean up stats
ElectricalBoy Feb 26, 2026
2d3b27e
clean up build
ElectricalBoy Feb 26, 2026
f1a5c36
update custom
ElectricalBoy Feb 26, 2026
5e96755
adjust access modifier
ElectricalBoy Feb 26, 2026
b416f16
use html entity over code
ElectricalBoy Feb 26, 2026
c2d09d4
slice buildRows
ElectricalBoy Feb 26, 2026
739c5ee
clean up GameTable
ElectricalBoy Feb 26, 2026
be4ac6d
type anno
ElectricalBoy Feb 26, 2026
3a9a91a
use isMain
ElectricalBoy Feb 26, 2026
c1d4461
rewrite charactergametable
ElectricalBoy Feb 26, 2026
2a2143a
lint
ElectricalBoy Feb 26, 2026
20bda21
adjust matchpage usage
ElectricalBoy Feb 27, 2026
873577e
missing return
ElectricalBoy Feb 28, 2026
b193bba
indentation
ElectricalBoy Feb 28, 2026
bb1cfe9
add missing length display
ElectricalBoy Feb 28, 2026
ed85fb6
restore notplayed filter
ElectricalBoy Feb 28, 2026
8b39b05
use compact date as default
ElectricalBoy Feb 28, 2026
7570c8e
make length sortable
ElectricalBoy Feb 28, 2026
99e740f
add patch display
ElectricalBoy Feb 28, 2026
8d21401
adjust background setting
ElectricalBoy Feb 28, 2026
209cd80
fix character table mode
ElectricalBoy Feb 28, 2026
5ed82fb
adjust deadlock custom
ElectricalBoy Feb 28, 2026
d1085f5
adjust dota2 custom
ElectricalBoy Feb 28, 2026
e55451a
add character table custom to commons
ElectricalBoy Feb 28, 2026
c4048b8
type annotation
ElectricalBoy Feb 28, 2026
1024c6d
update val custom type annotations
ElectricalBoy Feb 28, 2026
ef04c28
organize imports
ElectricalBoy Feb 28, 2026
fa3410c
type anno
ElectricalBoy Feb 28, 2026
b53ceb4
update val custom impl
ElectricalBoy Feb 28, 2026
fc7fda0
adjust column config
ElectricalBoy Feb 28, 2026
3e2274e
move date default to constructor
ElectricalBoy Feb 28, 2026
207d8d1
formatRounded
ElectricalBoy Feb 28, 2026
3b67520
remove unused import
ElectricalBoy Feb 28, 2026
e6feef5
add hover support
ElectricalBoy Feb 28, 2026
ce5acaa
short button in character table
ElectricalBoy Feb 28, 2026
78666a7
grayscale for bans
ElectricalBoy Feb 28, 2026
985ff7f
use mixin
ElectricalBoy Mar 1, 2026
aebae1b
remove unused args
ElectricalBoy Mar 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 97 additions & 79 deletions lua/wikis/commons/GameTable.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,143 +9,161 @@ 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')
local VodLink = Lua.import('Module:VodLink')

local MatchTable = Lua.import('Module:MatchTable')

local NOT_PLAYED = 'notplayed'
local SCORE_CONCAT = ' : '
local HtmlWidgets = Lua.import('Module:Widget/Html/All')
local TableWidgets = Lua.import('Module:Widget/Table2/All')
local WidgetUtil = Lua.import('Module:Widget/Util')

---@class GameTableMatch: MatchTableMatch
---@field games match2game[]
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
---@return GameTableMatch?
---@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)
---@cast matchRecord GameTableMatch
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)
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 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
elseif Logic.isEmpty(match.result.vs) then
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 = indexes[game.winner]

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)
return self:gameRow(match, game)
end)
))
end)

return display
return rows
end

return GameTable
Loading
Loading