2020-08-05 09:00:24 +01:00
|
|
|
import inputManager from 'inputManager';
|
|
|
|
import browser from 'browser';
|
|
|
|
import globalize from 'globalize';
|
|
|
|
import connectionManager from 'connectionManager';
|
|
|
|
import scrollHelper from 'scrollHelper';
|
|
|
|
import serverNotifications from 'serverNotifications';
|
|
|
|
import loading from 'loading';
|
|
|
|
import datetime from 'datetime';
|
|
|
|
import focusManager from 'focusManager';
|
|
|
|
import playbackManager from 'playbackManager';
|
|
|
|
import * as userSettings from 'userSettings';
|
|
|
|
import imageLoader from 'imageLoader';
|
|
|
|
import events from 'events';
|
|
|
|
import layoutManager from 'layoutManager';
|
|
|
|
import itemShortcuts from 'itemShortcuts';
|
|
|
|
import dom from 'dom';
|
|
|
|
import 'css!./guide.css';
|
|
|
|
import 'programStyles';
|
|
|
|
import 'material-icons';
|
|
|
|
import 'scrollStyles';
|
|
|
|
import 'emby-programcell';
|
|
|
|
import 'emby-button';
|
|
|
|
import 'paper-icon-button-light';
|
|
|
|
import 'emby-tabs';
|
|
|
|
import 'emby-scroller';
|
|
|
|
import 'flexStyles';
|
|
|
|
import 'webcomponents';
|
|
|
|
|
|
|
|
function showViewSettings(instance) {
|
|
|
|
import('guide-settings-dialog').then(({default: guideSettingsDialog}) => {
|
|
|
|
guideSettingsDialog.show(instance.categoryOptions).then(function () {
|
|
|
|
instance.refresh();
|
2019-01-10 15:39:37 +03:00
|
|
|
});
|
2020-08-05 09:00:24 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateProgramCellOnScroll(cell, scrollPct) {
|
|
|
|
let left = cell.posLeft;
|
|
|
|
if (!left) {
|
|
|
|
left = parseFloat(cell.style.left.replace('%', ''));
|
|
|
|
cell.posLeft = left;
|
|
|
|
}
|
|
|
|
let width = cell.posWidth;
|
|
|
|
if (!width) {
|
|
|
|
width = parseFloat(cell.style.width.replace('%', ''));
|
|
|
|
cell.posWidth = width;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const right = left + width;
|
|
|
|
const newPct = Math.max(Math.min(scrollPct, right), left);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const offset = newPct - left;
|
|
|
|
const pctOfWidth = (offset / width) * 100;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let guideProgramName = cell.guideProgramName;
|
|
|
|
if (!guideProgramName) {
|
|
|
|
guideProgramName = cell.querySelector('.guideProgramName');
|
|
|
|
cell.guideProgramName = guideProgramName;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let caret = cell.caret;
|
|
|
|
if (!caret) {
|
|
|
|
caret = cell.querySelector('.guide-programNameCaret');
|
|
|
|
cell.caret = caret;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (guideProgramName) {
|
|
|
|
if (pctOfWidth > 0 && pctOfWidth <= 100) {
|
|
|
|
guideProgramName.style.transform = 'translateX(' + pctOfWidth + '%)';
|
|
|
|
caret.classList.remove('hide');
|
|
|
|
} else {
|
|
|
|
guideProgramName.style.transform = 'none';
|
|
|
|
caret.classList.add('hide');
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
}
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let isUpdatingProgramCellScroll = false;
|
|
|
|
function updateProgramCellsOnScroll(programGrid, programCells) {
|
|
|
|
if (isUpdatingProgramCellScroll) {
|
|
|
|
return;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
isUpdatingProgramCellScroll = true;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
requestAnimationFrame(function () {
|
|
|
|
const scrollLeft = programGrid.scrollLeft;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const scrollPct = scrollLeft ? (scrollLeft / programGrid.scrollWidth) * 100 : 0;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:13:46 +01:00
|
|
|
for (const programCell of programCells) {
|
|
|
|
updateProgramCellOnScroll(programCell, scrollPct);
|
2020-08-05 09:00:24 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
isUpdatingProgramCellScroll = false;
|
|
|
|
});
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function onProgramGridClick(e) {
|
|
|
|
if (!layoutManager.tv) {
|
|
|
|
return;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const programCell = dom.parentWithClass(e.target, 'programCell');
|
|
|
|
if (programCell) {
|
|
|
|
let startDate = programCell.getAttribute('data-startdate');
|
|
|
|
let endDate = programCell.getAttribute('data-enddate');
|
|
|
|
startDate = datetime.parseISO8601Date(startDate, { toLocal: true }).getTime();
|
|
|
|
endDate = datetime.parseISO8601Date(endDate, { toLocal: true }).getTime();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const now = new Date().getTime();
|
|
|
|
if (now >= startDate && now < endDate) {
|
|
|
|
const channelId = programCell.getAttribute('data-channelid');
|
|
|
|
const serverId = programCell.getAttribute('data-serverid');
|
|
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
|
|
playbackManager.play({
|
|
|
|
ids: [channelId],
|
|
|
|
serverId: serverId
|
|
|
|
});
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function Guide(options) {
|
|
|
|
const self = this;
|
|
|
|
let items = {};
|
|
|
|
|
|
|
|
self.options = options;
|
|
|
|
self.categoryOptions = { categories: [] };
|
|
|
|
|
|
|
|
// 30 mins
|
|
|
|
const cellCurationMinutes = 30;
|
|
|
|
const cellDurationMs = cellCurationMinutes * 60 * 1000;
|
|
|
|
const msPerDay = 86400000;
|
|
|
|
|
|
|
|
let currentDate;
|
|
|
|
let currentStartIndex = 0;
|
|
|
|
let currentChannelLimit = 0;
|
|
|
|
let autoRefreshInterval;
|
|
|
|
let programCells;
|
|
|
|
let lastFocusDirection;
|
|
|
|
let programGrid;
|
|
|
|
|
|
|
|
self.refresh = function () {
|
|
|
|
currentDate = null;
|
|
|
|
reloadPage(options.element);
|
|
|
|
restartAutoRefresh();
|
|
|
|
};
|
|
|
|
|
|
|
|
self.pause = function () {
|
|
|
|
stopAutoRefresh();
|
|
|
|
};
|
|
|
|
|
|
|
|
self.resume = function (refreshData) {
|
|
|
|
if (refreshData) {
|
|
|
|
self.refresh();
|
|
|
|
} else {
|
2019-01-10 15:39:37 +03:00
|
|
|
restartAutoRefresh();
|
2020-08-05 09:00:24 +01:00
|
|
|
}
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
self.destroy = function () {
|
|
|
|
stopAutoRefresh();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
events.off(serverNotifications, 'TimerCreated', onTimerCreated);
|
|
|
|
events.off(serverNotifications, 'SeriesTimerCreated', onSeriesTimerCreated);
|
|
|
|
events.off(serverNotifications, 'TimerCancelled', onTimerCancelled);
|
|
|
|
events.off(serverNotifications, 'SeriesTimerCancelled', onSeriesTimerCancelled);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
setScrollEvents(options.element, false);
|
|
|
|
itemShortcuts.off(options.element);
|
|
|
|
items = {};
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function restartAutoRefresh() {
|
|
|
|
stopAutoRefresh();
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const intervalMs = 60000 * 15; // (minutes)
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
autoRefreshInterval = setInterval(function () {
|
|
|
|
self.refresh();
|
|
|
|
}, intervalMs);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function stopAutoRefresh() {
|
|
|
|
if (autoRefreshInterval) {
|
|
|
|
clearInterval(autoRefreshInterval);
|
|
|
|
autoRefreshInterval = null;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function normalizeDateToTimeslot(date) {
|
|
|
|
const minutesOffset = date.getMinutes() - cellCurationMinutes;
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (minutesOffset >= 0) {
|
|
|
|
date.setHours(date.getHours(), cellCurationMinutes, 0, 0);
|
|
|
|
} else {
|
|
|
|
date.setHours(date.getHours(), 0, 0, 0);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
return date;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function showLoading() {
|
|
|
|
loading.show();
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function hideLoading() {
|
|
|
|
loading.hide();
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function reloadGuide(context, newStartDate, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) {
|
|
|
|
const apiClient = connectionManager.getApiClient(options.serverId);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const channelQuery = {
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
StartIndex: 0,
|
|
|
|
EnableFavoriteSorting: userSettings.get('livetv-favoritechannelsattop') !== 'false'
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
channelQuery.UserId = apiClient.getCurrentUserId();
|
|
|
|
|
|
|
|
const channelLimit = 500;
|
|
|
|
currentChannelLimit = channelLimit;
|
|
|
|
|
|
|
|
showLoading();
|
|
|
|
|
|
|
|
channelQuery.StartIndex = currentStartIndex;
|
|
|
|
channelQuery.Limit = channelLimit;
|
|
|
|
channelQuery.AddCurrentProgram = false;
|
|
|
|
channelQuery.EnableUserData = false;
|
|
|
|
channelQuery.EnableImageTypes = 'Primary';
|
|
|
|
|
|
|
|
const categories = self.categoryOptions.categories || [];
|
|
|
|
const displayMovieContent = !categories.length || categories.indexOf('movies') !== -1;
|
|
|
|
const displaySportsContent = !categories.length || categories.indexOf('sports') !== -1;
|
|
|
|
const displayNewsContent = !categories.length || categories.indexOf('news') !== -1;
|
|
|
|
const displayKidsContent = !categories.length || categories.indexOf('kids') !== -1;
|
|
|
|
const displaySeriesContent = !categories.length || categories.indexOf('series') !== -1;
|
|
|
|
|
|
|
|
if (displayMovieContent && displaySportsContent && displayNewsContent && displayKidsContent) {
|
|
|
|
channelQuery.IsMovie = null;
|
|
|
|
channelQuery.IsSports = null;
|
|
|
|
channelQuery.IsKids = null;
|
|
|
|
channelQuery.IsNews = null;
|
|
|
|
channelQuery.IsSeries = null;
|
|
|
|
} else {
|
|
|
|
if (displayNewsContent) {
|
|
|
|
channelQuery.IsNews = true;
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
if (displaySportsContent) {
|
|
|
|
channelQuery.IsSports = true;
|
|
|
|
}
|
|
|
|
if (displayKidsContent) {
|
|
|
|
channelQuery.IsKids = true;
|
|
|
|
}
|
|
|
|
if (displayMovieContent) {
|
|
|
|
channelQuery.IsMovie = true;
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
if (displaySeriesContent) {
|
|
|
|
channelQuery.IsSeries = true;
|
|
|
|
}
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (userSettings.get('livetv-channelorder') === 'DatePlayed') {
|
|
|
|
channelQuery.SortBy = 'DatePlayed';
|
|
|
|
channelQuery.SortOrder = 'Descending';
|
|
|
|
} else {
|
|
|
|
channelQuery.SortBy = null;
|
|
|
|
channelQuery.SortOrder = null;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let date = newStartDate;
|
|
|
|
// Add one second to avoid getting programs that are just ending
|
|
|
|
date = new Date(date.getTime() + 1000);
|
|
|
|
|
|
|
|
// Subtract to avoid getting programs that are starting when the grid ends
|
|
|
|
const nextDay = new Date(date.getTime() + msPerDay - 2000);
|
|
|
|
|
|
|
|
// Normally we'd want to just let responsive css handle this,
|
|
|
|
// but since mobile browsers are often underpowered,
|
|
|
|
// it can help performance to get them out of the markup
|
|
|
|
const allowIndicators = dom.getWindowSize().innerWidth >= 600;
|
|
|
|
|
|
|
|
const renderOptions = {
|
|
|
|
showHdIcon: allowIndicators && userSettings.get('guide-indicator-hd') === 'true',
|
|
|
|
showLiveIndicator: allowIndicators && userSettings.get('guide-indicator-live') !== 'false',
|
|
|
|
showPremiereIndicator: allowIndicators && userSettings.get('guide-indicator-premiere') !== 'false',
|
|
|
|
showNewIndicator: allowIndicators && userSettings.get('guide-indicator-new') !== 'false',
|
|
|
|
showRepeatIndicator: allowIndicators && userSettings.get('guide-indicator-repeat') === 'true',
|
|
|
|
showEpisodeTitle: layoutManager.tv ? false : true
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
apiClient.getLiveTvChannels(channelQuery).then(function (channelsResult) {
|
|
|
|
const btnPreviousPage = context.querySelector('.btnPreviousPage');
|
|
|
|
const btnNextPage = context.querySelector('.btnNextPage');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (channelsResult.TotalRecordCount > channelLimit) {
|
|
|
|
context.querySelector('.guideOptions').classList.remove('hide');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
btnPreviousPage.classList.remove('hide');
|
|
|
|
btnNextPage.classList.remove('hide');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (channelQuery.StartIndex) {
|
|
|
|
context.querySelector('.btnPreviousPage').disabled = false;
|
2019-01-10 15:39:37 +03:00
|
|
|
} else {
|
2020-08-05 09:00:24 +01:00
|
|
|
context.querySelector('.btnPreviousPage').disabled = true;
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if ((channelQuery.StartIndex + channelLimit) < channelsResult.TotalRecordCount) {
|
|
|
|
btnNextPage.disabled = false;
|
|
|
|
} else {
|
|
|
|
btnNextPage.disabled = true;
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
} else {
|
|
|
|
context.querySelector('.guideOptions').classList.add('hide');
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const programFields = [];
|
|
|
|
|
|
|
|
const programQuery = {
|
|
|
|
UserId: apiClient.getCurrentUserId(),
|
|
|
|
MaxStartDate: nextDay.toISOString(),
|
|
|
|
MinEndDate: date.toISOString(),
|
|
|
|
channelIds: channelsResult.Items.map(function (c) {
|
|
|
|
return c.Id;
|
|
|
|
}).join(','),
|
|
|
|
ImageTypeLimit: 1,
|
|
|
|
EnableImages: false,
|
|
|
|
//EnableImageTypes: layoutManager.tv ? "Primary,Backdrop" : "Primary",
|
|
|
|
SortBy: 'StartDate',
|
|
|
|
EnableTotalRecordCount: false,
|
|
|
|
EnableUserData: false
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (renderOptions.showHdIcon) {
|
|
|
|
programFields.push('IsHD');
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (programFields.length) {
|
|
|
|
programQuery.Fields = programFields.join('');
|
|
|
|
}
|
|
|
|
|
|
|
|
apiClient.getLiveTvPrograms(programQuery).then(function (programsResult) {
|
|
|
|
renderGuide(context, date, channelsResult.Items, programsResult.Items, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender);
|
|
|
|
|
|
|
|
hideLoading();
|
2019-01-10 15:39:37 +03:00
|
|
|
});
|
2020-08-05 09:00:24 +01:00
|
|
|
});
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function getDisplayTime(date) {
|
|
|
|
if ((typeof date).toString().toLowerCase() === 'string') {
|
|
|
|
try {
|
|
|
|
date = datetime.parseISO8601Date(date, { toLocal: true });
|
|
|
|
} catch (err) {
|
|
|
|
return date;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
return datetime.getDisplayTime(date).toLowerCase();
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function getTimeslotHeadersHtml(startDate, endDateTime) {
|
|
|
|
let html = '';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
// clone
|
|
|
|
startDate = new Date(startDate.getTime());
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
html += '<div class="timeslotHeadersInner">';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
while (startDate.getTime() < endDateTime) {
|
|
|
|
html += '<div class="timeslotHeader">';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
html += getDisplayTime(startDate);
|
|
|
|
html += '</div>';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
// Add 30 mins
|
|
|
|
startDate.setTime(startDate.getTime() + cellDurationMs);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
return html;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function parseDates(program) {
|
|
|
|
if (!program.StartDateLocal) {
|
|
|
|
try {
|
|
|
|
program.StartDateLocal = datetime.parseISO8601Date(program.StartDate, { toLocal: true });
|
|
|
|
} catch (err) {
|
|
|
|
console.error('error parsing timestamp for start date');
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (!program.EndDateLocal) {
|
|
|
|
try {
|
|
|
|
program.EndDateLocal = datetime.parseISO8601Date(program.EndDate, { toLocal: true });
|
|
|
|
} catch (err) {
|
|
|
|
console.error('error parsing timestamp for end date');
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getTimerIndicator(item) {
|
|
|
|
let status;
|
|
|
|
|
|
|
|
if (item.Type === 'SeriesTimer') {
|
|
|
|
return '<span class="material-icons programIcon seriesTimerIcon fiber_smart_record"></span>';
|
|
|
|
} else if (item.TimerId || item.SeriesTimerId) {
|
|
|
|
status = item.Status || 'Cancelled';
|
|
|
|
} else if (item.Type === 'Timer') {
|
|
|
|
status = item.Status;
|
|
|
|
} else {
|
|
|
|
return '';
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (item.SeriesTimerId) {
|
|
|
|
if (status !== 'Cancelled') {
|
|
|
|
return '<span class="material-icons programIcon seriesTimerIcon fiber_smart_record"></span>';
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
return '<span class="material-icons programIcon seriesTimerIcon seriesTimerIcon-inactive fiber_smart_record"></span>';
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
return '<span class="material-icons programIcon timerIcon fiber_manual_record"></span>';
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function getChannelProgramsHtml(context, date, channel, programs, options, listInfo) {
|
|
|
|
let html = '';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const startMs = date.getTime();
|
|
|
|
const endMs = startMs + msPerDay - 1;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const outerCssClass = layoutManager.tv ? 'channelPrograms channelPrograms-tv' : 'channelPrograms';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
html += '<div class="' + outerCssClass + '" data-channelid="' + channel.Id + '">';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const clickAction = layoutManager.tv ? 'link' : 'programdialog';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const categories = self.categoryOptions.categories || [];
|
|
|
|
const displayMovieContent = !categories.length || categories.indexOf('movies') !== -1;
|
|
|
|
const displaySportsContent = !categories.length || categories.indexOf('sports') !== -1;
|
|
|
|
const displayNewsContent = !categories.length || categories.indexOf('news') !== -1;
|
|
|
|
const displayKidsContent = !categories.length || categories.indexOf('kids') !== -1;
|
|
|
|
const displaySeriesContent = !categories.length || categories.indexOf('series') !== -1;
|
|
|
|
const enableColorCodedBackgrounds = userSettings.get('guide-colorcodedbackgrounds') === 'true';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let programsFound;
|
|
|
|
const now = new Date().getTime();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
for (let i = listInfo.startIndex, length = programs.length; i < length; i++) {
|
|
|
|
const program = programs[i];
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (program.ChannelId !== channel.Id) {
|
|
|
|
if (programsFound) {
|
|
|
|
break;
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
continue;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
programsFound = true;
|
|
|
|
listInfo.startIndex++;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
parseDates(program);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const startDateLocalMs = program.StartDateLocal.getTime();
|
|
|
|
const endDateLocalMs = program.EndDateLocal.getTime();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (endDateLocalMs < startMs) {
|
|
|
|
continue;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (startDateLocalMs > endMs) {
|
|
|
|
break;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
items[program.Id] = program;
|
|
|
|
|
|
|
|
const renderStartMs = Math.max(startDateLocalMs, startMs);
|
|
|
|
let startPercent = (startDateLocalMs - startMs) / msPerDay;
|
|
|
|
startPercent *= 100;
|
|
|
|
startPercent = Math.max(startPercent, 0);
|
|
|
|
|
|
|
|
const renderEndMs = Math.min(endDateLocalMs, endMs);
|
|
|
|
let endPercent = (renderEndMs - renderStartMs) / msPerDay;
|
|
|
|
endPercent *= 100;
|
|
|
|
|
|
|
|
let cssClass = 'programCell itemAction';
|
|
|
|
let accentCssClass = null;
|
|
|
|
let displayInnerContent = true;
|
|
|
|
|
|
|
|
if (program.IsKids) {
|
|
|
|
displayInnerContent = displayKidsContent;
|
|
|
|
accentCssClass = 'kids';
|
|
|
|
} else if (program.IsSports) {
|
|
|
|
displayInnerContent = displaySportsContent;
|
|
|
|
accentCssClass = 'sports';
|
|
|
|
} else if (program.IsNews) {
|
|
|
|
displayInnerContent = displayNewsContent;
|
|
|
|
accentCssClass = 'news';
|
|
|
|
} else if (program.IsMovie) {
|
|
|
|
displayInnerContent = displayMovieContent;
|
|
|
|
accentCssClass = 'movie';
|
|
|
|
} else if (program.IsSeries) {
|
|
|
|
displayInnerContent = displaySeriesContent;
|
|
|
|
} else {
|
|
|
|
displayInnerContent = displayMovieContent && displayNewsContent && displaySportsContent && displayKidsContent && displaySeriesContent;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (displayInnerContent && enableColorCodedBackgrounds && accentCssClass) {
|
|
|
|
cssClass += ' programCell-' + accentCssClass;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (now >= startDateLocalMs && now < endDateLocalMs) {
|
|
|
|
cssClass += ' programCell-active';
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let timerAttributes = '';
|
|
|
|
if (program.TimerId) {
|
|
|
|
timerAttributes += ' data-timerid="' + program.TimerId + '"';
|
|
|
|
}
|
|
|
|
if (program.SeriesTimerId) {
|
|
|
|
timerAttributes += ' data-seriestimerid="' + program.SeriesTimerId + '"';
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const isAttribute = endPercent >= 2 ? ' is="emby-programcell"' : '';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
html += '<button' + isAttribute + ' data-action="' + clickAction + '"' + timerAttributes + ' data-channelid="' + program.ChannelId + '" data-id="' + program.Id + '" data-serverid="' + program.ServerId + '" data-startdate="' + program.StartDate + '" data-enddate="' + program.EndDate + '" data-type="' + program.Type + '" class="' + cssClass + '" style="left:' + startPercent + '%;width:' + endPercent + '%;">';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (displayInnerContent) {
|
|
|
|
const guideProgramNameClass = 'guideProgramName';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
html += '<div class="' + guideProgramNameClass + '">';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
html += '<div class="guide-programNameCaret hide"><span class="guideProgramNameCaretIcon material-icons keyboard_arrow_left"></span></div>';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
html += '<div class="guideProgramNameText">' + program.Name;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let indicatorHtml = null;
|
|
|
|
if (program.IsLive && options.showLiveIndicator) {
|
|
|
|
indicatorHtml = '<span class="liveTvProgram guideProgramIndicator">' + globalize.translate('Live') + '</span>';
|
|
|
|
} else if (program.IsPremiere && options.showPremiereIndicator) {
|
|
|
|
indicatorHtml = '<span class="premiereTvProgram guideProgramIndicator">' + globalize.translate('Premiere') + '</span>';
|
|
|
|
} else if (program.IsSeries && !program.IsRepeat && options.showNewIndicator) {
|
|
|
|
indicatorHtml = '<span class="newTvProgram guideProgramIndicator">' + globalize.translate('AttributeNew') + '</span>';
|
|
|
|
} else if (program.IsSeries && program.IsRepeat && options.showRepeatIndicator) {
|
|
|
|
indicatorHtml = '<span class="repeatTvProgram guideProgramIndicator">' + globalize.translate('Repeat') + '</span>';
|
|
|
|
}
|
|
|
|
html += indicatorHtml || '';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if ((program.EpisodeTitle && options.showEpisodeTitle)) {
|
|
|
|
html += '<div class="guideProgramSecondaryInfo">';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (program.EpisodeTitle && options.showEpisodeTitle) {
|
|
|
|
html += '<span class="programSecondaryTitle">' + program.EpisodeTitle + '</span>';
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
html += '</div>';
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
html += '</div>';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (program.IsHD && options.showHdIcon) {
|
|
|
|
if (layoutManager.tv) {
|
|
|
|
html += '<div class="programIcon guide-programTextIcon guide-programTextIcon-tv">HD</div>';
|
|
|
|
} else {
|
|
|
|
html += '<div class="programIcon guide-programTextIcon">HD</div>';
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
html += getTimerIndicator(program);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
html += '</div>';
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
html += '</button>';
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
html += '</div>';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
return html;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function renderChannelHeaders(context, channels, apiClient) {
|
|
|
|
let html = '';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:13:46 +01:00
|
|
|
for (const channel of channels) {
|
2020-08-05 09:00:24 +01:00
|
|
|
const hasChannelImage = channel.ImageTags.Primary;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let cssClass = 'guide-channelHeaderCell itemAction';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (layoutManager.tv) {
|
|
|
|
cssClass += ' guide-channelHeaderCell-tv';
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const title = [];
|
|
|
|
if (channel.ChannelNumber) {
|
|
|
|
title.push(channel.ChannelNumber);
|
|
|
|
}
|
|
|
|
if (channel.Name) {
|
|
|
|
title.push(channel.Name);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
html += '<button title="' + title.join(' ') + '" type="button" class="' + cssClass + '"' + ' data-action="link" data-isfolder="' + channel.IsFolder + '" data-id="' + channel.Id + '" data-serverid="' + channel.ServerId + '" data-type="' + channel.Type + '">';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (hasChannelImage) {
|
|
|
|
const url = apiClient.getScaledImageUrl(channel.Id, {
|
|
|
|
maxHeight: 220,
|
|
|
|
tag: channel.ImageTags.Primary,
|
|
|
|
type: 'Primary'
|
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
html += '<div class="guideChannelImage lazy" data-src="' + url + '"></div>';
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (channel.ChannelNumber) {
|
|
|
|
html += '<h3 class="guideChannelNumber">' + channel.ChannelNumber + '</h3>';
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (!hasChannelImage && channel.Name) {
|
|
|
|
html += '<div class="guideChannelName">' + channel.Name + '</div>';
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
html += '</button>';
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const channelList = context.querySelector('.channelsContainer');
|
|
|
|
channelList.innerHTML = html;
|
|
|
|
imageLoader.lazyChildren(channelList);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function renderPrograms(context, date, channels, programs, options) {
|
|
|
|
const listInfo = {
|
|
|
|
startIndex: 0
|
|
|
|
};
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const html = [];
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:13:46 +01:00
|
|
|
for (const channel of channels) {
|
|
|
|
html.push(getChannelProgramsHtml(context, date, channel, programs, options, listInfo));
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
programGrid.innerHTML = html.join('');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
programCells = programGrid.querySelectorAll('[is=emby-programcell]');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
updateProgramCellsOnScroll(programGrid, programCells);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function getProgramSortOrder(program, channels) {
|
|
|
|
const channelId = program.ChannelId;
|
|
|
|
let channelIndex = -1;
|
|
|
|
|
|
|
|
for (let i = 0, length = channels.length; i < length; i++) {
|
|
|
|
if (channelId === channels[i].Id) {
|
|
|
|
channelIndex = i;
|
|
|
|
break;
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const start = datetime.parseISO8601Date(program.StartDate, { toLocal: true });
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
return (channelIndex * 10000000) + (start.getTime() / 60000);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function renderGuide(context, date, channels, programs, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) {
|
|
|
|
programs.sort(function (a, b) {
|
|
|
|
return getProgramSortOrder(a, channels) - getProgramSortOrder(b, channels);
|
|
|
|
});
|
|
|
|
|
|
|
|
const activeElement = document.activeElement;
|
|
|
|
const itemId = activeElement && activeElement.getAttribute ? activeElement.getAttribute('data-id') : null;
|
|
|
|
let channelRowId = null;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (activeElement) {
|
|
|
|
channelRowId = dom.parentWithClass(activeElement, 'channelPrograms');
|
|
|
|
channelRowId = channelRowId && channelRowId.getAttribute ? channelRowId.getAttribute('data-channelid') : null;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
renderChannelHeaders(context, channels, apiClient);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const startDate = date;
|
|
|
|
const endDate = new Date(startDate.getTime() + msPerDay);
|
|
|
|
context.querySelector('.timeslotHeaders').innerHTML = getTimeslotHeadersHtml(startDate, endDate);
|
|
|
|
items = {};
|
|
|
|
renderPrograms(context, date, channels, programs, renderOptions);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (focusProgramOnRender) {
|
|
|
|
focusProgram(context, itemId, channelRowId, focusToTimeMs, startTimeOfDayMs);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
scrollProgramGridToTimeMs(context, scrollToTimeMs, startTimeOfDayMs);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function scrollProgramGridToTimeMs(context, scrollToTimeMs, startTimeOfDayMs) {
|
|
|
|
scrollToTimeMs -= startTimeOfDayMs;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const pct = scrollToTimeMs / msPerDay;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
programGrid.scrollTop = 0;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const scrollPos = pct * programGrid.scrollWidth;
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
nativeScrollTo(programGrid, scrollPos, true);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function focusProgram(context, itemId, channelRowId, focusToTimeMs, startTimeOfDayMs) {
|
|
|
|
let focusElem;
|
|
|
|
if (itemId) {
|
|
|
|
focusElem = context.querySelector('[data-id="' + itemId + '"]');
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (focusElem) {
|
|
|
|
focusManager.focus(focusElem);
|
|
|
|
} else {
|
|
|
|
let autoFocusParent;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (channelRowId) {
|
|
|
|
autoFocusParent = context.querySelector('[data-channelid="' + channelRowId + '"]');
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (!autoFocusParent) {
|
|
|
|
autoFocusParent = programGrid;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
focusToTimeMs -= startTimeOfDayMs;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const pct = (focusToTimeMs / msPerDay) * 100;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let programCell = autoFocusParent.querySelector('.programCell');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
while (programCell) {
|
|
|
|
let left = (programCell.style.left || '').replace('%', '');
|
|
|
|
left = left ? parseFloat(left) : 0;
|
|
|
|
let width = (programCell.style.width || '').replace('%', '');
|
|
|
|
width = width ? parseFloat(width) : 0;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (left >= pct || (left + width) >= pct) {
|
|
|
|
break;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
programCell = programCell.nextSibling;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (programCell) {
|
|
|
|
focusManager.focus(programCell);
|
2019-01-10 15:39:37 +03:00
|
|
|
} else {
|
2020-08-05 09:00:24 +01:00
|
|
|
focusManager.autoFocus(autoFocusParent, true);
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function nativeScrollTo(container, pos, horizontal) {
|
|
|
|
if (container.scrollTo) {
|
|
|
|
if (horizontal) {
|
|
|
|
container.scrollTo(pos, 0);
|
|
|
|
} else {
|
|
|
|
container.scrollTo(0, pos);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
} else {
|
|
|
|
if (horizontal) {
|
|
|
|
container.scrollLeft = Math.round(pos);
|
|
|
|
} else {
|
|
|
|
container.scrollTop = Math.round(pos);
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let lastGridScroll = 0;
|
|
|
|
let lastHeaderScroll = 0;
|
|
|
|
let scrollXPct = 0;
|
|
|
|
function onProgramGridScroll(context, elem, timeslotHeaders) {
|
|
|
|
if ((new Date().getTime() - lastHeaderScroll) >= 1000) {
|
|
|
|
lastGridScroll = new Date().getTime();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const scrollLeft = elem.scrollLeft;
|
|
|
|
scrollXPct = (scrollLeft * 100) / elem.scrollWidth;
|
|
|
|
nativeScrollTo(timeslotHeaders, scrollLeft, true);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
updateProgramCellsOnScroll(elem, programCells);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function onTimeslotHeadersScroll(context, elem) {
|
|
|
|
if ((new Date().getTime() - lastGridScroll) >= 1000) {
|
|
|
|
lastHeaderScroll = new Date().getTime();
|
|
|
|
nativeScrollTo(programGrid, elem.scrollLeft, true);
|
|
|
|
}
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function changeDate(page, date, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) {
|
|
|
|
const newStartDate = normalizeDateToTimeslot(date);
|
|
|
|
currentDate = newStartDate;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
reloadGuide(page, newStartDate, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender);
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function getDateTabText(date, isActive, tabIndex) {
|
|
|
|
const cssClass = isActive ? 'emby-tab-button guide-date-tab-button emby-tab-button-active' : 'emby-tab-button guide-date-tab-button';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let html = '<button is="emby-button" class="' + cssClass + '" data-index="' + tabIndex + '" data-date="' + date.getTime() + '">';
|
|
|
|
let tabText = datetime.toLocaleDateString(date, { weekday: 'short' });
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
tabText += '<br/>';
|
|
|
|
tabText += date.getDate();
|
|
|
|
html += '<div class="emby-button-foreground">' + tabText + '</div>';
|
|
|
|
html += '</button>';
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
return html;
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function setDateRange(page, guideInfo) {
|
|
|
|
const today = new Date();
|
|
|
|
const nowHours = today.getHours();
|
|
|
|
today.setHours(nowHours, 0, 0, 0);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let start = datetime.parseISO8601Date(guideInfo.StartDate, { toLocal: true });
|
|
|
|
const end = datetime.parseISO8601Date(guideInfo.EndDate, { toLocal: true });
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
start.setHours(nowHours, 0, 0, 0);
|
|
|
|
end.setHours(0, 0, 0, 0);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (start.getTime() >= end.getTime()) {
|
|
|
|
end.setDate(start.getDate() + 1);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
start = new Date(Math.max(today, start));
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let dateTabsHtml = '';
|
|
|
|
let tabIndex = 0;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
// TODO: Use date-fns
|
|
|
|
const date = new Date();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (currentDate) {
|
|
|
|
date.setTime(currentDate.getTime());
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
date.setHours(nowHours, 0, 0, 0);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let startTimeOfDayMs = (start.getHours() * 60 * 60 * 1000);
|
|
|
|
startTimeOfDayMs += start.getMinutes() * 60 * 1000;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
while (start <= end) {
|
|
|
|
const isActive = date.getDate() === start.getDate() && date.getMonth() === start.getMonth() && date.getFullYear() === start.getFullYear();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
dateTabsHtml += getDateTabText(start, isActive, tabIndex);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
start.setDate(start.getDate() + 1);
|
|
|
|
start.setHours(0, 0, 0, 0);
|
|
|
|
tabIndex++;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
page.querySelector('.emby-tabs-slider').innerHTML = dateTabsHtml;
|
|
|
|
page.querySelector('.guideDateTabs').refresh();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const newDate = new Date();
|
|
|
|
const newDateHours = newDate.getHours();
|
|
|
|
let scrollToTimeMs = newDateHours * 60 * 60 * 1000;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const minutes = newDate.getMinutes();
|
|
|
|
if (minutes >= 30) {
|
|
|
|
scrollToTimeMs += 30 * 60 * 1000;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const focusToTimeMs = ((newDateHours * 60) + minutes) * 60 * 1000;
|
|
|
|
changeDate(page, date, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, layoutManager.tv);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function reloadPage(page) {
|
|
|
|
showLoading();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const apiClient = connectionManager.getApiClient(options.serverId);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
apiClient.getLiveTvGuideInfo().then(function (guideInfo) {
|
|
|
|
setDateRange(page, guideInfo);
|
|
|
|
});
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function getChannelProgramsFocusableElements(container) {
|
|
|
|
const elements = container.querySelectorAll('.programCell');
|
|
|
|
|
|
|
|
const list = [];
|
|
|
|
// add 1 to avoid programs that are out of view to the left
|
|
|
|
const currentScrollXPct = scrollXPct + 1;
|
|
|
|
|
2020-08-05 09:13:46 +01:00
|
|
|
for (const elem of elements) {
|
2020-08-05 09:00:24 +01:00
|
|
|
let left = (elem.style.left || '').replace('%', '');
|
|
|
|
left = left ? parseFloat(left) : 0;
|
2020-08-05 09:13:46 +01:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let width = (elem.style.width || '').replace('%', '');
|
|
|
|
width = width ? parseFloat(width) : 0;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if ((left + width) >= currentScrollXPct) {
|
|
|
|
list.push(elem);
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
function onInputCommand(e) {
|
|
|
|
const target = e.target;
|
|
|
|
const programCell = dom.parentWithClass(target, 'programCell');
|
|
|
|
let container;
|
|
|
|
let channelPrograms;
|
|
|
|
let focusableElements;
|
|
|
|
let newRow;
|
|
|
|
|
|
|
|
switch (e.detail.command) {
|
|
|
|
case 'up':
|
|
|
|
if (programCell) {
|
|
|
|
container = programGrid;
|
|
|
|
channelPrograms = dom.parentWithClass(programCell, 'channelPrograms');
|
|
|
|
|
|
|
|
newRow = channelPrograms.previousSibling;
|
|
|
|
if (newRow) {
|
|
|
|
focusableElements = getChannelProgramsFocusableElements(newRow);
|
|
|
|
if (focusableElements.length) {
|
|
|
|
container = newRow;
|
2019-01-10 15:39:37 +03:00
|
|
|
} else {
|
2020-08-05 09:00:24 +01:00
|
|
|
focusableElements = null;
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
container = null;
|
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
} else {
|
|
|
|
container = null;
|
|
|
|
}
|
|
|
|
lastFocusDirection = e.detail.command;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
focusManager.moveUp(target, {
|
|
|
|
container: container,
|
|
|
|
focusableElements: focusableElements
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
case 'down':
|
|
|
|
if (programCell) {
|
|
|
|
container = programGrid;
|
|
|
|
channelPrograms = dom.parentWithClass(programCell, 'channelPrograms');
|
|
|
|
|
|
|
|
newRow = channelPrograms.nextSibling;
|
|
|
|
if (newRow) {
|
|
|
|
focusableElements = getChannelProgramsFocusableElements(newRow);
|
|
|
|
if (focusableElements.length) {
|
|
|
|
container = newRow;
|
2019-01-10 15:39:37 +03:00
|
|
|
} else {
|
2020-08-05 09:00:24 +01:00
|
|
|
focusableElements = null;
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
container = null;
|
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
} else {
|
|
|
|
container = null;
|
|
|
|
}
|
|
|
|
lastFocusDirection = e.detail.command;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
focusManager.moveDown(target, {
|
|
|
|
container: container,
|
|
|
|
focusableElements: focusableElements
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
case 'left':
|
|
|
|
container = programCell ? dom.parentWithClass(programCell, 'channelPrograms') : null;
|
|
|
|
// allow left outside the channelProgramsContainer when the first child is currently focused
|
|
|
|
if (container && !programCell.previousSibling) {
|
|
|
|
container = null;
|
|
|
|
}
|
|
|
|
lastFocusDirection = e.detail.command;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
focusManager.moveLeft(target, {
|
|
|
|
container: container
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
case 'right':
|
|
|
|
container = programCell ? dom.parentWithClass(programCell, 'channelPrograms') : null;
|
|
|
|
lastFocusDirection = e.detail.command;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
focusManager.moveRight(target, {
|
|
|
|
container: container
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
}
|
|
|
|
|
|
|
|
function onScrollerFocus(e) {
|
|
|
|
const target = e.target;
|
|
|
|
const programCell = dom.parentWithClass(target, 'programCell');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (programCell) {
|
|
|
|
const focused = target;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const id = focused.getAttribute('data-id');
|
|
|
|
const item = items[id];
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (item) {
|
|
|
|
events.trigger(self, 'focus', [
|
|
|
|
{
|
|
|
|
item: item
|
|
|
|
}]);
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (lastFocusDirection === 'left') {
|
|
|
|
if (programCell) {
|
|
|
|
scrollHelper.toStart(programGrid, programCell, true, true);
|
|
|
|
}
|
|
|
|
} else if (lastFocusDirection === 'right') {
|
|
|
|
if (programCell) {
|
|
|
|
scrollHelper.toCenter(programGrid, programCell, true, true);
|
|
|
|
}
|
|
|
|
} else if (lastFocusDirection === 'up' || lastFocusDirection === 'down') {
|
|
|
|
const verticalScroller = dom.parentWithClass(target, 'guideVerticalScroller');
|
|
|
|
if (verticalScroller) {
|
|
|
|
const focusedElement = programCell || dom.parentWithTag(target, 'BUTTON');
|
|
|
|
verticalScroller.toCenter(focusedElement, true);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function setScrollEvents(view, enabled) {
|
|
|
|
if (layoutManager.tv) {
|
|
|
|
const guideVerticalScroller = view.querySelector('.guideVerticalScroller');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (enabled) {
|
|
|
|
inputManager.on(guideVerticalScroller, onInputCommand);
|
|
|
|
} else {
|
|
|
|
inputManager.off(guideVerticalScroller, onInputCommand);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function onTimerCreated(e, apiClient, data) {
|
|
|
|
const programId = data.ProgramId;
|
|
|
|
// This could be null, not supported by all tv providers
|
|
|
|
const newTimerId = data.Id;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
// find guide cells by program id, ensure timer icon
|
|
|
|
const cells = options.element.querySelectorAll('.programCell[data-id="' + programId + '"]');
|
2020-08-05 09:13:46 +01:00
|
|
|
for (const cell of cells) {
|
2020-08-05 09:00:24 +01:00
|
|
|
const icon = cell.querySelector('.timerIcon');
|
|
|
|
if (!icon) {
|
|
|
|
cell.querySelector('.guideProgramName').insertAdjacentHTML('beforeend', '<span class="timerIcon material-icons programIcon fiber_manual_record"></span>');
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (newTimerId) {
|
|
|
|
cell.setAttribute('data-timerid', newTimerId);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function onSeriesTimerCreated(e, apiClient, data) {
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function onTimerCancelled(e, apiClient, data) {
|
|
|
|
const id = data.Id;
|
|
|
|
// find guide cells by timer id, remove timer icon
|
|
|
|
const cells = options.element.querySelectorAll('.programCell[data-timerid="' + id + '"]');
|
2020-08-05 09:13:46 +01:00
|
|
|
|
|
|
|
for (const cell of cells) {
|
2020-08-05 09:00:24 +01:00
|
|
|
const icon = cell.querySelector('.timerIcon');
|
2020-08-05 09:13:46 +01:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (icon) {
|
|
|
|
icon.parentNode.removeChild(icon);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2020-08-05 09:13:46 +01:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
cell.removeAttribute('data-timerid');
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
function onSeriesTimerCancelled(e, apiClient, data) {
|
|
|
|
const id = data.Id;
|
|
|
|
// find guide cells by timer id, remove timer icon
|
|
|
|
const cells = options.element.querySelectorAll('.programCell[data-seriestimerid="' + id + '"]');
|
2020-08-05 09:13:46 +01:00
|
|
|
|
|
|
|
for (const cell of cells) {
|
2020-08-05 09:00:24 +01:00
|
|
|
const icon = cell.querySelector('.seriesTimerIcon');
|
2020-08-05 09:13:46 +01:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (icon) {
|
|
|
|
icon.parentNode.removeChild(icon);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2020-08-05 09:13:46 +01:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
cell.removeAttribute('data-seriestimerid');
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2020-08-05 09:00:24 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
import('text!./tvguide.template.html').then(({default: template}) => {
|
|
|
|
const context = options.element;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
context.classList.add('tvguide');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
context.innerHTML = globalize.translateHtml(template, 'core');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
programGrid = context.querySelector('.programGrid');
|
|
|
|
const timeslotHeaders = context.querySelector('.timeslotHeaders');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (layoutManager.tv) {
|
|
|
|
dom.addEventListener(context.querySelector('.guideVerticalScroller'), 'focus', onScrollerFocus, {
|
|
|
|
capture: true,
|
2019-11-23 00:29:38 +09:00
|
|
|
passive: true
|
|
|
|
});
|
2020-08-05 09:00:24 +01:00
|
|
|
} else if (layoutManager.desktop) {
|
|
|
|
timeslotHeaders.classList.add('timeslotHeaders-desktop');
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (browser.iOS || browser.osx) {
|
|
|
|
context.querySelector('.channelsContainer').classList.add('noRubberBanding');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
programGrid.classList.add('noRubberBanding');
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
dom.addEventListener(programGrid, 'scroll', function (e) {
|
|
|
|
onProgramGridScroll(context, this, timeslotHeaders);
|
|
|
|
}, {
|
|
|
|
passive: true
|
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
dom.addEventListener(timeslotHeaders, 'scroll', function () {
|
|
|
|
onTimeslotHeadersScroll(context, this);
|
|
|
|
}, {
|
|
|
|
passive: true
|
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
programGrid.addEventListener('click', onProgramGridClick);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
context.querySelector('.btnNextPage').addEventListener('click', function () {
|
|
|
|
currentStartIndex += currentChannelLimit;
|
|
|
|
reloadPage(context);
|
|
|
|
restartAutoRefresh();
|
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
context.querySelector('.btnPreviousPage').addEventListener('click', function () {
|
|
|
|
currentStartIndex = Math.max(currentStartIndex - currentChannelLimit, 0);
|
|
|
|
reloadPage(context);
|
|
|
|
restartAutoRefresh();
|
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
context.querySelector('.btnGuideViewSettings').addEventListener('click', function () {
|
|
|
|
showViewSettings(self);
|
|
|
|
restartAutoRefresh();
|
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
context.querySelector('.guideDateTabs').addEventListener('tabchange', function (e) {
|
|
|
|
const allTabButtons = e.target.querySelectorAll('.guide-date-tab-button');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const tabButton = allTabButtons[parseInt(e.detail.selectedTabIndex)];
|
|
|
|
if (tabButton) {
|
|
|
|
const previousButton = e.detail.previousIndex == null ? null : allTabButtons[parseInt(e.detail.previousIndex)];
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const date = new Date();
|
|
|
|
date.setTime(parseInt(tabButton.getAttribute('data-date')));
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
const scrollWidth = programGrid.scrollWidth;
|
|
|
|
let scrollToTimeMs;
|
|
|
|
if (scrollWidth) {
|
|
|
|
scrollToTimeMs = (programGrid.scrollLeft / scrollWidth) * msPerDay;
|
|
|
|
} else {
|
|
|
|
scrollToTimeMs = 0;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
if (previousButton) {
|
|
|
|
const previousDate = new Date();
|
|
|
|
previousDate.setTime(parseInt(previousButton.getAttribute('data-date')));
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
scrollToTimeMs += (previousDate.getHours() * 60 * 60 * 1000);
|
|
|
|
scrollToTimeMs += (previousDate.getMinutes() * 60 * 1000);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
let startTimeOfDayMs = (date.getHours() * 60 * 60 * 1000);
|
|
|
|
startTimeOfDayMs += (date.getMinutes() * 60 * 1000);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
changeDate(context, date, scrollToTimeMs, scrollToTimeMs, startTimeOfDayMs, false);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
});
|
|
|
|
|
2020-08-05 09:00:24 +01:00
|
|
|
setScrollEvents(context, true);
|
|
|
|
itemShortcuts.on(context);
|
|
|
|
|
|
|
|
events.trigger(self, 'load');
|
|
|
|
|
|
|
|
events.on(serverNotifications, 'TimerCreated', onTimerCreated);
|
|
|
|
events.on(serverNotifications, 'SeriesTimerCreated', onSeriesTimerCreated);
|
|
|
|
events.on(serverNotifications, 'TimerCancelled', onTimerCancelled);
|
|
|
|
events.on(serverNotifications, 'SeriesTimerCancelled', onSeriesTimerCancelled);
|
|
|
|
|
|
|
|
self.refresh();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export default Guide;
|