diff --git a/dashboard-ui/bower_components/emby-webcomponents/.bower.json b/dashboard-ui/bower_components/emby-webcomponents/.bower.json index 270b73a86f..6ca547c633 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/.bower.json +++ b/dashboard-ui/bower_components/emby-webcomponents/.bower.json @@ -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", diff --git a/dashboard-ui/bower_components/emby-webcomponents/clearbutton.css b/dashboard-ui/bower_components/emby-webcomponents/clearbutton.css new file mode 100644 index 0000000000..2d3f8d6800 --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/clearbutton.css @@ -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; +} \ No newline at end of file diff --git a/dashboard-ui/bower_components/emby-webcomponents/guide/guide.css b/dashboard-ui/bower_components/emby-webcomponents/guide/guide.css new file mode 100644 index 0000000000..8026047144 --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/guide/guide.css @@ -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; +} diff --git a/dashboard-ui/bower_components/emby-webcomponents/guide/guide.js b/dashboard-ui/bower_components/emby-webcomponents/guide/guide.js new file mode 100644 index 0000000000..a591c808bd --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/guide/guide.js @@ -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 += '
'; + + while (startDate.getTime() < endDateTime) { + + html += '
'; + + html += getDisplayTime(startDate); + html += '
'; + + // Add 30 mins + startDate.setTime(startDate.getTime() + cellDurationMs); + } + html += '
'; + + 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 += '
'; + + 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 += ''; + } + + html += '
'; + + 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 += ''; + } + + 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 = '' + text.replace(' ', ' '); + 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; +}); \ No newline at end of file diff --git a/dashboard-ui/bower_components/emby-webcomponents/guide/tvguide.template.html b/dashboard-ui/bower_components/emby-webcomponents/guide/tvguide.template.html new file mode 100644 index 0000000000..523e8dd410 --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/guide/tvguide.template.html @@ -0,0 +1,22 @@ +
+
+ +
+
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+

+ ${ButtonUnlockGuide} +
\ No newline at end of file diff --git a/dashboard-ui/bower_components/emby-webcomponents/router.js b/dashboard-ui/bower_components/emby-webcomponents/router.js index cd95b32e0e..cda661f27a 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/router.js +++ b/dashboard-ui/bower_components/emby-webcomponents/router.js @@ -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); } diff --git a/dashboard-ui/bower_components/emby-webcomponents/shortcuts.js b/dashboard-ui/bower_components/emby-webcomponents/shortcuts.js new file mode 100644 index 0000000000..05802cd3ab --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/shortcuts.js @@ -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 + }; + +}); \ No newline at end of file diff --git a/dashboard-ui/bower_components/iron-icon/.bower.json b/dashboard-ui/bower_components/iron-icon/.bower.json index 9784e3a3b7..f0167baf13 100644 --- a/dashboard-ui/bower_components/iron-icon/.bower.json +++ b/dashboard-ui/bower_components/iron-icon/.bower.json @@ -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" } \ No newline at end of file diff --git a/dashboard-ui/bower_components/iron-selector/.bower.json b/dashboard-ui/bower_components/iron-selector/.bower.json index c88ed41aaf..43e942ccc6 100644 --- a/dashboard-ui/bower_components/iron-selector/.bower.json +++ b/dashboard-ui/bower_components/iron-selector/.bower.json @@ -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" } \ No newline at end of file diff --git a/dashboard-ui/components/tvguide/tvguide.js b/dashboard-ui/components/tvguide/tvguide.js deleted file mode 100644 index ce6eb08966..0000000000 --- a/dashboard-ui/components/tvguide/tvguide.js +++ /dev/null @@ -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 += '
'; - - while (startDate.getTime() < endDateTime) { - - html += '
'; - html += '
'; - - html += LibraryBrowser.getDisplayTime(startDate); - html += '
'; - html += '
'; - - // Add 30 mins - startDate.setTime(startDate.getTime() + cellDurationMs); - } - html += '
'; - - 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 += '
'; - - 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 += ''; - - html += '
'; - html += program.Name; - html += '
'; - - html += '
'; - if (program.IsLive) { - html += '' + Globalize.translate('LabelLiveProgram') + '  '; - } - else if (program.IsPremiere) { - html += '' + Globalize.translate('LabelPremiereProgram') + '  '; - } - else if (program.IsSeries && !program.IsRepeat) { - html += '' + Globalize.translate('LabelNewProgram') + '  '; - } - - html += LibraryBrowser.getDisplayTime(program.StartDateLocal); - html += ' - '; - html += LibraryBrowser.getDisplayTime(program.EndDateLocal); - - if (program.SeriesTimerId) { - html += '
'; - html += '
'; - html += '
'; - } - else if (program.TimerId) { - - html += '
'; - } - html += '
'; - - if (addAccent) { - html += '
'; - } - - html += '
'; - } - - html += '
'; - - 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 += '
'; - - html += ''; - - var hasChannelImage = channel.ImageTags.Primary; - var cssClass = hasChannelImage ? 'guideChannelInfo guideChannelInfoWithImage' : 'guideChannelInfo'; - - html += '
' + channel.Number + '
'; - - if (hasChannelImage) { - - var url = ApiClient.getScaledImageUrl(channel.Id, { - maxHeight: 44, - maxWidth: 70, - tag: channel.ImageTags.Primary, - type: "Primary" - }); - - html += '
'; - } else { - html += '
' + channel.Name + '
'; - } - - html += '
'; - - html += '
'; - } - - 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 = '' + text.replace(' ', ' '); - 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(); - }; -}); \ No newline at end of file diff --git a/dashboard-ui/components/tvguide/tvguide.template.html b/dashboard-ui/components/tvguide/tvguide.template.html deleted file mode 100644 index a92f85aea5..0000000000 --- a/dashboard-ui/components/tvguide/tvguide.template.html +++ /dev/null @@ -1,19 +0,0 @@ -
-
-
-
- -
-
-
-
-
-
-
-
-
-
- \ No newline at end of file diff --git a/dashboard-ui/css/librarymenu.css b/dashboard-ui/css/librarymenu.css index 9c4134a8d1..d3cd621df2 100644 --- a/dashboard-ui/css/librarymenu.css +++ b/dashboard-ui/css/librarymenu.css @@ -13,7 +13,8 @@ .absolutePageTabContent { margin: 0 !important; width: 100% !important; - top: 98px !important; + /* Page needs to supply padding */ + top: 92px !important; } .sidebarDivider { diff --git a/dashboard-ui/css/livetv.css b/dashboard-ui/css/livetv.css index 9266ec73bf..71e44e5d78 100644 --- a/dashboard-ui/css/livetv.css +++ b/dashboard-ui/css/livetv.css @@ -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; +} diff --git a/dashboard-ui/css/site.css b/dashboard-ui/css/site.css index fc427859b2..01a8972837 100644 --- a/dashboard-ui/css/site.css +++ b/dashboard-ui/css/site.css @@ -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; diff --git a/dashboard-ui/devices/ios/ios.css b/dashboard-ui/devices/ios/ios.css index d119d36ceb..97695f49c1 100644 --- a/dashboard-ui/devices/ios/ios.css +++ b/dashboard-ui/devices/ios/ios.css @@ -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; } diff --git a/dashboard-ui/livetv.html b/dashboard-ui/livetv.html index d529211d31..5cd9b808f8 100644 --- a/dashboard-ui/livetv.html +++ b/dashboard-ui/livetv.html @@ -56,7 +56,7 @@
-
+
diff --git a/dashboard-ui/scripts/librarybrowser.js b/dashboard-ui/scripts/librarybrowser.js index 13b2b1678d..68893fae80 100644 --- a/dashboard-ui/scripts/librarybrowser.js +++ b/dashboard-ui/scripts/librarybrowser.js @@ -3877,13 +3877,13 @@ if (item.IsSeries && !item.IsRepeat) { require(['livetvcss']); - miscInfo.push('' + Globalize.translate('LabelNewProgram') + ''); + miscInfo.push('' + Globalize.translate('AttributeNew') + ''); } if (item.IsLive) { - miscInfo.push('' + Globalize.translate('LabelLiveProgram') + ''); + miscInfo.push('' + Globalize.translate('AttributeLive') + ''); } diff --git a/dashboard-ui/scripts/livetvchannel.js b/dashboard-ui/scripts/livetvchannel.js index 33a8857c81..72a25b500f 100644 --- a/dashboard-ui/scripts/livetvchannel.js +++ b/dashboard-ui/scripts/livetvchannel.js @@ -59,13 +59,13 @@ html += '
'; if (program.IsLive) { - html += '' + Globalize.translate('LabelLiveProgram') + '  '; + html += '' + Globalize.translate('AttributeLive') + '  '; } else if (program.IsPremiere) { - html += '' + Globalize.translate('LabelPremiereProgram') + '  '; + html += '' + Globalize.translate('AttributePremiere') + '  '; } else if (program.IsSeries && !program.IsRepeat) { - html += '' + Globalize.translate('LabelNewProgram') + '  '; + html += '' + Globalize.translate('AttributeNew') + '  '; } var minutes = program.RunTimeTicks / 600000000; diff --git a/dashboard-ui/scripts/livetvguide.js b/dashboard-ui/scripts/livetvguide.js index 9501f4d287..bdbf482d8e 100644 --- a/dashboard-ui/scripts/livetvguide.js +++ b/dashboard-ui/scripts/livetvguide.js @@ -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 }); } }; diff --git a/dashboard-ui/scripts/livetvsuggested.js b/dashboard-ui/scripts/livetvsuggested.js index e4f0719e68..0b70aaf1fb 100644 --- a/dashboard-ui/scripts/livetvsuggested.js +++ b/dashboard-ui/scripts/livetvsuggested.js @@ -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 diff --git a/dashboard-ui/scripts/registrationservices.js b/dashboard-ui/scripts/registrationservices.js index f77e2945c9..42a16e2047 100644 --- a/dashboard-ui/scripts/registrationservices.js +++ b/dashboard-ui/scripts/registrationservices.js @@ -297,4 +297,5 @@ } }; + return window.RegistrationServices; }); \ No newline at end of file diff --git a/dashboard-ui/scripts/site.js b/dashboard-ui/scripts/site.js index 7cd0d239cc..fabdfbad4f 100644 --- a/dashboard-ui/scripts/site.js +++ b/dashboard-ui/scripts/site.js @@ -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)) { diff --git a/dashboard-ui/strings/en-US.json b/dashboard-ui/strings/en-US.json index 5b94ccd593..177e162e9b 100644 --- a/dashboard-ui/strings/en-US.json +++ b/dashboard-ui/strings/en-US.json @@ -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.",