diff --git a/lua/wikis/commons/PortalStatistics.lua b/lua/wikis/commons/PortalStatistics.lua
index ca70c4d6318..3668a18df5f 100644
--- a/lua/wikis/commons/PortalStatistics.lua
+++ b/lua/wikis/commons/PortalStatistics.lua
@@ -28,6 +28,11 @@ local Tier = Lua.import('Module:Tier/Custom')
local Opponent = Lua.import('Module:Opponent/Custom')
local OpponentDisplay = Lua.import('Module:OpponentDisplay/Custom')
+local Box = Lua.import('Module:Widget/Basic/Box')
+local Html = Lua.import('Module:Widget/Html')
+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
local ConditionNode = Condition.Node
@@ -39,9 +44,9 @@ local ConditionUtil = Condition.Util
local Count = Lua.import('Module:Count')
local CURRENCY_FORMAT_OPTIONS = {dashIfZero = true, displayCurrencyCode = false, formatValue = true}
-local CURRENT_YEAR = tonumber(os.date('%Y')) --[[@as integer]]
-local DATE = os.date('%F') --[[@as string]]
-local TIMESTAMP = DateExt.readTimestamp(DATE) --[[@as integer]]
+local TIMESTAMP = DateExt.getCurrentTimestamp()
+local CURRENT_YEAR = DateExt.getYearOf()
+local DATE = DateExt.toYmdInUtc(TIMESTAMP)
local DEFAULT_ALLOWED_PLACES = {'1', '2', '3', '1-2', '1-3', '2-3', '2-4', '3-4'}
local DEFAULT_ROUND_PRECISION = Info.defaultRoundPrecision or 2
local LANG = mw.getContentLanguage()
@@ -68,7 +73,7 @@ Section: Chart Entry Functions
---@param args table?
----@return Html
+---@return Renderable
function StatisticsPortal.gameEarningsChart(args)
args = args or {}
@@ -91,7 +96,7 @@ end
---@param args table?
----@return Html
+---@return Renderable
function StatisticsPortal.modeEarningsChart(args)
args = args or {}
@@ -110,7 +115,7 @@ end
---@param args table?
----@return Html
+---@return Renderable
function StatisticsPortal.topEarningsChart(args)
args = args or {}
args.limit = tonumber(args.limit) or 10
@@ -170,113 +175,93 @@ Section: Coverage Breakdown
---@param args table?
----@return Html
+---@return VNode
function StatisticsPortal.coverageStatistics(args)
args = args or {}
args.alignSide = Logic.readBool(args.alignSide)
- local wrapper = mw.html.create('div')
- local tournamentTable = wrapper:tag('div')
- local matchTable = wrapper:tag('div')
+ local statsChildren = {
+ StatisticsPortal.coverageTournamentTable(args),
+ StatisticsPortal.coverageMatchTable(args)
+ }
if args.alignSide then
- tournamentTable
- :addClass('template-box')
- :css('padding-right', '2em')
- matchTable
- :addClass('template-box')
- :css('padding-right', '2em')
+ return Box{
+ paddingRight = '2em',
+ children = statsChildren,
+ }
+ else
+ return Html.Div{
+ children = statsChildren,
+ }
end
-
- tournamentTable:node(StatisticsPortal.coverageTournamentTable(args))
- matchTable:node(StatisticsPortal.coverageMatchTable(args))
-
- return wrapper
end
---@param args table?
----@return Html
+---@return Renderable
function StatisticsPortal.coverageMatchTable(args)
args = args or {}
args.multiGame = Logic.readBool(args.multiGame)
args.customGames = StatisticsPortal._isTableOrSplitOrDefault(args.customGames, GAMES)
- local matchTable = mw.html.create('table')
- :addClass('wikitable wikitable-striped')
-
- matchTable:tag('caption')
- :wikitext(args.matchTableTitle or (Logic.readBool(args.alignSide) and '
' or ''))
- :css('text-align', 'center')
-
- local matchHeader = matchTable:tag('tr')
-
- if Logic.readBool(args.multiGame) then
- matchHeader:tag('th')
- :wikitext('Game')
- end
-
- matchHeader
- :tag('th'):wikitext(args.matchesTitle or 'Matches'):done()
- :tag('th'):wikitext(args.gamesTitle or 'Games')
-
- if Logic.readBool(args.multiGame) then
- for _, game in Table.iter.spairs(args.customGames) do
- matchTable:node(StatisticsPortal._coverageMatchTableRow(args, {
- game = game,
- year = args.year
- }
- )
- )
- end
- end
-
- matchTable:node(StatisticsPortal._coverageMatchTableRow(args, {
- year = args.year
- }
+ local tableHeader = TableWidgets.Row{
+ children = WidgetUtil.collect(
+ args.multiGame and TableWidgets.CellHeader{children = 'Game'} or nil,
+ TableWidgets.CellHeader{children = args.matchesTitle or 'Matches'},
+ TableWidgets.CellHeader{children = args.gamesTitle or 'Games'}
)
+ }
+
+ local tableRow = WidgetUtil.collect(
+ args.multiGame and Array.map(args.customGames, function(game)
+ return StatisticsPortal._coverageMatchTableRow(args, {game = game, year = args.year})
+ end) or nil,
+ StatisticsPortal._coverageMatchTableRow(args, {year = args.year})
)
- return matchTable
+ return TableWidgets.Table{
+ caption = args.matchTableTitle or (args.alignSide and Html.Br{} or ''),
+ children = {
+ TableWidgets.TableHeader{children = tableHeader},
+ TableWidgets.TableBody{children = tableRow}
+ }
+ }
end
---@param args table
---@param parameters table
----@return Html
+---@return Renderable
function StatisticsPortal._coverageMatchTableRow(args, parameters)
- local resultsRow = mw.html.create('tr')
- local tagType = (Logic.readBool(args.multiGame) and not parameters.game) and 'th' or 'td'
-
- if Logic.readBool(args.multiGame) then
- resultsRow:node(StatisticsPortal._returnGameCell(args, parameters, tagType))
- end
+ local isHeaderRow = Logic.readBool(args.multiGame) and not parameters.game
+ local CellComponent = isHeaderRow and TableWidgets.CellHeader or TableWidgets.Cell
local matchCountValue
local gameCountValue
- if Info.config.match2.status == 2 then
- matchCountValue = Count.match2game(parameters)
- gameCountValue = Count.match2(parameters)
- else
+ if Info.config.match2.status == 0 then
+ ---@diagnostic disable-next-line: deprecated
matchCountValue = Count.matches(parameters)
+ ---@diagnostic disable-next-line: deprecated
gameCountValue = Count.games(parameters)
+ else
+ matchCountValue = Count.match2game(parameters)
+ gameCountValue = Count.match2(parameters)
end
- resultsRow:tag(tagType)
- :wikitext(LANG:formatNum(matchCountValue))
- :css('text-align', 'right')
-
- resultsRow:tag(tagType)
- :wikitext(LANG:formatNum(gameCountValue))
- :css('text-align', 'right')
-
- return resultsRow
+ return TableWidgets.Row{
+ children = WidgetUtil.collect(
+ Logic.readBool(args.multiGame) and StatisticsPortal._returnGameCell(args, parameters, isHeaderRow) or nil,
+ CellComponent{align = 'right', children = LANG:formatNum(matchCountValue)},
+ CellComponent{align = 'right', children = LANG:formatNum(gameCountValue)}
+ )
+ }
end
---@param args table?
----@return Html
+---@return Renderable
function StatisticsPortal.coverageTournamentTable(args)
args = args or {}
args.multiGame = Logic.readBool(args.multiGame)
@@ -287,51 +272,45 @@ function StatisticsPortal.coverageTournamentTable(args)
args.showTierTypes = StatisticsPortal._isTableOrSplitOrDefault(args.showTierTypes, {})
args.filterByStatus = Logic.readBool(args.filterByStatus) or false
- local tournamentTable = mw.html.create('table')
- :addClass('wikitable wikitable-striped')
-
- tournamentTable:tag('caption')
- :wikitext(args.tournamentTableTitle or 'Tournaments Covered')
- :css('text-align', 'center')
-
- tournamentTable:node(StatisticsPortal._coverageTournamentTableHeader(args))
-
- if Logic.readBool(args.multiGame) then
- for _, game in Table.iter.spairs(args.customGames) do
- tournamentTable:node(StatisticsPortal._coverageTournamentTableRow(args, {
- game = game,
- year = args.year,
- filterByStatus = args.filterByStatus
- }
- )
- )
- end
- end
-
- tournamentTable:node(StatisticsPortal._coverageTournamentTableRow(args, {
+ local tableRow = WidgetUtil.collect(
+ args.multiGame and Array.map(args.customGames, function(game)
+ return StatisticsPortal._coverageTournamentTableRow(args, {
+ game = game,
year = args.year,
filterByStatus = args.filterByStatus
- }
- )
+ })
+ end) or nil,
+ StatisticsPortal._coverageTournamentTableRow(args, {
+ year = args.year,
+ filterByStatus = args.filterByStatus
+ })
)
- return tournamentTable
+ return TableWidgets.Table{
+ caption = args.tournamentTableTitle or 'Tournaments Covered',
+ children = {
+ TableWidgets.TableHeader{children = StatisticsPortal._coverageTournamentTableHeader(args)},
+ TableWidgets.TableBody{children = tableRow}
+ }
+ }
end
---@param args table
---@param parameters table
----@return Html
+---@return Renderable
function StatisticsPortal._coverageTournamentTableRow(args, parameters)
- local resultsRow = mw.html.create('tr')
- local tagType = (Logic.readBool(args.multiGame) and not parameters.game) and 'th' or 'td'
+ local isHeaderRow = Logic.readBool(args.multiGame) and not parameters.game
+ local CellComponent = isHeaderRow and TableWidgets.CellHeader or TableWidgets.Cell
local runningTally = 0
- if Logic.readBool(args.multiGame) then
- resultsRow:node(StatisticsPortal._returnGameCell(args, parameters, tagType))
- end
+ local gameCell = Logic.readBool(args.multiGame)
+ and StatisticsPortal._returnGameCell(args, parameters, isHeaderRow)
+ or nil
local countData = Count.tournamentsByTier(parameters)
+
+ local tierCells = {}
for rowIndex, rowValue in Tier.iterate('tiers') do
if String.isNotEmpty(rowValue.value) and tonumber(rowValue.value) > 0 then
if not args.customTiers or Array.any(Array.extractValues(args.customTiers), function(value)
@@ -346,95 +325,88 @@ function StatisticsPortal._coverageTournamentTableRow(args, parameters)
end
)
runningTally = runningTally + tournamentCount
- resultsRow:tag(tagType)
- :wikitext(LANG:formatNum(tournamentCount))
- :css('text-align', 'right')
+ table.insert(tierCells, CellComponent{align = 'right', children = LANG:formatNum(tournamentCount)})
end
end
end
- if #args.showTierTypes then
- for _, tierTypeValue in ipairs(args.showTierTypes) do
- local _, tierTypeData = Tier.raw(nil, tierTypeValue)
- if tierTypeData then
- local count = Array.reduce(
- Array.map(Array.extractValues(countData),
- function(typeCounts, index)
- return Table.extract(typeCounts, tierTypeValue) or 0
- end
- ),
- Operator.add, 0
- )
- runningTally = runningTally + count
- resultsRow:tag(tagType)
- :wikitext(LANG:formatNum(count))
- :css('text-align', 'right')
+ local tierTypeCells = Array.map(args.showTierTypes, function(tierTypeValue)
+ local _, tierTypeData = Tier.raw(nil, tierTypeValue)
+ if tierTypeData then
+ local count = Array.reduce(
+ Array.map(Array.extractValues(countData), function(typeCounts)
+ return Table.extract(typeCounts, tierTypeValue) or 0
+ end),
+ Operator.add, 0
+ )
+ runningTally = runningTally + count
+ return CellComponent{align = 'right', children = LANG:formatNum(count)}
end
- end
- end
+ end)
+ local otherCell
if String.isNotEmpty(args.showOther) then
local countOther = Array.reduce(
- Array.flatten(Array.map(Array.extractValues(countData),
- function(typeCounts, index)
- return Table.isNotEmpty(typeCounts) and Array.extractValues(typeCounts) or 0
- end
- )), Operator.add, 0) --[[@as number]]
+ Array.flatMap(Array.extractValues(countData), function(typeCounts)
+ return Table.isNotEmpty(typeCounts) and Array.extractValues(typeCounts) or 0
+ end
+ ), Operator.add, 0) --[[@as number]]
runningTally = runningTally + countOther
- resultsRow:tag(tagType)
- :wikitext(LANG:formatNum(countOther))
- :css('text-align', 'right')
+ otherCell = CellComponent{align = 'right', children = LANG:formatNum(countOther)}
end
- resultsRow:tag(tagType)
- :wikitext(LANG:formatNum(runningTally))
- :css('text-align', 'right')
-
- return resultsRow:allDone()
+ return TableWidgets.Row{
+ children = WidgetUtil.collect(
+ gameCell,
+ tierCells,
+ tierTypeCells,
+ otherCell,
+ CellComponent{align = 'right', children = LANG:formatNum(runningTally)}
+ )
+ }
end
---@param args table
----@return Html
+---@return Renderable
function StatisticsPortal._coverageTournamentTableHeader(args)
- local headerRow = mw.html.create('tr')
-
- if Logic.readBool(args.multiGame) then
- headerRow:tag('th')
- :wikitext('Game')
- end
-
+ local tierHeaderCells = {}
for headerIndex, headerValue in Tier.iterate('tiers') do
if String.isNotEmpty(headerValue.value) and tonumber(headerValue.value) > 0 then
if not args.customTiers or Array.any(Array.extractValues(args.customTiers), function(value)
return value == headerIndex
end) then
- headerRow:tag('th')
- :wikitext(Tier.displaySingle(headerValue, {link = true}))
+ table.insert(tierHeaderCells, TableWidgets.CellHeader{
+ children = Tier.displaySingle(headerValue, {link = true})
+ })
end
end
end
+ local tierTypeHeaderCells = {}
if #args.showTierTypes then
for _, tierTypeValue in ipairs(args.showTierTypes) do
local _, tierTypeData = Tier.raw(nil, tierTypeValue)
if tierTypeData then
- headerRow:tag('th')
- :wikitext(Tier.displaySingle(tierTypeData, {link = true, short = true}))
+ table.insert(tierTypeHeaderCells, TableWidgets.CellHeader{
+ children = Tier.displaySingle(tierTypeData, {link = true, short = true})
+ })
end
end
end
- if String.isNotEmpty(args.showOther) then
- headerRow:tag('th')
- :wikitext(Abbreviation.make{text = 'Other',
- title = 'Includes otherwise unlisted tournaments (e.g. with tiertypes, misc.)'})
- end
-
- headerRow:tag('th')
- :wikitext('Total')
-
- return headerRow
+ return TableWidgets.Row{
+ children = WidgetUtil.collect(
+ Logic.readBool(args.multiGame) and TableWidgets.CellHeader{children = 'Game'} or nil,
+ tierHeaderCells,
+ tierTypeHeaderCells,
+ String.isNotEmpty(args.showOther) and TableWidgets.CellHeader{
+ children = Abbreviation.make{text = 'Other',
+ title = 'Includes otherwise unlisted tournaments (e.g. with tiertypes, misc.)'}
+ } or nil,
+ TableWidgets.CellHeader{children = 'Total'}
+ )
+ }
end
--[[
@@ -443,7 +415,7 @@ Section: Prizepool Breakdown
---@param args table?
----@return Html
+---@return Renderable
function StatisticsPortal.prizepoolBreakdown(args)
args = args or {}
args.showAverage = Logic.readBool(args.showAverage)
@@ -452,21 +424,21 @@ function StatisticsPortal.prizepoolBreakdown(args)
local yearTable, defaultYearTable = StatisticsPortal._returnCustomYears(args)
local rowLimit = Math.round(((Logic.readBool(args.showAverage) and 1 or 0) + 1 + Table.size(yearTable)) / 2)
- local wrapper = mw.html.create('div')
-
- local prizepoolTable = wrapper:tag('div')
- :addClass('table-responsive')
- :tag('table')
- :addClass('wikitable wikitable-striped')
- :css('width', '100%')
- :css('text-align', 'center')
-
- prizepoolTable:tag('caption')
- :wikitext('Prize Money Awarded')
- :css('text-align', 'center')
+ local tables = {}
+ local headerCells = {}
+ local resultCells = {}
- local headerRow = prizepoolTable:tag('tr')
- local resultsRow = prizepoolTable:tag('tr')
+ local function finalizeTable()
+ table.insert(tables, TableWidgets.Table{
+ caption = 'Prize Money Awarded',
+ children = {
+ TableWidgets.TableHeader{children = TableWidgets.Row{children = headerCells}},
+ TableWidgets.TableBody{children = TableWidgets.Row{children = resultCells}}
+ }
+ })
+ headerCells = {}
+ resultCells = {}
+ end
local prizepoolSum = 0
local prevYear = args.startYear
@@ -496,10 +468,12 @@ function StatisticsPortal.prizepoolBreakdown(args)
prizepoolSum = prizepoolSum + (tonumber(data[1].sum_prizepool) or 0)
if Array.any(Array.extractValues(yearTable), function(value) return value == yearValue end) then
- headerRow:tag('th')
- :wikitext(StatisticsPortal._returnCustomYearText(prevYear, yearValue))
- resultsRow:tag('td')
- :wikitext(Currency.display(US_DOLLAR, prizepoolSum or 0, CURRENCY_FORMAT_OPTIONS))
+ table.insert(headerCells, TableWidgets.CellHeader{
+ children = StatisticsPortal._returnCustomYearText(prevYear, yearValue)
+ })
+ table.insert(resultCells, TableWidgets.Cell{
+ children = Currency.display(US_DOLLAR, prizepoolSum or 0, CURRENCY_FORMAT_OPTIONS)
+ })
prizepoolSum = 0
prevYear = yearValue + 1
colIndex = colIndex + 1
@@ -507,17 +481,7 @@ function StatisticsPortal.prizepoolBreakdown(args)
if colIndex > rowLimit and rowLimit > 8 then
colIndex = 1
- wrapper:tag('span'):wikitext('
')
-
- prizepoolTable = wrapper:tag('div')
- :addClass('table-responsive')
- :tag('table')
- :addClass('wikitable wikitable-striped')
- :css('width', '100%')
- :css('text-align', 'center')
-
- headerRow = prizepoolTable:tag('tr')
- resultsRow = prizepoolTable:tag('tr')
+ finalizeTable()
end
end
@@ -541,28 +505,39 @@ function StatisticsPortal.prizepoolBreakdown(args)
}
)
local totalPrizePool = tonumber(totalData[1].sum_prizepool) or 0
- headerRow:tag('th')
- :wikitext('Total')
- resultsRow:tag('td')
- :wikitext(Currency.display(US_DOLLAR, totalPrizePool, CURRENCY_FORMAT_OPTIONS))
- :css('font-weight', 'bold')
+
+ table.insert(headerCells, TableWidgets.CellHeader{children = 'Total'})
+ table.insert(resultCells, TableWidgets.Cell{
+ children = Html.B{children = Currency.display(US_DOLLAR, totalPrizePool, CURRENCY_FORMAT_OPTIONS)}
+ })
if Logic.readBool(args.showAverage) then
- headerRow:tag('th')
- :tag('abbr')
- :attr('title', 'Average Prizepool per Tournament')
- :wikitext('AVG PPT')
- resultsRow:tag('td')
- :wikitext(Currency.display(US_DOLLAR, totalPrizePool / (Count.tournaments() or 1), CURRENCY_FORMAT_OPTIONS))
- :css('font-weight', 'bold')
+ table.insert(headerCells, TableWidgets.CellHeader{
+ children = Html.Abbr{title = 'Average Prizepool per Tournament', children = 'AVG PPT'}
+ })
+ table.insert(resultCells, TableWidgets.Cell{
+ children = Html.B{children = Currency.display(
+ US_DOLLAR, totalPrizePool / (Count.tournaments() or 1), CURRENCY_FORMAT_OPTIONS
+ )}
+ })
end
- return wrapper
+ finalizeTable()
+
+ local wrapperChildren = {}
+ for index, tableWidget in ipairs(tables) do
+ if index > 1 then
+ table.insert(wrapperChildren, Html.Br{})
+ end
+ table.insert(wrapperChildren, tableWidget)
+ end
+
+ return Html.Div{children = wrapperChildren}
end
---@param args table?
----@return Html
+---@return VNode
function StatisticsPortal.pieChartBreakdown(args)
args = args or {}
args.height = args.height or 300
@@ -572,58 +547,62 @@ function StatisticsPortal.pieChartBreakdown(args)
args.multiGame = Logic.readBool(args.multiGame)
args.multiMode = Logic.readBool(args.multiMode)
- local wrapper = mw.html.create('div')
-
- wrapper:node(mw.html.create('div')
- :addClass('template-box')
- :css('padding-right', '5em')
- :css('font-size', '85%')
- :css('text-align', 'center')
- :wikitext('Tournament Type')
- :node(StatisticsPortal._getPieChartData(
- args, 'type', 'Mixed', TYPES
- ))
- )
+ local wrapperChildren = {
+ Html.Div{
+ classes = {'template-box'},
+ css = {
+ ['padding-right'] = '5em',
+ ['font-size'] = '85%',
+ ['text-align'] = 'center',
+ },
+ children = {
+ 'Tournament Type',
+ StatisticsPortal._getPieChartData(
+ args, 'type', 'Mixed', TYPES
+ ),
+ },
+ },
+ }
if args.multiGame then
local games = Array.map(StatisticsPortal._isTableOrSplitOrDefault(args.customGames, GAMES), function(game)
return Game.toIdentifier{game = game, useDefault = false} or game
end)
- wrapper:node(mw.html.create('div')
- :addClass('template-box')
- :css('padding-right', '5em')
- :css('font-size', '85%')
- :css('text-align', 'center')
- :wikitext('Game Breakdown')
- :node(StatisticsPortal._getPieChartData(
- args, 'game', 'Other', games
- ))
- )
+ table.insert(wrapperChildren, Html.Div{
+ classes = {'template-box'},
+ css = {
+ ['padding-right'] = '5em',
+ ['font-size'] = '85%',
+ ['text-align'] = 'center',
+ },
+ children = {
+ 'Game Breakdown',
+ StatisticsPortal._getPieChartData(args, 'game', 'Other', games),
+ },
+ })
end
if args.multiMode then
- wrapper:node(mw.html.create('div')
- :addClass('template-box')
- :css('padding-right', '5em')
- :css('font-size', '85%')
- :css('text-align', 'center')
- :wikitext('Mode Breakdown')
- :node(StatisticsPortal._getPieChartData(
- args, 'mode', 'Other', StatisticsPortal._isTableOrSplitOrDefault(args.customModes, {'Team'})
- ))
- )
+ table.insert(wrapperChildren, Box{
+ paddingRight = '5em',
+ children = {
+ 'Mode Breakdown',
+ StatisticsPortal._getPieChartData(
+ args, 'mode', 'Other', StatisticsPortal._isTableOrSplitOrDefault(args.customModes, {'Team'})
+ ),
+ },
+ })
end
- if Logic.readBool(args.hideKey) then
- return wrapper
+ if args.hideKey then
+ return Html.Div{children = wrapperChildren}
end
- if Logic.readBool(args.detailedKey) then
- wrapper:node(mw.html.create('div')
- :addClass('template-box')
- :node(StatisticsPortal.prizepoolBreakdown(args))
- )
- return wrapper
+ if args.detailedKey then
+ table.insert(wrapperChildren, Box{
+ children = StatisticsPortal.prizepoolBreakdown(args),
+ })
+ return Html.Div{children = wrapperChildren}
end
local conditions = StatisticsPortal._returnBaseConditions()
@@ -652,32 +631,32 @@ function StatisticsPortal.pieChartBreakdown(args)
order = 'sortdate desc',
})
- local summaryTable = mw.html.create('table')
- :addClass('wikitable')
- :css('text-align', 'center')
- :css('font-weight', 'bold')
-
- summaryTable:tag('tr')
- :tag('th'):wikitext('Total prize money awarded')
-
- summaryTable:tag('tr')
- :tag('td')
- :wikitext(Currency.display(US_DOLLAR, data[1].sum_prizepool or 0, CURRENCY_FORMAT_OPTIONS))
- :attr('data-sort-type', 'currency')
- :css('font-weight', 'bold')
+ local summaryTable = TableWidgets.Table{
+ children = {
+ TableWidgets.TableHeader{children = TableWidgets.Row{
+ children = TableWidgets.CellHeader{children = 'Total prize money awarded'}
+ }},
+ TableWidgets.TableBody{children = TableWidgets.Row{
+ children = TableWidgets.Cell{
+ attributes = {['data-sort-type'] = 'currency'},
+ children = Html.B{children = Currency.display(
+ US_DOLLAR, data[1].sum_prizepool or 0, CURRENCY_FORMAT_OPTIONS
+ )}
+ }
+ }}
+ }
+ }
- wrapper:node(mw.html.create('div')
- :addClass('template-box')
- :css('padding-right', '1em')
- :node(summaryTable)
- )
+ table.insert(wrapperChildren, Box{
+ paddingRight = '1em',
+ children = summaryTable,
+ })
- return wrapper
+ return Html.Div{children = wrapperChildren}
end
-
---@param args table?
----@return Html
+---@return Renderable
function StatisticsPortal.earningsTable(args)
args = args or {}
args.limit = tonumber(args.limit) or 20
@@ -717,20 +696,13 @@ function StatisticsPortal.earningsTable(args)
local opponentPlacements = StatisticsPortal._cacheOpponentPlacementData(args)
- local tbl = mw.html.create('table')
- :addClass('wikitable wikitable-striped wikitable-bordered sortable')
- :css('margin-left', '0px')
- :css('margin-right', 'auto')
- :css('width', '100%')
-
- tbl:node(StatisticsPortal._earningsTableHeader(args))
-
+ local tableRow = {}
for opponentIndex, opponent in ipairs(opponentData) do
- local opponentDisplay
local earnings = earningsFunction(opponent)
if opponentIndex > args.limit or earnings < args.minimumEarnings then break end
+ local opponentDisplay
if args.opponentType == Opponent.team then
opponentDisplay = OpponentDisplay.BlockOpponent{
opponent = Opponent.readOpponentArgs{template = opponent.template, type = Opponent.team},
@@ -742,10 +714,18 @@ function StatisticsPortal.earningsTable(args)
}
end
local placements = opponentPlacements[opponent.pagename] or {}
- tbl:node(StatisticsPortal._earningsTableRow(args, placements, earnings, opponentIndex, opponentDisplay))
+ table.insert(tableRow,
+ StatisticsPortal._earningsTableRow(args, placements, earnings, opponentIndex, opponentDisplay))
end
- return mw.html.create('div'):addClass('table-responsive'):node(tbl)
+ return TableWidgets.Table{
+ sortable = true,
+ css = {['margin-left'] = '0px', ['margin-right'] = 'auto', width = '100%'},
+ children = {
+ TableWidgets.TableHeader{children = StatisticsPortal._earningsTableHeader(args)},
+ TableWidgets.TableBody{children = tableRow}
+ }
+ }
end
@@ -755,7 +735,7 @@ Section: Player Age Table Breakdown
---@param args table?
----@return Html
+---@return Renderable
function StatisticsPortal.playerAgeTable(args)
args = args or {}
args.earnings = tonumber(args.earnings) or 500
@@ -790,32 +770,38 @@ function StatisticsPortal.playerAgeTable(args)
local playerData = StatisticsPortal._getPlayers(args.limit, conditions:toString(), args.order)
- local tbl = mw.html.create('table')
- :addClass('wikitable wikitable-striped sortable')
- :css('margin-left', '0px')
- :css('margin-right', 'auto')
-
- tbl:tag('tr')
- :tag('th'):wikitext('ID'):addClass('unsortable'):done()
- :tag('th'):wikitext('Age')
+ local tableHeader = TableWidgets.Row{
+ children = {
+ TableWidgets.CellHeader{unsortable = true, children = 'ID'},
+ TableWidgets.CellHeader{children = 'Age'}
+ }
+ }
- for _, player in ipairs(playerData) do
+ local tableRow = Array.map(playerData, function(player)
local birthdate = DateExt.readTimestamp(player.birthdate) --[[@as integer]]
local age = os.date('*t', os.difftime(TIMESTAMP, birthdate))
local yearAge = age.year - 1970
local dayAge = age.yday - 1
- tbl:tag('tr')
- :tag('td')
- :node(OpponentDisplay.BlockOpponent{
+ return TableWidgets.Row{
+ children = {
+ TableWidgets.Cell{children = OpponentDisplay.BlockOpponent{
opponent = StatisticsPortal._toOpponent(player),
showPlayerTeam = true,
- }):done()
- :tag('td')
- :wikitext(yearAge .. ' years, ' .. dayAge .. ' days')
- end
+ }},
+ TableWidgets.Cell{children = yearAge .. ' years, ' .. dayAge .. ' days'}
+ }
+ }
+ end)
- return mw.html.create('div'):addClass('table-responsive'):node(tbl)
+ return TableWidgets.Table{
+ sortable = true,
+ css = {['margin-left'] = '0px', ['margin-right'] = 'auto'},
+ children = {
+ TableWidgets.TableHeader{children = tableHeader},
+ TableWidgets.TableBody{children = tableRow}
+ }
+ }
end
@@ -912,7 +898,7 @@ end
---@param groupBy string
---@param defaultValue string
---@param groupValues table
----@return table
+---@return Renderable
function StatisticsPortal._getPieChartData(args, groupBy, defaultValue, groupValues)
table.insert(groupValues, defaultValue)
defaultValue = string.lower(defaultValue or '')
@@ -1006,13 +992,13 @@ function StatisticsPortal._cacheModeEarningsData(config)
end
local earningsData = Table.map(Array.range(config.startYear, CURRENT_YEAR), function(_, year)
- return year, Table.map(config.customInputs, function(_, mode)
- return mode, 0
- end)
+ return year, Table.map(config.customInputs, function(_, mode)
+ return mode, 0
end)
+ end)
local processData = function(item)
- local year = tonumber(item.date:sub(1, 4))
+ local year = DateExt.getYearOf(item.date)
if String.isNotEmpty(item[config.variable]) then
local arg = item[config.variable]
if earningsData[year][arg] then
@@ -1030,10 +1016,10 @@ function StatisticsPortal._cacheModeEarningsData(config)
Lpdb.executeMassQuery('placement', queryParameters, processData)
return Array.map(Array.extractValues(earningsData, Table.iter.spairs), function(value)
- return Array.map(config.customInputs, function(key)
- return value[key]
- end)
- end)
+ return Array.map(config.customInputs, function(key)
+ return value[key]
+ end)
+ end)
end
@@ -1117,42 +1103,34 @@ Section: Display Functions
---@param args table
---@param parameters table
----@param tagType string
----@return Html
-function StatisticsPortal._returnGameCell(args, parameters, tagType)
- local gameCell = mw.html.create(tagType)
- if Logic.readBool(args.multiGame) and not parameters.game then
- gameCell:wikitext('Total')
- elseif Logic.readBool(args.multiGame) then
- gameCell:wikitext(parameters.game)
- end
- return gameCell
+---@param isHeaderRow boolean
+---@return Renderable
+function StatisticsPortal._returnGameCell(args, parameters, isHeaderRow)
+ local CellComponent = isHeaderRow and TableWidgets.CellHeader or TableWidgets.Cell
+ local text = (Logic.readBool(args.multiGame) and not parameters.game) and 'Total' or parameters.game
+ return CellComponent{children = text}
end
---@param args table
----@return Html
+---@return Renderable
function StatisticsPortal._earningsTableHeader(args)
local columnText = args.opponentType == Opponent.team and 'Organization' or 'Player'
- local row = mw.html.create('tr')
- :tag('th'):wikitext('#'):addClass('unsortable'):done()
- :tag('th'):wikitext(columnText):addClass('unsortable'):done()
- :tag('th'):wikitext('Achievements'):css('width', '200px'):addClass('unsortable'):done()
- :tag('th'):node(Medals.display{medal = 1}):done()
- :tag('th'):node(Medals.display{medal = 2}):done()
- :tag('th'):node(Medals.display{medal = 3}):done()
-
- if Logic.readBool(args.displayShowMatches) then
- row:tag('th'):wikitext('Show
Match')
- end
-
- row:tag('th')
- :tag('abbr')
- :attr('title', 'Total earnings across all games')
- :wikitext('Earnings')
-
- return row
+ return TableWidgets.Row{
+ children = WidgetUtil.collect(
+ TableWidgets.CellHeader{unsortable = true, children = '#'},
+ TableWidgets.CellHeader{unsortable = true, children = columnText},
+ TableWidgets.CellHeader{unsortable = true, width = '200px', children = 'Achievements'},
+ TableWidgets.CellHeader{children = Medals.display{medal = 1}},
+ TableWidgets.CellHeader{children = Medals.display{medal = 2}},
+ TableWidgets.CellHeader{children = Medals.display{medal = 3}},
+ Logic.readBool(args.displayShowMatches) and TableWidgets.CellHeader{children = 'Show
Match'} or nil,
+ TableWidgets.CellHeader{
+ children = Html.Abbr{title = 'Total earnings across all games', children = 'Earnings'}
+ }
+ )
+ }
end
@@ -1160,28 +1138,22 @@ end
---@param placements table
---@param earnings number
---@param opponentIndex number
----@param opponentDisplay Widget|Html
----@return Html
+---@param opponentDisplay Renderable
+---@return Renderable
function StatisticsPortal._earningsTableRow(args, placements, earnings, opponentIndex, opponentDisplay)
- local row = mw.html.create('tr')
- :css('line-height', '25px')
- :css('text-align', 'center')
- :tag('td'):wikitext(opponentIndex):done()
- :tag('td'):css('text-align', 'left'):node(opponentDisplay):done()
- :tag('td'):wikitext(StatisticsPortal._achievementsDisplay(placements.sWinData or {})):done()
- :tag('td'):wikitext(placements['1'] or '0'):done()
- :tag('td'):wikitext(placements['2'] or '0'):done()
- :tag('td'):wikitext(placements['3'] or '0'):done()
-
- if Logic.readBool(args.displayShowMatches) then
- row:tag('td'):wikitext(placements.showWins or 0)
- end
-
- row:tag('td')
- :css('text-align', 'right')
- :wikitext(Currency.display(US_DOLLAR, earnings, CURRENCY_FORMAT_OPTIONS))
-
- return row
+ return TableWidgets.Row{
+ css = {['line-height'] = '25px', ['text-align'] = 'center'},
+ children = WidgetUtil.collect(
+ TableWidgets.Cell{children = opponentIndex},
+ TableWidgets.Cell{align = 'left', children = opponentDisplay},
+ TableWidgets.Cell{children = StatisticsPortal._achievementsDisplay(placements.sWinData or {})},
+ TableWidgets.Cell{children = placements['1'] or '0'},
+ TableWidgets.Cell{children = placements['2'] or '0'},
+ TableWidgets.Cell{children = placements['3'] or '0'},
+ Logic.readBool(args.displayShowMatches) and TableWidgets.Cell{children = placements.showWins or 0} or nil,
+ TableWidgets.Cell{align = 'right', children = Currency.display(US_DOLLAR, earnings, CURRENCY_FORMAT_OPTIONS)}
+ )
+ }
end
@@ -1210,11 +1182,11 @@ end
---@param config table
---@param chartData table
----@return Html
+---@return Renderable
function StatisticsPortal._drawChart(config, chartData)
- return mw.html.create('div')
- :addClass('table-responsive')
- :node(mw.ext.Charts.chart({
+ return Html.Div{
+ class = 'table-responsive',
+ children = mw.ext.Charts.chart({
grid = {
left = '15%',
right = '12%',
@@ -1234,24 +1206,24 @@ function StatisticsPortal._drawChart(config, chartData)
series = chartData,
labels = config.labels,
})
- )
+ }
end
---@param args table
---@param chartData table
----@return Html
+---@return Renderable
function StatisticsPortal._drawPieChart(args, chartData)
- return mw.html.create('div')
- :addClass('table-responsive')
- :node(mw.ext.Charts.piechart{
+ return Html.Div{
+ class = 'table-responsive',
+ children = mw.ext.Charts.piechart{
size = {
height = args.height,
width = args.width
},
data = chartData
}
- )
+ }
end
@@ -1275,7 +1247,7 @@ end
---@param yearSeriesData table
---@param nonYearCategories table
---@param transpose boolean?
----@return Html
+---@return Renderable
function StatisticsPortal._buildChartData(config, yearSeriesData, nonYearCategories, transpose)
local yearTable, defaultYearTable = StatisticsPortal._returnCustomYears(config)
local prevYear = config.startYear
@@ -1360,10 +1332,10 @@ function StatisticsPortal._removeCategories(categoryNames, seriesData)
local lastNotEmpty = 1
local isEmptyCategory = Array.map(Array.map(categoryNames, function(_, catIndex)
- local truthValue = Array.all(Array.map(seriesData, function(_, index)
- return seriesData[index][catIndex] end), function(value)
- return value == 0
- end)
+ local truthValue = Array.all(Array.map(seriesData, function(_, index)
+ return seriesData[index][catIndex] end), function(value)
+ return value == 0
+ end)
if not truthValue then
lastNotEmpty = catIndex
end
@@ -1381,12 +1353,13 @@ function StatisticsPortal._removeCategories(categoryNames, seriesData)
end)
categoryNames = Array.filter(categoryNames, function(_, catIndex)
- return Logic.readBool(isEmptyCategory[catIndex]) end)
+ return Logic.readBool(isEmptyCategory[catIndex]) end)
seriesData = Array.map(seriesData, function(_, index)
- return Array.filter(seriesData[index], function(_, catIndex)
- return Logic.readBool(isEmptyCategory[catIndex]) end)
+ return Array.filter(seriesData[index], function(_, catIndex)
+ return Logic.readBool(isEmptyCategory[catIndex])
end)
+ end)
return categoryNames, seriesData
end
@@ -1469,8 +1442,7 @@ function StatisticsPortal._isTableOrSplitOrDefault(input, default)
elseif String.isEmpty(input) then
return default or {}
end
- ---@cast input -nil
- return Array.map(mw.text.split(input, ',', true), String.trim)
+ return Array.parseCommaSeparatedString(input)
end