Apex Legends Esports Wiki

READ MORE

Apex Legends Esports Wiki
Advertisement

To edit the documentation or categories for this module, click here.


local util_args = require('Module:ArgsUtil')
local util_cargo = require('Module:CargoUtil')
local util_esports = require('Module:EsportsUtil')
local util_table = require('Module:TableUtil')
local util_text = require('Module:TextUtil')
local util_vars = require('Module:VarsUtil')
local bracket_wiki = require('Module:Bracket/Wiki') -- wiki localization per game

local m_team = require('Module:Team')

local ROWS_PER_TEAM = 6
local ROWS_PER_TITLE = 2
local ROWS_PER_HLINE = 1
local ROUNDWIDTH = 12
local LINEWIDTH = '3em'
local SCOREWIDTH = 2

local sep = '%s*,%s*'

local h = {}

function h.processArgs(tpl_args)
	-- format tpl_args
	local args = {}
	for k, v in pairs(tpl_args) do
		if type(k) ~= 'string' then
			-- pass
		elseif k:find('R%d+M%d+_.*_') then
			local r, m, val, team = k:match('R(%d+)M(%d+)_(.*)_(%d+)')
			r = tonumber(r)
			m = tonumber(m)
			h.initializeMatch(args, r, m)
			if val == 'team' then
				args[r][m]['team' .. team][val] = m_team.teamlinkname(v)
			else
				args[r][m]['team' .. team][val] = v
			end
		elseif k:find('R%d+M%d+_.*') then
			local r, m, val = k:match('R(%d+)M(%d+)_(.*)')
			r = tonumber(r)
			m = tonumber(m)
			h.initializeMatch(args, r, m)
			args[r][m][val] = v
		elseif k:find('R%d+_') then
			local r, val = k:match('R(%d+)_(.*)')
			r = tonumber(r)
			h.initializeMatch(args, r)
			args[r][val] = v
		else
			args[k] = v
		end
	end
	return args
end	

function h.initializeMatch(args, r, m)
	if not args[r] then
		args[r] = {}
	end
	if not args[r][m] and m then
		args[r][m] = { team1 = {}, team2 = {} }
	end
end

function h.processSettings(settings, args)
	-- in theory this could be done in the settings module before returning but
	-- this way the code is a bit more hidden from users editing stuff
	-- and also this makes the settings module closer to a read-only table that you
	-- import (and clone) here which i guess is nice?
	-- tbh im not sure if this was the right way to do it tho
	for r, col in ipairs(settings) do
		local m = #col.matches
		while m >= 1 do
			-- need to iterate backwards bc we'll delete third-place matches if hidden
			local match = col.matches[m]
			local lines = col.lines and col.lines[m]
			if lines and lines.reseed then
				lines.class = lines.class:format(args.reseed or 'reseeding')
			end
			if match.argtoshow then
				if not util_args.castAsBool(args[match.argtoshow]) then
					if col.matches[m+1] then
						col.matches[m+1].above = (col.matches[m+1].above or 0) + (match.above or 0) + 6
					end
					table.remove(col.matches,m)
				end
			end
			m = m - 1
		end
	end
end

-- cargo
function h.addCargoData(args, settings)
	local overviewPage = util_esports.getOverviewPage(args.page)
	local data = h.doCargoQuery(overviewPage)
	if not next(data) then
		return
	end
	local processed = h.processCargoData(data)
	h.addProcessedToArgs(args, settings, processed, overviewPage)
end

function h.doCargoQuery(page)
	local query = {
		tables = 'MatchSchedule',
		fields = {
			'Team1',
			'Team2',
			'Team1Final',
			'Team2Final',
			'Winner',
			'FF',
			'Team1Score',
			'Team2Score',
			'Tab',
			'N_MatchInTab',
			'UniqueMatch'
		},
		where = ('OverviewPage="%s"'):format(page),
		types = {
			-- keep winner as a string since that's what's expected from args sigh
			Team1Score = 'number',
			Team2Score = 'number',
			FF = 'number'
		}
	}
	return util_cargo.queryAndCast(query)
end

function h.processCargoData(data)
	local processed = {}
	for _, row in ipairs(data) do
		h.sortFF(row)
		processed[('%s_%s'):format(row.Tab,row.N_MatchInTab)] = {
			winner = row.Winner,
			team1 = { score = row.Team1Score, team = row.Team1, teamfinal = row.Team1Final },
			team2 = { score = row.Team2Score, team = row.Team2, teamfinal = row.Team2Final },
		}
	end
	return processed
end

function h.sortFF(row)
	if row.FF == 1 then
		row.Team1Score = 'FF'
		row.Team2Score = 'W'
	elseif row.FF == 2 then
		row.Team1Score = 'W'
		row.Team2Score = 'FF'
	end
end

function h.addProcessedToArgs(args, settings, processed, overviewPage)
	for r, col in ipairs(settings) do
		h.initializeMatch(args, r)
		local title = args[r] and args[r].title or col.matches.title or ''
		for m, _ in ipairs(col.matches) do
			h.initializeMatch(args, r, m)
			local argmatch = args[r] and args[r][m]
			if argmatch and argmatch.cargomatch then
				h.addMatchCargoToMatch(argmatch, processed[argmatch.cargomatch])
			else
				local uniquematch = ('%s_%s'):format(
					title,
					m
				)
				if not argmatch then
					h.initializeMatch(args, r, m)
					argmatch = args[r][m]
				end
				h.addMatchCargoToMatch(argmatch, processed[uniquematch])
			end
		end
	end
end

function h.addMatchCargoToMatch(argMatch, cargoDataMatch)
	if not cargoDataMatch then
		return
	end
	-- allow arg data to overwrite cargo data always if applicable
	argMatch.winner = argMatch.winner or cargoDataMatch.winner
	for _, team in ipairs({ 'team1', 'team2' }) do
		for k, v in pairs(cargoDataMatch[team]) do
			argMatch[team][k] = argMatch[team][k] or v
		end
	end
end

-- print
function h.makeOutput(args, settings)
	local output = mw.html.create()
	local bracketN = util_vars.setGlobalIndex('BracketToggler')
	if settings.togglers then
		local togglers = h.makeTogglerButtons(settings.togglers, bracketN)
		local tblRound1 = output:tag('div')
			:addClass(h.allToggleClass(bracketN))
			:addClass(h.roundToggleClass(bracketN, 1))
		h.printBracket(args, settings, tblRound1, togglers)
		for i, toggle in ipairs(settings.togglers) do
			h.fixColumnLabelsForToggle(settings, toggle.bracket, i)
			table.remove(args, 1)
			h.processSettings(toggle.bracket, args)
			local tbl = output:tag('div')
				:addClass(h.allToggleClass(bracketN))
				:addClass(h.roundToggleClass(bracketN, i + 1))
				:addClass('toggle-section-hidden')
			table.remove(togglers, 1)
			h.printBracket(args, toggle.bracket, tbl, togglers)
		end
	else
		h.printBracket(args, settings, output:tag('div'), {})
	end
	return output
end

function h.allToggleClass(n, isAttr)
	local dot = isAttr and '.' or ''
	return ('%sbracket-toggle-allrounds-%s'):format(dot, n)
end

function h.roundToggleClass(n, i, isAttr)
	local dot = isAttr and '.' or ''
	return ('%sbracket-toggle-round-%s-%s'):format(dot, n, i)
end

function h.fixColumnLabelsForToggle(settings, bracket, i)
	for k, col in ipairs(bracket) do
		col.matches.title = settings[k + i].matches.title
	end
end

function h.makeTogglerButtons(togglers, n)
	local tbl = {}
	tbl[1] = h.makeToggler(n, 1)
	for i, _ in ipairs(togglers) do
		if i == #togglers then
			tbl[#tbl+1] = h.makeLastToggler(n)
		else
			-- first add 1 because we already did 1 from the default bracket
			tbl[#tbl+1] = h.makeToggler(n, i + 1)
		end
	end
	return tbl
end

function h.makeToggler(n, i)
	local div = mw.html.create('div')
		:addClass('bracket-toggler')
		:wikitext('[')
	div:tag('span')
		:addClass('alwaysactive-toggler')
		:attr('data-toggler-hide', h.allToggleClass(n, true))
		:attr('data-toggler-show', h.roundToggleClass(n, i + 1, true))
		:wikitext('x')
	div:wikitext(']')
	return div
end

function h.makeLastToggler(n)
	local div = mw.html.create('div')
		:addClass('bracket-toggler')
	div:tag('span')
		:addClass('alwaysactive-toggler')
		:attr('data-toggler-hide', h.allToggleClass(n, true))
		:attr('data-toggler-show', h.roundToggleClass(n, 1, true))
		:wikitext('<<')
	return div
end

function h.printBracket(args, settings, tbl, togglers)
	tbl:addClass('bracket-grid')
		:css({
			['grid-template-columns'] = h.getGTC(settings, args),
			['grid-template-rows'] = h.getGTR(settings, args.notitle)
		})
	for round, col in ipairs(settings) do
		h.addLinesColumn(tbl, col.lines, round, not args.notitle)
		h.addMatchesColumn(tbl, args, col.matches, round, not args.notitle, togglers[round])
	end
	return tbl
end

function h.getGTC(settings, args)
	local scores = {}
	for round, col in ipairs(settings) do
		scores[round] = args[round] and tonumber(args[round].extendedscore or '') or col.extendedscore or 1
	end
	local firstcol = settings[1].lines and next(settings[1].lines)
	local firstwidth = firstcol and LINEWIDTH or '0'
	return h.getCustomGTC(scores, args.roundwidth, firstwidth)
end

function h.getCustomGTC(scores, roundwidth, firstwidth)
	if roundwidth then
		roundwidth = tonumber(roundwidth:gsub('em','') or '')
	else
		roundwidth = ROUNDWIDTH
	end
	for k, v in ipairs(scores) do
		scores[k] = (SCOREWIDTH * (v - 1) + roundwidth) .. 'em'
	end
	return firstwidth .. ' ' .. table.concat(scores, ' 3em ')
end


function h.getGTR(settings, notitle)
	local max = 0
	for _, col in ipairs(settings) do
		local total = 0
		for _, match in ipairs(col.matches) do
			total = total + (match.above or 0)
			if match.display == 'match' then
				total = total + ROWS_PER_TEAM
			elseif match.display == 'hline' then
				total = total + ROWS_PER_HLINE
			end
		end
		if total > max then
			max = total
		end
	end
	if not notitle then max = max + ROWS_PER_TITLE end
	return ('repeat(%s,1fr)'):format(max)
end

function h.addLinesColumn(tbl, lineData, r, addtitle)
	local roundname = 'round' .. (r - 1)
	if not lineData then
		return
	end
	for m, row in ipairs(lineData) do
		if m == 1 and addtitle then
			h.addBracketLine(tbl, roundname, row, 2)
		else
			h.addBracketLine(tbl, roundname, row, 0)
		end
	end
	return
end

function h.addBracketLine(tbl, roundname, linerow, extra)
	if linerow.above + extra > 0 then
		tbl:tag('div')
			:addClass('bracket-line')
			:addClass(roundname)
			:cssText(('grid-row:span %s;'):format(linerow.above + extra))
	end
	tbl:tag('div')
		:addClass('bracket-line')
		:addClass(linerow.class)
		:addClass(roundname)
		:cssText(('grid-row:span %s;'):format(linerow.height))
	return
end

function h.addMatchesColumn(tbl, args, data, r, addtitle, toggler)
	local roundname = 'round' .. r
	if addtitle then
		local title = args[r] and args[r].title or data.title or ''
		h.makeTitle(tbl, roundname, title, toggler)
	end
	for m, row in ipairs(data) do
		local game = args[r] and args[r][m] or { team1 = {}, team2 = {} }
		if row.above then
			h.addSpacer(tbl, roundname, row.above)
		end
		if row.display == 'match' then
			h.makeMatch(tbl, game, roundname, not args.nolabels and row.label, args.teamstyle)
		elseif row.display == 'hline' then
			h.makeHorizontalCell(tbl, roundname)
		end
	end
	return
end

function h.makeTitle(tbl, roundname, text, toggler)
	local outerdiv = tbl:tag('div')
		:addClass('bracket-grid-header')
		:addClass(roundname)
	local innerdiv = outerdiv:tag('div')
		:addClass('bracket-header-content')
		:wikitext(text)
	if toggler then
		innerdiv:node(toggler)
	end
end

function h.makeHorizontalCell(tbl, roundname)
	tbl:tag('div')
		:addClass('bracket-spacer')
		:addClass('horizontal')
		:addClass(roundname)
	return
end

function h.makeMatch(tbl, game, roundname, label, teamstyle)
	if game.label then label = game.label end
	h.addSpacer(tbl, roundname, nil, label)
	h.makeTeam(tbl, roundname, game, game.team1, '1', teamstyle)
	h.makeTeam(tbl, roundname, game, game.team2, '2', teamstyle)
	h.addSpacer(tbl, roundname)
	return
end

function h.addSpacer(tbl, roundname, n, label)
	local div = tbl:tag('div')
		:addClass('bracket-spacer')
		:addClass(roundname)
	if label then
		div:wikitext(label)
	end
	if n then
		div:cssText(('grid-row:span %s;'):format(n))
	end
	return
end

function h.makeTeam(tbl, roundname, game, data, n, teamstyle)
	local isWinner = game.winner == n
	local isbye = util_args.castAsBool(data.bye)
	local line = tbl:tag('div')
		:addClass('bracket-team')
		:addClass(roundname)
		:addClass(game.class)
	util_esports.addTeamHighlighter(line, data.teamfinal or data.playerlink or data.player or data.team)
	if isWinner then
		line:addClass('bracket-winner')
	end
	local team = line:tag('div')
		:addClass('bracket-team-name')
	if data.free then
		team:wikitext(data.free)
	elseif isbye then
		team:wikitext('BYE')
		line:addClass('bracket-bye')
	else
		bracket_wiki.teamDisplay(team, data, teamstyle)
	end
	h.makeScore(line, data.score, isbye, game.winners, n)
end

function h.makeScore(line, score, isbye, winners, n)
	local tbl = util_text.split(tostring(score or ''),sep)
	tbl_win = winners and util_text.split(winners, sep) or {}
	for k, v in ipairs(tbl) do
		local div = line:tag('div')
			:addClass('bracket-team-points')
			:wikitext(v or (isbye and '-') or '')
		if tbl_win[k] == n then
			div:addClass('bracket-score-winner')
		elseif tbl_win[k] then
			div:addClass('bracket-score-loser')
		end
	end
end

local p = {}

function p.main(frame)
	local tpl_args = util_args.merge(true)
	-- use require instead of loadData so that we can use next() and #
	local settings = require('Module:Bracket/'.. tpl_args[1])
	local args = h.processArgs(tpl_args)
	h.processSettings(settings, args)
	if util_args.castAsBool(args.cargo) then
		h.addCargoData(args, settings)
	end
	return h.makeOutput(args, settings)
end

return p
Advertisement