Module:Archive/EventsTable
From Liquipedia Rocket League Wiki
| The above documentation is transcluded from Module:Archive/EventsTable/doc. (edit | history) Editors can experiment in this module's sandbox (create | mirror) and testcases (create) pages. Subpages of this module. |
---- This module creates a table that contains a set of events determined by the input
-- @author XtratoS
-- @release 1.03
local p = {}
local getArgs = require('Module:Arguments').getArgs
local utils = require('Module:LuaUtils')
local resolveRedirect = require('Module:Redirect').luaMain
local split = require('Module:StringUtils').split
local trim = require('Module:StringUtils').trim
local contains = require('Module:StringUtils').contains
local expandTemplate = utils.frame.expandTemplate
local protectedExpansion = utils.frame.protectedExpansion
local ZINDEX = 9000
local DivTable = require('Module:DivTable')
--- Creates the table using tournaments organized by the provided organizer.
-- @tparam frame frame
-- @treturn string the html table
function p.organizer(frame)
local args = getArgs(frame)
local organizer = resolveRedirect(getArg(args, 'organizer'))
local limit = getArg(args, 'limit', '500')
local conditions =
'[[organizers_organizer1::'..organizer..']] OR'..
'[[organizers_organizer2::'..organizer..']] OR'..
'[[organizers_organizer3::'..organizer..']] OR'..
'[[organizers_organizer4::'..organizer..']] OR'..
'[[organizers_organizer5::'..organizer..']] OR'..
'[[organizers_organizer1::'..args.organizer..']] OR'..
'[[organizers_organizer2::'..args.organizer..']] OR'..
'[[organizers_organizer3::'..args.organizer..']] OR'..
'[[organizers_organizer4::'..args.organizer..']] OR'..
'[[organizers_organizer5::'..args.organizer..']]'
conditions = applyFilters(args, conditions)
local tournamentsData = mw.ext.LiquipediaDB.lpdb('tournament', {
conditions = conditions,
query = 'name, series, sortdate, type, location, pagename, liquipediatier, prizepool, extradata',
order = 'sortdate desc, name asc',
limit = limit
})
return p.makeResultsHTMLTable(frame, tournamentsData)
end
--- Creates the table using tournaments organized by the provided series.
-- @tparam frame frame
-- @treturn string the html table
function p.series(frame)
local args = getArgs(frame)
local conditions = ''
for _, series in pairs(split(args.series, ',')) do
conditions = conditions .. '[[series::' .. series .. ']] OR '
end
conditions = conditions:sub(1, -4)
local limit = getArg(args, 'limit', '500')
conditions = applyFilters(args, conditions)
local tournamentsData = mw.ext.LiquipediaDB.lpdb('tournament', {
conditions = conditions,
query = 'name, series, sortdate, type, location, pagename, liquipediatier, prizepool, extradata',
order = 'sortdate desc, name asc',
limit = limit
})
return p.makeResultsHTMLTable(frame, tournamentsData)
end
--- Adds filters to query conditions
-- @tfield table args the original template arguments
-- @tfield string conditions the conditions string before applying filters
-- @treturn string filteredConditions the conditions string after applying filters
function applyFilters(args, conditions)
if (args['start-year']) then
conditions = '(' .. conditions .. ') AND [[sortdate::>' .. args['start-year'] .. '-01-01]]'
end
if (args['end-year']) then
conditions = '(' .. conditions .. ') AND [[sortdate::<' .. args['end-year'] .. '-01-01]]'
end
if (args['year']) then
conditions = '(' .. conditions .. ')' ..
'AND [[sortdate::>' .. args['year'] .. '-01-01]]'..
'AND [[sortdate::<' .. args['year'] .. '-12-31]]'
end
return conditions
end
--- Queried tournaments data
-- @tfield string name
-- @tfield string series
-- @tfield string sortdate
-- @tfield string type
-- @tfield string location
-- @tfield string pagename
-- @tfield string liquipediatier
-- @tfield string prizepool
-- @tfield tournamentExtraData extradata
-- @table tournamentData
--- Extradata of queried tournament
-- @tfield string participantsnumber
-- @tfield string mode
-- @table tournamentExtraData
--- Creates the html table
-- Creates the placements table
-- @tparam frame frame
-- @tparam {tournamentData,...} data the queried data of tournaments
-- @treturn string text representing the html table
function p.makeResultsHTMLTable(frame, data)
local tableNode = DivTable.create():setStriped(true)
tableNode.root:addClass('tournament-card')
createResultsHeaderRow(tableNode)
local bottomPadding = createResultsTableBody(frame, tableNode, data)
tableNode.root:css('padding-bottom', bottomPadding..'px')
return tostring(tableNode:create())
end
--- Creates the html table body for a touranments table
-- @tparam frame frame
-- @tparam node tableNode the html table node
-- @tparam {tournamentData,...} data the queried data of tournaments
-- @treturn number bottomPadding the number of pixels to apply as bottom padding for the whole table
function createResultsTableBody(frame, tableNode, data)
local year = '0'
local lastTableRowWinnersTableRowCount = 0
for _, tournament in ipairs(data) do
local tournamentYear = string.sub(tournament.sortdate, 1, 4)
if (year ~= tournamentYear) then
year = tournamentYear
-- tableNode:row(DivTable.HeaderRow():cell(mw.html.create('div'):wikitext(tournamentYear)))
end
local locationFlag, locationText = extractLocationData(tournament.location)
local tableRow = DivTable.Row()
:cell(mw.html.create('div'):addClass('EventDetails'):addClass('Date'):addClass('Header'):wikitext(tournament.sortdate))
:cell(mw.html.create('div'):addClass('EventDetails'):addClass('Location'):addClass('Header'):wikitext(protectedExpansion(frame, 'Flag/'.. locationFlag:lower())..' '..(locationText or tournament.type)))
:cell(mw.html.create('div'):addClass('EventDetails'):addClass('Location'):addClass('Header'):wikitext(protectedExpansion(frame, 'Tier/'..tournament.liquipediatier)))
:cell(mw.html.create('div'):addClass('Tournament'):addClass('Header'):wikitext(
expandWithFallback(
frame,
'LeagueIconSmall/'..tournament.series:lower(),
{},
function()
return protectedExpansion(frame, 'LeagueIconSmall/none')
end
) .. ' [['..tournament.pagename..'|'..tournament.name..']]'
))
:cell(mw.html.create('div'):addClass('EventDetails'):addClass('Prize'):addClass('Header'):wikitext(
'$'..
mw.getContentLanguage():formatNum(
tonumber(tournament.prizepool)
)
))
:cell(
mw.html.create('div')
:addClass('EventDetails')
:addClass('PlayerNumber')
:addClass('Header')
:wikitext(
(tournament.extradata.participantsnumber or '?') ..
tostring(
mw.html.create('span')
:addClass('PlayerNumberSuffix')
:wikitext(' participants')
:done()
)
)
)
lastTableRowWinnersTableRowCount = addWinnersDataToRow(frame, tournament, tableRow)
tableNode:row(tableRow)
end
local bottomPadding = (lastTableRowWinnersTableRowCount - 1) * 35 + 40
return bottomPadding
end
function extractLocationData(locationString)
if contains(locationString, ',') == false then
return locationString, nil
end
local country = mw.text.split(locationString, ',')[2]:lower():sub(3)
local city = mw.text.split(locationString, ',')[1]
return country, city
end
--- Queried placements data
-- @tfield string mode
-- @tfield string participant
-- @tfield string participantflag
-- @tfield string placement
-- @tfield placementExtraData extradata
-- @table placementData
--- Extradata of queried placement
-- @tfield string mode
-- @table placementExtraData
--- Adds the columns corresponding to Winner and Runner-up header cells
-- @tparam frame frame
-- @tparam tournamentData tournament the tournament which is being renderred in this row
-- @tparam DivTableRow tableRow the table row node
-- @treturn number firstPlaceOwnersCount the number of players that won the 1st place prize
function addWinnersDataToRow(frame, tournament, tableRow)
local mode = tournament.extradata.mode
local resultOwnerType = mode == '1v1' and 'Player' or 'Team'
local placementData = mw.ext.LiquipediaDB.lpdb('placement', {
conditions =
'[[pagename::'..tournament.pagename..']] AND ('..
'[[placement::1]] OR'..
'[[placement::1-2]] OR'..
'[[placement::1-3]] OR'..
'[[placement::1-4]] OR'..
'[[placement::1-5]] OR'..
'[[placement::1-6]] OR'..
'[[placement::1-7]] OR'..
'[[placement::1-8]] OR'..
'[[placement::2]])',
query = 'mode, participant, participantflag, extradata, placement',
order = 'placement asc'
})
local dataByPlacement = {}
for _, placement in ipairs(placementData) do
if (placement.placement ~= '' and placement.participant:lower() ~= 'tbd') then
local placementNumber = tonumber(string.sub(placement.placement, 1, (placement.placement..'-'):find('%-')-1))
if not dataByPlacement[placementNumber] then
dataByPlacement[placementNumber] = {}
end
table.insert(dataByPlacement[placementNumber], placement)
end
end
local firstPlaceOwnersCount = dataByPlacement[1] and #dataByPlacement[1] or 0
if firstPlaceOwnersCount > 1 then
ZINDEX = ZINDEX - 1
local container = mw.html.create('div')
:addClass('table-responsive')
:css('position', 'relative')
:css('z-index', ZINDEX)
:css('overflow', 'visible')
local title_1 = tostring(
mw.html.create('div')
:css('width', '60px')
:css('display', 'inline-block')
:css('text-align', 'center')
:wikitext(protectedExpansion(frame, 'medal', {1}))
)..(
firstPlaceOwnersCount..'x '
)
local title_2 = resultOwnerType..'s'
local firstPlaceTable = createExpandableTable(frame, title_1)
addFirstPlaceTable(frame, firstPlaceTable, dataByPlacement[1], resultOwnerType)
container:node(firstPlaceTable:done())
tableRow
:cell(mw.html.create('div'):addClass('Placement'):addClass('FirstPlace'):node(container))
:cell(mw.html.create('div'):addClass('Placement'):addClass('SecondPlace'):wikitext(''))
elseif firstPlaceOwnersCount == 1 then
local first = dataByPlacement[1][1]
local second = (dataByPlacement[2] or {})[1]
tableRow
:cell(mw.html.create('div'):addClass('Placement'):addClass('FirstPlace'):wikitext(renderParticipant(frame, first, resultOwnerType)))
:cell(mw.html.create('div'):addClass('Placement'):addClass('SecondPlace'):wikitext(second and renderParticipant(frame, second, resultOwnerType) or abbr('To be determined (or to be decided)', 'TBD')))
-- SHOW FIRST AND SECOND PLACE
else
tableRow
:cell(mw.html.create('div'):addClass('Placement'):addClass('FirstPlace'):wikitext(
tostring(
mw.html.create('span')
:css('display', 'inline-block')
:css('width', '60px')
)..' '..
abbr('To be determined (or to be decided)', 'TBD')
))
:cell(mw.html.create('div'):addClass('Placement'):addClass('SecondPlace'):wikitext(
tostring(
mw.html.create('span')
:css('display', 'inline-block')
:css('width', '60px')
)..' '..
abbr('To be determined (or to be decided)', 'TBD')
))
end
return firstPlaceOwnersCount
end
--- Converts a div into an exapndable table container and returns the table node
-- @tparam frame frame
-- @tparam node container the div node to insert the table into
-- @tparam string title the text to include in the table's header
function createExpandableTable(frame, title)
return mw.html.create('div')
:css('margin-top', '-12px')
:css('position', 'absolute')
:tag('table')
:addClass('collapsible')
:addClass('collapsed')
:addClass('wikitable')
:addClass('wikitable-striped')
:css('background-color', 'transparent !important')
:tag('tr')
:css('background-color', 'transparent !important')
:css('border', '1px solid transparent !important')
:tag('th')
:css('background-color', 'transparent !important')
:css('border-color', 'transparent !important')
:css('border-right', '0px')
:css('padding', '0px')
:wikitext(title)
:done()
:done()
end
--- Creates and abbr tag
-- @tparam string title
-- @tparam string content
-- @treturn string the created span node
function abbr(title, content)
return tostring(
mw.html.create('abbr')
:attr('title', title)
:wikitext(content)
)
end
--- Adds the first place table to the provided table node
-- @tparam frame frame
-- @tparam node tableNode
-- @tparam {placementData,...} placements
-- @tparam string participantType the type of the participant (team or player)
-- @treturn nil
function addFirstPlaceTable(frame, tableNode, placements, participantType)
local lastElement
local temp
for _, placement in pairs(placements) do
temp = tableNode
:tag('tr')
:css('border-right', '2px solid #a2a9b1')
:css('border-left', '2px solid #a2a9b1')
:css('box-shadow', '6px 6px 12px rgba(0, 0, 0, 0.5)')
:tag('td')
:css('padding', '5px 12px 5px 0px')
:css('text-align', 'left')
:css('white-space', 'nowrap')
:wikitext(renderParticipant(frame, placement, participantType))
:done()
if (lastElement) then
lastElement = temp
else
lastElement = temp:css('border-top', '2px solid #a2a9b1')
end
end
lastElement:css('border-bottom', '2px solid #a2a9b1')
end
--- Creates an html span that contains a team or a player to show in the rightmost columns in the table
-- @tparam frame frame
-- @tparam placementData placement
-- @tparam string participantType
-- @treturn string the renderred team or player
function renderParticipant(frame, placement, participantType)
if (participantType == 'Player') then
local playerSpan = mw.html.create('span')
:css('width', '60px')
:css('display', 'inline-block')
:css('text-align', 'center')
:wikitext(protectedExpansion(frame, 'Flag/'..placement.participantflag:lower()))
:done()
return tostring(playerSpan)..'[['..placement.participant..']]'
else
return protectedExpansion(frame, 'TeamShort', {placement.participant})
end
end
--- Creates header row and appends it to the provided table wrapper
-- @tparam DivTable tableNode the DivTable object
-- @treturn node the table node
function createResultsHeaderRow(tableNode)
tableNode:row(
DivTable.HeaderRow()
:cell(mw.html.create('div'):wikitext('Date'))
:cell(mw.html.create('div'):wikitext('Location'))
:cell(mw.html.create('div'):wikitext('Tier'))
:cell(mw.html.create('div'):wikitext('Tournament'))
:cell(mw.html.create('div'):wikitext('Prize'))
:cell(mw.html.create('div'):wikitext(tostring(mw.html.create('abbr'):attr('title', 'Number of participants'):wikitext('#P'))))
:cell(mw.html.create('div'):wikitext('Winner'))
:cell(mw.html.create('div'):wikitext('Runner-up'))
)
return
end
--- Expands a template if exists, otherwise calls the fallback function
-- @tparam frame frame
-- @tparam string title title of the template to expand
-- @tparam ?table args arguments to use while expanding the template
-- @tparam function fallback a function that returns the value to return in-case the template doesn't exist
-- @treturn string the exapanded template if it exists, otherwise the result of calling fallback function
function expandWithFallback(frame, title, args, fallback)
local status, result = pcall(expandTemplate, frame, title, args)
if status == true then
return result
else
return fallback()
end
end
--- Gets an argument from the provided argument if exists, otherwise throws an error
-- @tparam table args the template arguments
-- @tparam string argName the name of the argument to return
-- @tparam ?string default the value to return if the argument isn't found, if nil then the function throws and returns an error
-- @treturn string the argument value or default if provided, if not provided then throws an error
function getArg(args, argName, default)
local argVal = args[argName]
if (argVal) then
return argVal
end
if (default) then
return default
end
return error('Argument "' .. argName .. '" is required')
end
return p