Module:ArchiveTeam portal list: Difference between revisions
From Liquipedia Marvel Rivals Wiki
No edit summary Tag: Manual revert |
test |
||
| Line 1: | Line 1: | ||
local Lua = require('Module:Lua') | local Lua = require('Module:Lua') | ||
local Arguments = require('Module:Arguments') | |||
local Lpdb = require('Module:Lpdb') | |||
local Countdown = Lua.import('Module:Countdown') | local Countdown = Lua.import('Module:Countdown') | ||
local DateExt = Lua.import('Module:Date/Ext') | local DateExt = Lua.import('Module:Date/Ext') | ||
local Flags = Lua.import('Module:Flags') | local Flags = Lua.import('Module:Flags') | ||
local | local Widgets = Lua.import('Module:Widget/Html/All') | ||
local Div = | local Div = Widgets.Div | ||
local Span = | local Span = Widgets.Span | ||
local Link = Lua.import('Module:Widget/Basic/Link') | |||
local Button = Lua.import('Module:Widget/Basic/Button') | |||
local Image = Lua.import('Module:Widget/Image') | |||
local | local TeamPortal = {} | ||
local | local config = { | ||
MAX_PLAYERS = 8, | |||
DEFAULT_TEAMS = 10, | |||
BLANK_PLAYER_IMAGE = 'Blank Player Image nopadding.png' | |||
} | |||
-- Sanitizes a | ---Sanitizes a string for use as an HTML class name. | ||
---@param class string | ---@param class string | ||
---@return string | ---@return string | ||
| Line 31: | Line 37: | ||
end | end | ||
-- Creates | ---Creates and renders the team portal. | ||
- | ---@param frame table | ||
-- @param frame table | ---@return string | ||
-- @return string | |||
function TeamPortal.create(frame) | function TeamPortal.create(frame) | ||
local args = Arguments.getArgs(frame) | local args = Arguments.getArgs(frame) | ||
local lang = mw.language.getContentLanguage() | local lang = mw.language.getContentLanguage() | ||
local lpdbData = Lpdb.call('team', { | |||
local lpdbData = | limit = args.teams or config.DEFAULT_TEAMS, | ||
limit = DEFAULT_TEAMS | |||
conditions = '[[pageid::!0]] AND [[disbanddate::' .. DateExt.defaultDate .. ']]', | conditions = '[[pageid::!0]] AND [[disbanddate::' .. DateExt.defaultDate .. ']]', | ||
order = 'earnings desc', | order = 'earnings desc', | ||
| Line 48: | Line 51: | ||
}) | }) | ||
local portalItems = {} | local portalItems = {} | ||
for i, teamData in ipairs(lpdbData) do | |||
for | |||
local teamName = teamData.name | local teamName = teamData.name | ||
local teamPageName = teamData.pagename | local teamPageName = teamData.pagename | ||
local teamEarnings = lang:formatNum(tonumber(teamData.earnings)) | local teamEarnings = lang:formatNum(tonumber(teamData.earnings)) | ||
local sanitizedTeamId = TeamPortal._sanitizeClass(teamPageName) | |||
local sanitizedTeamId = TeamPortal._sanitizeClass( | |||
-- Create | -- Create card title | ||
local cardTitle = Div{ | local cardTitle = Div{ | ||
classes = {'tp-rank-card-title', 'mw-customtoggle-' .. sanitizedTeamId}, | classes = {'tp-rank-card-title', 'mw-customtoggle-' .. sanitizedTeamId}, | ||
children = | children = { | ||
Span{classes = {'tp-rank-number'}, children = {'#' .. i}}, | |||
mw.ext.TeamTemplate.teamicon(teamName), | |||
Span{classes = {'tp-team-name'}, children = {teamName}}, | |||
Span{classes = {'tp-total-earnings'}, children = { | |||
Span{classes = {'tp-total-earnings-text'}, children = {'Total Earnings:'}}, | |||
' $' .. teamEarnings | |||
}} | |||
} | |||
} | } | ||
-- | -- Build collapsible content sections | ||
local | local playerContainer = TeamPortal._buildPlayerSection(teamPageName) | ||
local nextMatchSection = TeamPortal._buildNextMatchSection(teamName) | local nextMatchSection = TeamPortal._buildNextMatchSection(teamName) | ||
local latestTransferSection = TeamPortal._buildLatestTransferSection(teamName, lang) | |||
local buttonRow = TeamPortal._buildButtonRow(teamPageName) | |||
local latestTransferSection = TeamPortal._buildLatestTransferSection( | |||
local buttonRow = | |||
-- Assemble the team box | -- Assemble the team box | ||
| Line 119: | Line 85: | ||
} | } | ||
if i ~= 1 then | |||
table.insert(teamBox.props.classes, 'mw-collapsed') | table.insert(teamBox.props.classes, 'mw-collapsed') | ||
end | end | ||
local card = Div{classes = {'tp-rank-card'}, children = {cardTitle, teamBox}} | |||
local card = Div{ | table.insert(portalItems, Div{classes = {'team-portal-list'}, children = {card}}) | ||
end | end | ||
return tostring(Div{children = portalItems}:render()) | |||
end | end | ||
-- Builds player | ---Builds the player display section. | ||
-- @param teamPageName string | ---@param teamPageName string | ||
- | ---@return WidgetDiv | ||
-- @return | function TeamPortal._buildPlayerSection(teamPageName) | ||
function TeamPortal. | local squadData = Lpdb.call('squadplayer', { | ||
local squadData = | limit = config.MAX_PLAYERS, | ||
limit = MAX_PLAYERS | |||
conditions = '[[pagename::' .. teamPageName .. ']] AND [[leavedate::' .. DateExt.defaultDate .. ']] ' | conditions = '[[pagename::' .. teamPageName .. ']] AND [[leavedate::' .. DateExt.defaultDate .. ']] ' | ||
.. 'AND [[inactivedate::' .. DateExt.defaultDate .. ']] AND [[type::player]]', | .. 'AND [[inactivedate::' .. DateExt.defaultDate .. ']] AND [[type::player]]', | ||
| Line 161: | Line 109: | ||
local playerRows = {} | local playerRows = {} | ||
for i, squadPlayerData in ipairs(squadData) do | |||
local playerData = Lpdb.call('player', { | |||
for | conditions = '[[pageid::!0]] AND [[pagename::' .. (squadPlayerData.link or ''):gsub(' ', '_') .. ']]', | ||
local | |||
conditions = '[[pageid::!0]] AND | |||
query = 'pagename, id, nationality, image', | query = 'pagename, id, nationality, image', | ||
limit = 1 | limit = 1 | ||
}) | })[1] or {} | ||
local playerPage = playerData.pagename or '' | |||
playerFlag = | local displayId = playerData.id or squadPlayerData.id or '' | ||
local playerFlag = playerData.nationality or '' | |||
local playerImage = Image{ | |||
page = playerData.image or config.BLANK_PLAYER_IMAGE, | |||
local | width = 186, height = 140, | ||
link = playerPage ~= '' and playerPage or nil, | |||
} | } | ||
local | local nameWidget = (displayId ~= '' and playerPage ~= '') and Link{page = playerPage, children = {displayId}} or displayId | ||
local flagIcon = playerFlag ~= '' and Flags.Icon({ flag = playerFlag, shouldLink = playerPage ~= '' }) or '' | |||
} | |||
table.insert(playerRows, Div{ | |||
classes = {'tp-player-' .. i}, | |||
classes = {'tp-player-' .. | |||
css = {['text-align'] = 'center', ['margin-bottom'] = '2px'}, | css = {['text-align'] = 'center', ['margin-bottom'] = '2px'}, | ||
children = { | children = { | ||
Div{classes = {'tp-photo'}, css = {['margin-bottom'] = '5px'}, children = {playerImage}}, | |||
Div{classes = {'tp-name'}, children = {flagIcon, (flagIcon ~= '' and nameWidget ~= '') and '\t' or '', nameWidget}} | |||
} | |||
}) | }) | ||
end | end | ||
return '' | return Div{ | ||
css = { | |||
display = 'flex', ['flex-wrap'] = 'wrap', ['justify-content'] = 'center', | |||
['align-items'] = 'flex-start', gap = '15px', padding = '5px 0' | |||
}, | |||
children = playerRows | |||
} | |||
end | end | ||
-- Builds the next match section | ---Builds the next match section. | ||
-- @param teamName string | ---@param teamName string | ||
-- @return | ---@return WidgetDiv | ||
function TeamPortal._buildNextMatchSection(teamName) | function TeamPortal._buildNextMatchSection(teamName) | ||
local matchData = Lpdb.call('match', { | |||
local matchData = | |||
limit = 1, | limit = 1, | ||
conditions = '[[pageid::!-1]] AND [[finished::0]] AND [[dateexact::1]] ' | conditions = '[[pageid::!-1]] AND [[finished::0]] AND [[dateexact::1]] ' | ||
.. 'AND ([[opponent1::' .. teamName .. ']] OR [[opponent2::' .. teamName .. ']])', | .. 'AND ([[opponent1::' .. teamName .. ']] OR [[opponent2::' .. teamName .. ']])', | ||
order = 'date asc', | order = 'date asc', | ||
query = 'pagename, tickername | query = 'pagename, tickername, opponent1, opponent2, date', | ||
}) | })[1] | ||
local | local elements = {'Next Match'} | ||
if matchData then | |||
local opponent = (teamName == matchData.opponent1) and matchData.opponent2 or matchData.opponent1 | |||
table.insert(elements, Span{classes = {'tp-vs-team'}, children = {'<br>' .. (opponent ~= 'TBD' and mw.ext.TeamTemplate.team(opponent) or 'TBD')}}) | |||
local tourneyLink = Link{page = matchData.pagename, children = {matchData.tickername or matchData.pagename}} | |||
table.insert(elements, Span{classes = {'tp-tournament'}, children = {'<br>', tourneyLink}}) | |||
if matchData.date then | |||
table.insert(elements, Span{classes = {'tp-countdown'}, children = {'<br>', Countdown.create({ date = matchData.date })}}) | |||
if matchData | |||
local | |||
table.insert( | |||
end | end | ||
end | end | ||
return Div{ | return Div{classes = {'tp-next-match'}, children = {Div{classes = {'tp-sub-title'}, children = elements}}} | ||
end | end | ||
-- Builds the latest transfer section | ---Builds the latest transfer section. | ||
-- @param | ---@param teamName string | ||
-- @param lang table | ---@param lang table | ||
-- @return | ---@return WidgetDiv | ||
function TeamPortal._buildLatestTransferSection( | function TeamPortal._buildLatestTransferSection(teamName, lang) | ||
local teamNameUc = teamName:gsub('^%l', mw.ustring.upper) | |||
local transferData = | local transferData = Lpdb.call('transfer', { | ||
limit = 1, | limit = 1, | ||
conditions = '[[fromteam::' .. teamNameUc .. ']] OR [[toteam::' .. teamNameUc .. ']]', | conditions = '[[fromteam::' .. teamNameUc .. ']] OR [[toteam::' .. teamNameUc .. ']]', | ||
order = 'date desc', | order = 'date desc', | ||
query = 'player, nationality, fromteam, toteam, role1, role2, date, extradata', | query = 'player, nationality, fromteam, toteam, role1, role2, date, extradata', | ||
}) | })[1] | ||
local transferText = '' | local transferText = '' | ||
if transferData | if transferData then | ||
local | local player = transferData.player or '' | ||
local | local displayId = (transferData.extradata and transferData.extradata.displayname) or player | ||
local | local date = transferData.date and lang:formatDate('F j, Y', transferData.date) or '' | ||
if | if player ~= '' and date ~= '' then | ||
local | local flagIcon = transferData.nationality and Flags.Icon({ flag = transferData.nationality, shouldLink = true }) or '' | ||
local playerLink = Link{page = displayId, children = {player}} | |||
if teamNameUc == transferData.fromteam then | |||
local role = transferData.role1 and (' (' .. transferData.role1 .. ')') or '' | |||
transferText = {'<br>', flagIcon, '\t', playerLink, '\tleaves on\t', date, role} | |||
elseif teamNameUc == transferData.toteam then | |||
local role = transferData.role2 and (' (' .. transferData.role2 .. ')') or '' | |||
transferText = {'<br>', flagIcon, '\t', playerLink, '\tjoins on\t', date, role} | |||
transferText = '<br>' | |||
transferText = '<br>' | |||
end | end | ||
end | end | ||
| Line 416: | Line 212: | ||
classes = {'tp-latest-transfer'}, | classes = {'tp-latest-transfer'}, | ||
children = { | children = { | ||
Div{ | Div{classes = {'tp-sub-title'}, children = { | ||
'Latest Transfer', | |||
Span{classes = {'tp-transfer'}, children = transferText} | |||
}} | |||
} | |||
} | |||
} | end | ||
---Builds the navigation button row. | |||
---@param teamPageName string | |||
---@return WidgetDiv | |||
function TeamPortal._buildButtonRow(teamPageName) | |||
return Div{ | |||
classes = {'tp-button-row'}, | |||
children = { | |||
Button{page = teamPageName, classes = {'tp-button'}, children = {'Team Page'}}, | |||
Button{page = teamPageName .. '/Results', classes = {'tp-button'}, children = {'Results'}}, | |||
Button{page = teamPageName .. '/Played Matches', classes = {'tp-button'}, children = {'Played Matches'}}, | |||
} | } | ||
} | } | ||
Revision as of 19:16, 23 October 2025
Documentation for this module may be created at Module:ArchiveTeam portal list/doc
local Lua = require('Module:Lua')
local Arguments = require('Module:Arguments')
local Lpdb = require('Module:Lpdb')
local Countdown = Lua.import('Module:Countdown')
local DateExt = Lua.import('Module:Date/Ext')
local Flags = Lua.import('Module:Flags')
local Widgets = Lua.import('Module:Widget/Html/All')
local Div = Widgets.Div
local Span = Widgets.Span
local Link = Lua.import('Module:Widget/Basic/Link')
local Button = Lua.import('Module:Widget/Basic/Button')
local Image = Lua.import('Module:Widget/Image')
local TeamPortal = {}
local config = {
MAX_PLAYERS = 8,
DEFAULT_TEAMS = 10,
BLANK_PLAYER_IMAGE = 'Blank Player Image nopadding.png'
}
---Sanitizes a string for use as an HTML class name.
---@param class string
---@return string
function TeamPortal._sanitizeClass(class)
class = class:gsub('%s', '_')
class = mw.uri.encode(class, 'PATH')
class = class:gsub('[^A-Za-z0-9%-_]', function(c)
return string.format('.%02x', string.byte(c))
end)
if class:match('^[%d]') or class:match('^%-[%d]') then
class = '_' .. class
end
return class
end
---Creates and renders the team portal.
---@param frame table
---@return string
function TeamPortal.create(frame)
local args = Arguments.getArgs(frame)
local lang = mw.language.getContentLanguage()
local lpdbData = Lpdb.call('team', {
limit = args.teams or config.DEFAULT_TEAMS,
conditions = '[[pageid::!0]] AND [[disbanddate::' .. DateExt.defaultDate .. ']]',
order = 'earnings desc',
query = 'name, pagename, earnings',
})
local portalItems = {}
for i, teamData in ipairs(lpdbData) do
local teamName = teamData.name
local teamPageName = teamData.pagename
local teamEarnings = lang:formatNum(tonumber(teamData.earnings))
local sanitizedTeamId = TeamPortal._sanitizeClass(teamPageName)
-- Create card title
local cardTitle = Div{
classes = {'tp-rank-card-title', 'mw-customtoggle-' .. sanitizedTeamId},
children = {
Span{classes = {'tp-rank-number'}, children = {'#' .. i}},
mw.ext.TeamTemplate.teamicon(teamName),
Span{classes = {'tp-team-name'}, children = {teamName}},
Span{classes = {'tp-total-earnings'}, children = {
Span{classes = {'tp-total-earnings-text'}, children = {'Total Earnings:'}},
' $' .. teamEarnings
}}
}
}
-- Build collapsible content sections
local playerContainer = TeamPortal._buildPlayerSection(teamPageName)
local nextMatchSection = TeamPortal._buildNextMatchSection(teamName)
local latestTransferSection = TeamPortal._buildLatestTransferSection(teamName, lang)
local buttonRow = TeamPortal._buildButtonRow(teamPageName)
-- Assemble the team box
local teamBox = Div{
classes = {'tp-team-box', 'mw-collapsible'},
attributes = {id = 'mw-customcollapsible-' .. sanitizedTeamId},
children = {playerContainer, nextMatchSection, latestTransferSection, buttonRow}
}
if i ~= 1 then
table.insert(teamBox.props.classes, 'mw-collapsed')
end
local card = Div{classes = {'tp-rank-card'}, children = {cardTitle, teamBox}}
table.insert(portalItems, Div{classes = {'team-portal-list'}, children = {card}})
end
return tostring(Div{children = portalItems}:render())
end
---Builds the player display section.
---@param teamPageName string
---@return WidgetDiv
function TeamPortal._buildPlayerSection(teamPageName)
local squadData = Lpdb.call('squadplayer', {
limit = config.MAX_PLAYERS,
conditions = '[[pagename::' .. teamPageName .. ']] AND [[leavedate::' .. DateExt.defaultDate .. ']] '
.. 'AND [[inactivedate::' .. DateExt.defaultDate .. ']] AND [[type::player]]',
order = 'id asc',
query = 'link, id',
})
local playerRows = {}
for i, squadPlayerData in ipairs(squadData) do
local playerData = Lpdb.call('player', {
conditions = '[[pageid::!0]] AND [[pagename::' .. (squadPlayerData.link or ''):gsub(' ', '_') .. ']]',
query = 'pagename, id, nationality, image',
limit = 1
})[1] or {}
local playerPage = playerData.pagename or ''
local displayId = playerData.id or squadPlayerData.id or ''
local playerFlag = playerData.nationality or ''
local playerImage = Image{
page = playerData.image or config.BLANK_PLAYER_IMAGE,
width = 186, height = 140,
link = playerPage ~= '' and playerPage or nil,
}
local nameWidget = (displayId ~= '' and playerPage ~= '') and Link{page = playerPage, children = {displayId}} or displayId
local flagIcon = playerFlag ~= '' and Flags.Icon({ flag = playerFlag, shouldLink = playerPage ~= '' }) or ''
table.insert(playerRows, Div{
classes = {'tp-player-' .. i},
css = {['text-align'] = 'center', ['margin-bottom'] = '2px'},
children = {
Div{classes = {'tp-photo'}, css = {['margin-bottom'] = '5px'}, children = {playerImage}},
Div{classes = {'tp-name'}, children = {flagIcon, (flagIcon ~= '' and nameWidget ~= '') and '\t' or '', nameWidget}}
}
})
end
return Div{
css = {
display = 'flex', ['flex-wrap'] = 'wrap', ['justify-content'] = 'center',
['align-items'] = 'flex-start', gap = '15px', padding = '5px 0'
},
children = playerRows
}
end
---Builds the next match section.
---@param teamName string
---@return WidgetDiv
function TeamPortal._buildNextMatchSection(teamName)
local matchData = Lpdb.call('match', {
limit = 1,
conditions = '[[pageid::!-1]] AND [[finished::0]] AND [[dateexact::1]] '
.. 'AND ([[opponent1::' .. teamName .. ']] OR [[opponent2::' .. teamName .. ']])',
order = 'date asc',
query = 'pagename, tickername, opponent1, opponent2, date',
})[1]
local elements = {'Next Match'}
if matchData then
local opponent = (teamName == matchData.opponent1) and matchData.opponent2 or matchData.opponent1
table.insert(elements, Span{classes = {'tp-vs-team'}, children = {'<br>' .. (opponent ~= 'TBD' and mw.ext.TeamTemplate.team(opponent) or 'TBD')}})
local tourneyLink = Link{page = matchData.pagename, children = {matchData.tickername or matchData.pagename}}
table.insert(elements, Span{classes = {'tp-tournament'}, children = {'<br>', tourneyLink}})
if matchData.date then
table.insert(elements, Span{classes = {'tp-countdown'}, children = {'<br>', Countdown.create({ date = matchData.date })}})
end
end
return Div{classes = {'tp-next-match'}, children = {Div{classes = {'tp-sub-title'}, children = elements}}}
end
---Builds the latest transfer section.
---@param teamName string
---@param lang table
---@return WidgetDiv
function TeamPortal._buildLatestTransferSection(teamName, lang)
local teamNameUc = teamName:gsub('^%l', mw.ustring.upper)
local transferData = Lpdb.call('transfer', {
limit = 1,
conditions = '[[fromteam::' .. teamNameUc .. ']] OR [[toteam::' .. teamNameUc .. ']]',
order = 'date desc',
query = 'player, nationality, fromteam, toteam, role1, role2, date, extradata',
})[1]
local transferText = ''
if transferData then
local player = transferData.player or ''
local displayId = (transferData.extradata and transferData.extradata.displayname) or player
local date = transferData.date and lang:formatDate('F j, Y', transferData.date) or ''
if player ~= '' and date ~= '' then
local flagIcon = transferData.nationality and Flags.Icon({ flag = transferData.nationality, shouldLink = true }) or ''
local playerLink = Link{page = displayId, children = {player}}
if teamNameUc == transferData.fromteam then
local role = transferData.role1 and (' (' .. transferData.role1 .. ')') or ''
transferText = {'<br>', flagIcon, '\t', playerLink, '\tleaves on\t', date, role}
elseif teamNameUc == transferData.toteam then
local role = transferData.role2 and (' (' .. transferData.role2 .. ')') or ''
transferText = {'<br>', flagIcon, '\t', playerLink, '\tjoins on\t', date, role}
end
end
end
return Div{
classes = {'tp-latest-transfer'},
children = {
Div{classes = {'tp-sub-title'}, children = {
'Latest Transfer',
Span{classes = {'tp-transfer'}, children = transferText}
}}
}
}
end
---Builds the navigation button row.
---@param teamPageName string
---@return WidgetDiv
function TeamPortal._buildButtonRow(teamPageName)
return Div{
classes = {'tp-button-row'},
children = {
Button{page = teamPageName, classes = {'tp-button'}, children = {'Team Page'}},
Button{page = teamPageName .. '/Results', classes = {'tp-button'}, children = {'Results'}},
Button{page = teamPageName .. '/Played Matches', classes = {'tp-button'}, children = {'Played Matches'}},
}
}
end
return TeamPortal