Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 15 additions & 2 deletions components/match_ticker/commons/match_ticker.lua
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@ local DEFAULT_RECENT_ORDER = 'date desc, liquipediatier asc, tournament asc'
local DEFAULT_LIVE_HOURS = 8
local NOW = os.date('%Y-%m-%d %H:%M', os.time(os.date('!*t') --[[@as osdateparam]]))

--- Extract externally if it grows
---@param matchTickerConfig MatchTickerConfig
---@return unknown # Todo: Add interface for MatchTickerDisplay
local MatchTickerDisplayFactory = function (matchTickerConfig)
if matchTickerConfig.newStyle then
return Lua.import('Module:MatchTicker/DisplayComponents/New')
else
return Lua.import('Module:MatchTicker/DisplayComponents')
end
end

---@class MatchTickerConfig
---@field tournaments string[]
---@field limit integer
Expand All @@ -80,6 +91,7 @@ local NOW = os.date('%Y-%m-%d %H:%M', os.time(os.date('!*t') --[[@as osdateparam
---@field onlyHighlightOnValue string?
---@field tiers string[]?
---@field tierTypes string[]?
---@field newStyle boolean?

---@class MatchTicker
---@operator call(table): MatchTicker
Expand All @@ -88,8 +100,6 @@ local NOW = os.date('%Y-%m-%d %H:%M', os.time(os.date('!*t') --[[@as osdateparam
---@field matches table[]?
local MatchTicker = Class.new(function(self, args) self:init(args) end)

MatchTicker.DisplayComponents = Lua.import('Module:MatchTicker/DisplayComponents')

---@param args table?
---@return table
function MatchTicker:init(args)
Expand Down Expand Up @@ -124,6 +134,7 @@ function MatchTicker:init(args)
tierTypes = args.tiertypes and Array.filter(
Array.parseCommaSeparatedString(args.tiertypes), FnUtil.curry(Tier.isValid, 1)
) or nil,
newStyle = Logic.readBool(args.newStyle),
}

--min 1 of them has to be set; recent can not be set while any of the others is set
Expand Down Expand Up @@ -164,6 +175,8 @@ function MatchTicker:init(args)
end
config.wrapperClasses = wrapperClasses

MatchTicker.DisplayComponents = MatchTickerDisplayFactory(config)

self.config = config

return self
Expand Down
9 changes: 9 additions & 0 deletions components/match_ticker/commons/match_ticker_custom.lua
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ function CustomMatchTicker.mainPage(frame)
return MatchTicker(args):query():create()
end

---Entry point for display on the main page with the new style
---@param frame Frame?
---@return Html
function CustomMatchTicker.newMainPage(frame)
local args = Arguments.getArgs(frame)
args.newStyle = true
return MatchTicker(args):query():create():addClass('new-match-style')
end

---Entry point for display on player pages
---@param frame Frame?
---@return Html
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ function Versus:create()

return self.root
:node(mw.html.create('div')
:css('line-height', '1.1'):node(upperText or VS)
:addClass('versus-upper'):node(upperText or VS)
):node(mw.html.create('div')
:addClass('versus-lower'):wikitext('(' .. lowerText .. ')')
)
Expand All @@ -123,6 +123,7 @@ function Versus:scores()

local scores, scores2 = {}, {}
local hasSecondScore
local delimiter = '<span>:</span>'

local setWinner = function(score, opponentIndex)
if winner == opponentIndex then
Expand All @@ -135,20 +136,20 @@ function Versus:scores()
local score = Logic.isNotEmpty(opponent.status) and opponent.status ~= SCORE_STATUS and opponent.status
or tonumber(opponent.score) or -1

table.insert(scores, setWinner(score ~= -1 and score or 0, opponentIndex))
table.insert(scores, '<span>' .. setWinner(score ~= -1 and score or 0, opponentIndex) .. '</span>' )

local score2 = tonumber((opponent.extradata or {}).score2) or 0
table.insert(scores2, setWinner(score2, opponentIndex))
table.insert(scores2, '<span>' .. setWinner(score2, opponentIndex) .. '</span>' )
if score2 > 0 then
hasSecondScore = true
end
end)

if hasSecondScore then
return table.concat(scores, ':'), table.concat(scores2, ':')
return table.concat(scores, delimiter), table.concat(scores2, delimiter)
end

return table.concat(scores, ':')
return table.concat(scores, delimiter)
end

---Display class for matches shown within a match ticker
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
---
-- @Liquipedia
-- wiki=commons
-- page=Module:MatchTicker/DisplayComponents/New
--
-- Please see https://github.com/Liquipedia/Lua-Modules to contribute
--

-- Holds DisplayComponents for the MatchTicker module
-- It contains the new html structure intented to be use for the new Dota2 Main Page (for now)
-- Will most likely be expanded to other games in the future and other pages

local Class = require('Module:Class')
local Countdown = require('Module:Countdown')
local DateExt = require('Module:Date/Ext')
local LeagueIcon = require('Module:LeagueIcon')
local Logic = require('Module:Logic')
local Lua = require('Module:Lua')
local Timezone = require('Module:Timezone')
local StreamLinks = require('Module:Links/Stream')
local Page = require('Module:Page')
local DefaultMatchTickerDisplayComponents = require('Module:MatchTicker/DisplayComponents')

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

local OpponentLibraries = require('Module:OpponentLibraries')
local Opponent = OpponentLibraries.Opponent
local OpponentDisplay = OpponentLibraries.OpponentDisplay

local CURRENT_PAGE = mw.title.getCurrentTitle().text
local HIGHLIGHT_CLASS = 'tournament-highlighted-bg'
local TOURNAMENT_DEFAULT_ICON = 'Generic_Tournament_icon.png'

---Display class for matches shown within a match ticker
---@class NewMatchTickerScoreBoard
---@operator call(table): NewMatchTickerScoreBoard
---@field root Html
---@field match table
local ScoreBoard = Class.new(
function(self, match)
self.root = mw.html.create('div'):addClass('match-scoreboard')
self.match = match
end
)

---@return Html
function ScoreBoard:create()
local match = self.match
local winner = tonumber(match.winner)

return self.root
:node(self:opponent(match.match2opponents[1], winner == 1, true):addClass('team-left'))
:node(self:versus())
:node(self:opponent(match.match2opponents[2], winner == 2):addClass('team-right'))
end

---@param opponentData table
---@param isWinner boolean
---@param flip boolean?
---@return Html
function ScoreBoard:opponent(opponentData, isWinner, flip)
local opponent = Opponent.fromMatch2Record(opponentData)
---@cast opponent -nil
if Opponent.isEmpty(opponent) or Opponent.isTbd(opponent) and opponent.type ~= Opponent.literal then
opponent = Opponent.tbd(Opponent.literal)
end

local opponentName = Opponent.toName(opponent)
if not opponentName then
mw.logObject(opponent, 'Invalid Opponent, Opponent.toName returns nil')
opponentName = ''
end

local opponentDisplay = mw.html.create('div')
:node(OpponentDisplay.InlineOpponent{
opponent = opponent,
teamStyle = 'short',
flip = flip,
showLink = opponentName:gsub('_', ' ') ~= CURRENT_PAGE
})

if isWinner then
opponentDisplay:addClass('match-winner')
end

return opponentDisplay
end

---@return Html
function ScoreBoard:versus()
return mw.html.create('div')
:addClass('versus')
:node(DefaultMatchTickerDisplayComponents.Versus(self.match):create())
end

---Display class for the details of a match displayed at the bottom of a match ticker
---@class NewMatchTickerDetails
---@operator call(table): NewMatchTickerMatch
---@field root Html
---@field hideTournament boolean
---@field onlyHighlightOnValue string?
---@field match table
local Details = Class.new(
function(self, args)
assert(args.match, 'No Match passed to MatchTickerDetails class')
self.root = mw.html.create('div'):addClass('match-details')
self.hideTournament = args.hideTournament
self.onlyHighlightOnValue = args.onlyHighlightOnValue
self.match = args.match
end
)

---@return Html
function Details:create()
local highlightCondition = HighlightConditions.match or HighlightConditions.tournament
if highlightCondition(self.match, {onlyHighlightOnValue = self.onlyHighlightOnValue}) then
self.root:addClass(HIGHLIGHT_CLASS)
end

return self.root
:node(self:streams())
:node(self:tournament())
:node(self:countdown())
end

---It will display both countdown and date of the match so the user can select which one to show
---@return Html
function Details:countdown()
local match = self.match

local dateString
if Logic.readBool(match.dateexact) then
local timestamp = DateExt.readTimestamp(match.date) + (Timezone.getOffset(match.extradata.timezoneid) or 0)
dateString = DateExt.formatTimestamp('F j, Y - H:i', timestamp) .. ' '
.. (Timezone.getTimezoneString(match.extradata.timezoneid) or (Timezone.getTimezoneString('UTC')))
else
dateString = mw.getContentLanguage():formatDate('F j, Y', match.date) .. (Timezone.getTimezoneString('UTC'))
end

local countdownArgs = {
date = dateString,
finished = match.finished
}

local countdownDisplay = mw.html.create('span')
:addClass('match-countdown')
:node(Countdown._create(countdownArgs))

return countdownDisplay
end

---@return Html?
function Details:streams()
local match = self.match
local links = mw.html.create('div')
:addClass('match-streams')

links:wikitext(table.concat(StreamLinks.buildDisplays(StreamLinks.filterStreams(match.stream)) or {}))

return links
end

---@return Html?
function Details:tournament()
if self.hideTournament then
return
end

local match = self.match

local icon = LeagueIcon.display{
icon = Logic.emptyOr(match.icon, TOURNAMENT_DEFAULT_ICON),
iconDark = match.icondark,
link = match.pagename,
name = match.tournament,
options = {noTemplate = true},
}

local displayName = Logic.emptyOr(
match.tickername,
match.tournament,
match.parent:gsub('_', ' ')
)

return mw.html.create('div')
:addClass('match-tournament')
:node(mw.html.create('div')
:addClass('tournament-icon')
:node(mw.html.create('div')
:wikitext(icon)
)
)
:node(mw.html.create('div')
:addClass('tournament-text')
:wikitext(Page.makeInternalLink({}, displayName, match.pagename))
)

end

---Display class for matches shown within a match ticker
---@class NewMatchTickerMatch
---@operator call({config: MatchTickerConfig, match: table}): NewMatchTickerMatch
---@field root Html
---@field config MatchTickerConfig
---@field match table
local Match = Class.new(
function(self, args)
self.root = mw.html.create('div'):addClass('match')
self.config = args.config
self.match = args.match
end
)

---@return Html
function Match:create()
self.root:node(self:standardMatchRow())
self.root:node(self:detailsRow())

return self.root
end

---@return Html
function Match:standardMatchRow()
return ScoreBoard(self.match):create()
end

---@return Html
function Match:detailsRow()
return Details{
match = self.match,
hideTournament = self.config.hideTournament,
onlyHighlightOnValue = self.config.onlyHighlightOnValue
}:create()
end

return {
Match = Match,
Details = Details,
ScoreBoard = ScoreBoard,
}
Loading