Module:MatchList

From Leaguepedia | League of Legends Esports Wiki
Jump to: navigation, search

Documentation for this module may be created at Module:MatchList/doc

local util_args = require('Module:ArgsUtil')
local util_cargo = require('Module:CargoUtil')
local util_esports = require('Module:EsportsUtil')
local util_footnote = require('Module:FootnoteUtil')
local util_html = require('Module:HTMLUtil')
local util_table = require('Module:TableUtil')
local util_text = require('Module:TextUtil')
local util_time = require('Module:TimeUtil')
local util_toggle = require('Module:ToggleUtil')
local m_team = require('Module:Team')

local lang = mw.getLanguage('en')

local TZ = { 'CD', 'You', 'PST', 'CET', 'KST' }
local NORMAL_TZ = { 'PST', 'CET', 'KST' }

local HIDDENCLASS = 'matches-hiddentab'

local TAB_TOGGLES = {
	all = {
		show_attr = '.ml-allw',
		hide_attr = '.ml-btn',
		show_class = 'ml-allw',
		hide_class = 'ml-btn',
		hiddenclass = HIDDENCLASS,
	},
	week = {
		show_attr = '.ml-w%s',
		hide_attr = '.ml-btn%s',
		hiddenclass = HIDDENCLASS,
		show_class = 'ml-allw ml-w%s',
		hide_class = 'ml-btn ml-btn%s',
	},
	row = 'ml-allw ml-w%s %s',
	daterange = 'ml-btn ml-btn%s %s',
}

local i18n = {
	results_init = 'Results',
	results = 'Schedule',
	Countdown = 'CD',
	You = 'You',
	PST = 'PST',
	CET = 'CET',
	KST = 'KST',
	Countdown_title = 'Show countdown to series start',
	You_title = 'Show times/dates in local system time',
	PST_title = 'Show times/dates in PST',
	CET_title = 'Show times/dates in CET',
	KST_title = 'Show times/dates in KST',
	helptext = [[Toggle between Results & Schedule to prefer showing match results when available or always show start time. Toggle between CD (countdown), your local time zone, or PST/CET/KST to change time zone display of dates & times.]]
}
local WIDTHS = { 110, 25, 25, 110 }

local RS_TOGGLES = {
	hiddenclass = 'matchlist-rs-hidden',
	order = { 'res', 'sch' },
	displays = {
		res = i18n.results_init,
		sch = i18n.results
	},
}

local TZ_TOGGLES = {
	init = 'You',
	order = { 'CD', 'You', 'PST', 'CET', 'KST' },
	attrs = {
		title = {
			CD = i18n.Countdown_title,
			You = i18n.You_title,
			PST = i18n.PST_title,
			CET = i18n.CET_title,
			KST = i18n.KST_title
		},
	}
}

local HASFLEX = false

local h = {}

-- match cargo
function h.getMatchData(page, args)
	local outergroup = args.outergroup or 'Tab'
	local innergroup = args.innergroup or 'Date'
	local matchResult = util_cargo.queryAndCast(h.makeMatchQuery(page, args))
	local matchData = util_cargo.groupResultOrdered(matchResult, outergroup)
	for i, tab in ipairs(matchData) do
		for j, row in ipairs(tab) do
			h.processMatchRow(row, i, j, innergroup, tab[j-1] or {}, tab[j+1] or {})
		end
	end
	return matchData
end

function h.makeMatchQuery(page, args)
	local query = {
		tables = 'MatchSchedule',
		fields = h.makeMatchFields(args),
		where = h.makeMatchWhere(page, args),
		orderBy = 'N_Page ASC, N_TabInPage ASC, N_MatchInTab ASC',
		types = {
			Winner = 'number',
			Team1Score = 'number',
			Team2Score = 'number',
			FF = 'number',
			N_TabInPage = 'number',
			HasTime = 'boolean'
		},
		limit = 9999,
		groupBy = 'UniqueMatch',
	}
	return query
end

function h.makeMatchFields(args)
	local tbl = {
			'Team1',
			'Team2',
			'Team1Final',
			'Team2Final',
			'Winner',
			'Team1Score',
			'Team2Score',
			'FF',
			'Tab',
			'N_TabInPage',
			'UniqueMatch',
			'DateTime_UTC=UTC',
			'DateTime_PST=PST',
			'DateTime_KST=KST',
			'DateTime_CET=CET',
			'HasTime',
			'OverviewPage',
			'MatchDay',
			'Stream',
			'IsFlexibleStart'
		}
	if not util_args.castAsBool(args.nofootnotes) then
		util_table.mergeArrays(tbl, { 'Team1Footnote', 'Team2Footnote', 'Footnote' })
	end
	return tbl
end

function h.makeMatchWhere(page, args)
	local tbl = {
		('OverviewPage="%s"'):format(page)
	}
	if args.team then
		local teamlink = m_team.teamlinkname(args.team)
		tbl[#tbl+1] = ('(Team1Final="%s" OR Team2Final="%s")'):format(teamlink, teamlink)
	end
	return util_table.concat(tbl,' AND ')
end

function h.processMatchRow(row, i, j, innergroup, lastrow, nextrow)
	if row.UTC then
		h.processDateTime(row, i, j, lastrow)
	else
		h.setDatesTBD(row)
	end
	if row.FF then
		row.Team1Score = row.FF == 2 and 'W' or 'FF'
		row.Team2Score = row.FF == 1 and 'W' or 'FF'
	end
	if innergroup then
		row.innergroup = row[innergroup]
	end
	if nextrow.MatchDay and nextrow.MatchDay ~= row.MatchDay then
		row.NewDay = true
	end
	if util_args.castAsBool(row.IsFlexibleStart) then
		HASFLEX = true
	end
	return row
end

function h.processDateTime(row, i, j, lastrow)
	for _, tz in ipairs(NORMAL_TZ) do
		row[tz .. '_Time'] = row[tz]:match('(%d%d:%d%d):%d%d')
		
		local date = lang:formatDate('D Y-m-d',row[tz])
		row[tz .. '_Date'] = date
		row[tz .. '_isNewDate'] = date ~= lastrow[tz .. '_Date']
	end
	if row.HasTime then
		h.setTimesYou(row, row.UTC, i, j)
	else
		h.setTimesTBD(row)
	end
end

function h.setTimesYou(row, UTC, i, j)
	row.You_Time = util_time.timeInLocal(UTC)
	row.CD_Time = util_time.countdown(UTC, h.getCountdownSettings(row, i, j))
	row.You_Date = util_time.dateInLocal(UTC)
	row.You_Date_Range = util_time.dateInLocalMatches(UTC)
end

function h.getCountdownSettings(row, i, j)
	if row.Stream then
		return {
			options = { 'matches-format', 'no-leading-zeros' },
			data_end = 'toggle',
			default = '<span class="matchlist-streamlink-icon"></span>',
			i = ('%s_%s'):format(i, j)
		}
	else
		return {
			options = { 'matches-format', 'no-leading-zeros' }
		}
	end
end

function h.setTimesTBD(row)
	for _, tz in ipairs(TZ) do
		row[tz .. '_Time'] = 'TBD'
	end
	row.You_Date = 'TBD'
	row.You_Date_Range = 'TBD'
	return
end

function h.setDatesTBD(row)
	for _, tz in ipairs(TZ) do
		row[tz .. '_Date'] = 'TBD'
	end
	row.You_Date = 'TBD'
	row.You_Date_Range = 'TBD'
	h.setTimesTBD(row)
end

-- print
function h.makeOutput(data, thisweek)
	util_footnote.initializeAllFootnotes()
	local tbl = mw.html.create('div'):attr('id','matchlist')
	if HASFLEX then
		h.addFlexNote(tbl)
	end
	util_toggle.printSectionToggler(tbl, TAB_TOGGLES.all)
	h.addToggles(tbl)
	for i, tab in ipairs(data) do
		h.printTab(tbl, tab, thisweek == i)
	end
	util_footnote.printFootnotes(tbl)
	return tbl
end	

function h.addToggles(tbl)
	h.addResultsToggle(tbl)
	h.addTZToggle(tbl)
	tbl:tag('div'):css('clear','left')
	return
end

function h.addResultsToggle(tbl)
	local div = tbl:tag('div')
		:addClass('toggle-button')
	util_toggle.printOptionFromListTogglers(div, RS_TOGGLES)
end

function h.addTZToggle(tbl)
	local div = tbl:tag('div'):addClass('toggle-button')
	util_toggle.printOptionFromListTogglers(div, TZ_TOGGLES)
	div:wikitext('|')
	util_html.printHelpText(div, i18n.helptext)
end

function h.addFlexNote(tbl)
	tbl:wikitext(mw.getCurrentFrame():expandTemplate{title='FlexNotice',args={''}})
end

function h.printTab(tbl, tab, isfocused)
	local tbl_tab = tbl:tag('table')
		:addClass('wikitable')
		:addClass('matchlist')
	h.addTabHeader(tbl_tab, tab.index, tab.name, isfocused)
	h.addDateRange(
		tbl_tab,
		tab,
		h.getDateRangeToggleClass(tab.index, isfocused)
	)
	util_html.makeEmptyWidthRowPX(tbl_tab, WIDTHS)
	local toggle_class = h.getRowToggleClass(tab.index, isfocused)
	for k, row in ipairs(tab) do
		h.addFullRow(tbl_tab, row, toggle_class, k == 1)
	end
	return
end

function h.addTabHeader(tbl, i, name, isfocused)
	local data = mw.clone(TAB_TOGGLES.week)
	util_toggle.prepDataByWeek(data, i)
	data.initshown = isfocused
	util_toggle.printToggleHeader(tbl, 4, name, data)
	return
end

function h.addDateRange(tbl, tab_data, daterowclass)
	local tr = tbl:tag('tr')
		:addClass(daterowclass)
	local td = tr:tag('td')
		:attr('colspan',4)
	local n = #tab_data
	for _, tz in ipairs(NORMAL_TZ) do
		h.addNormalTZDatesToRangeCell(
			td:tag('span'),
			tz,
			tab_data[1][tz .. '_Date'],
			tab_data[n][tz .. '_Date']
		)
	end
	h.addYouTZDatesToRangeCell(
		td:tag('span'),
		tab_data[1].You_Date_Range,
		tab_data[n].You_Date_Range
	)
end

function h.addNormalTZDatesToRangeCell(span, tz, text1, text2)
	text1 = text1 ~= 'TBD' and lang:formatDate('D j M', text1) or text1
	text2 = text2 ~= 'TBD' and lang:formatDate('D j M', text2) or text2
	span:addClass('matchlist-daterange') -- for css, toggle displays handled through util below
		:wikitext(text1)
	if text2 ~= text1 then
		span:wikitext(' - ')
		span:wikitext(text2)
	end
	util_toggle.oflCellClasses(span, TZ_TOGGLES, tz)
	return
end

function h.addYouTZDatesToRangeCell(span, text1, text2)
	-- this is a special case because we need extra classes for JS to do its thing
	-- because we don't know if the dates are the same or not
	-- given that this is already special, we may as well do You and CD as one instead of splitting
	util_toggle.oflCellClasses(span, TZ_TOGGLES, 'You')
	span:addClass('matchlist-daterange')
		:addClass('matchlist-daterange-you')
		:addClass(TZ_TOGGLES.classes.CD) -- manually add this one because it's the same as YOU
	span:tag('span')
		:addClass('matchlist-daterange-you-1')
		:wikitext(text1)
	span:tag('span')
		:addClass('matchlist-daterange-you-hyphen')
		:wikitext(' - ')
	span:tag('span')
		:addClass('matchlist-daterange-you-hyphen')
		:wikitext(text2)
	return
end

function h.getDateRangeToggleClass(i, isfocused)
	return TAB_TOGGLES.daterange:format(i, not isfocused and '' or HIDDENCLASS)
end

function h.getRowToggleClass(i, isfocused)
	return TAB_TOGGLES.row:format(i, isfocused and '' or HIDDENCLASS)
end

function h.addFullRow(tbl_tab, row, toggle_class, isfirst)
	h.addDateRow(tbl_tab, row, toggle_class, isfirst)
	local tr = tbl_tab:tag('tr')
		:addClass(toggle_class)
	if row.UTC then
		tr:attr('data-date',util_time.strToDateStr(row.UTC))
	end
	if row.NewDay then
		tr:addClass('matchlist-newday')
	end
	if util_args.castAsBool(row.IsFlexibleStart) then
		tr:addClass('matchlist-flex')
	end
	h.printTeam1(tr, row)
	h.printMiddle(tr, row)
	h.printTeam2(tr, row)
end

function h.addDateRow(tbl, row, toggle_class, isfirst)
	for _, tz in ipairs(NORMAL_TZ) do
		if row[tz .. '_isNewDate'] then
			local tr = tbl:tag('tr')
				:addClass(toggle_class)
			h.addNormalTZDateToRow(tr, tz, row[tz .. '_Date'])
		end
	end
	local tr = tbl:tag('tr')
		:addClass(toggle_class)
	h.addYouTZDateToRow(tr, row.You_Date)
	if isfirst then
		tr:attr('data-isfirst','yes')
	end
	return
end

function h.addNormalTZDateToRow(tr, tz, text)
	tr:addClass('matchlist-date')
	util_toggle.oflCellClasses(tr, TZ_TOGGLES, tz)
	local td = tr:tag('td')
				:attr('colspan','4')
	td:wikitext(text)
	return
end

function h.addYouTZDateToRow(tr, text)
	tr:addClass('matchlist-date')
		:addClass('matchlist-you-date') -- to select and remove the 'You' rows
		:addClass(TZ_TOGGLES.classes.CD)
	util_toggle.oflCellClasses(tr, TZ_TOGGLES, 'You')
	local td = tr:tag('td')
		:attr('colspan','4')
	td:wikitext(text)
	return td
end

function h.printTeam1(tr, row)
	local td = tr:tag('td')
		:addClass('matchlist-team1')
	util_esports.addTeamHighlighter(td, row.Team1Final)
	util_footnote.tagFootnote(td, row.Team1Footnote)
	td:wikitext(m_team.leftshort(row.Team1))
	if row.Winner == 1 then
		td:addClass('matchlist-winner-team')
	elseif row.Winner == 0 then
		td:addClass('matchlist-tied-team')
	end
	return
end

function h.printTeam2(tr, row)
	local td = tr:tag('td')
		:addClass('matchlist-team2')
	util_esports.addTeamHighlighter(td, row.Team2Final)
	td:wikitext(m_team.rightshort(row.Team2))
	util_footnote.tagFootnotes(td, h.team2Footnotes(row))
	if row.Winner == 2 then
		td:addClass('matchlist-winner-team')
	elseif row.Winner == 0 then
		td:addClass('matchlist-tied-team')
	end
	return
end

function h.team2Footnotes(row)
	local tbl = { row.Team2Footnote, row.Footnote }
	util_table.removeFalseEntries(tbl, 2)
	return tbl
end

function h.printMiddle(tr, row)
	if (row.Team1Score and row.Team2Score) or row.Winner then
		h.printScore(tr, row)
		h.printTime(tr, row, true)
	else
		h.printTime(tr, row)
	end
end

function h.printScore(tr, row, suppresstoggle)
	local td1 = h.printOneScore(tr, row.Team1Score, row.Team1Final)
	local td2 = h.printOneScore(tr, row.Team2Score, row.Team2Final)
	if row.Winner == 1 then
		td1:addClass('matchlist-winner-score')
	elseif row.Winner == 2 then
		td2:addClass('matchlist-winner-score')
	elseif row.Winner == 0 then
		td1:addClass('matchlist-tied-score')
		td2:addClass('matchlist-tied-score')
	end
	if not suppresstoggle then
		util_toggle.oflCellClasses(td1, RS_TOGGLES, 'res')
		util_toggle.oflCellClasses(td2, RS_TOGGLES, 'res')
	end
	return
end

function h.printOneScore(tr, score, team)
	local td = tr:tag('td'):wikitext(score)
		:addClass('matchlist-score')
	util_esports.addTeamHighlighter(td, team)
	return td
end

function h.printTime(tr, row, usetoggle)
	local td = tr:tag('td')
		:attr('colspan','2')
		:addClass('matchlist-time-cell')
		:addClass('plainlinks')
	if usetoggle then
		util_toggle.oflCellClasses(td, RS_TOGGLES, 'sch')
	end
	for _, tz in ipairs(TZ) do
		local span = td:tag('span')
		if row.Stream then
			span:wikitext('[', row.Stream, ' ', row[tz .. '_Time'], ']')
		else
			span:wikitext(row[tz .. '_Time'])
		end
		util_toggle.oflCellClasses(span, TZ_TOGGLES, tz)
	end
	return
end

local p = {}
function p.main(frame)
	local args = util_args.merge(true)
	local overviewPage = util_esports.getOverviewPage(args.page)
	local matchData = h.getMatchData(overviewPage, args)
	local this = tonumber(args.This or '')
	return h.makeOutput(matchData, this)
end

function p.printSingleTab(args)
	local args = util_args.merge(true)
	local overviewPage = util_esports.getOverviewPage(args.page)
	local data_tab = h.getMatchData(overviewPage, args)
	local tbl_tab = mw.html.create('table')
		:addClass('wikitable')
		:addClass('matchlist')
	util_html.makeColspanHeader(tbl_tab, args.display, 4)
	util_html.makeEmptyWidthRowPX(tbl_tab, WIDTHS)
	local lastgroup
	for k, row in ipairs(data_tab[1] or {}) do
		if row.innergroup ~= lastgroup then
			tbl_tab:tag('tr'):addClass('matchlist-date')
				:tag('td'):attr('colspan',4):wikitext(row.innergroup)
			lastgroup = row.innergroup
		end
		local tr = tbl_tab:tag('tr')
		h.printTeam1(tr, row)
		h.printScore(tr, row, true)
		h.printTeam2(tr, row)
	end
	return tbl_tab
end

return p