// !! Note !! To support old TVs, no EcmaScript 5 or newer here !! // Check it here - https://eslint.org/demo (function (window) { var $ = window.jQuery, GAME_TIMER_STATUS = { NONE: 'NONE', MESSAGE: 'MESSAGE', ONGOING: 'ONGOING', ENDED: 'ENDED' }, TIMER_TYPE = { PAUSE: 'PAUSE', GROUP_GAME: 'GROUP_GAME', PLAYOFF_GAME: 'PLAYOFF_GAME', BREAK: 'BREAK', MESSAGE: 'MESSAGE' }, LOADER_STATUS = { OK: 'OK', IN_PROGRESS: 'IN_PROGRESS', FAILED: 'FAILED' }, TIMER_MODE = { STANDALONE: 'STANDALONE', // Standalone display screen EMBEDDED: 'EMBEDDED' // Block in LBPF WP page }, TIMER_DATA_SOURCE = { NETWORK: 'NETWORK', PARENT: 'PARENT' }, config = { lang: 'lv', timerDataUrl: 'https://gebook.app/page/client/jenoti/v1/bpong/timer', currentTimeUrl: 'https://gebook.app/page/client/jenoti/v1/current-time', soundsUrl: '/timer2/sounds/', timerId: 'main', clockFormat: 'HH:mm:ss', timerLoadInterval: 10, mode: TIMER_MODE.STANDALONE, hasSounds: false, displayFnc: null, statusFnc: null, onLoadFnc: null, onTickFnc: null }, tickerHandle = null, loaderHandle = null, gameTimer = {}, isPopup = false, hasDisplayFnc = false, hasStatusFnc = false, hasOnLoadFnc = false, hasOnTickFnc = false, clockAdjustSeconds = 0; function getEmptyGameTimerData() { return { id: null, client: { id: "jenoti", name: "Jenoti", timeZone: "Europe/Riga" }, description: { title: null }, status: GAME_TIMER_STATUS.NONE, tournament: null, optionList: [ "SHOW_TEAM_NAMES" ], startTime: null, timerItemList: [] } } function readTimerIdFromUrl() { const urlParams = new URLSearchParams(window.location.search); return urlParams.get('timerId'); } function readLangFromUrl() { const urlParams = new URLSearchParams(window.location.search); return urlParams.get('lang'); } function init(newConfig) { const timerIdFromUrl = readTimerIdFromUrl(); if (timerIdFromUrl) { config.timerId = timerIdFromUrl; } const langFromUrl = readLangFromUrl(); if (langFromUrl) { config.lang = langFromUrl; } // $.extend(config, newConfig); $.ajaxSetup({ cache: false, traditional: true }); _.templateSettings.variable = 'data'; // hasDisplayFnc = _.isFunction(config.displayFnc); hasStatusFnc = _.isFunction(config.statusFnc); hasOnLoadFnc = _.isFunction(config.onLoadFnc); hasOnTickFnc = _.isFunction(config.onTickFnc); // gameTimer = initGameTimer(getEmptyGameTimerData()); if (config.mode === TIMER_MODE.STANDALONE && window.opener) { isPopup = true; } else { checkLoader(); } startTicker(); // $.get(config.currentTimeUrl) .done(function (data) { clockAdjustSeconds = moment.duration(moment(data).diff(moment.utc())).asWholeSeconds(); console.log('clockAdjustSeconds', clockAdjustSeconds); }); } function checkLoader() { window.clearInterval(loaderHandle); if (config.timerLoadInterval) { loaderHandle = window.setInterval(loadFromServer, config.timerLoadInterval * 1000); } loadFromServer(); } function loadFromServer() { if (hasStatusFnc) { config.statusFnc(LOADER_STATUS.IN_PROGRESS, TIMER_DATA_SOURCE.NETWORK, gameTimer); } $.ajax({ url: config.timerDataUrl + '/' + config.timerId + '?lang=' + config.lang, type: 'GET', dataType: 'json' }) .done(function (data) { //console.log('Ajax ok', data, config, gameTimer); setGameTimerData(data); if (hasStatusFnc) { config.statusFnc(LOADER_STATUS.OK, TIMER_DATA_SOURCE.NETWORK, gameTimer); } if (hasOnLoadFnc) { config.onLoadFnc(gameTimer); } }) .fail(function (jqXHR) { //console.log('Ajax fail', jqXHR, config, gameTimer); if (hasStatusFnc) { config.statusFnc(LOADER_STATUS.FAILED, TIMER_DATA_SOURCE.NETWORK, gameTimer); } }); } function setGameTimerData(gameTimerData) { gameTimer = initGameTimer(gameTimerData); } function startTicker() { window.clearInterval(tickerHandle); tickerHandle = window.setInterval(onTick, 1000); onTick(); } function onTick() { if (isPopup) { if (hasStatusFnc) { config.statusFnc(LOADER_STATUS.IN_PROGRESS, TIMER_DATA_SOURCE.PARENT, gameTimer); } var parentGameTimer = window.opener && window.opener.bpongTimer && _.isFunction(window.opener.bpongTimer.gameTimer) ? window.opener.bpongTimer.gameTimer() : null; if (parentGameTimer) { gameTimer = parentGameTimer; if (hasStatusFnc) { config.statusFnc(LOADER_STATUS.OK, TIMER_DATA_SOURCE.PARENT, gameTimer); } } else { gameTimer = recalculateGameTimer(gameTimer); if (hasStatusFnc) { config.statusFnc(LOADER_STATUS.FAILED, TIMER_DATA_SOURCE.PARENT, gameTimer); } } } else { gameTimer = recalculateGameTimer(gameTimer); } if (hasDisplayFnc || config.hasSounds) { var displayData = getDisplayData(gameTimer); if (hasDisplayFnc) { config.displayFnc(displayData, gameTimer); } checkIfSoundIsNeeded(displayData); } if (hasOnTickFnc) { config.onTickFnc(gameTimer); } } function initGameTimer(gameTimerData) { var gt = { dataOriginal: gameTimerData, data: !gameTimerData ? null : _.cloneDeep(gameTimerData), now: null, startTime: null, // Tournament start time. Indicates if timers are processed at all. targetTime: null, currentTimerIndex: null, currentDuration: null, getCurrentTimer: function () { return this.currentTimerIndex === null ? null : this.data.timerItemList[this.currentTimerIndex]; }, getNextTimer: function () { if (this.currentTimerIndex === null && this.data.timerItemList.length > 0) { return this.data.timerItemList[0]; } if (this.currentTimerIndex >= 0 && this.currentTimerIndex < this.data.timerItemList.length - 1) { return this.data.timerItemList[this.currentTimerIndex + 1]; } return null; } }; // if (!_.isArray(gt.data.timerItemList)) { gt.data.timerItemList = []; } if (!gt.data.status) { gt.data.status = GAME_TIMER_STATUS.NONE; } if (!_.isInteger(gt.data.utcOffsetMinutes)) { gt.data.utcOffsetMinutes = moment().utcOffset(); } // gt.now = moment.utc().tz(gt.data.client.timeZone).add(clockAdjustSeconds, 's'); gt.startTime = moment.utc(gt.data.startTime).tz(gt.data.client.timeZone); gt.targetTime = moment(gt.startTime); if (!gt.data.startTime || !gt.startTime.isValid() || !gt.now.isValid()) { gt.data.startTime = null; gt.startTime = null; gt.now = null; } if (!gt.data.startTime && gt.data.status === GAME_TIMER_STATUS.ONGOING) { gt.data.status = GAME_TIMER_STATUS.NONE; } return recalculateGameTimer(gt); } function recalculateGameTimer(gt) { gt.now = moment.utc().tz(gt.data.client.timeZone).add(clockAdjustSeconds, 's'); if (gt.data.status !== GAME_TIMER_STATUS.ONGOING) { return gt; } if (gt.now.isBefore(gt.startTime)) { return calculateDiff(gt); } if (gt.currentTimerIndex === null && gt.data.timerItemList.length > 0) { gt.currentTimerIndex = 0; gt.targetTime.add(gt.data.timerItemList[0].durationSeconds, 's'); } while (gt.now.isAfter(gt.targetTime) && gt.currentTimerIndex < gt.data.timerItemList.length - 1) { gt.targetTime.add(gt.data.timerItemList[++gt.currentTimerIndex].durationSeconds, 's'); } if (gt.now.isBefore(gt.targetTime)) { return calculateDiff(gt); } // now is after all the timers -> tournament has been ended gt.data.status = GAME_TIMER_STATUS.ENDED; gt.targetTime = null; gt.currentTimerIndex = null; return calculateDiff(gt); } function calculateDiff(gt) { if (gt.targetTime) { var duration = moment.duration(gt.targetTime.diff(gt.now)).add(1, 's'); gt.currentDuration = { duration: duration, seconds: duration.asWholeSeconds(), formatted: duration.formatTimerStr() } } else { gt.currentDuration = null; } return gt; } function getNextTimerText(timers, currentTimerIndex) { if (timers.length > currentTimerIndex + 1) { var nextTimer = timers[currentTimerIndex + 1]; if (nextTimer.type === TIMER_TYPE.GROUP_GAME || nextTimer.type === TIMER_TYPE.PLAYOFF_GAME) { var texts = getTimerTexts(timers, currentTimerIndex + 1); return texts.mainMessage + (texts.subMessage ? ' (' + texts.subMessage + ')' : '') + ' sāksies pēc'; } } return ''; } function findMaxPlayOffRoundIndex(timers) { var maxRoundIndex = 0; _.forEach(timers, function (timer) { if (timer.type === TIMER_TYPE.PLAYOFF_GAME) { maxRoundIndex = Math.max(maxRoundIndex, timer.roundIndex); } }); return maxRoundIndex; } function getTimerMainText(timers, currentTimerIndex) { var timer = timers[currentTimerIndex]; switch (timer.type) { case TIMER_TYPE.PAUSE: return 'Pārtraukums starp kārtām'; case TIMER_TYPE.BREAK: case TIMER_TYPE.MESSAGE: return 'Pārtraukums'; case TIMER_TYPE.GROUP_GAME: return '' + (timer.roundIndex + 1) + '. grupas spēle'; case TIMER_TYPE.PLAYOFF_GAME: var maxPlayOffRoundIndex = findMaxPlayOffRoundIndex(timers); switch (maxPlayOffRoundIndex - timer.roundIndex) { case 0: return 'Fināls'; case 1: return 'Pusfināls'; case 2: return 'Ceturtdaļfināls'; } return '' + (timer.roundIndex + 1) + '. play-off kārta'; } return ''; } function getTimerSubText(timers, currentTimerIndex) { var timer = timers[currentTimerIndex]; var text1 = ''; var text2 = ''; switch (timer.type) { case TIMER_TYPE.GROUP_GAME: text1 = timer.tableFrom && timer.tableTo ? 'grupas "' + (timer.tableFrom + 1) + '" līdz "' + (timer.tableTo + 1) + '"' : ''; text2 = timer.roundSubIndex ? '' + (timer.roundSubIndex + 1) + '. spēle' : ''; break; case TIMER_TYPE.PLAYOFF_GAME: text1 = timer.tableFrom && timer.tableTo ? 'komandas ' + (2 * timer.tableFrom + 1) + ' līdz ' + ((timer.tableTo + 1) * 2) + '' : ''; text2 = timer.roundSubIndex ? '' + (timer.roundSubIndex + 1) + '. spēle' : ''; break; } return text1 + (text1 && text2 ? ', ' : '') + text2; } function getTimerTexts(timers, currentTimerIndex) { var timer = timers[currentTimerIndex], messages = { mainMessage: timer.mainMessage ? timer.mainMessage : getTimerMainText(timers, currentTimerIndex), subMessage: timer.subMessage ? timer.subMessage : getTimerSubText(timers, currentTimerIndex) }; if (!messages.subMessage && (timer.type === TIMER_TYPE.PAUSE || timer.type === TIMER_TYPE.BREAK)) { messages.subMessage = timer.subMessage ? timer.subMessage : getNextTimerText(timers, currentTimerIndex); } return messages; } function formatClock(time) { return time.format(config.clockFormat); } function getDisplayData(gt) { var displayData = { gt: gt, mainMessage: '', // Message to display subMessage: '', // Description for the message center: '', // Main countdown text clock: formatClock(!gt || !gt.now ? moment() : gt.now) }; if (!gt || !gt.data || !gt.data.status) { return displayData; } switch (gt.data.status) { case GAME_TIMER_STATUS.NONE: break; case GAME_TIMER_STATUS.MESSAGE: displayData.mainMessage = gt.data.description && gt.data.description.statusMessageText ? gt.data.description.statusMessageText : 'Pārtraukums'; break; case GAME_TIMER_STATUS.ENDED: displayData.mainMessage = gt.data.description && gt.data.description.statusEndedText ? gt.data.description.statusEndedText : 'Laiks beidzies'; displayData.center = '0'; break; case GAME_TIMER_STATUS.ONGOING: if (gt.currentTimerIndex != null) { var timerMessages = getTimerTexts(gt.data.timerItemList, gt.currentTimerIndex); displayData.mainMessage = timerMessages.mainMessage; displayData.subMessage = timerMessages.subMessage; } else { if (gt.data.timerItemList.length > 0) { displayData.mainMessage = getNextTimerText(gt.data.timerItemList, -1); } else { displayData.mainMessage = 'Spēle sāksies pēc'; } } if (gt.currentDuration) { displayData.center = gt.currentDuration.formatted; } } displayData.mainMessage = displayData.mainMessage ? displayData.mainMessage : ''; displayData.subMessage = displayData.subMessage ? displayData.subMessage : ''; displayData.center = displayData.center ? displayData.center : ''; return displayData; } function checkIfSoundIsNeeded(displayData) { if (!config.hasSounds || !window.bpongTimerSounds) { return; } if (!displayData || !displayData.gt || !displayData.gt.data || displayData.gt.data.status != GAME_TIMER_STATUS.ONGOING) { return; } if (!displayData.gt.currentDuration || !displayData.gt.currentDuration.seconds) { return; } window.bpongTimerSounds.ticker(displayData); } window.bpongTimer = { GAME_TIMER_STATUS: GAME_TIMER_STATUS, TIMER_TYPE: TIMER_TYPE, LOADER_STATUS: LOADER_STATUS, TIMER_MODE: TIMER_MODE, TIMER_DATA_SOURCE: TIMER_DATA_SOURCE, // gameTimer: function () { return gameTimer; }, config: function () { return config; }, setSoundsEnabled: function (val) { config.hasSounds = val === true; }, setGameTimerData: setGameTimerData, readTimerIdFromUrl: readTimerIdFromUrl, readLangFromUrl: readLangFromUrl, init: init, loadFromServer: loadFromServer, initGameTimer: initGameTimer, recalculateGameTimer: recalculateGameTimer, calculateDiff: calculateDiff, getDisplayData: getDisplayData, formatClock: formatClock, getEmptyGameTimerData: getEmptyGameTimerData, getTimerMainText: getTimerMainText, getTimerSubText: getTimerSubText, getTimerTexts: getTimerTexts, findMaxPlayOffRoundIndex: findMaxPlayOffRoundIndex }; return window.bpongTimer; })(window);