1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

make tv guide standalone component

This commit is contained in:
Luke Pulverenti 2015-10-08 15:12:53 -04:00
parent 85c77ac6ed
commit 45250e4540
9 changed files with 614 additions and 513 deletions

View file

@ -0,0 +1,521 @@
define(['livetvcss', 'scripts/livetvcomponents'], function () {
return function (options) {
var self = this;
self.refresh = function () {
reloadPage(options.element);
};
// 30 mins
var cellCurationMinutes = 30;
var cellDurationMs = cellCurationMinutes * 60 * 1000;
var msPerDay = 86400000;
var currentDate;
var defaultChannels = 50;
var channelLimit = 1000;
var channelQuery = {
StartIndex: 0,
Limit: defaultChannels,
EnableFavoriteSorting: true
};
var channelsPromise;
function normalizeDateToTimeslot(date) {
var minutesOffset = date.getMinutes() - cellCurationMinutes;
if (minutesOffset >= 0) {
date.setHours(date.getHours(), cellCurationMinutes, 0, 0);
} else {
date.setHours(date.getHours(), 0, 0, 0);
}
return date;
}
function reloadChannels(page) {
channelsPromise = null;
reloadGuide(page);
}
function reloadGuide(page) {
Dashboard.showModalLoadingMsg();
channelQuery.UserId = Dashboard.getCurrentUserId();
channelQuery.Limit = Math.min(channelQuery.Limit || defaultChannels, channelLimit);
channelQuery.AddCurrentProgram = false;
channelsPromise = channelsPromise || ApiClient.getLiveTvChannels(channelQuery);
var date = currentDate;
var nextDay = new Date(date.getTime() + msPerDay - 1);
Logger.log(nextDay);
channelsPromise.done(function (channelsResult) {
ApiClient.getLiveTvPrograms({
UserId: Dashboard.getCurrentUserId(),
MaxStartDate: nextDay.toISOString(),
MinEndDate: date.toISOString(),
channelIds: channelsResult.Items.map(function (c) {
return c.Id;
}).join(','),
ImageTypeLimit: 1,
EnableImageTypes: "Primary"
}).done(function (programsResult) {
renderGuide(page, date, channelsResult.Items, programsResult.Items);
Dashboard.hideModalLoadingMsg();
LibraryBrowser.setLastRefreshed(page);
});
if (options.enablePaging !== false) {
var channelPagingHtml = LibraryBrowser.getQueryPagingHtml({
startIndex: channelQuery.StartIndex,
limit: channelQuery.Limit,
totalRecordCount: channelsResult.TotalRecordCount,
updatePageSizeSetting: false,
showLimit: true
});
var channelPaging = page.querySelector('.channelPaging');
channelPaging.innerHTML = channelPagingHtml;
$(channelPaging);
}
Events.on(page.querySelector('.btnNextPage'), 'click', function () {
channelQuery.StartIndex += channelQuery.Limit;
reloadChannels(page);
});
Events.on(page.querySelector('.btnPreviousPage'), 'click', function () {
channelQuery.StartIndex -= channelQuery.Limit;
reloadChannels(page);
});
Events.on(page.querySelector('#selectPageSize'), 'change', function () {
channelQuery.Limit = parseInt(this.value);
channelQuery.StartIndex = 0;
reloadChannels(page);
});
});
}
function getTimeslotHeadersHtml(startDate, endDateTime) {
var html = '';
// clone
startDate = new Date(startDate.getTime());
html += '<div class="timeslotHeadersInner">';
while (startDate.getTime() < endDateTime) {
html += '<div class="timeslotHeader">';
html += '<div class="timeslotHeaderInner">';
html += LibraryBrowser.getDisplayTime(startDate);
html += '</div>';
html += '</div>';
// Add 30 mins
startDate.setTime(startDate.getTime() + cellDurationMs);
}
html += '</div>';
return html;
}
function parseDates(program) {
if (!program.StartDateLocal) {
try {
program.StartDateLocal = parseISO8601Date(program.StartDate, { toLocal: true });
} catch (err) {
}
}
if (!program.EndDateLocal) {
try {
program.EndDateLocal = parseISO8601Date(program.EndDate, { toLocal: true });
} catch (err) {
}
}
return null;
}
function getChannelProgramsHtml(page, date, channel, programs) {
var html = '';
var startMs = date.getTime();
var endMs = startMs + msPerDay - 1;
programs = programs.filter(function (curr) {
return curr.ChannelId == channel.Id;
});
html += '<div class="channelPrograms">';
for (var i = 0, length = programs.length; i < length; i++) {
var program = programs[i];
if (program.ChannelId != channel.Id) {
continue;
}
parseDates(program);
if (program.EndDateLocal.getTime() < startMs) {
continue;
}
if (program.StartDateLocal.getTime() > endMs) {
break;
}
var renderStartMs = Math.max(program.StartDateLocal.getTime(), startMs);
var startPercent = (program.StartDateLocal.getTime() - startMs) / msPerDay;
startPercent *= 100;
startPercent = Math.max(startPercent, 0);
var renderEndMs = Math.min(program.EndDateLocal.getTime(), endMs);
var endPercent = (renderEndMs - renderStartMs) / msPerDay;
endPercent *= 100;
html += '<div class="programCell" style="left:' + startPercent + '%;width:' + endPercent + '%;">';
var cssClass = "programCellInner";
var addAccent = true;
if (program.IsKids) {
cssClass += " childProgramInfo";
} else if (program.IsSports) {
cssClass += " sportsProgramInfo";
} else if (program.IsNews) {
cssClass += " newsProgramInfo";
} else if (program.IsMovie) {
cssClass += " movieProgramInfo";
}
else {
cssClass += " plainProgramInfo";
addAccent = false;
}
html += '<a href="itemdetails.html?id=' + program.Id + '" class="' + cssClass + '" data-programid="' + program.Id + '">';
html += '<div class="guideProgramName">';
html += program.Name;
html += '</div>';
html += '<div class="guideProgramTime">';
if (program.IsLive) {
html += '<span class="liveTvProgram">' + Globalize.translate('LabelLiveProgram') + '&nbsp;&nbsp;</span>';
}
else if (program.IsPremiere) {
html += '<span class="premiereTvProgram">' + Globalize.translate('LabelPremiereProgram') + '&nbsp;&nbsp;</span>';
}
else if (program.IsSeries && !program.IsRepeat) {
html += '<span class="newTvProgram">' + Globalize.translate('LabelNewProgram') + '&nbsp;&nbsp;</span>';
}
html += LibraryBrowser.getDisplayTime(program.StartDateLocal);
html += ' - ';
html += LibraryBrowser.getDisplayTime(program.EndDateLocal);
if (program.SeriesTimerId) {
html += '<div class="timerCircle seriesTimerCircle"></div>';
html += '<div class="timerCircle seriesTimerCircle"></div>';
html += '<div class="timerCircle seriesTimerCircle"></div>';
}
else if (program.TimerId) {
html += '<div class="timerCircle"></div>';
}
html += '</div>';
if (addAccent) {
html += '<div class="programAccent"></div>';
}
html += '</a>';
html += '</div>';
}
html += '</div>';
return html;
}
function renderPrograms(page, date, channels, programs) {
var html = [];
for (var i = 0, length = channels.length; i < length; i++) {
html.push(getChannelProgramsHtml(page, date, channels[i], programs));
}
var programGrid = page.querySelector('.programGrid');
programGrid.innerHTML = html.join('');
$(programGrid).scrollTop(0).scrollLeft(0);
if (options.enableHoverMenu) {
$(programGrid).createGuideHoverMenu('.programCellInner');
}
}
function renderChannelHeaders(page, channels) {
var html = '';
for (var i = 0, length = channels.length; i < length; i++) {
var channel = channels[i];
html += '<div class="channelHeaderCellContainer">';
html += '<div class="channelHeaderCell">';
html += '<a class="channelHeaderCellInner" href="itemdetails.html?id=' + channel.Id + '">';
var hasChannelImage = channel.ImageTags.Primary;
var cssClass = hasChannelImage ? 'guideChannelInfo guideChannelInfoWithImage' : 'guideChannelInfo';
html += '<div class="' + cssClass + '">' + channel.Name + '<br/>' + channel.Number + '</div>';
if (hasChannelImage) {
var url = ApiClient.getScaledImageUrl(channel.Id, {
maxHeight: 35,
maxWidth: 60,
tag: channel.ImageTags.Primary,
type: "Primary"
});
html += '<div class="guideChannelImage lazy" data-src="' + url + '"></div>';
}
html += '</a>';
html += '</div>';
html += '</div>';
}
var channelList = page.querySelector('.channelList');
channelList.innerHTML = html;
ImageLoader.lazyChildren(channelList);
}
function renderGuide(page, date, channels, programs) {
renderChannelHeaders(page, channels);
var startDate = date;
var endDate = new Date(startDate.getTime() + msPerDay);
page.querySelector('.timeslotHeaders').innerHTML = getTimeslotHeadersHtml(startDate, endDate);
renderPrograms(page, date, channels, programs);
}
var gridScrolling = false;
var headersScrolling = false;
function onProgramGridScroll(page, elem) {
if (!headersScrolling) {
gridScrolling = true;
$(page.querySelector('.timeslotHeaders')).scrollLeft($(elem).scrollLeft());
gridScrolling = false;
}
}
function onTimeslotHeadersScroll(page, elem) {
if (!gridScrolling) {
headersScrolling = true;
$(page.querySelector('.programGrid')).scrollLeft($(elem).scrollLeft());
headersScrolling = false;
}
}
function changeDate(page, date) {
currentDate = normalizeDateToTimeslot(date);
reloadGuide(page);
var text = LibraryBrowser.getFutureDateText(date);
text = '<span class="currentDay">' + text.replace(' ', ' </span>');
page.querySelector('.currentDate').innerHTML = text;
}
var dateOptions = [];
function setDateRange(page, guideInfo) {
var today = new Date();
today.setHours(today.getHours(), 0, 0, 0);
var start = parseISO8601Date(guideInfo.StartDate, { toLocal: true });
var end = parseISO8601Date(guideInfo.EndDate, { toLocal: true });
start.setHours(0, 0, 0, 0);
end.setHours(0, 0, 0, 0);
if (start.getTime() >= end.getTime()) {
end.setDate(start.getDate() + 1);
}
start = new Date(Math.max(today, start));
dateOptions = [];
while (start <= end) {
dateOptions.push({
name: LibraryBrowser.getFutureDateText(start),
id: start.getTime(),
ironIcon: 'today'
});
start.setDate(start.getDate() + 1);
start.setHours(0, 0, 0, 0);
}
var date = new Date();
if (currentDate) {
date.setTime(currentDate.getTime());
}
changeDate(page, date);
}
function reloadPageAfterValidation(page, limit) {
channelLimit = limit;
ApiClient.getLiveTvGuideInfo().done(function (guideInfo) {
setDateRange(page, guideInfo);
});
}
function reloadPage(page) {
$('.guideRequiresUnlock', page).hide();
RegistrationServices.validateFeature('livetv').done(function () {
Dashboard.showModalLoadingMsg();
reloadPageAfterValidation(page, 1000);
}).fail(function () {
Dashboard.showModalLoadingMsg();
var limit = 5;
$('.guideRequiresUnlock', page).show();
$('.unlockText', page).html(Globalize.translate('MessageLiveTvGuideRequiresUnlock', limit));
reloadPageAfterValidation(page, limit);
});
}
function selectDate(page) {
require(['actionsheet'], function () {
ActionSheetElement.show({
items: dateOptions,
showCancel: true,
title: Globalize.translate('HeaderSelectDate'),
callback: function (id) {
var date = new Date();
date.setTime(parseInt(id));
changeDate(page, date);
}
});
});
}
ApiClient.ajax({
type: 'GET',
url: 'components/tvguide/tvguide.template.html'
}).done(function (template) {
var tabContent = options.element;
tabContent.innerHTML = template;
Events.on(tabContent.querySelector('.programGrid'), 'scroll', function () {
onProgramGridScroll(tabContent, this);
});
if ($.browser.mobile) {
tabContent.querySelector('.tvGuide').classList.add('mobileGuide');
} else {
tabContent.querySelector('.tvGuide').classList.remove('mobileGuide');
Events.on(tabContent.querySelector('.timeslotHeaders'), 'scroll', function () {
onTimeslotHeadersScroll(tabContent, this);
});
}
if (AppInfo.enableHeadRoom && options.enableHeadRoom) {
requirejs(["thirdparty/headroom"], function () {
// construct an instance of Headroom, passing the element
var headroom = new Headroom(tabContent.querySelector('.tvGuideHeader'));
// initialise
headroom.init();
});
}
$('.btnUnlockGuide', tabContent).on('click', function () {
reloadPage(tabContent);
});
$('.btnSelectDate', tabContent).on('click', function () {
selectDate(tabContent);
});
self.refresh();
});
};
});

View file

@ -0,0 +1,19 @@
<div class="tvGuide">
<div class="tvGuideHeader">
<div class="channelTimeslotHeader">
<div class="timeslotHeaderInner">
<a class="btnSelectDate" href="#" style="display:block;padding-left:5px;color:#fff;text-decoration:none;font-weight:normal!important;padding:5px 10px 4px 0;font-size:13px;"><iron-icon icon="schedule" style="margin-right:3px;width:18px;height:18px;"></iron-icon><span class="currentDate" style="vertical-align: middle;"></span></a>
</div>
</div>
<div class="timeslotHeaders hiddenScrollX"></div>
</div>
<div class="programContainer">
<div class="channelList"></div>
<div class="programGrid hiddenScrollX"></div>
</div>
<div class="channelPaging"></div>
</div>
<div class="guideRequiresUnlock readOnlyContent" style="margin:1em auto;text-align:center;display:none;padding:1em;">
<p class="unlockText"></p>
<paper-button raised class="secondary block btnUnlockGuide"><iron-icon icon="check"></iron-icon><span>${ButtonUnlockGuide}</span></paper-button>
</div>

View file

@ -2,6 +2,10 @@
background: #161616; background: #161616;
} }
.tvGuide {
text-align: left;
}
.tvGuideHeader { .tvGuideHeader {
white-space: nowrap; white-space: nowrap;
position: fixed; position: fixed;

View file

@ -75,6 +75,20 @@
padding: 1.5em 1em 2em 1em; padding: 1.5em 1em 2em 1em;
} }
.guide {
height: 400px;
overflow: auto;
background-color: #000 !important;
}
.guide .tvGuideHeader {
position: static !important;
}
.guide .programContainer {
margin-top: 0 !important;
}
#videoPlayer .nowPlayingImage img { #videoPlayer .nowPlayingImage img {
height: auto !important; height: auto !important;
max-width: 180px; max-width: 180px;

View file

@ -67,25 +67,6 @@
</neon-animatable> </neon-animatable>
<neon-animatable> <neon-animatable>
<div class="pageTabContent guideTabContent" style="width:auto;" data-index="1"> <div class="pageTabContent guideTabContent" style="width:auto;" data-index="1">
<div class="tvGuide">
<div class="tvGuideHeader">
<div class="channelTimeslotHeader">
<div class="timeslotHeaderInner">
<a class="btnSelectDate" href="#" style="display:block;padding-left:5px;color:#fff;text-decoration:none;font-weight:normal!important;padding:5px 10px 4px 0;font-size:13px;"><iron-icon icon="schedule" style="margin-right:3px;width:18px;height:18px;"></iron-icon><span class="currentDate" style="vertical-align: middle;"></span></a>
</div>
</div>
<div class="timeslotHeaders hiddenScrollX"></div>
</div>
<div class="programContainer">
<div class="channelList"></div>
<div class="programGrid hiddenScrollX"></div>
</div>
<div class="channelPaging"></div>
</div>
<div class="guideRequiresUnlock readOnlyContent" style="margin:1em auto;text-align:center;display:none;padding:1em;">
<p class="unlockText"></p>
<paper-button raised class="secondary block btnUnlockGuide"><iron-icon icon="check"></iron-icon><span>${ButtonUnlockGuide}</span></paper-button>
</div>
</div> </div>
</neon-animatable> </neon-animatable>
<neon-animatable> <neon-animatable>

View file

@ -349,6 +349,13 @@
}); });
} }
function onHoverOut() {
if (showOverlayTimeout) {
clearTimeout(showOverlayTimeout);
showOverlayTimeout = null;
}
}
function onHoverIn() { function onHoverIn() {
if (showOverlayTimeout) { if (showOverlayTimeout) {
@ -385,6 +392,7 @@
} }
return this.on('mouseenter', childSelector, onHoverIn) return this.on('mouseenter', childSelector, onHoverIn)
.on('mouseleave', childSelector, onHoverOut)
.on('click', childSelector, onProgramClicked); .on('click', childSelector, onProgramClicked);
}; };

View file

@ -1,504 +1,24 @@
(function ($, document) { (function ($, document) {
// 30 mins
var cellCurationMinutes = 30;
var cellDurationMs = cellCurationMinutes * 60 * 1000;
var msPerDay = 86400000;
var currentDate;
var defaultChannels = 50;
var channelLimit = 1000;
var channelQuery = {
StartIndex: 0,
Limit: defaultChannels,
EnableFavoriteSorting: true
};
var channelsPromise;
function normalizeDateToTimeslot(date) {
var minutesOffset = date.getMinutes() - cellCurationMinutes;
if (minutesOffset >= 0) {
date.setHours(date.getHours(), cellCurationMinutes, 0, 0);
} else {
date.setHours(date.getHours(), 0, 0, 0);
}
return date;
}
function reloadChannels(page) {
channelsPromise = null;
reloadGuide(page);
}
function reloadGuide(page) {
Dashboard.showModalLoadingMsg();
channelQuery.UserId = Dashboard.getCurrentUserId();
channelQuery.Limit = Math.min(channelQuery.Limit || defaultChannels, channelLimit);
channelQuery.AddCurrentProgram = false;
channelsPromise = channelsPromise || ApiClient.getLiveTvChannels(channelQuery);
var date = currentDate;
var nextDay = new Date(date.getTime() + msPerDay - 1);
Logger.log(nextDay);
channelsPromise.done(function (channelsResult) {
ApiClient.getLiveTvPrograms({
UserId: Dashboard.getCurrentUserId(),
MaxStartDate: nextDay.toISOString(),
MinEndDate: date.toISOString(),
channelIds: channelsResult.Items.map(function (c) {
return c.Id;
}).join(','),
ImageTypeLimit: 1,
EnableImageTypes: "Primary"
}).done(function (programsResult) {
renderGuide(page, date, channelsResult.Items, programsResult.Items);
Dashboard.hideModalLoadingMsg();
LibraryBrowser.setLastRefreshed(page);
});
var channelPagingHtml = LibraryBrowser.getQueryPagingHtml({
startIndex: channelQuery.StartIndex,
limit: channelQuery.Limit,
totalRecordCount: channelsResult.TotalRecordCount,
updatePageSizeSetting: false,
showLimit: true
});
var channelPaging = page.querySelector('.channelPaging');
channelPaging.innerHTML = channelPagingHtml;
$(channelPaging).trigger('create');
Events.on(page.querySelector('.btnNextPage'), 'click', function () {
channelQuery.StartIndex += channelQuery.Limit;
reloadChannels(page);
});
Events.on(page.querySelector('.btnPreviousPage'), 'click', function () {
channelQuery.StartIndex -= channelQuery.Limit;
reloadChannels(page);
});
Events.on(page.querySelector('#selectPageSize'), 'change', function () {
channelQuery.Limit = parseInt(this.value);
channelQuery.StartIndex = 0;
reloadChannels(page);
});
});
}
function getTimeslotHeadersHtml(startDate, endDateTime) {
var html = '';
// clone
startDate = new Date(startDate.getTime());
html += '<div class="timeslotHeadersInner">';
while (startDate.getTime() < endDateTime) {
html += '<div class="timeslotHeader">';
html += '<div class="timeslotHeaderInner">';
html += LibraryBrowser.getDisplayTime(startDate);
html += '</div>';
html += '</div>';
// Add 30 mins
startDate.setTime(startDate.getTime() + cellDurationMs);
}
html += '</div>';
return html;
}
function parseDates(program) {
if (!program.StartDateLocal) {
try {
program.StartDateLocal = parseISO8601Date(program.StartDate, { toLocal: true });
} catch (err) {
}
}
if (!program.EndDateLocal) {
try {
program.EndDateLocal = parseISO8601Date(program.EndDate, { toLocal: true });
} catch (err) {
}
}
return null;
}
function getChannelProgramsHtml(page, date, channel, programs) {
var html = '';
var startMs = date.getTime();
var endMs = startMs + msPerDay - 1;
programs = programs.filter(function (curr) {
return curr.ChannelId == channel.Id;
});
html += '<div class="channelPrograms">';
for (var i = 0, length = programs.length; i < length; i++) {
var program = programs[i];
if (program.ChannelId != channel.Id) {
continue;
}
parseDates(program);
if (program.EndDateLocal.getTime() < startMs) {
continue;
}
if (program.StartDateLocal.getTime() > endMs) {
break;
}
var renderStartMs = Math.max(program.StartDateLocal.getTime(), startMs);
var startPercent = (program.StartDateLocal.getTime() - startMs) / msPerDay;
startPercent *= 100;
startPercent = Math.max(startPercent, 0);
var renderEndMs = Math.min(program.EndDateLocal.getTime(), endMs);
var endPercent = (renderEndMs - renderStartMs) / msPerDay;
endPercent *= 100;
html += '<div class="programCell" style="left:' + startPercent + '%;width:' + endPercent + '%;">';
var cssClass = "programCellInner";
var addAccent = true;
if (program.IsKids) {
cssClass += " childProgramInfo";
} else if (program.IsSports) {
cssClass += " sportsProgramInfo";
} else if (program.IsNews) {
cssClass += " newsProgramInfo";
} else if (program.IsMovie) {
cssClass += " movieProgramInfo";
}
else {
cssClass += " plainProgramInfo";
addAccent = false;
}
html += '<a href="itemdetails.html?id=' + program.Id + '" class="' + cssClass + '" data-programid="' + program.Id + '">';
html += '<div class="guideProgramName">';
html += program.Name;
html += '</div>';
html += '<div class="guideProgramTime">';
if (program.IsLive) {
html += '<span class="liveTvProgram">' + Globalize.translate('LabelLiveProgram') + '&nbsp;&nbsp;</span>';
}
else if (program.IsPremiere) {
html += '<span class="premiereTvProgram">' + Globalize.translate('LabelPremiereProgram') + '&nbsp;&nbsp;</span>';
}
else if (program.IsSeries && !program.IsRepeat) {
html += '<span class="newTvProgram">' + Globalize.translate('LabelNewProgram') + '&nbsp;&nbsp;</span>';
}
html += LibraryBrowser.getDisplayTime(program.StartDateLocal);
html += ' - ';
html += LibraryBrowser.getDisplayTime(program.EndDateLocal);
if (program.SeriesTimerId) {
html += '<div class="timerCircle seriesTimerCircle"></div>';
html += '<div class="timerCircle seriesTimerCircle"></div>';
html += '<div class="timerCircle seriesTimerCircle"></div>';
}
else if (program.TimerId) {
html += '<div class="timerCircle"></div>';
}
html += '</div>';
if (addAccent) {
html += '<div class="programAccent"></div>';
}
html += '</a>';
html += '</div>';
}
html += '</div>';
return html;
}
function renderPrograms(page, date, channels, programs) {
var html = [];
for (var i = 0, length = channels.length; i < length; i++) {
html.push(getChannelProgramsHtml(page, date, channels[i], programs));
}
var programGrid = page.querySelector('.programGrid');
programGrid.innerHTML = html.join('');
$(programGrid).scrollTop(0).scrollLeft(0)
.createGuideHoverMenu('.programCellInner');
}
function renderChannelHeaders(page, channels) {
var html = '';
for (var i = 0, length = channels.length; i < length; i++) {
var channel = channels[i];
html += '<div class="channelHeaderCellContainer">';
html += '<div class="channelHeaderCell">';
html += '<a class="channelHeaderCellInner" href="itemdetails.html?id=' + channel.Id + '">';
var hasChannelImage = channel.ImageTags.Primary;
var cssClass = hasChannelImage ? 'guideChannelInfo guideChannelInfoWithImage' : 'guideChannelInfo';
html += '<div class="' + cssClass + '">' + channel.Name + '<br/>' + channel.Number + '</div>';
if (hasChannelImage) {
var url = ApiClient.getScaledImageUrl(channel.Id, {
maxHeight: 35,
maxWidth: 60,
tag: channel.ImageTags.Primary,
type: "Primary"
});
html += '<div class="guideChannelImage lazy" data-src="' + url + '"></div>';
}
html += '</a>';
html += '</div>';
html += '</div>';
}
var channelList = page.querySelector('.channelList');
channelList.innerHTML = html;
ImageLoader.lazyChildren(channelList);
}
function renderGuide(page, date, channels, programs) {
renderChannelHeaders(page, channels);
var startDate = date;
var endDate = new Date(startDate.getTime() + msPerDay);
page.querySelector('.timeslotHeaders').innerHTML = getTimeslotHeadersHtml(startDate, endDate);
renderPrograms(page, date, channels, programs);
}
var gridScrolling = false;
var headersScrolling = false;
function onProgramGridScroll(page, elem) {
if (!headersScrolling) {
gridScrolling = true;
$(page.querySelector('.timeslotHeaders')).scrollLeft($(elem).scrollLeft());
gridScrolling = false;
}
}
function onTimeslotHeadersScroll(page, elem) {
if (!gridScrolling) {
headersScrolling = true;
$(page.querySelector('.programGrid')).scrollLeft($(elem).scrollLeft());
headersScrolling = false;
}
}
function changeDate(page, date) {
currentDate = normalizeDateToTimeslot(date);
reloadGuide(page);
var text = LibraryBrowser.getFutureDateText(date);
text = '<span class="currentDay">' + text.replace(' ', ' </span>');
page.querySelector('.currentDate').innerHTML = text;
}
var dateOptions = [];
function setDateRange(page, guideInfo) {
var today = new Date();
today.setHours(today.getHours(), 0, 0, 0);
var start = parseISO8601Date(guideInfo.StartDate, { toLocal: true });
var end = parseISO8601Date(guideInfo.EndDate, { toLocal: true });
start.setHours(0, 0, 0, 0);
end.setHours(0, 0, 0, 0);
if (start.getTime() >= end.getTime()) {
end.setDate(start.getDate() + 1);
}
start = new Date(Math.max(today, start));
dateOptions = [];
while (start <= end) {
dateOptions.push({
name: LibraryBrowser.getFutureDateText(start),
id: start.getTime(),
ironIcon: 'today'
});
start.setDate(start.getDate() + 1);
start.setHours(0, 0, 0, 0);
}
var date = new Date();
if (currentDate) {
date.setTime(currentDate.getTime());
}
changeDate(page, date);
}
function reloadPageAfterValidation(page, limit) {
channelLimit = limit;
ApiClient.getLiveTvGuideInfo().done(function (guideInfo) {
setDateRange(page, guideInfo);
});
}
function reloadPage(page) {
$('.guideRequiresUnlock', page).hide();
RegistrationServices.validateFeature('livetv').done(function () {
Dashboard.showModalLoadingMsg();
reloadPageAfterValidation(page, 1000);
}).fail(function () {
Dashboard.showModalLoadingMsg();
var limit = 5;
$('.guideRequiresUnlock', page).show();
$('.unlockText', page).html(Globalize.translate('MessageLiveTvGuideRequiresUnlock', limit));
reloadPageAfterValidation(page, limit);
});
}
function selectDate(page) {
require(['actionsheet'], function () {
ActionSheetElement.show({
items: dateOptions,
showCancel: true,
title: Globalize.translate('HeaderSelectDate'),
callback: function (id) {
var date = new Date();
date.setTime(parseInt(id));
changeDate(page, date);
}
});
});
}
window.LiveTvPage.initGuideTab = function (page, tabContent) { window.LiveTvPage.initGuideTab = function (page, tabContent) {
Events.on(tabContent.querySelector('.programGrid'), 'scroll', function () {
onProgramGridScroll(tabContent, this);
});
if ($.browser.mobile) {
tabContent.querySelector('.tvGuide').classList.add('mobileGuide');
} else {
tabContent.querySelector('.tvGuide').classList.remove('mobileGuide');
Events.on(tabContent.querySelector('.timeslotHeaders'), 'scroll', function () {
onTimeslotHeadersScroll(tabContent, this);
});
}
if (AppInfo.enableHeadRoom) {
requirejs(["thirdparty/headroom"], function () {
// construct an instance of Headroom, passing the element
var headroom = new Headroom(tabContent.querySelector('.tvGuideHeader'));
// initialise
headroom.init();
});
}
$('.btnUnlockGuide', tabContent).on('click', function () {
reloadPage(tabContent);
});
$('.btnSelectDate', tabContent).on('click', function () {
selectDate(tabContent);
});
}; };
window.LiveTvPage.renderGuideTab = function (page, tabContent) { window.LiveTvPage.renderGuideTab = function (page, tabContent) {
if (page.guideInstance) {
if (LibraryBrowser.needsRefresh(tabContent)) { if (LibraryBrowser.needsRefresh(tabContent)) {
reloadPage(tabContent); page.guideInstance.refresh();
}
} else {
require(['tvguide'], function (tvguide) {
page.guideInstance = new tvguide({
element: tabContent,
enableHeadRoom: true,
enableHoverMenu: true
});
});
} }
}; };

View file

@ -626,6 +626,35 @@
} }
}; };
self.toggleGuide = function () {
var button = document.querySelector('.mediaButton.guideButton');
var nowPlayingInfo = document.querySelector('.videoControls .guide');
if (button.classList.contains('active')) {
button.classList.remove('active');
document.querySelector('.videoControls').classList.add('hiddenOnIdle');
fadeOutDown(nowPlayingInfo);
} else {
button.classList.add('active');
document.querySelector('.videoControls').classList.remove('hiddenOnIdle');
nowPlayingInfo.classList.remove('hide');
fadeInUp(nowPlayingInfo);
if (!self.guideInstance) {
require(['tvguide'], function (tvguide) {
self.guideInstance = new tvguide({
element: nowPlayingInfo,
enablePaging: false
});
});
}
}
};
function fadeInUp(elem) { function fadeInUp(elem) {
var keyframes = [ var keyframes = [
{ transform: 'translate3d(0, 100%, 0)', offset: 0 }, { transform: 'translate3d(0, 100%, 0)', offset: 0 },
@ -682,6 +711,9 @@
html += '<div class="nowPlayingTabs"></div>'; html += '<div class="nowPlayingTabs"></div>';
html += '</div>'; // nowPlayingInfo html += '</div>'; // nowPlayingInfo
html += '<div class="guide hide">';
html += '</div>'; // guide
html += '<div class="videoControlButtons">'; html += '<div class="videoControlButtons">';
html += '<paper-icon-button icon="skip-previous" class="previousTrackButton mediaButton videoTrackControl hide" onclick="MediaPlayer.previousTrack();"></paper-icon-button>'; html += '<paper-icon-button icon="skip-previous" class="previousTrackButton mediaButton videoTrackControl hide" onclick="MediaPlayer.previousTrack();"></paper-icon-button>';
@ -701,6 +733,7 @@
html += '<paper-icon-button icon="fullscreen" class="mediaButton fullscreenButton" onclick="MediaPlayer.toggleFullscreen();" id="video-fullscreenButton"></paper-icon-button>'; html += '<paper-icon-button icon="fullscreen" class="mediaButton fullscreenButton" onclick="MediaPlayer.toggleFullscreen();" id="video-fullscreenButton"></paper-icon-button>';
html += '<paper-icon-button icon="info" class="mediaButton infoButton" onclick="MediaPlayer.toggleInfo();"></paper-icon-button>'; html += '<paper-icon-button icon="info" class="mediaButton infoButton" onclick="MediaPlayer.toggleInfo();"></paper-icon-button>';
//html += '<paper-icon-button icon="dvr" class="mediaButton guideButton" onclick="MediaPlayer.toggleGuide();"></paper-icon-button>';
html += '</div>'; html += '</div>';
html += '</div>'; // videoControls html += '</div>'; // videoControls

View file

@ -2023,7 +2023,8 @@ var AppInfo = {};
} }
var paths = { var paths = {
velocity: "bower_components/velocity/velocity.min" velocity: "bower_components/velocity/velocity.min",
tvguide: 'components/tvguide/tvguide'
}; };
if (Dashboard.isRunningInCordova()) { if (Dashboard.isRunningInCordova()) {