Leaguepedia | League of Legends Esports Wiki
[checked revision][checked revision]
([ST] add title attr)
([ST])
Line 115: Line 115:
   
 
function h.makeWhere(page, args)
 
function h.makeWhere(page, args)
  +
if args.where then return args.where end
 
local tbl = {
 
local tbl = {
 
('OverviewPage="%s"'):format(page),
 
('OverviewPage="%s"'):format(page),

Revision as of 05:32, 12 June 2021

Edit the documentation or categories for this module. This module has an i18n file.


local util_args = require('Module:ArgsUtil')
local util_cargo = require('Module:CargoUtil')
local util_esports = require('Module:EsportsUtil')
local util_form = require('Module:FormUtil')
local util_html = require('Module:HtmlUtil')
local util_map = require('Module:MapUtil')
local util_math = require('Module:MathUtil')
local util_table = require('Module:TableUtil')
local util_text = require('Module:TextUtil')
local util_toggle = require('Module:ToggleUtil')
local util_tournament = require('Module:TournamentUtil')
local util_vars = require('Module:VarsUtil')
local lang = mw.getLanguage('en')

local i18n = require('Module:I18nUtil')
local m_team = require('Module:Team')
local Region = require('Module:Region')

local SHOW_LINKS = true

local sep = '%s*,%s*'
local CLASSES = {
	init = 'crossbox-cell',
	[1] = 'crossbox-win crossbox-cell',
	[0] = 'crossbox-draw crossbox-cell',
	[-1] = 'crossbox-loss crossbox-cell'
}

local TOTALCLASSES = {
	init = 'crossbox-total',
	[1] = 'crossbox-total crossbox-total-win',
	[0] = 'crossbox-total crossbox-total-draw',
	[-1] = 'crossbox-total crossbox-total-loss'
}

local TOGGLES = {
	order = { 'match', 'game' },
}

local FORM_INFO = { form = 'TeamHeadToHeadSchedule', template = 'TH2HS' }

local h = {}
local p = {}
function p.fromCargo(frame)
	i18n.init('Crossbox')
	local args = util_args.merge()
	if not args.crossboxtype then
		error('Must specify |crossboxtype=')
	end
	local crossboxtype = lang:lc(args.crossboxtype)
	local overviewPage = util_esports.getOverviewPage(args.page)
	local data = h.getData(overviewPage, args)
	if util_args.castAsBool(args.initializeall) then
		h.addZeroes(data)
	end
	return h.makeOutput(data, crossboxtype, util_args.castAsBool(args.groups))
end

function p.fromArgs(frame)
	i18n.init('Crossbox')
	local args = util_args.merge()
	h.setConstants(args)
	if not args.crossboxtype then
		error('Must specify |crossboxtype=')
	end
	local crossboxtype = lang:lc(args.crossboxtype)
	local data = h.getDataFromArgs(args)
	return h.makeOutput(data, crossboxtype, util_args.castAsBool(args.groups))
end

function h.setConstants(args)
	if util_args.castAsBool(args.nolinks) then
		SHOW_LINKS = false
	end
end

-- CARGO DATA COLLECTION

function h.getData(overviewPage, args)
	local result = h.makeAndRunQuery(overviewPage, args)
	if #result == 0 then
		return {}
	end
	local data = h.parseResult(result)
	local groupresult
	if util_args.castAsBool(args.groups) or args.onlygroup then
		groupresult = util_tournament.getGroups(overviewPage)
		if #groupresult == 0 then
			args.groups = false
		else
			h.addGroupDataToTeams(data, groupresult)
		end
	end
	local teamlist = h.getTeamOrder(args.teamlist, groupresult, args.onlygroup)
	h.sortData(data, teamlist)
	return data
end

function h.makeAndRunQuery(page, args)
	local query = {
		tables = 'MatchSchedule',
		fields = {
			'Team1Final=Team1',
			'Team2Final=Team2',
			'Winner',
			'Team1Score [number]',
			'Team2Score [number]',
			'FF [number]',
		},
		groupBy = 'MatchId',
		where = h.makeWhere(page, args),
	}
	return util_cargo.queryAndCast(query)
end

function h.makeWhere(page, args)
	if args.where then return args.where end
	local tbl = {
		('OverviewPage="%s"'):format(page),
	}
	if lang:lc(args.tiebreakers or '') == 'only' then
		tbl[#tbl+1] = '(IsTiebreaker = "1")'
	elseif not util_args.castAsBool(args.tiebreakers) then
		tbl[#tbl+1] = '(IsTiebreaker != "1" OR IsTiebreaker IS NULL)'
	end
	if args.excludetabs then
		for v in util_text.gsplit(args.excludetabs, sep) do
			tbl[#tbl+1] = ('Tab != "%s"'):format(v)
		end
	end
	if args.onlytabs then
		local onlyrounds_tbl = {}
		for v in util_text.gsplit(args.onlytabs, sep) do
			onlyrounds_tbl[#onlyrounds_tbl+1] = ('Tab = "%s"'):format(v)
		end
		tbl[#tbl+1] = ('(%s)'):format(util_table.concat(onlyrounds_tbl, ' OR '))
	end
	return util_table.concat(tbl, ' AND ')
end

function h.parseResult(result)
	local teams = {}
	for _, row in ipairs(result) do
		local team1, team2 = row.Team1, row.Team2
		h.initializeMatchup(teams, team1, team2)
		h.addResults(teams, row, team1, team2)
	end
	return teams
end

function h.initializeMatchup(teams, team1, team2)
	if not team1 or not team2 then
		return
	end
	h.initializeTeam(teams, team1)
	h.initializeTeam(teams, team2)
	if teams[team1][team2] then
		return
	end
	h.addMatchupZeroes(teams[team1], team1, team2)
	h.addMatchupZeroes(teams[team2], team2, team1)
	return
end

function h.addMatchupZeroes(team1tbl, team1, team2)
	team1tbl[team2] = {
		wgames = 0,
		lgames = 0,
		wins = 0,
		losses = 0,
		ties = 0,
		team2 = team2,
		link = h.getLink(team1, team2)
	}
end

function h.getLink(team1, team2)
	if not SHOW_LINKS then return nil end
	return util_form.makeTableCellFilterLink(FORM_INFO, {team1, team2}, 'crossbox-match-link')
end

function h.initializeTeam(tbl, team)
	if tbl[team] then
		return
	end
	tbl[#tbl+1] = team
	tbl[team] = { wgames = 0, lgames = 0, wins = 0, losses = 0, ties = 0, team = team }
	return
end

function h.addResults(teams, row, team1, team2)
	if not team1 or not team2 then
		return
	end
	local results = {
		[team1] = h.getResults('1', '2', row),
		[team2] = h.getResults('2', '1', row)
	}
	local opponents = { [team1] = team2, [team2] = team1 }
	for team, data in pairs(results) do
		for k, v in pairs(data) do
			teams[team][opponents[team]][k] = teams[team][opponents[team]][k] + v
			teams[team][k] = teams[team][k] + v
		end
	end
	return
end

function h.getResults(n, vs, row)
	local lossesFromFF = row.FF == 0 and 1 or 0
	return {
		wins = row.Winner == n and 1 or 0,
		losses = row.Winner == vs and 1 or 0 + lossesFromFF,
		ties = row.Winner == '0' and row.FF ~= 0 and 1 or 0,
		wgames = row['Team' .. n .. 'Score'],
		lgames = row['Team' .. vs .. 'Score']
	}
end

function h.addGroupDataToTeams(data, groupresult)
	local dict = util_cargo.makeConstDict(groupresult, 'Team', 'GroupDisplay')
	for _, team in ipairs(data) do
		data[team].group = dict[team]
	end
end

function h.getTeamOrder(teamlist, groupresult, onlygroup)
	if teamlist then
		return util_map.split(teamlist, sep, m_team.teamlinkname)
	elseif groupresult then
		if onlygroup then
			for k, row in ipairs(groupresult) do
				if row.GroupName ~= onlygroup then
					groupresult[k] = false
				end
			end
			util_table.removeFalseEntries(groupresult)
		end
		return util_table.arrayFromField(groupresult, 'Team')
	else
		return nil
	end
end

function h.sortData(tbl, teamlist)
	if teamlist then
		local onlyteams = util_table.hash(teamlist)
		for k, v in ipairs(tbl) do
			if not onlyteams[v] then
				tbl[k] = false
			end
		end
		util_table.removeFalseEntries(tbl)
	end
	if teamlist then
		util_table.sortByKeyOrder(tbl, teamlist)
	else
		table.sort(tbl, function(a, b)
			return lang:lc(a) < lang:lc(b)
		end
		)
	end
	return
end

-- ARGS DATA COLLECTION

function h.getDataFromArgs(args)
	local teams = util_args.numberedArgsToTable(args, 'team')
	local groups = args.groups and util_text.split(args.groups, sep) or {}
	util_map.inPlace(teams, m_team.teamlinkname)
	for i, team1 in ipairs(teams) do
		teams[team1] = {
			wgames = 0,
			lgames = 0,
			wins = 0,
			losses = 0,
			ties = 0,
			group = groups[i],
			region = Region(args['region' .. i]),
			team = team1
		}
		for j, team2 in ipairs(teams) do
			local link = h.getLink(team1, team2)
			teams[team1][team2] = { team2 = team2, link = link }
			h.addSeriesScore(teams[team1][team2], teams[team1], args[('t%st%sscore'):format(i, j)])
			h.addGameScore(teams[team1][team2], teams[team1], args[('t%st%sgames'):format(i, j)])
		end
	end
	return teams
end

function h.addSeriesScore(teamtbl, totaltbl, arg)
	if not arg then return end
	local numbers = util_text.split(arg, '%s*-%s*')
	if #numbers < 2 then
		error(('A series arg with value "%s" has incorrect formatting, must be "x - x" or "x - x - x"'):format(arg))
	end
	if #numbers == 3 then
		teamtbl.wins = tonumber(numbers[1] or '') or 0
		teamtbl.ties = tonumber(numbers[2] or '') or 0
		teamtbl.losses = tonumber(numbers[3] or '') or 0
		teamtbl.wgames = 2 * teamtbl.wins + teamtbl.ties
		teamtbl.lgames = 2 * teamtbl.losses + teamtbl.ties
		totaltbl.wgames = totaltbl.wgames + teamtbl.wgames
		totaltbl.lgames = totaltbl.lgames + teamtbl.lgames
	elseif #numbers == 2 then
		teamtbl.wins = tonumber(numbers[1] or '') or 0
		teamtbl.losses = tonumber(numbers[2] or '') or 0
		teamtbl.ties = 0
	end
	totaltbl.wins = totaltbl.wins + teamtbl.wins
	totaltbl.losses = totaltbl.losses + teamtbl.losses
	totaltbl.ties = totaltbl.ties + teamtbl.ties
	return
end

function h.addGameScore(teamtbl, totaltbl, arg)
	if not arg then return end
	local w, l = arg:match('(%d+)%s*-%s*(%d+)')
	if not w or not l then
		error(('A game arg with value "%s" has incorrect formatting, must be "x - x"'):format(arg))
	end
	teamtbl.wgames = tonumber(w or '') or 0
	teamtbl.lgames = tonumber(l or '') or 0
	totaltbl.wgames = totaltbl.wgames + teamtbl.wgames
	totaltbl.lgames = totaltbl.lgames + teamtbl.lgames
	return
end

function h.addZeroes(data)
	for _, team in ipairs(data) do
		for _, team2 in ipairs(data) do
			if not data[team][team2] then
				h.addMatchupZeroes(data[team], team2)
			end
		end
	end
end

-- DISPLAY

function h.makeOutput(data, crossboxtype, usegroups)
	local output = mw.html.create()
	if crossboxtype ~= 'bo1' then
		h.printToggler(output)
	end
	h.printTable(output, data, crossboxtype, usegroups)
	return output
end

function h.printToggler(tbl)
	local div = tbl:tag('div')
		:addClass('toggle-button')
	util_toggle.printOptionFromListTogglers(div, TOGGLES)
	util_html.clear(tbl)
	return
end

function h.printTable(output, data, crossboxtype, usegroups)
	local f = h.getCellFunction(crossboxtype)
	local div = output:tag('div')
		:addClass('crossbox-outer')
	local tbl = div:tag('table')
		:addClass('wikitable2')
		:addClass('plainlinks')
		:addClass('crossbox')
	h.printHeading(tbl, data, crossboxtype, usegroups)
	for _, team in ipairs(data) do
		local tr = h.printRow(tbl, team, data, f, usegroups)
	end
	return output
end

function h.getCellFunction(bestof)
	if bestof == 'bo1' then
		return h.printCellBO1
	elseif bestof == 'bo2' then
		return h.printCellBO2
	else
		return h.printCellBO3
	end
end

function h.printHeading(tbl, data, crossboxtype, usegroups)
	local tr = tbl:tag('tr')
	tr:tag('td')
		:addClass('crossbox-mirror')
		:addClass('crossbox-firstcol')
	if usegroups then
		tr:tag('td')
			:addClass('crossbox-mirror')
	end
	for _, team  in ipairs(data) do
		local th = h.printTeamCell(tr, team, data[team])
		th:addClass('crossbox-teamvs')
			:attr('data-crossbox-highlight-vs', team)
	end
	tr:tag('th'):wikitext(i18n.print('total'))
	tr:tag('th'):wikitext(i18n.print('wr'))
	return
end

function h.printTeamCell(tr, team, teamData)
	local th = tr:tag('th')
		:addClass('crossbox-cell')
	if teamData.region then
		th:wikitext(teamData.region:image())
	end
	th:wikitext(m_team.onlyimage(team,{size=45}))
		:attr('title', m_team.teamname(team))
	return th
end

function h.printRow(tbl, team, data, f, usegroups)
	local tr = tbl:tag('tr')
	util_esports.addTeamHighlighter(tr, team)
	if usegroups then
		tr:tag('th')
			:wikitext(data[team].group)
			:addClass('crossbox-firstcol')
	end
	local th = h.printTeamCell(tr, team, data[team])
	if not usegroups then
		th:addClass('crossbox-firstcol')
	end
	for _, v in ipairs(data) do
		h.printCell(tr, data, team, v, f)
	end
	f(tr, data[team], TOTALCLASSES)
	f(tr, data[team], TOTALCLASSES, true)
	return tr
end

function h.printCell(tr, data, team1, team2, f)
	if team1 == team2 then
		tr:tag('td')
			:addClass('crossbox-mirror')
			:addClass('crossbox-cell')
			:attr('data-crossbox-highlight-vs', team2)
		return
	elseif not data[team1][team2] then
		tr:tag('td')
			:addClass('crossbox-cell')
			:attr('data-crossbox-highlight-vs', team2)
		return
	else
		return f(tr, data[team1][team2], CLASSES)
	end
end

function h.printCellBO1(tr, teamdata, classes, isPercent)
	local w, l = teamdata.wins, teamdata.losses
	local td = h.printRecordCell(tr, teamdata.team2)
	h.addColorClass(td, w, l, 0, classes)
	local div = h.printRecordDiv(td)
	
	if w and l then
		if not isPercent then
			div:wikitext(('%s - %s'):format(w, l))
			div:wikitext(teamdata.link)
		else
			h.printPercent(div, w, l)
		end
	end
	return
end

function h.printCellBO2(tr, teamdata, classes, isPercent)
	local w, l, t = teamdata.wins, teamdata.losses, teamdata.ties
	local tdMatch = h.printRecordCell(tr, teamdata.team2, 'match')
	h.addColorClass(tdMatch, w, l, t, classes)
	local divSeries = h.printRecordDiv(tdMatch)
	
	wg, lg = teamdata.wgames, teamdata.lgames
	local tdGame = h.printRecordCell(tr, teamdata.team2, 'game')
	h.addColorClass(tdGame, wg, lg, 0, classes)
	local divGame = h.printRecordDiv(tdGame)
	
	if not isPercent then
		divSeries:wikitext(('%s - %s - %s'):format(w, t, l), teamdata.link)
		divGame:wikitext(('%s - %s'):format(wg, lg), teamdata.link)
	else
		divSeries:wikitext('-')
		h.printPercent(divGame, wg, lg)
	end
end

function h.printCellBO3(tr, teamdata, classes, isPercent)
	local w, l = teamdata.wins, teamdata.losses
	local tdMatch = h.printRecordCell(tr, teamdata.team2, 'match')
	h.addColorClass(tdMatch, w, l, 0, classes)
	local divMatch = h.printRecordDiv(tdMatch)
	
	wg, lg = teamdata.wgames, teamdata.lgames
	local tdGame = h.printRecordCell(tr, teamdata.team2, 'game')
	h.addColorClass(tdGame, wg, lg, 0, classes)
	local divGame = h.printRecordDiv(tdGame)
	
	if not isPercent then
		divMatch:wikitext(('%s - %s'):format(w, l), teamdata.link)
		divGame:wikitext(('%s - %s'):format(wg, lg), teamdata.link)
	else
		h.printPercent(divMatch, w, l)
		h.printPercent(divGame, wg, lg)
	end
end

function h.printRecordCell(tr, team2, cellType)
	local td = tr:tag('td')
		:attr('data-crossbox-highlight-vs', team2)
	if cellType then
		util_toggle.oflCellClasses(td, TOGGLES, cellType)	
	end
	return td
end

function h.addColorClass(td, w, l, t, lookup)
	w = w or 0
	l = l or 0
	t = t or 0
	if w + l + t == 0 then
		td:addClass(lookup.init)
	else
		td:addClass(lookup[util_math.sign(w-l)])
	end
end

function h.printRecordDiv(td)
	local div = td:tag('div')
		:addClass('table-cell-container')
	return div
end

function h.printPercent(div, w, l)
	div:wikitext(util_esports.winrate(w, l, .01), '%')
end

return p