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

unify guide between web and theater

This commit is contained in:
Luke Pulverenti 2016-04-26 14:28:04 -04:00
parent e8c224ae0b
commit af4e8c5529
23 changed files with 1314 additions and 1024 deletions

View file

@ -16,12 +16,12 @@
},
"devDependencies": {},
"ignore": [],
"version": "1.2.39",
"_release": "1.2.39",
"version": "1.2.45",
"_release": "1.2.45",
"_resolution": {
"type": "version",
"tag": "1.2.39",
"commit": "956d151bb5506eea13c56b69f21220b55d2b7d35"
"tag": "1.2.45",
"commit": "9c7b62bb1c95ce96c86da19d7d961eda9042acf7"
},
"_source": "https://github.com/MediaBrowser/emby-webcomponents.git",
"_target": "^1.2.0",

View file

@ -0,0 +1,12 @@
.clearButton {
background: transparent;
border: 0 !important;
padding: 0 !important;
cursor: pointer;
outline: none !important;
color: inherit;
width: 100%;
vertical-align: middle;
font-family: inherit;
font-size: inherit;
}

View file

@ -0,0 +1,382 @@
.tvguide {
display: flex;
flex-direction: column;
align-items: initial;
}
.tvGuideHeader {
white-space: nowrap;
width: 100%;
flex-shrink: 0;
}
.tvGuideHeader.headroom--unpinned {
-webkit-transform: translateY(-98px);
transform: translateY(-98px);
}
.tvProgramSectionHeader {
margin: 0;
}
.tvProgram {
display: block;
text-decoration: none;
white-space: nowrap;
position: relative;
}
.tvProgramTimeSlotInner {
padding: .5em;
}
.tvProgramInfo {
vertical-align: middle;
padding: .5em .5em;
border-bottom: .65vh solid #121212;
}
.tvProgramCurrentTimeSlot {
background-color: green;
}
.tvProgramName {
color: #fff;
margin-bottom: .5em;
}
.tvProgramTime {
color: #fff;
}
.newTvProgram {
color: yellow;
text-transform: uppercase;
}
.liveTvProgram {
color: #64A239;
text-transform: uppercase;
}
.premiereTvProgram {
color: orange;
text-transform: uppercase;
}
.programAccent {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 2px;
}
.sportsProgramInfo .programAccent {
background-color: #0A7C33;
}
.newsProgramInfo .programAccent {
background-color: #523378;
}
.movieProgramInfo .programAccent {
background-color: #A43913;
}
.childProgramInfo .programAccent {
background-color: #0B487D;
}
.timerCircle {
display: inline-block;
width: 1em;
height: 1em;
border-radius: 50%;
background: #cc0000;
border: 1px solid #cc3333;
margin-left: 1em;
}
.seriesTimerCircle {
position: relative;
margin-left: 0;
left: 21px;
opacity: .3;
}
.itemMiscInfo .seriesTimerCircle:first-child {
margin-left: 1em;
}
.seriesTimerCircle + .seriesTimerCircle {
opacity: .65;
left: 0;
}
.seriesTimerCircle + .seriesTimerCircle + .seriesTimerCircle {
opacity: 1;
left: -21px;
}
.channelTimeslotHeader {
float: left;
}
.timeslotHeaders {
white-space: nowrap;
}
.mobileGuide .timeslotHeaders {
overflow-x: hidden;
}
.programContainer {
white-space: nowrap;
position: relative;
}
.programGridContainer {
margin-left: 12.2vw;
}
.channelPrograms {
white-space: nowrap;
position: relative;
}
.channelPrograms, .timeslotHeadersInner {
width: 1800vw;
}
@media all and (min-width: 600px) {
.channelPrograms, .timeslotHeadersInner {
width: 1400vw;
}
}
@media all and (min-width: 800px) {
.channelPrograms, .timeslotHeadersInner {
width: 1200vw;
}
}
@media all and (min-width: 1280px) {
.channelPrograms, .timeslotHeadersInner {
width: 660vw;
}
}
.timeslotHeader {
display: inline-flex;
align-items: center;
text-indent: .35em;
}
.channelHeaderCell, .channelTimeslotHeader {
overflow: hidden;
text-overflow: ellipsis;
border-right: 1px solid #121212;
width: 24vw;
background: rgba(40, 40, 40, .9);
display: flex;
align-items: center;
color: #fff !important;
text-decoration: none;
}
@media all and (min-width: 500px) {
.channelHeaderCell, .channelTimeslotHeader {
width: 16vw;
}
}
@media all and (min-width: 600px) {
.channelHeaderCell, .channelTimeslotHeader {
width: 16vw;
}
}
@media all and (min-width: 800px) {
.channelHeaderCell, .channelTimeslotHeader {
width: 14vw;
}
}
@media all and (min-width: 1280px) {
.channelHeaderCell, .channelTimeslotHeader {
width: 12vw;
}
}
.btnSelectDate {
color: #fff;
padding-left: .5em;
}
.channelHeaderCell {
border-bottom: .65vh solid #121212 !important;
background-size: auto 65.7%;
background-position: 90% center;
background-repeat: no-repeat;
}
@media all and (max-width: 800px) {
.guideCurrentDay {
display: none;
}
}
@media all and (max-width: 1280px) {
.guideChannelInfoWithImage .guideChannelName {
display: none;
}
}
.channelPrograms, .channelHeaderCell {
height: 15vh;
}
@media all and (min-height: 500px) {
.channelPrograms, .channelHeaderCell {
height: 10.5vh;
}
}
@media all and (min-height: 600px) {
.channelPrograms, .channelHeaderCell {
height: 9vh;
}
}
@media all and (min-height: 720px) {
.channelPrograms, .channelHeaderCell {
height: 6vh;
}
.layout-tv .channelPrograms, .layout-tv .channelHeaderCell {
height: 7.6vh;
}
}
.channelTimeslotHeader {
border-right-color: transparent;
}
.channelTimeslotHeader, .timeslotHeader {
background: transparent;
}
.timeslotHeader, .channelTimeslotHeader {
height: 5.75vh;
}
.pointerInput .channelHeaderCell:hover {
background-color: #444;
}
.channelList {
float: left;
}
.programGrid {
padding-bottom: 4px;
}
.timeslotHeader {
width: 2.0833333333333333333333333333333%;
}
.programCell {
position: absolute;
top: 0;
/* Unfortunately the borders using vh get rounded while the bottom property doesn't. So this is a little hack to try and make them even*/
bottom: .59vh;
border-left: .65vh solid #121212 !important;
background-color: rgba(32, 32, 32, .95);
display: flex;
color: #fff !important;
text-decoration: none;
overflow: hidden;
align-items: center;
}
.timeslotCellInner {
position: absolute;
bottom: 0;
overflow: hidden;
width: 100%;
top: 0;
display: block;
text-decoration: none;
color: #fff !important;
}
.guideProgramName {
padding: 0 .5em 0;
overflow: hidden;
text-overflow: ellipsis;
}
.guideProgramTime {
padding: 0 .5em .35em;
color: #bbb;
}
.programCell iron-icon {
margin-left: auto;
margin-right: .5em;
height: 3.5vh;
width: 3.5vh;
color: #ddd;
flex-shrink: 0;
}
.programCell iron-icon + iron-icon {
margin-left: .25em;
}
.guideChannelInfo {
display: inline-block;
max-width: 110px;
overflow: hidden;
white-space: nowrap;
padding-left: .7em;
}
.guideChannelName {
margin-left: auto;
margin-right: .3em;
max-width: 6vw;
text-overflow: ellipsis;
overflow: hidden;
}
.channelList, .programGrid {
height: auto !important;
}
.programCell:focus, .channelHeaderCell:focus, .btnSelectDate:focus {
background-color: #52B54B;
outline: none !important;
}
.programCell:focus .programAccent {
background-color: transparent !important;
}
.timerIcon, .seriesTimerIcon {
color: #cc3333 !important;
}

View file

@ -0,0 +1,633 @@
define(['globalize', 'connectionManager', 'loading', 'scrollHelper', 'datetime', 'focusManager', 'imageLoader', 'events', 'layoutManager', 'itemShortcuts', 'registrationservices', 'clearButtonStyle', 'css!./guide.css', 'scrollStyles'], function (globalize, connectionManager, loading, scrollHelper, datetime, focusManager, imageLoader, events, layoutManager, itemShortcuts, registrationServices) {
var baseUrl;
function Guide(options) {
var self = this;
var items = {};
self.refresh = function () {
reloadPage(options.element);
};
self.destroy = function () {
itemShortcuts.off(options.element);
items = {};
};
// 30 mins
var cellCurationMinutes = 30;
var cellDurationMs = cellCurationMinutes * 60 * 1000;
var msPerDay = 86400000;
var currentDate;
var channelQuery = {
StartIndex: 0,
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 showLoading() {
loading.show();
}
function hideLoading() {
loading.hide();
}
function getChannelLimit(context) {
return registrationServices.validateFeature('livetv').then(function () {
var limit = 400;
context.querySelector('.guideRequiresUnlock').classList.add('hide');
return limit;
}, function () {
var limit = 5;
context.querySelector('.guideRequiresUnlock').classList.remove('hide');
context.querySelector('.unlockText').innerHTML = globalize.translate('MessageLiveTvGuideRequiresUnlock', limit);
return limit;
});
}
function reloadGuide(context, newStartDate) {
var apiClient = connectionManager.currentApiClient();
channelQuery.UserId = apiClient.getCurrentUserId();
getChannelLimit(context).then(function (channelLimit) {
showLoading();
channelQuery.Limit = channelLimit;
channelQuery.AddCurrentProgram = false;
channelsPromise = channelsPromise || apiClient.getLiveTvChannels(channelQuery);
var 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
var nextDay = new Date(date.getTime() + msPerDay - 2000);
console.log(nextDay);
channelsPromise.then(function (channelsResult) {
apiClient.getLiveTvPrograms({
UserId: apiClient.getCurrentUserId(),
MaxStartDate: nextDay.toISOString(),
MinEndDate: date.toISOString(),
channelIds: channelsResult.Items.map(function (c) {
return c.Id;
}).join(','),
ImageTypeLimit: 1,
EnableImageTypes: "Primary,Backdrop",
SortBy: "StartDate"
}).then(function (programsResult) {
renderGuide(context, date, channelsResult.Items, programsResult.Items, apiClient);
hideLoading();
});
});
});
}
function getDisplayTime(date) {
if ((typeof date).toString().toLowerCase() === 'string') {
try {
date = datetime.parseISO8601Date(date, { toLocal: true });
} catch (err) {
return date;
}
}
return datetime.getDisplayTime(date).toLowerCase();
}
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 += getDisplayTime(startDate);
html += '</div>';
// Add 30 mins
startDate.setTime(startDate.getTime() + cellDurationMs);
}
html += '</div>';
return html;
}
function parseDates(program) {
if (!program.StartDateLocal) {
try {
program.StartDateLocal = datetime.parseISO8601Date(program.StartDate, { toLocal: true });
} catch (err) {
}
}
if (!program.EndDateLocal) {
try {
program.EndDateLocal = datetime.parseISO8601Date(program.EndDate, { toLocal: true });
} catch (err) {
}
}
return null;
}
function getChannelProgramsHtml(context, 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;
}
items[program.Id] = program;
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;
var cssClass = "programCell clearButton itemAction";
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 += '<button data-action="link" data-isfolder="' + program.IsFolder + '" data-id="' + program.Id + '" data-serverid="' + program.ServerId + '" data-type="' + program.Type + '" class="' + cssClass + '" style="left:' + startPercent + '%;width:' + endPercent + '%;">';
var guideProgramNameClass = "guideProgramName";
html += '<div class="' + guideProgramNameClass + '">';
if (program.IsLive) {
html += '<span class="liveTvProgram">' + globalize.translate('core#AttributeLive') + '&nbsp;</span>';
}
else if (program.IsPremiere) {
html += '<span class="premiereTvProgram">' + globalize.translate('core#AttributePremiere') + '&nbsp;</span>';
}
else if (program.IsSeries && !program.IsRepeat) {
html += '<span class="newTvProgram">' + globalize.translate('core#AttributeNew') + '&nbsp;</span>';
}
html += program.Name;
html += '</div>';
if (program.IsHD) {
html += '<iron-icon icon="core:hd"></iron-icon>';
}
if (program.SeriesTimerId) {
html += '<iron-icon class="seriesTimerIcon" icon="core:fiber-smart-record"></iron-icon>';
}
else if (program.TimerId) {
html += '<iron-icon class="timerIcon" icon="core:fiber-manual-record"></iron-icon>';
}
if (addAccent) {
html += '<div class="programAccent"></div>';
}
html += '</button>';
}
html += '</div>';
return html;
}
function renderPrograms(context, date, channels, programs) {
var html = [];
for (var i = 0, length = channels.length; i < length; i++) {
html.push(getChannelProgramsHtml(context, date, channels[i], programs));
}
var programGrid = context.querySelector('.programGrid');
programGrid.innerHTML = html.join('');
programGrid.scrollTop = 0;
programGrid.scrollLeft = 0;
}
function renderChannelHeaders(context, channels, apiClient) {
var html = '';
for (var i = 0, length = channels.length; i < length; i++) {
var channel = channels[i];
var hasChannelImage = channel.ImageTags.Primary;
var dataSrc = '';
if (hasChannelImage) {
var url = apiClient.getScaledImageUrl(channel.Id, {
maxHeight: 200,
tag: channel.ImageTags.Primary,
type: "Primary"
});
dataSrc = ' data-src="' + url + '"';
}
html += '<button type="button" class="channelHeaderCell clearButton itemAction lazy"' + dataSrc + ' data-action="link" data-isfolder="' + channel.IsFolder + '" data-id="' + channel.Id + '" data-serverid="' + channel.ServerId + '" data-type="' + channel.Type + '">';
var cssClass = hasChannelImage ? 'guideChannelInfo guideChannelInfoWithImage' : 'guideChannelInfo';
html += '<div class="' + cssClass + '"><div class="guideChannelName">' + channel.Number + '</div></div>';
html += '</button>';
}
var channelList = context.querySelector('.channelList');
channelList.innerHTML = html;
imageLoader.lazyChildren(channelList);
}
function renderGuide(context, date, channels, programs, apiClient) {
//var list = [];
//channels.forEach(function(i) {
// list.push(i);
//});
//channels.forEach(function (i) {
// list.push(i);
//});
//channels.forEach(function (i) {
// list.push(i);
//});
//channels.forEach(function (i) {
// list.push(i);
//});
//channels.forEach(function (i) {
// list.push(i);
//});
//channels.forEach(function (i) {
// list.push(i);
//});
//channels.forEach(function (i) {
// list.push(i);
//});
//channels.forEach(function (i) {
// list.push(i);
//});
//channels.forEach(function (i) {
// list.push(i);
//});
//channels.forEach(function (i) {
// list.push(i);
//});
//channels.forEach(function (i) {
// list.push(i);
//});
//channels.forEach(function (i) {
// list.push(i);
//});
//channels = list;
renderChannelHeaders(context, channels, apiClient);
var startDate = date;
var endDate = new Date(startDate.getTime() + msPerDay);
context.querySelector('.timeslotHeaders').innerHTML = getTimeslotHeadersHtml(startDate, endDate);
items = {};
renderPrograms(context, date, channels, programs);
if (layoutManager.tv) {
focusManager.autoFocus(context.querySelector('.programGrid'), true);
}
}
function nativeScrollTo(container, pos, horizontal) {
if (container.scrollTo) {
if (horizontal) {
container.scrollTo(pos, 0);
} else {
container.scrollTo(0, pos);
}
} else {
if (horizontal) {
container.scrollLeft = Math.round(pos);
} else {
container.scrollTop = Math.round(pos);
}
}
}
var lastGridScroll = 0;
var lastHeaderScroll = 0;
function onProgramGridScroll(context, elem, timeslotHeaders) {
if ((new Date().getTime() - lastHeaderScroll) >= 1000) {
lastGridScroll = new Date().getTime();
nativeScrollTo(timeslotHeaders, elem.scrollLeft, true);
}
}
function onTimeslotHeadersScroll(context, elem, programGrid) {
if ((new Date().getTime() - lastGridScroll) >= 1000) {
lastHeaderScroll = new Date().getTime();
nativeScrollTo(programGrid, elem.scrollLeft, true);
}
}
function getFutureDateText(date) {
var weekday = [];
weekday[0] = globalize.translate('core#OptionSundayShort');
weekday[1] = globalize.translate('core#OptionMondayShort');
weekday[2] = globalize.translate('core#OptionTuesdayShort');
weekday[3] = globalize.translate('core#OptionWednesdayShort');
weekday[4] = globalize.translate('core#OptionThursdayShort');
weekday[5] = globalize.translate('core#OptionFridayShort');
weekday[6] = globalize.translate('core#OptionSaturdayShort');
var day = weekday[date.getDay()];
date = date.toLocaleDateString();
if (date.toLowerCase().indexOf(day.toLowerCase()) == -1) {
return day + " " + date;
}
return date;
}
function changeDate(page, date) {
var newStartDate = normalizeDateToTimeslot(date);
currentDate = newStartDate;
reloadGuide(page, newStartDate);
var text = getFutureDateText(date);
text = '<span class="guideCurrentDay">' + text.replace(' ', ' </span>');
page.querySelector('.btnSelectDate').innerHTML = text;
}
var dateOptions = [];
function setDateRange(page, guideInfo) {
var today = new Date();
today.setHours(today.getHours(), 0, 0, 0);
var start = datetime.parseISO8601Date(guideInfo.StartDate, { toLocal: true });
var end = datetime.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: getFutureDateText(start),
id: start.getTime()
});
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 reloadPage(page) {
showLoading();
var apiClient = connectionManager.currentApiClient();
apiClient.getLiveTvGuideInfo().then(function (guideInfo) {
setDateRange(page, guideInfo);
});
}
function selectDate(page) {
require(['actionsheet'], function (actionsheet) {
actionsheet.show({
items: dateOptions,
title: globalize.translate('core#HeaderSelectDate'),
callback: function (id) {
var date = new Date();
date.setTime(parseInt(id));
changeDate(page, date);
}
});
});
}
function createVerticalScroller(view, pageInstance) {
if (layoutManager.tv) {
scrollHelper.centerFocus.on(view.querySelector('.smoothScrollY'), false);
var programGrid = view.querySelector('.programGrid');
scrollHelper.centerFocus.on(programGrid, true);
}
}
function parentWithClass(elem, className) {
while (!elem.classList || !elem.classList.contains(className)) {
elem = elem.parentNode;
if (!elem) {
return null;
}
}
return elem;
}
var selectedMediaInfoTimeout;
var focusedElement;
function onProgramGridFocus(e) {
var programCell = parentWithClass(e.target, 'programCell');
if (!programCell) {
return;
}
focusedElement = e.target;
if (selectedMediaInfoTimeout) {
clearTimeout(selectedMediaInfoTimeout);
}
selectedMediaInfoTimeout = setTimeout(onSelectedMediaInfoTimeout, 700);
}
function onSelectedMediaInfoTimeout() {
var focused = focusedElement
if (focused && document.activeElement == focused) {
var id = focused.getAttribute('data-id');
var item = items[id];
if (item) {
events.trigger(self, 'focus', [
{
item: item
}]);
}
}
}
fetch(baseUrl + '/tvguide.template.html', { mode: 'no-cors' }).then(function (response) {
return response.text();
}).then(function (template) {
var context = options.element;
context.innerHTML = globalize.translateDocument(template, 'core');
var programGrid = context.querySelector('.programGrid');
var timeslotHeaders = context.querySelector('.timeslotHeaders');
programGrid.addEventListener('focus', onProgramGridFocus, true);
programGrid.addEventListener('scroll', function () {
onProgramGridScroll(context, this, timeslotHeaders);
});
timeslotHeaders.addEventListener('scroll', function () {
onTimeslotHeadersScroll(context, this, programGrid);
});
context.querySelector('.btnSelectDate').addEventListener('click', function () {
selectDate(context);
});
context.querySelector('.btnUnlockGuide').addEventListener('click', function () {
reloadPage(context);
});
context.classList.add('tvguide');
createVerticalScroller(context, self);
itemShortcuts.on(context);
self.refresh();
});
};
Guide.setBaseUrl = function (url) {
baseUrl = url;
};
return Guide;
});

View file

@ -0,0 +1,22 @@
<div class="tvGuideHeader">
<div class="channelTimeslotHeader">
<button class="btnSelectDate clearButton" style="display:block;"></button>
</div>
<div class="timeslotHeaders smoothScrollX" style="scroll-behavior: auto;"></div>
</div>
<div class="smoothScrollY guideVerticalScroller" style="flex-grow: 1;">
<div class="programContainer">
<div class="channelList"></div>
<div class="programGridContainer programGrid smoothScrollX" style="white-space: nowrap;">
</div>
</div>
</div>
<div class="guideRequiresUnlock readOnlyContent hide" style="margin:1em auto;text-align:center;padding:1em;flex-shrink:0;">
<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

@ -271,17 +271,17 @@ define(['loading', 'viewManager', 'skinManager', 'pluginManager', 'backdrop', 'b
var apiClient = connectionManager.currentApiClient();
var pathname = ctx.pathname.toLowerCase();
console.log('Emby.Page - processing path request ' + pathname);
console.log('embyRouter - processing path request ' + pathname);
if ((!apiClient || !apiClient.isLoggedIn()) && !route.anonymous) {
console.log('Emby.Page - route does not allow anonymous access, redirecting to login');
console.log('embyRouter - route does not allow anonymous access, redirecting to login');
beginConnectionWizard();
return;
}
if (apiClient && apiClient.isLoggedIn()) {
console.log('Emby.Page - user is authenticated');
console.log('embyRouter - user is authenticated');
var isCurrentRouteStartup = currentRouteInfo ? currentRouteInfo.route.startup : true;
if (ctx.isBack && (route.isDefaultRoute || route.startup) && !isCurrentRouteStartup) {
@ -289,7 +289,7 @@ define(['loading', 'viewManager', 'skinManager', 'pluginManager', 'backdrop', 'b
return;
}
else if (route.isDefaultRoute) {
console.log('Emby.Page - loading skin home page');
console.log('embyRouter - loading skin home page');
skinManager.loadUserSkin();
return;
} else if (route.roles) {
@ -303,7 +303,7 @@ define(['loading', 'viewManager', 'skinManager', 'pluginManager', 'backdrop', 'b
}
}
console.log('Emby.Page - proceeding to ' + pathname);
console.log('embyRouter - proceeding to ' + pathname);
callback();
}
@ -484,8 +484,10 @@ define(['loading', 'viewManager', 'skinManager', 'pluginManager', 'backdrop', 'b
function showItem(item) {
if (typeof (item) === 'string') {
Emby.Models.item(item).then(showItem);
require(['connectionManager'], function (connectionManager) {
var apiClient = connectionManager.currentApiClient();
apiClient.getItem(apiClient.getCurrentUserId(), item).then(showItem);
});
} else {
skinManager.getCurrentSkin().showItem(item);
}

View file

@ -0,0 +1,168 @@
define(['playbackManager', 'inputManager', 'connectionManager', 'embyRouter'], function (playbackManager, inputManager, connectionManager, embyRouter) {
function playAllFromHere(card, serverId) {
var cards = card.parentNode.querySelectorAll('.itemAction[data-id]');
var ids = [];
var foundCard = false;
for (var i = 0, length = cards.length; i < length; i++) {
if (cards[i] == card) {
foundCard = true;
}
if (foundCard) {
ids.push(cards[i].getAttribute('data-id'));
}
}
playbackManager.play({
ids: ids,
serverId: serverId
});
}
function showSlideshow(startItemId, serverId) {
var apiClient = connectionManager.getApiClient(serverId);
var userId = apiClient.getCurrentUserId();
return apiClient.getItem(userId, startItemId).then(function (item) {
return apiClient.getItems(userId, {
MediaTypes: 'Photo',
Filters: 'IsNotFolder',
ParentId: item.ParentId
}).then(function (result) {
var items = result.Items;
var index = items.map(function (i) {
return i.Id;
}).indexOf(startItemId);
if (index == -1) {
index = 0;
}
require(['slideshow'], function (slideshow) {
var newSlideShow = new slideshow({
showTitle: false,
cover: false,
items: items,
startIndex: index,
interval: 8000,
interactive: true
});
newSlideShow.show();
});
});
});
}
function showItem(options) {
if (options.Type == 'Photo') {
showSlideshow(options.Id, options.ServerId);
return;
}
embyRouter.showItem(options);
}
function executeAction(card, action) {
var id = card.getAttribute('data-id');
var serverId = card.getAttribute('data-serverid');
var type = card.getAttribute('data-type');
var isfolder = card.getAttribute('data-isfolder') == 'true';
if (action == 'link') {
showItem({
Id: id,
Type: type,
IsFolder: isfolder,
ServerId: serverId
});
}
else if (action == 'instantmix') {
playbackManager.instantMix(id, serverId);
}
else if (action == 'play') {
var startPositionTicks = parseInt(card.getAttribute('data-startpositionticks') || '0');
playbackManager.play({
ids: [id],
startPositionTicks: startPositionTicks,
serverId: serverId
});
}
else if (action == 'playallfromhere') {
playAllFromHere(card, serverId);
}
else if (action == 'setplaylistindex') {
}
}
function onClick(e) {
var card = parentWithClass(e.target, 'itemAction');
if (card) {
var action = card.getAttribute('data-action');
if (action) {
executeAction(card, action);
}
}
}
function parentWithClass(elem, className) {
while (!elem.classList || !elem.classList.contains(className)) {
elem = elem.parentNode;
if (!elem) {
return null;
}
}
return elem;
}
function onCommand(e) {
var cmd = e.detail.command;
if (cmd == 'play') {
var card = parentWithClass(e.target, 'itemAction');
if (card) {
executeAction(card, cmd);
}
}
}
function on(context) {
context.addEventListener('click', onClick);
inputManager.on(context, onCommand);
}
function off(context) {
context.removeEventListener('click', onClick);
inputManager.off(context, onCommand);
}
return {
on: on,
off: off
};
});

View file

@ -32,14 +32,14 @@
"web-component-tester": "^4.0.0",
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
},
"homepage": "https://github.com/PolymerElements/iron-icon",
"homepage": "https://github.com/polymerelements/iron-icon",
"_release": "1.0.8",
"_resolution": {
"type": "version",
"tag": "v1.0.8",
"commit": "f36b38928849ef3853db727faa8c9ef104d611eb"
},
"_source": "git://github.com/PolymerElements/iron-icon.git",
"_source": "git://github.com/polymerelements/iron-icon.git",
"_target": "^1.0.0",
"_originalSource": "PolymerElements/iron-icon"
"_originalSource": "polymerelements/iron-icon"
}

View file

@ -36,7 +36,7 @@
"tag": "v1.4.0",
"commit": "554f7418fdbd97688eb21518b5f8172167d53a95"
},
"_source": "git://github.com/polymerelements/iron-selector.git",
"_source": "git://github.com/PolymerElements/iron-selector.git",
"_target": "^1.0.0",
"_originalSource": "polymerelements/iron-selector"
"_originalSource": "PolymerElements/iron-selector"
}

View file

@ -1,519 +0,0 @@
define(['jQuery', 'livetvcss', 'scripts/livetvcomponents', 'scrollStyles'], 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 = browserInfo.mobile ? 50 : 100;
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.showLoadingMsg();
channelQuery.UserId = Dashboard.getCurrentUserId();
channelQuery.Limit = Math.min(channelQuery.Limit || defaultChannels, channelLimit);
channelQuery.AddCurrentProgram = false;
channelsPromise = channelsPromise || ApiClient.getLiveTvChannels(channelQuery);
var date = currentDate;
// 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
var nextDay = new Date(date.getTime() + msPerDay - 2000);
console.log(nextDay);
channelsPromise.then(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,
EnableImages: false,
SortBy: "StartDate"
}).then(function (programsResult) {
renderGuide(page, date, channelsResult.Items, programsResult.Items);
Dashboard.hideLoadingMsg();
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);
}
page.querySelector('.btnNextPage').addEventListener('click', function () {
channelQuery.StartIndex += channelQuery.Limit;
reloadChannels(page);
});
page.querySelector('.btnPreviousPage').addEventListener('click', function () {
channelQuery.StartIndex -= channelQuery.Limit;
reloadChannels(page);
});
page.querySelector('#selectPageSize').addEventListener('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;
var cssClass = "programCell";
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 + '" style="left:' + startPercent + '%;width:' + endPercent + '%;">';
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>';
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);
}
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 += '<a class="channelHeaderCell" href="itemdetails.html?id=' + channel.Id + '">';
var hasChannelImage = channel.ImageTags.Primary;
var cssClass = hasChannelImage ? 'guideChannelInfo guideChannelInfoWithImage' : 'guideChannelInfo';
html += '<div class="' + cssClass + '">' + channel.Number + '</div>';
if (hasChannelImage) {
var url = ApiClient.getScaledImageUrl(channel.Id, {
maxHeight: 44,
maxWidth: 70,
tag: channel.ImageTags.Primary,
type: "Primary"
});
html += '<div class="guideChannelImage lazy" data-src="' + url + '"></div>';
} else {
html += '<div class="guideChannelName">' + channel.Name + '</div>';
}
html += '</a>';
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().then(function (guideInfo) {
setDateRange(page, guideInfo);
});
}
function reloadPage(page) {
$('.guideRequiresUnlock', page).hide();
RegistrationServices.validateFeature('livetv').then(function () {
Dashboard.showLoadingMsg();
reloadPageAfterValidation(page, 1000);
}, function () {
Dashboard.showLoadingMsg();
var limit = 5;
$('.guideRequiresUnlock', page).show();
$('.unlockText', page).html(Globalize.translate('MessageLiveTvGuideRequiresUnlock', limit));
reloadPageAfterValidation(page, limit);
});
}
function selectDate(page) {
require(['actionsheet'], function (actionsheet) {
actionsheet.show({
items: dateOptions,
showCancel: true,
title: Globalize.translate('HeaderSelectDate'),
callback: function (id) {
var date = new Date();
date.setTime(parseInt(id));
changeDate(page, date);
}
});
});
}
var xhr = new XMLHttpRequest();
xhr.open('GET', 'components/tvguide/tvguide.template.html', true);
xhr.onload = function (e) {
var template = this.response;
var tabContent = options.element;
tabContent.innerHTML = Globalize.translateDocument(template);
tabContent.querySelector('.programGrid').addEventListener('scroll', function (e) {
onProgramGridScroll(tabContent, e.target);
});
if (browserInfo.mobile) {
tabContent.querySelector('.tvGuide').classList.add('mobileGuide');
} else {
tabContent.querySelector('.tvGuide').classList.remove('mobileGuide');
tabContent.querySelector('.timeslotHeaders').addEventListener('scroll', function (e) {
onTimeslotHeadersScroll(tabContent, e.target);
});
}
if (AppInfo.enableHeadRoom && options.enableHeadRoom) {
requirejs(["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();
}
xhr.send();
};
});

View file

@ -1,19 +0,0 @@
<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 smoothScrollX"></div>
</div>
<div class="programContainer">
<div class="channelList"></div>
<div class="programGrid smoothScrollX"></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

@ -13,7 +13,8 @@
.absolutePageTabContent {
margin: 0 !important;
width: 100% !important;
top: 98px !important;
/* Page needs to supply padding */
top: 92px !important;
}
.sidebarDivider {

View file

@ -1,421 +1,12 @@
.guideTabContent {
background: #161616;
}
.tvGuide {
text-align: left;
}
.tvGuideHeader {
white-space: nowrap;
position: fixed;
top: 95px;
left: 0;
z-index: 100;
max-width: 100%;
}
.neon-animating .tvGuideHeader {
position: static;
}
.tvGuideHeader.headroom--unpinned {
-webkit-transform: translateY(-98px);
transform: translateY(-98px);
}
.tvProgramSectionHeader {
margin: 0;
}
.tvProgram {
display: block;
text-decoration: none;
font-weight: normal !important;
white-space: nowrap;
position: relative;
}
.detailSectionHeader + .tvProgram {
border-top: 6px solid #161616;
margin-top: 1px;
}
.tvProgramTimeSlot {
width: 80px;
vertical-align: middle;
font-weight: bold;
color: #fff;
position: absolute;
top: 0;
left: 0;
bottom: 0;
border-bottom: 6px solid #161616;
}
.tvProgramTimeSlotInner {
padding: .5em;
}
.tvProgramInfo {
vertical-align: middle;
padding: .5em .5em;
border-bottom: 6px solid #161616;
}
.tvProgramTimeSlot + .tvProgramInfo {
margin-left: 80px;
border-left: 6px solid #161616;
position: relative;
}
.tvProgramCurrentTimeSlot {
background-color: green;
}
.tvProgramName {
color: #fff;
font-weight: bold;
margin-bottom: .5em;
}
.tvProgramTime {
color: #fff;
}
.newTvProgram {
color: #E88606;
}
.liveTvProgram {
color: #64A239;
}
.premiereTvProgram {
color: yellow;
}
.programAccent {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 2px;
}
.sportsProgramInfo .programAccent {
background-color: #0A7C33;
}
.newsProgramInfo .programAccent {
background-color: #523378;
}
.movieProgramInfo .programAccent {
background-color: #A43913;
}
.childProgramInfo .programAccent {
background-color: #0B487D;
}
.timerCircle {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
background: #cc0000;
border: 1px solid #cc3333;
margin-left: 1em;
}
.seriesTimerCircle {
position: relative;
margin-left: 0;
left: 21px;
opacity: .3;
}
.itemMiscInfo .seriesTimerCircle:first-child {
margin-left: 1em;
}
.seriesTimerCircle + .seriesTimerCircle {
opacity: .65;
left: 0;
}
.seriesTimerCircle + .seriesTimerCircle + .seriesTimerCircle {
opacity: 1;
left: -21px;
}
.channelImageContainer .itemDetailImage {
max-width: 200px;
max-height: 110px;
margin-top: 1em;
margin-bottom: 1em;
}
.channelTimeslotHeader {
float: left;
}
.timeslotHeaders {
white-space: nowrap;
}
.mobileGuide .timeslotHeaders {
overflow-x: hidden;
}
.programContainer {
white-space: nowrap;
position: relative;
margin: 0 auto;
margin-top: 44px;
}
.mobileGuide .programContainer {
margin-top: 38px;
}
.channelPrograms {
white-space: nowrap;
height: 61px;
position: relative;
}
.channelPrograms, .timeslotHeadersInner {
width: 12000px;
}
.timeslotHeader {
display: inline-block;
}
.timeslotHeaderInner {
padding: .6em .35em .5em;
font-weight: 400;
}
.channelTimeslotHeader .timeslotHeaderInner {
padding-top: .4em;
}
.channelHeaderCell, .channelTimeslotHeader {
overflow: hidden;
text-overflow: ellipsis;
border-right: 1px solid #161616;
width: 199px;
background: #303030;
}
.channelHeaderCell {
border-bottom: 0 !important;
}
.channelHeaderCellContainer + .channelHeaderCellContainer .channelHeaderCell {
border-top: 6px solid #161616;
}
.channelTimeslotHeader {
border-right-color: #52B54B;
}
.channelTimeslotHeader, .timeslotHeader {
background: #52B54B;
}
.timeslotHeader, .channelTimeslotHeader {
height: 42px;
}
.channelHeaderCell {
padding: 0;
text-decoration: none;
font-weight: 400 !important;
color: #fff !important;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.pointerInput .channelHeaderCell:hover {
background-color: #444;
}
.channelList {
float: left;
font-weight: 400;
}
.programGrid {
padding-bottom: 4px;
}
.programGrid, .timeslotHeaders {
margin-left: 200px;
}
.timeslotHeader {
width: 2.0833333333333333333333333333333%;
}
.programCell {
position: absolute;
top: 0;
bottom: 6px;
border-left: 6px solid #161616;
background-color: #212121;
display: block;
color: #fff !important;
text-decoration: none;
font-weight: 400 !important;
overflow: hidden;
}
.timeslotCellInner {
position: absolute;
bottom: 0;
overflow: hidden;
width: 100%;
top: 0;
display: block;
text-decoration: none;
font-weight: normal !important;
color: #fff !important;
}
.channelHeaderCell {
height: 55px;
}
.guideProgramName {
padding: .5em .5em .35em;
}
.guideProgramTime {
padding: 0 .5em .35em;
color: #bbb;
}
.guideChannelInfo {
display: inline-block;
max-width: 110px;
overflow: hidden;
white-space: nowrap;
margin-left: .5em;
margin-right: auto;
}
.guideChannelImage {
width: 70px;
height: 44px;
background-size: contain;
background-position: right center;
background-repeat: no-repeat;
margin-right: .5em;
}
.guideChannelName {
margin-right: .5em;
max-width: 50%;
overflow: hidden;
text-overflow: ellipsis;
}
@media (max-width: 1920px) {
.channelPrograms, .timeslotHeadersInner {
width: 10000px;
}
}
@media (max-width: 1600px) {
.channelPrograms, .timeslotHeadersInner {
width: 8000px;
}
}
@media (max-width: 600px) {
.guideChannelInfoWithImage {
display: none;
}
.timerPageImageContainer {
display: none !important;
}
.channelHeaderCell, .channelTimeslotHeader {
width: 98px;
}
.programGrid, .timeslotHeaders {
margin-left: 99px;
}
.currentDay {
display: none;
}
.channelPrograms, .timeslotHeadersInner {
width: 6500px;
}
.timeslotHeaderInner {
padding-top: .8em;
}
.channelTimeslotHeader a {
padding-left: 0 !important;
}
.channelTimeslotHeader i {
margin-right: 4px !important;
}
.channelTimeslotHeader .timeslotHeaderInner {
padding-top: .5em;
}
}
.channelList, .programGrid {
height: auto !important;
}
.itemOverlayContent {
width: 200px;
}
@media (min-width: 800px) {
.itemOverlayContent {
width: 300px;
}
.channelList, .timeslotHeaderInner {
font-size: 110%;
}
}
@media (min-width: 1000px) {
.itemOverlayContent {
width: 400px;
}
}
@media (min-width: 1200px) {
.itemOverlayContent {
width: 500px;
}
background: #121212;
}
.chkAdvanced {
margin-left: auto;
}
/* Allow vertical space for anything that slides up at the bottom */
.guideVerticalScroller {
padding-bottom: 160px;
}

View file

@ -300,6 +300,10 @@ body {
height: 100%;
}
body.autoScrollY {
overflow-y: auto !important;
}
/* Without this, no content will be displayed in mobile safari */
.pageContainer {
overflow-x: visible !important;

View file

@ -106,14 +106,6 @@
color: #52B54B !important;
}
.channelTimeslotHeader {
border-right-color: #52B54B !important;
}
.channelTimeslotHeader, .timeslotHeader {
background: #52B54B !important;
}
.libraryViewNav, paper-tabs {
font-size: 12px;
}
@ -126,18 +118,6 @@ h1, h1 a {
font-weight: 400;
}
.channelList {
font-weight: 400;
}
.channelHeaderCellInner {
font-weight: 400;
}
.tvGuideHeader {
top: 86px !important;
}
.libraryMenuButtonText {
font-weight: 500 !important;
position: absolute;
@ -188,18 +168,6 @@ div.cardBox {
background: #1c1c1c;
}
@media (min-width: 600px) {
/* This needs a little extra space to account for the longer date format */
.channelHeaderCell, .channelTimeslotHeader {
width: 209px;
}
.programGrid, .timeslotHeaders {
margin-left: 210px;
}
}
.bottomFab {
bottom: 120px !important;
}

View file

@ -56,7 +56,7 @@
<br />
</div>
</div>
<div class="pageTabContent guideTabContent hide" style="width: auto;" data-index="1">
<div class="pageTabContent absolutePageTabContent guideTabContent hide" style="width: auto; display: flex;padding-bottom: 0;" data-index="1">
</div>
<div class="pageTabContent channelsTabContent hide" data-index="2">
<div class="viewSettings">

View file

@ -3877,13 +3877,13 @@
if (item.IsSeries && !item.IsRepeat) {
require(['livetvcss']);
miscInfo.push('<span class="newTvProgram">' + Globalize.translate('LabelNewProgram') + '</span>');
miscInfo.push('<span class="newTvProgram">' + Globalize.translate('AttributeNew') + '</span>');
}
if (item.IsLive) {
miscInfo.push('<span class="liveTvProgram">' + Globalize.translate('LabelLiveProgram') + '</span>');
miscInfo.push('<span class="liveTvProgram">' + Globalize.translate('AttributeLive') + '</span>');
}

View file

@ -59,13 +59,13 @@
html += '<div class="tvProgramTime">';
if (program.IsLive) {
html += '<span class="liveTvProgram">' + Globalize.translate('LabelLiveProgram') + '&nbsp;&nbsp;</span>';
html += '<span class="liveTvProgram">' + Globalize.translate('AttributeLive') + '&nbsp;&nbsp;</span>';
}
else if (program.IsPremiere) {
html += '<span class="premiereTvProgram">' + Globalize.translate('LabelPremiereProgram') + '&nbsp;&nbsp;</span>';
html += '<span class="premiereTvProgram">' + Globalize.translate('AttributePremiere') + '&nbsp;&nbsp;</span>';
}
else if (program.IsSeries && !program.IsRepeat) {
html += '<span class="newTvProgram">' + Globalize.translate('LabelNewProgram') + '&nbsp;&nbsp;</span>';
html += '<span class="newTvProgram">' + Globalize.translate('AttributeNew') + '&nbsp;&nbsp;</span>';
}
var minutes = program.RunTimeTicks / 600000000;

View file

@ -1,4 +1,4 @@
define([], function () {
define(['tvguide', 'embyRouter'], function (tvguide, embyRouter) {
window.LiveTvPage.initGuideTab = function (page, tabContent) {
@ -11,12 +11,9 @@
page.guideInstance.refresh();
}
} else {
require(['tvguide'], function (tvguide) {
page.guideInstance = new tvguide({
element: tabContent,
enableHeadRoom: true
});
page.guideInstance = new tvguide({
element: tabContent,
enableHeadRoom: true
});
}
};

View file

@ -207,6 +207,22 @@
});
pageIdOn('viewshow', "liveTvSuggestedPage", function () {
var page = this;
// Needed on the guide tab
// Ideally this should be moved to the guide tab on show/hide
document.body.classList.add('autoScrollY');
});
pageIdOn('viewbeforehide', "liveTvSuggestedPage", function () {
var page = this;
document.body.classList.remove('autoScrollY');
});
window.LiveTvPage = {
renderSuggestedTab: renderSuggestedTab,
initSuggestedTab: initSuggestedTab

View file

@ -297,4 +297,5 @@
}
};
return window.RegistrationServices;
});

View file

@ -1481,7 +1481,7 @@ var AppInfo = {};
console.log('loaded ApiClient singleton');
resolve();
});
}
}
});
});
});
@ -1605,7 +1605,6 @@ var AppInfo = {};
var paths = {
velocity: bowerPath + "/velocity/velocity.min",
tvguide: 'components/tvguide/tvguide',
ironCardList: 'components/ironcardlist/ironcardlist',
scrollThreshold: 'components/scrollthreshold',
directorybrowser: 'components/directorybrowser/directorybrowser',
@ -1635,7 +1634,9 @@ var AppInfo = {};
layoutManager: embyWebComponentsBowerPath + "/layoutmanager",
pageJs: embyWebComponentsBowerPath + '/page.js/page',
focusManager: embyWebComponentsBowerPath + "/focusmanager",
datetime: embyWebComponentsBowerPath + "/datetime",
globalize: embyWebComponentsBowerPath + "/globalize",
itemShortcuts: embyWebComponentsBowerPath + "/shortcuts",
imageLoader: embyWebComponentsBowerPath + "/images/imagehelper"
};
@ -1667,6 +1668,11 @@ var AppInfo = {};
define("backdrop", [embyWebComponentsBowerPath + "/backdrop/backdrop"], returnFirstDependency);
define("fetchHelper", [embyWebComponentsBowerPath + "/fetchhelper"], returnFirstDependency);
define("tvguide", [embyWebComponentsBowerPath + "/guide/guide", 'embyRouter'], function (tvGuide, embyRouter) {
tvGuide.setBaseUrl(embyRouter.baseUrl() + '/bower_components/emby-webcomponents/guide');
return tvGuide;
});
define("viewManager", [embyWebComponentsBowerPath + "/viewmanager"], function (viewManager) {
viewManager.dispatchPageEvents(true);
return viewManager;
@ -1786,12 +1792,13 @@ var AppInfo = {};
define('webcomponentsjs', [bowerPath + '/webcomponentsjs/webcomponents-lite.min.js']);
define('native-promise-only', [bowerPath + '/native-promise-only/lib/npo.src']);
define("fingerprintjs2", [bowerPath + '/fingerprintjs2/fingerprint2'], returnFirstDependency);
define("clearButtonStyle", ['css!' + embyWebComponentsBowerPath + '/clearbutton']);
if (Dashboard.isRunningInCordova()) {
define('registrationservices', ['cordova/registrationservices']);
define('registrationservices', ['cordova/registrationservices'], returnFirstDependency);
} else {
define('registrationservices', ['scripts/registrationservices']);
define('registrationservices', ['scripts/registrationservices'], returnFirstDependency);
}
if (Dashboard.isRunningInCordova()) {
@ -1866,6 +1873,12 @@ var AppInfo = {};
};
});
// mock this for now. not used in this app
define("playbackManager", [], function () {
return {
};
});
// mock this for now. not used in this app
define("pluginManager", [], function () {
return {
@ -1884,7 +1897,7 @@ var AppInfo = {};
define('dialogText', ['globalize'], getDialogText());
define("router", [embyWebComponentsBowerPath + '/router'], function (embyRouter) {
define("embyRouter", [embyWebComponentsBowerPath + '/router'], function (embyRouter) {
embyRouter.showLocalLogin = function (apiClient, serverId, manualLogin) {
Dashboard.navigate('login.html?serverid=' + serverId);
@ -1907,6 +1920,17 @@ var AppInfo = {};
Dashboard.navigate('mypreferencesmenu.html?userId=' + ApiClient.getCurrentUserId());
};
embyRouter.showItem = function (item) {
if (typeof (item) === 'string') {
require(['connectionManager'], function (connectionManager) {
var apiClient = connectionManager.currentApiClient();
apiClient.getItem(apiClient.getCurrentUserId(), item).then(showItem);
});
} else {
Dashboard.navigate(LibraryBrowser.getHref(item));
}
};
return embyRouter;
});
}
@ -2873,7 +2897,7 @@ var AppInfo = {};
var deps = [];
deps.push('imageLoader');
deps.push('router');
deps.push('embyRouter');
deps.push('layoutManager');
if (!(AppInfo.isNativeApp && browserInfo.android)) {

View file

@ -266,6 +266,13 @@
"OptionContinuing": "Continuing",
"OptionEnded": "Ended",
"HeaderAirDays": "Air Days",
"OptionSundayShort": "Sun",
"OptionMondayShort": "Mon",
"OptionTuesdayShort": "Tue",
"OptionWednesdayShort": "Wed",
"OptionThursdayShort": "Thu",
"OptionFridayShort": "Fri",
"OptionSaturdayShort": "Sat",
"OptionSunday": "Sunday",
"OptionMonday": "Monday",
"OptionTuesday": "Tuesday",
@ -1845,9 +1852,9 @@
"OptionProductionLocations": "Production Locations",
"OptionBirthLocation": "Birth Location",
"LabelAllChannels": "All channels",
"LabelLiveProgram": "LIVE",
"LabelNewProgram": "NEW",
"LabelPremiereProgram": "PREMIERE",
"AttributeNew": "New",
"AttributePremiere": "Premiere",
"AttributeLive": "Live",
"LabelHDProgram": "HD",
"HeaderChangeFolderType": "Change Content Type",
"HeaderChangeFolderTypeHelp": "To change the type, please remove and rebuild the library with the new type.",