diff --git a/dashboard-ui/bower_components/emby-apiclient/sync/contentuploader.js b/dashboard-ui/bower_components/emby-apiclient/sync/contentuploader.js index 9fa5d2ca74..5a1fbe294e 100644 --- a/dashboard-ui/bower_components/emby-apiclient/sync/contentuploader.js +++ b/dashboard-ui/bower_components/emby-apiclient/sync/contentuploader.js @@ -6,7 +6,7 @@ self.uploadImages = function (server) { - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); LocalAssetManager.getCameraPhotos().then(function (photos) { @@ -77,7 +77,7 @@ function uploadFile(file, apiClient) { - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); require(['fileupload', "cryptojs-sha1"], function () { diff --git a/dashboard-ui/bower_components/emby-apiclient/sync/mediasync.js b/dashboard-ui/bower_components/emby-apiclient/sync/mediasync.js index 5ee7a511fd..78d0c3e818 100644 --- a/dashboard-ui/bower_components/emby-apiclient/sync/mediasync.js +++ b/dashboard-ui/bower_components/emby-apiclient/sync/mediasync.js @@ -6,7 +6,7 @@ self.sync = function (apiClient, serverInfo, options) { - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); reportOfflineActions(apiClient, serverInfo).then(function () { @@ -36,7 +36,7 @@ console.log('Begin reportOfflineActions'); - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); require(['localassetmanager'], function () { @@ -67,7 +67,7 @@ console.log('Begin syncData'); - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); require(['localassetmanager'], function () { @@ -117,7 +117,7 @@ console.log('Begin removeLocalItems'); - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); removeNextLocalItem(syncDataResult.ItemIdsToRemove, 0, serverId, deferred); @@ -146,7 +146,7 @@ console.log('Begin removeLocalItem'); - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); require(['localassetmanager'], function () { @@ -164,7 +164,7 @@ console.log('Begin getNewMedia'); - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); apiClient.getReadySyncItems(apiClient.deviceId()).then(function (jobItems) { @@ -201,7 +201,7 @@ console.log('Begin getNewItem'); - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); require(['localassetmanager'], function () { @@ -240,7 +240,7 @@ function downloadMedia(apiClient, jobItem, localItem, options) { console.log('Begin downloadMedia'); - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); require(['localassetmanager'], function () { @@ -276,7 +276,7 @@ function getImages(apiClient, jobItem, localItem) { console.log('Begin getImages'); - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); getNextImage(0, apiClient, localItem, deferred); @@ -348,7 +348,7 @@ function downloadImage(apiClient, serverId, itemId, imageTag, imageType) { console.log('Begin downloadImage'); - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); require(['localassetmanager'], function () { @@ -380,7 +380,7 @@ function getSubtitles(apiClient, jobItem, localItem) { console.log('Begin getSubtitles'); - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); require(['localassetmanager'], function () { @@ -424,7 +424,7 @@ function getItemSubtitle(file, apiClient, jobItem, localItem, mediaSource) { console.log('Begin getItemSubtitle'); - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); var subtitleStream = mediaSource.MediaStreams.filter(function (m) { return m.Type == 'Subtitle' && m.Index == file.Index; @@ -461,7 +461,7 @@ function syncUserItemAccess(syncDataResult, serverId) { console.log('Begin syncUserItemAccess'); - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); var itemIds = []; for (var id in syncDataResult.ItemUserAccess) { @@ -494,7 +494,7 @@ function syncUserAccessForItem(itemId, syncDataResult) { console.log('Begin syncUserAccessForItem'); - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); require(['localassetmanager'], function () { diff --git a/dashboard-ui/components/directorybrowser/directorybrowser.js b/dashboard-ui/components/directorybrowser/directorybrowser.js index d2283bc5f7..21cf94b7a4 100644 --- a/dashboard-ui/components/directorybrowser/directorybrowser.js +++ b/dashboard-ui/components/directorybrowser/directorybrowser.js @@ -3,7 +3,7 @@ var systemInfo; function getSystemInfo() { - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); if (systemInfo) { deferred.resolveWith(null, [systemInfo]); diff --git a/dashboard-ui/components/imagedownloader/imagedownloader.js b/dashboard-ui/components/imagedownloader/imagedownloader.js index 27baed54be..5b115347cc 100644 --- a/dashboard-ui/components/imagedownloader/imagedownloader.js +++ b/dashboard-ui/components/imagedownloader/imagedownloader.js @@ -324,7 +324,7 @@ return { show: function (itemId, itemType, imageType) { - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); currentDeferred = deferred; hasChanges = false; diff --git a/dashboard-ui/components/imageeditor/imageeditor.js b/dashboard-ui/components/imageeditor/imageeditor.js index 89752aee65..d3945a4521 100644 --- a/dashboard-ui/components/imageeditor/imageeditor.js +++ b/dashboard-ui/components/imageeditor/imageeditor.js @@ -297,7 +297,7 @@ return { show: function (itemId, options) { - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); currentDeferred = deferred; hasChanges = false; diff --git a/dashboard-ui/components/imageuploader/imageuploader.js b/dashboard-ui/components/imageuploader/imageuploader.js index 1dbb5062c5..d4489c50d7 100644 --- a/dashboard-ui/components/imageuploader/imageuploader.js +++ b/dashboard-ui/components/imageuploader/imageuploader.js @@ -185,7 +185,7 @@ return { show: function (itemId, options) { - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); currentDeferred = deferred; hasChanges = false; diff --git a/dashboard-ui/components/itemidentifier/itemidentifier.js b/dashboard-ui/components/itemidentifier/itemidentifier.js index cc5c00cf1f..bdfa4ae810 100644 --- a/dashboard-ui/components/itemidentifier/itemidentifier.js +++ b/dashboard-ui/components/itemidentifier/itemidentifier.js @@ -336,7 +336,7 @@ return { show: function (itemId) { - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); currentDeferred = deferred; hasChanges = false; diff --git a/dashboard-ui/components/medialibrarycreator/medialibrarycreator.js b/dashboard-ui/components/medialibrarycreator/medialibrarycreator.js index 1dcc85d7cd..b9e3005656 100644 --- a/dashboard-ui/components/medialibrarycreator/medialibrarycreator.js +++ b/dashboard-ui/components/medialibrarycreator/medialibrarycreator.js @@ -180,7 +180,7 @@ self.show = function (options) { - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); currentOptions = options; currentDeferred = deferred; diff --git a/dashboard-ui/components/medialibraryeditor/medialibraryeditor.js b/dashboard-ui/components/medialibraryeditor/medialibraryeditor.js index 9357e97ae5..a6700126e0 100644 --- a/dashboard-ui/components/medialibraryeditor/medialibraryeditor.js +++ b/dashboard-ui/components/medialibraryeditor/medialibraryeditor.js @@ -134,7 +134,7 @@ self.show = function (options) { - var deferred = DeferredBuilder.Deferred(); + var deferred = jQuery.Deferred(); currentOptions = options; currentDeferred = deferred; diff --git a/dashboard-ui/css/card.css b/dashboard-ui/css/card.css index 91dd2650db..c0f9a23d6b 100644 --- a/dashboard-ui/css/card.css +++ b/dashboard-ui/css/card.css @@ -55,7 +55,7 @@ } .defaultBackground .cardImage { - background-color: #333; + background-color: #303030; } .homeTopViews .defaultBackground .cardImage { @@ -109,7 +109,7 @@ } .ui-body-b .visualCardBox { - background: rgba(40,40,40,.85); + background: rgba(56,56,56,.85); border-radius: 3px; } diff --git a/dashboard-ui/css/librarymenu.css b/dashboard-ui/css/librarymenu.css index 031beca8e8..49eaba4118 100644 --- a/dashboard-ui/css/librarymenu.css +++ b/dashboard-ui/css/librarymenu.css @@ -200,11 +200,11 @@ } .viewMenuBar, .libraryViewNav { - background-color: #101010; + background-color: #080808; } .viewMenuBar.semiTransparent { - background-color: rgba(18, 18, 18, .55); + background-color: rgba(15, 15, 15, .3); } .paperLibraryViewNav { diff --git a/dashboard-ui/devices/android/android.css b/dashboard-ui/devices/android/android.css index 0c79a2940d..f36baba19e 100644 --- a/dashboard-ui/devices/android/android.css +++ b/dashboard-ui/devices/android/android.css @@ -1,31 +1,7 @@ -.viewMenuBar, .libraryViewNav:not(.paperLibraryViewNav), paper-tabs { - background-color: #080808; -} - - .viewMenuBar.semiTransparent { - background-color: rgba(15, 15, 15, .3); - } - -.background-theme-b, paper-dialog.background-theme-b { - background-color: #1A1A1A; -} - -.defaultBackground .cardImage { - background-color: #303030; -} - -.ui-body-b .visualCardBox { - background: rgba(56,56,56,.85); -} - -.libraryViewNav { +.libraryViewNav { box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.2); } - .libraryViewNav a { + .libraryViewNav a, paper-tab { font-weight: 500 !important; - } - -paper-tab { - font-weight: 500 !important; -} + } \ No newline at end of file diff --git a/dashboard-ui/devices/windowsphone/wp.css b/dashboard-ui/devices/windowsphone/wp.css new file mode 100644 index 0000000000..f3842e9d89 --- /dev/null +++ b/dashboard-ui/devices/windowsphone/wp.css @@ -0,0 +1,22 @@ +html, body, .ui-btn, .pageTitle { + font-family: 'Segoe UI', Arial, sans-serif; +} + +.viewMenuBar { + background-color: #000; +} + +.libraryViewNav, .libraryViewNav paper-tabs { + background-color: transparent; + box-shadow: none; + text-transform: lowercase; + font-size: 240%; +} + + .libraryViewNav a, paper-tab { + font-weight: 400 !important; + } + +.background-theme-b, paper-dialog.background-theme-b { + background: #161616; +} diff --git a/dashboard-ui/legacy/deferred.js b/dashboard-ui/legacy/deferred.js deleted file mode 100644 index e5632d538e..0000000000 --- a/dashboard-ui/legacy/deferred.js +++ /dev/null @@ -1,16 +0,0 @@ -(function (globalScope) { - - globalScope.DeferredBuilder = { - - Deferred: function () { - return jQuery.Deferred(); - }, - - when: function (promises) { - - return jQuery.when(promises); - } - - }; - -})(window); \ No newline at end of file diff --git a/dashboard-ui/scripts/librarybrowser.js b/dashboard-ui/scripts/librarybrowser.js index 750ddcba43..32e79ef411 100644 --- a/dashboard-ui/scripts/librarybrowser.js +++ b/dashboard-ui/scripts/librarybrowser.js @@ -1,3704 +1,3714 @@ -var LibraryBrowser = (function (window, document, screen) { +define(['playlistManager'], function (playlistManager) { - // Regular Expressions for parsing tags and attributes - var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g, - // Match everything outside of normal chars and " (quote character) - NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; + var libraryBrowser = (function (window, document, screen) { - /** - * Escapes all potentially dangerous characters, so that the - * resulting string can be safely inserted into attribute or - * element text. - * @param value - * @returns {string} escaped text - */ - function htmlEncode(value) { - return value. - replace(/&/g, '&'). - replace(SURROGATE_PAIR_REGEXP, function (value) { - var hi = value.charCodeAt(0); - var low = value.charCodeAt(1); - return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';'; - }). - replace(NON_ALPHANUMERIC_REGEXP, function (value) { - return '&#' + value.charCodeAt(0) + ';'; - }). - replace(//g, '>'); - } + // Regular Expressions for parsing tags and attributes + var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g, + // Match everything outside of normal chars and " (quote character) + NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; - var pageSizeKey = 'pagesize_v4'; - - function getDesiredAspect(shape) { - - if (shape) { - shape = shape.toLowerCase(); - if (shape.indexOf('portrait') != -1) { - return (2 / 3); - } - if (shape.indexOf('backdrop') != -1) { - return (16 / 9); - } - if (shape.indexOf('square') != -1) { - return 1; - } + /** + * Escapes all potentially dangerous characters, so that the + * resulting string can be safely inserted into attribute or + * element text. + * @param value + * @returns {string} escaped text + */ + function htmlEncode(value) { + return value. + replace(/&/g, '&'). + replace(SURROGATE_PAIR_REGEXP, function (value) { + var hi = value.charCodeAt(0); + var low = value.charCodeAt(1); + return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';'; + }). + replace(NON_ALPHANUMERIC_REGEXP, function (value) { + return '&#' + value.charCodeAt(0) + ';'; + }). + replace(//g, '>'); } - return null; - } - var libraryBrowser = { - getDefaultPageSize: function (key, defaultValue) { + var pageSizeKey = 'pagesize_v4'; - return 100; - var saved = appStorage.getItem(key || pageSizeKey); + function getDesiredAspect(shape) { - if (saved) { - return parseInt(saved); + if (shape) { + shape = shape.toLowerCase(); + if (shape.indexOf('portrait') != -1) { + return (2 / 3); + } + if (shape.indexOf('backdrop') != -1) { + return (16 / 9); + } + if (shape.indexOf('square') != -1) { + return 1; + } } + return null; + } - if (defaultValue) { - return defaultValue; - } + var libraryBrowser = { + getDefaultPageSize: function (key, defaultValue) { - return 100; - }, + return 100; + var saved = appStorage.getItem(key || pageSizeKey); - getDefaultItemsView: function (view, mobileView) { + if (saved) { + return parseInt(saved); + } - return browserInfo.mobile ? mobileView : view; + if (defaultValue) { + return defaultValue; + } - }, + return 100; + }, - getSavedQueryKey: function (modifier) { + getDefaultItemsView: function (view, mobileView) { - return window.location.href.split('#')[0] + (modifier || ''); - }, + return browserInfo.mobile ? mobileView : view; - loadSavedQueryValues: function (key, query) { + }, - var values = appStorage.getItem(key + '_' + Dashboard.getCurrentUserId()); + getSavedQueryKey: function (modifier) { - if (values) { + return window.location.href.split('#')[0] + (modifier || ''); + }, - values = JSON.parse(values); + loadSavedQueryValues: function (key, query) { - return $.extend(query, values); - } + var values = appStorage.getItem(key + '_' + Dashboard.getCurrentUserId()); - return query; - }, + if (values) { - saveQueryValues: function (key, query) { + values = JSON.parse(values); - var values = {}; + return $.extend(query, values); + } - if (query.SortBy) { - values.SortBy = query.SortBy; - } - if (query.SortOrder) { - values.SortOrder = query.SortOrder; - } + return query; + }, - try { - appStorage.setItem(key + '_' + Dashboard.getCurrentUserId(), JSON.stringify(values)); - } catch (e) { + saveQueryValues: function (key, query) { - } - }, + var values = {}; - saveViewSetting: function (key, value) { + if (query.SortBy) { + values.SortBy = query.SortBy; + } + if (query.SortOrder) { + values.SortOrder = query.SortOrder; + } - try { - appStorage.setItem(key + '_' + Dashboard.getCurrentUserId() + '_view', value); - } catch (e) { + try { + appStorage.setItem(key + '_' + Dashboard.getCurrentUserId(), JSON.stringify(values)); + } catch (e) { - } - }, + } + }, - getSavedView: function (key) { + saveViewSetting: function (key, value) { - var val = appStorage.getItem(key + '_' + Dashboard.getCurrentUserId() + '_view'); + try { + appStorage.setItem(key + '_' + Dashboard.getCurrentUserId() + '_view', value); + } catch (e) { - return val; - }, + } + }, - getSavedViewSetting: function (key) { + getSavedView: function (key) { - return new Promise(function (resolve, reject) { + var val = appStorage.getItem(key + '_' + Dashboard.getCurrentUserId() + '_view'); - var val = LibraryBrowser.getSavedView(key); - resolve(val); - }); - }, + return val; + }, - needsRefresh: function (elem) { + getSavedViewSetting: function (key) { - var last = parseInt(elem.getAttribute('data-lastrefresh') || '0'); + return new Promise(function (resolve, reject) { - if (!last) { - return true; - } + var val = LibraryBrowser.getSavedView(key); + resolve(val); + }); + }, - if (NavHelper.isBack()) { - console.log('Not refreshing data because IsBack=true'); - return false; - } + needsRefresh: function (elem) { - var now = new Date().getTime(); - var cacheDuration; + var last = parseInt(elem.getAttribute('data-lastrefresh') || '0'); - if (AppInfo.isNativeApp) { - cacheDuration = 300000; - } else if (browserInfo.ipad || browserInfo.iphone || browserInfo.android) { - cacheDuration = 10000; - } else { - cacheDuration = 30000; - } + if (!last) { + return true; + } - if ((now - last) < cacheDuration) { - console.log('Not refreshing data due to age'); - return false; - } - - return true; - }, - - setLastRefreshed: function (elem) { - - elem.setAttribute('data-lastrefresh', new Date().getTime()); - elem.classList.add('hasrefreshtime'); - }, - - enableFullPaperTabs: function () { - - if (browserInfo.animate && !browserInfo.mobile) { - //return true; - } - - return AppInfo.isNativeApp; - }, - - animatePaperTabs: function () { - - if (!LibraryBrowser.enableFullPaperTabs()) { - return false; - } - - if (!browserInfo.animate) { - return false; - } - - if (browserInfo.mobile) { - return false; - } - - return true; - }, - - allowSwipe: function (target) { - - function allowSwipeOn(elem) { - - if (elem.tagName == 'PAPER-SLIDER') { + if (NavHelper.isBack()) { + console.log('Not refreshing data because IsBack=true'); return false; } - if (elem.classList) { - return !elem.classList.contains('hiddenScrollX') && !elem.classList.contains('smoothScrollX'); + var now = new Date().getTime(); + var cacheDuration; + + if (AppInfo.isNativeApp) { + cacheDuration = 300000; + } else if (browserInfo.ipad || browserInfo.iphone || browserInfo.android) { + cacheDuration = 10000; + } else { + cacheDuration = 30000; + } + + if ((now - last) < cacheDuration) { + console.log('Not refreshing data due to age'); + return false; } return true; - } + }, - var parent = target; - while (parent != null) { - if (!allowSwipeOn(parent)) { + setLastRefreshed: function (elem) { + + elem.setAttribute('data-lastrefresh', new Date().getTime()); + elem.classList.add('hasrefreshtime'); + }, + + enableFullPaperTabs: function () { + + if (browserInfo.animate && !browserInfo.mobile) { + //return true; + } + + return AppInfo.isNativeApp; + }, + + animatePaperTabs: function () { + + if (!LibraryBrowser.enableFullPaperTabs()) { return false; } - parent = parent.parentNode; - } - return true; - }, - - getTabsAnimationConfig: function (elem, reverse) { - - if (browserInfo.mobile) { - - } - - return { - // scale up - 'entry': { - name: 'fade-in-animation', - node: elem, - timing: { duration: 160, easing: 'ease-out' } - }, - // fade out - 'exit': { - name: 'fade-out-animation', - node: elem, - timing: { duration: 200, easing: 'ease-out' } + if (!browserInfo.animate) { + return false; } - }; - }, + if (browserInfo.mobile) { + return false; + } - configureSwipeTabs: function (ownerpage, tabs, pages) { + return true; + }, + + allowSwipe: function (target) { + + function allowSwipeOn(elem) { + + if (elem.tagName == 'PAPER-SLIDER') { + return false; + } + + if (elem.classList) { + return !elem.classList.contains('hiddenScrollX') && !elem.classList.contains('smoothScrollX'); + } + + return true; + } + + var parent = target; + while (parent != null) { + if (!allowSwipeOn(parent)) { + return false; + } + parent = parent.parentNode; + } + + return true; + }, + + getTabsAnimationConfig: function (elem, reverse) { - if (LibraryBrowser.animatePaperTabs()) { if (browserInfo.mobile) { - require(['slide-left-animation', 'slide-from-right-animation'], function () { - pages.entryAnimation = 'slide-from-right-animation'; - pages.exitAnimation = 'slide-left-animation'; - }); - } else { - - require(['fade-in-animation', 'fade-out-animation'], function () { - pages.entryAnimation = 'fade-in-animation'; - pages.exitAnimation = 'fade-out-animation'; - }); - } - } - - var pageCount = pages.querySelectorAll('neon-animatable').length; - - require(['hammer'], function (Hammer) { - - var hammertime = new Hammer(pages); - hammertime.get('swipe').set({ direction: Hammer.DIRECTION_HORIZONTAL }); - - hammertime.on('swipeleft', function (e) { - if (LibraryBrowser.allowSwipe(e.target)) { - var selected = parseInt(pages.selected || '0'); - if (selected < (pageCount - 1)) { - if (LibraryBrowser.animatePaperTabs()) { - pages.entryAnimation = 'slide-from-right-animation'; - pages.exitAnimation = 'slide-left-animation'; - } - tabs.selectNext(); - } - } - }); - - hammertime.on('swiperight', function (e) { - if (LibraryBrowser.allowSwipe(e.target)) { - var selected = parseInt(pages.selected || '0'); - if (selected > 0) { - if (LibraryBrowser.animatePaperTabs()) { - pages.entryAnimation = 'slide-from-left-animation'; - pages.exitAnimation = 'slide-right-animation'; - } - tabs.selectPrevious(); - } - } - }); - }); - }, - - navigateOnLibraryTabSelect: function () { - return !LibraryBrowser.enableFullPaperTabs(); - }, - - configurePaperLibraryTabs: function (ownerpage, tabs, pages) { - - // Causing iron-select to not fire in IE and safari - if (browserInfo.chrome) { - tabs.noink = true; - } - - if (LibraryBrowser.enableFullPaperTabs()) { - - if (browserInfo.safari) { - tabs.noSlide = true; - tabs.noBar = true; - } else { - LibraryBrowser.configureSwipeTabs(ownerpage, tabs, pages); } - $('.libraryViewNav', ownerpage).addClass('paperLibraryViewNav').removeClass('libraryViewNavWithMinHeight'); - - } else { - - tabs.noSlide = true; - tabs.noBar = true; - - var legacyTabs = $('.legacyTabs', ownerpage); - - pages.addEventListener('iron-select', function (e) { - - var selected = pages.selected; - $('a', legacyTabs).removeClass('ui-btn-active')[selected].classList.add('ui-btn-active'); - }); - - $('.libraryViewNav', ownerpage).removeClass('libraryViewNavWithMinHeight'); - } - - $(ownerpage).on('pagebeforeshow', LibraryBrowser.onTabbedpagebeforeshow); - - pages.addEventListener('iron-select', function () { - // When transition animations are used, add a content loading delay to allow the animations to finish - // Otherwise with both operations happening at the same time, it can cause the animation to not run at full speed. - var pgs = this; - var delay = LibraryBrowser.animatePaperTabs() || !tabs.noSlide ? 300 : 0; - - setTimeout(function () { - pgs.dispatchEvent(new CustomEvent("tabchange", {})); - }, delay); - }); - - function fadeOutLeft(elem, iterations) { - var keyframes = [{ opacity: '1', transform: 'none', offset: 0 }, - { opacity: '0', transform: 'translate3d(-100%, 0, 0)', offset: 1 }]; - var timing = { duration: 300, iterations: iterations }; - return elem.animate(keyframes, timing); - } - if (!LibraryBrowser.navigateOnLibraryTabSelect()) { - tabs.addEventListener('iron-select', function () { - - var animateTab = !browserInfo.safari; - animateTab = false; - - var selected = pages.selected; - if (selected != null && animateTab) { - var newValue = this.selected; - var currentTab = pages.querySelectorAll('.pageTabContent')[selected]; - - fadeOutLeft(currentTab, 1).onfinish = function () { - pages.selected = newValue; - }; + return { + // scale up + 'entry': { + name: 'fade-in-animation', + node: elem, + timing: { duration: 160, easing: 'ease-out' } + }, + // fade out + 'exit': { + name: 'fade-out-animation', + node: elem, + timing: { duration: 200, easing: 'ease-out' } } - else { - pages.selected = this.selected; + }; + + }, + + configureSwipeTabs: function (ownerpage, tabs, pages) { + + if (LibraryBrowser.animatePaperTabs()) { + if (browserInfo.mobile) { + + require(['slide-left-animation', 'slide-from-right-animation'], function () { + pages.entryAnimation = 'slide-from-right-animation'; + pages.exitAnimation = 'slide-left-animation'; + }); + } else { + + require(['fade-in-animation', 'fade-out-animation'], function () { + pages.entryAnimation = 'fade-in-animation'; + pages.exitAnimation = 'fade-out-animation'; + }); } + } + + var pageCount = pages.querySelectorAll('neon-animatable').length; + + require(['hammer'], function (Hammer) { + + var hammertime = new Hammer(pages); + hammertime.get('swipe').set({ direction: Hammer.DIRECTION_HORIZONTAL }); + + hammertime.on('swipeleft', function (e) { + if (LibraryBrowser.allowSwipe(e.target)) { + var selected = parseInt(pages.selected || '0'); + if (selected < (pageCount - 1)) { + if (LibraryBrowser.animatePaperTabs()) { + pages.entryAnimation = 'slide-from-right-animation'; + pages.exitAnimation = 'slide-left-animation'; + } + tabs.selectNext(); + } + } + }); + + hammertime.on('swiperight', function (e) { + if (LibraryBrowser.allowSwipe(e.target)) { + var selected = parseInt(pages.selected || '0'); + if (selected > 0) { + if (LibraryBrowser.animatePaperTabs()) { + pages.entryAnimation = 'slide-from-left-animation'; + pages.exitAnimation = 'slide-right-animation'; + } + tabs.selectPrevious(); + } + } + }); }); - } - }, + }, - onTabbedpagebeforeshow: function () { + navigateOnLibraryTabSelect: function () { + return !LibraryBrowser.enableFullPaperTabs(); + }, - var page = this; - var delay = 0; - var isFirstLoad = false; + configurePaperLibraryTabs: function (ownerpage, tabs, pages) { - if (!page.getAttribute('data-firstload')) { - delay = 300; - isFirstLoad = true; - page.setAttribute('data-firstload', '1'); - } - - if (delay) { - setTimeout(function () { - - LibraryBrowser.onTabbedpagebeforeshowInternal(page, isFirstLoad); - }, delay); - } else { - LibraryBrowser.onTabbedpagebeforeshowInternal(page, isFirstLoad); - } - }, - - onTabbedpagebeforeshowInternal: function (page, isFirstLoad) { - - if (isFirstLoad) { - - console.log('selected tab is null, checking query string'); - - var selected = parseInt(getParameterByName('tab') || '0'); - - console.log('selected tab will be ' + selected); + // Causing iron-select to not fire in IE and safari + if (browserInfo.chrome) { + tabs.noink = true; + } if (LibraryBrowser.enableFullPaperTabs()) { - var tabs = page.querySelector('paper-tabs'); - if (tabs.selected) { - // showTab was called - return; + if (browserInfo.safari) { + tabs.noSlide = true; + tabs.noBar = true; + } else { + LibraryBrowser.configureSwipeTabs(ownerpage, tabs, pages); } - tabs.selected = selected; + + $('.libraryViewNav', ownerpage).addClass('paperLibraryViewNav').removeClass('libraryViewNavWithMinHeight'); } else { - page.querySelector('neon-animated-pages').selected = selected; + + tabs.noSlide = true; + tabs.noBar = true; + + var legacyTabs = $('.legacyTabs', ownerpage); + + pages.addEventListener('iron-select', function (e) { + + var selected = pages.selected; + $('a', legacyTabs).removeClass('ui-btn-active')[selected].classList.add('ui-btn-active'); + }); + + $('.libraryViewNav', ownerpage).removeClass('libraryViewNavWithMinHeight'); } - } else { + $(ownerpage).on('pagebeforeshow', LibraryBrowser.onTabbedpagebeforeshow); - var pages = page.querySelector('neon-animated-pages'); + pages.addEventListener('iron-select', function () { + // When transition animations are used, add a content loading delay to allow the animations to finish + // Otherwise with both operations happening at the same time, it can cause the animation to not run at full speed. + var pgs = this; + var delay = LibraryBrowser.animatePaperTabs() || !tabs.noSlide ? 300 : 0; - // Go back to the first tab - if (LibraryBrowser.enableFullPaperTabs() && !NavHelper.isBack()) { - if (pages.selected) { + setTimeout(function () { + pgs.dispatchEvent(new CustomEvent("tabchange", {})); + }, delay); + }); - var entryAnimation = pages.entryAnimation; - var exitAnimation = pages.exitAnimation; - pages.entryAnimation = null; - pages.exitAnimation = null; + function fadeOutLeft(elem, iterations) { + var keyframes = [{ opacity: '1', transform: 'none', offset: 0 }, + { opacity: '0', transform: 'translate3d(-100%, 0, 0)', offset: 1 }]; + var timing = { duration: 300, iterations: iterations }; + return elem.animate(keyframes, timing); + } + if (!LibraryBrowser.navigateOnLibraryTabSelect()) { + tabs.addEventListener('iron-select', function () { - page.querySelector('paper-tabs').selected = 0; + var animateTab = !browserInfo.safari; + animateTab = false; - pages.entryAnimation = entryAnimation; - pages.exitAnimation = exitAnimation; + var selected = pages.selected; + if (selected != null && animateTab) { + var newValue = this.selected; + var currentTab = pages.querySelectorAll('.pageTabContent')[selected]; - return; + fadeOutLeft(currentTab, 1).onfinish = function () { + pages.selected = newValue; + }; + } + else { + pages.selected = this.selected; + } + }); + } + }, + + onTabbedpagebeforeshow: function () { + + var page = this; + var delay = 0; + var isFirstLoad = false; + + if (!page.getAttribute('data-firstload')) { + delay = 300; + isFirstLoad = true; + page.setAttribute('data-firstload', '1'); + } + + if (delay) { + setTimeout(function () { + + LibraryBrowser.onTabbedpagebeforeshowInternal(page, isFirstLoad); + }, delay); + } else { + LibraryBrowser.onTabbedpagebeforeshowInternal(page, isFirstLoad); + } + }, + + onTabbedpagebeforeshowInternal: function (page, isFirstLoad) { + + if (isFirstLoad) { + + console.log('selected tab is null, checking query string'); + + var selected = parseInt(getParameterByName('tab') || '0'); + + console.log('selected tab will be ' + selected); + + if (LibraryBrowser.enableFullPaperTabs()) { + + var tabs = page.querySelector('paper-tabs'); + if (tabs.selected) { + // showTab was called + return; + } + tabs.selected = selected; + + } else { + page.querySelector('neon-animated-pages').selected = selected; } - } - pages.dispatchEvent(new CustomEvent("tabchange", {})); - } - }, - showTab: function (url, index) { + } else { - if (!LibraryBrowser.enableFullPaperTabs()) { + var pages = page.querySelector('neon-animated-pages'); - if (index) { - url = replaceQueryString(url, 'tab', index); - } - Dashboard.navigate(url); - return; - } + // Go back to the first tab + if (LibraryBrowser.enableFullPaperTabs() && !NavHelper.isBack()) { + if (pages.selected) { - var afterNavigate = function () { - if (window.location.href.toLowerCase().indexOf(url.toLowerCase()) != -1) { + var entryAnimation = pages.entryAnimation; + var exitAnimation = pages.exitAnimation; + pages.entryAnimation = null; + pages.exitAnimation = null; - var pages = this.querySelector('neon-animated-pages'); - - if (pages) { - - var entryAnimation = pages.entryAnimation; - var exitAnimation = pages.exitAnimation; - pages.entryAnimation = null; - pages.exitAnimation = null; - - var tabs = this.querySelector('paper-tabs'); - - // For some reason the live tv page will not switch tabs in IE and safari - var delay = browserInfo.chrome ? 0 : 100; - - setTimeout(function () { - var noSlide = tabs.noSlide; - tabs.noSlide = true; - tabs.selected = index; + page.querySelector('paper-tabs').selected = 0; pages.entryAnimation = entryAnimation; pages.exitAnimation = exitAnimation; - tabs.noSlide = noSlide; - }, delay); - } - } - }; - - if (window.location.href.toLowerCase().indexOf(url.toLowerCase()) != -1) { - - afterNavigate.call($($.mobile.activePage)[0]); - } else { - $(document).one('pagebeforeshow', '.page', afterNavigate); - Dashboard.navigate(url); - } - }, - - canShare: function (item, user) { - - return user.Policy.EnablePublicSharing; - }, - - getDateParamValue: function (date) { - - function formatDigit(i) { - return i < 10 ? "0" + i : i; - } - - var d = date; - - return "" + d.getFullYear() + formatDigit(d.getMonth() + 1) + formatDigit(d.getDate()) + formatDigit(d.getHours()) + formatDigit(d.getMinutes()) + formatDigit(d.getSeconds()); - }, - - playAllFromHere: function (fn, index) { - - fn(index, 100, "MediaSources,Chapters").then(function (result) { - - MediaController.play({ - items: result.Items - }); - }); - }, - - queueAllFromHere: function (query, index) { - - fn(index, 100, "MediaSources,Chapters").then(function (result) { - - MediaController.queue({ - items: result.Items - }); - }); - }, - - getItemCountsHtml: function (options, item) { - - var counts = []; - - var childText; - - if (item.Type == 'Playlist') { - - childText = ''; - - if (item.CumulativeRunTimeTicks) { - - var minutes = item.CumulativeRunTimeTicks / 600000000; - - minutes = minutes || 1; - - childText += Globalize.translate('ValueMinutes', Math.round(minutes)); - - } else { - childText += Globalize.translate('ValueMinutes', 0); - } - - counts.push(childText); - - } - else if (options.context == "movies") { - - if (item.MovieCount) { - - childText = item.MovieCount == 1 ? - Globalize.translate('ValueOneMovie') : - Globalize.translate('ValueMovieCount', item.MovieCount); - - counts.push(childText); - } - if (item.TrailerCount) { - - childText = item.TrailerCount == 1 ? - Globalize.translate('ValueOneTrailer') : - Globalize.translate('ValueTrailerCount', item.TrailerCount); - - counts.push(childText); - } - - } else if (options.context == "tv") { - - if (item.SeriesCount) { - - childText = item.SeriesCount == 1 ? - Globalize.translate('ValueOneSeries') : - Globalize.translate('ValueSeriesCount', item.SeriesCount); - - counts.push(childText); - } - if (item.EpisodeCount) { - - childText = item.EpisodeCount == 1 ? - Globalize.translate('ValueOneEpisode') : - Globalize.translate('ValueEpisodeCount', item.EpisodeCount); - - counts.push(childText); - } - - } else if (options.context == "games") { - - if (item.GameCount) { - - childText = item.GameCount == 1 ? - Globalize.translate('ValueOneGame') : - Globalize.translate('ValueGameCount', item.GameCount); - - counts.push(childText); - } - } else if (options.context == "music") { - - if (item.AlbumCount) { - - childText = item.AlbumCount == 1 ? - Globalize.translate('ValueOneAlbum') : - Globalize.translate('ValueAlbumCount', item.AlbumCount); - - counts.push(childText); - } - if (item.SongCount) { - - childText = item.SongCount == 1 ? - Globalize.translate('ValueOneSong') : - Globalize.translate('ValueSongCount', item.SongCount); - - counts.push(childText); - } - if (item.MusicVideoCount) { - - childText = item.MusicVideoCount == 1 ? - Globalize.translate('ValueOneMusicVideo') : - Globalize.translate('ValueMusicVideoCount', item.MusicVideoCount); - - counts.push(childText); - } - } - - return counts.join(' • '); - }, - - getArtistLinksHtml: function (artists, cssClass) { - - var html = []; - - for (var i = 0, length = artists.length; i < length; i++) { - - var artist = artists[i]; - - var css = cssClass ? (' class="' + cssClass + '"') : ''; - html.push('' + artist.Name + ''); - - } - - html = html.join(' / '); - - return html; - }, - - playInExternalPlayer: function (id) { - - Dashboard.loadExternalPlayer().then(function () { - ExternalPlayer.showMenu(id); - }); - }, - - showPlayMenu: function (positionTo, itemId, itemType, isFolder, mediaType, resumePositionTicks) { - - var externalPlayers = AppInfo.supportsExternalPlayers && AppSettings.enableExternalPlayers(); - - if (!resumePositionTicks && mediaType != "Audio" && !isFolder) { - - if (!externalPlayers || mediaType != "Video") { - - MediaController.play(itemId); - return; - } - } - - var menuItems = []; - - if (resumePositionTicks) { - menuItems.push({ - name: Globalize.translate('ButtonResume'), - id: 'resume', - ironIcon: 'play-arrow' - }); - } - - menuItems.push({ - name: Globalize.translate('ButtonPlay'), - id: 'play', - ironIcon: 'play-arrow' - }); - - if (!isFolder && externalPlayers && mediaType != "Audio") { - menuItems.push({ - name: Globalize.translate('ButtonPlayExternalPlayer'), - id: 'externalplayer', - ironIcon: 'airplay' - }); - } - - if (MediaController.canQueueMediaType(mediaType, itemType)) { - menuItems.push({ - name: Globalize.translate('ButtonQueue'), - id: 'queue', - ironIcon: 'playlist-add' - }); - } - - if (itemType == "Audio" || itemType == "MusicAlbum" || itemType == "MusicArtist" || itemType == "MusicGenre") { - menuItems.push({ - name: Globalize.translate('ButtonInstantMix'), - id: 'instantmix', - ironIcon: 'shuffle' - }); - } - - if (isFolder || itemType == "MusicArtist" || itemType == "MusicGenre") { - menuItems.push({ - name: Globalize.translate('ButtonShuffle'), - id: 'shuffle', - ironIcon: 'shuffle' - }); - } - - require(['actionsheet'], function (actionsheet) { - - actionsheet.show({ - items: menuItems, - positionTo: positionTo, - callback: function (id) { - - switch (id) { - - case 'play': - MediaController.play(itemId); - break; - case 'externalplayer': - LibraryBrowser.playInExternalPlayer(itemId); - break; - case 'resume': - MediaController.play({ - ids: [itemId], - startPositionTicks: resumePositionTicks - }); - break; - case 'queue': - MediaController.queue(itemId); - break; - case 'instantmix': - MediaController.instantMix(itemId); - break; - case 'shuffle': - MediaController.shuffle(itemId); - break; - default: - break; + return; } } + pages.dispatchEvent(new CustomEvent("tabchange", {})); + } + }, + + showTab: function (url, index) { + + if (!LibraryBrowser.enableFullPaperTabs()) { + + if (index) { + url = replaceQueryString(url, 'tab', index); + } + Dashboard.navigate(url); + return; + } + + var afterNavigate = function () { + if (window.location.href.toLowerCase().indexOf(url.toLowerCase()) != -1) { + + var pages = this.querySelector('neon-animated-pages'); + + if (pages) { + + var entryAnimation = pages.entryAnimation; + var exitAnimation = pages.exitAnimation; + pages.entryAnimation = null; + pages.exitAnimation = null; + + var tabs = this.querySelector('paper-tabs'); + + // For some reason the live tv page will not switch tabs in IE and safari + var delay = browserInfo.chrome ? 0 : 100; + + setTimeout(function () { + var noSlide = tabs.noSlide; + tabs.noSlide = true; + tabs.selected = index; + + pages.entryAnimation = entryAnimation; + pages.exitAnimation = exitAnimation; + tabs.noSlide = noSlide; + + }, delay); + } + } + }; + + if (window.location.href.toLowerCase().indexOf(url.toLowerCase()) != -1) { + + afterNavigate.call($($.mobile.activePage)[0]); + } else { + $(document).one('pagebeforeshow', '.page', afterNavigate); + Dashboard.navigate(url); + } + }, + + canShare: function (item, user) { + + return user.Policy.EnablePublicSharing; + }, + + getDateParamValue: function (date) { + + function formatDigit(i) { + return i < 10 ? "0" + i : i; + } + + var d = date; + + return "" + d.getFullYear() + formatDigit(d.getMonth() + 1) + formatDigit(d.getDate()) + formatDigit(d.getHours()) + formatDigit(d.getMinutes()) + formatDigit(d.getSeconds()); + }, + + playAllFromHere: function (fn, index) { + + fn(index, 100, "MediaSources,Chapters").then(function (result) { + + MediaController.play({ + items: result.Items + }); + }); + }, + + queueAllFromHere: function (query, index) { + + fn(index, 100, "MediaSources,Chapters").then(function (result) { + + MediaController.queue({ + items: result.Items + }); + }); + }, + + getItemCountsHtml: function (options, item) { + + var counts = []; + + var childText; + + if (item.Type == 'Playlist') { + + childText = ''; + + if (item.CumulativeRunTimeTicks) { + + var minutes = item.CumulativeRunTimeTicks / 600000000; + + minutes = minutes || 1; + + childText += Globalize.translate('ValueMinutes', Math.round(minutes)); + + } else { + childText += Globalize.translate('ValueMinutes', 0); + } + + counts.push(childText); + + } + else if (options.context == "movies") { + + if (item.MovieCount) { + + childText = item.MovieCount == 1 ? + Globalize.translate('ValueOneMovie') : + Globalize.translate('ValueMovieCount', item.MovieCount); + + counts.push(childText); + } + if (item.TrailerCount) { + + childText = item.TrailerCount == 1 ? + Globalize.translate('ValueOneTrailer') : + Globalize.translate('ValueTrailerCount', item.TrailerCount); + + counts.push(childText); + } + + } else if (options.context == "tv") { + + if (item.SeriesCount) { + + childText = item.SeriesCount == 1 ? + Globalize.translate('ValueOneSeries') : + Globalize.translate('ValueSeriesCount', item.SeriesCount); + + counts.push(childText); + } + if (item.EpisodeCount) { + + childText = item.EpisodeCount == 1 ? + Globalize.translate('ValueOneEpisode') : + Globalize.translate('ValueEpisodeCount', item.EpisodeCount); + + counts.push(childText); + } + + } else if (options.context == "games") { + + if (item.GameCount) { + + childText = item.GameCount == 1 ? + Globalize.translate('ValueOneGame') : + Globalize.translate('ValueGameCount', item.GameCount); + + counts.push(childText); + } + } else if (options.context == "music") { + + if (item.AlbumCount) { + + childText = item.AlbumCount == 1 ? + Globalize.translate('ValueOneAlbum') : + Globalize.translate('ValueAlbumCount', item.AlbumCount); + + counts.push(childText); + } + if (item.SongCount) { + + childText = item.SongCount == 1 ? + Globalize.translate('ValueOneSong') : + Globalize.translate('ValueSongCount', item.SongCount); + + counts.push(childText); + } + if (item.MusicVideoCount) { + + childText = item.MusicVideoCount == 1 ? + Globalize.translate('ValueOneMusicVideo') : + Globalize.translate('ValueMusicVideoCount', item.MusicVideoCount); + + counts.push(childText); + } + } + + return counts.join(' • '); + }, + + getArtistLinksHtml: function (artists, cssClass) { + + var html = []; + + for (var i = 0, length = artists.length; i < length; i++) { + + var artist = artists[i]; + + var css = cssClass ? (' class="' + cssClass + '"') : ''; + html.push('' + artist.Name + ''); + + } + + html = html.join(' / '); + + return html; + }, + + playInExternalPlayer: function (id) { + + Dashboard.loadExternalPlayer().then(function () { + ExternalPlayer.showMenu(id); + }); + }, + + showPlayMenu: function (positionTo, itemId, itemType, isFolder, mediaType, resumePositionTicks) { + + var externalPlayers = AppInfo.supportsExternalPlayers && AppSettings.enableExternalPlayers(); + + if (!resumePositionTicks && mediaType != "Audio" && !isFolder) { + + if (!externalPlayers || mediaType != "Video") { + + MediaController.play(itemId); + return; + } + } + + var menuItems = []; + + if (resumePositionTicks) { + menuItems.push({ + name: Globalize.translate('ButtonResume'), + id: 'resume', + ironIcon: 'play-arrow' + }); + } + + menuItems.push({ + name: Globalize.translate('ButtonPlay'), + id: 'play', + ironIcon: 'play-arrow' }); - }); - }, - - supportsEditing: function (itemType) { - - if (itemType == "UserRootFolder" || /*itemType == "CollectionFolder" ||*/ itemType == "UserView") { - return false; - } - - return true; - }, - - getMoreCommands: function (item, user) { - - var commands = []; - - if (LibraryBrowser.supportsAddingToCollection(item)) { - commands.push('addtocollection'); - } - - if (PlaylistManager.supportsPlaylists(item)) { - commands.push('playlist'); - } - - if (item.Type == 'BoxSet' || item.Type == 'Playlist') { - commands.push('delete'); - } - else if (item.CanDelete) { - commands.push('delete'); - } - - if (user.Policy.IsAdministrator) { - - if (LibraryBrowser.supportsEditing(item.Type)) { - commands.push('edit'); + if (!isFolder && externalPlayers && mediaType != "Audio") { + menuItems.push({ + name: Globalize.translate('ButtonPlayExternalPlayer'), + id: 'externalplayer', + ironIcon: 'airplay' + }); } - if (item.MediaType == 'Video' && item.Type != 'TvChannel' && item.Type != 'Program' && item.LocationType != 'Virtual') { - commands.push('editsubtitles'); + if (MediaController.canQueueMediaType(mediaType, itemType)) { + menuItems.push({ + name: Globalize.translate('ButtonQueue'), + id: 'queue', + ironIcon: 'playlist-add' + }); } - commands.push('editimages'); - } - if (user.Policy.IsAdministrator) { - - commands.push('refresh'); - } - - if (SyncManager.isAvailable(item, user)) { - commands.push('sync'); - } - - if (item.CanDownload) { - if (AppInfo.supportsDownloading) { - commands.push('download'); + if (itemType == "Audio" || itemType == "MusicAlbum" || itemType == "MusicArtist" || itemType == "MusicGenre") { + menuItems.push({ + name: Globalize.translate('ButtonInstantMix'), + id: 'instantmix', + ironIcon: 'shuffle' + }); } - } - if (LibraryBrowser.canShare(item, user)) { - commands.push('share'); - } + if (isFolder || itemType == "MusicArtist" || itemType == "MusicGenre") { + menuItems.push({ + name: Globalize.translate('ButtonShuffle'), + id: 'shuffle', + ironIcon: 'shuffle' + }); + } - if (item.Type == "Movie" || - item.Type == "Trailer" || - item.Type == "Series" || - item.Type == "Game" || - item.Type == "BoxSet" || - item.Type == "Person" || - item.Type == "Book" || - item.Type == "MusicAlbum" || - item.Type == "MusicArtist") { + require(['actionsheet'], function (actionsheet) { + + actionsheet.show({ + items: menuItems, + positionTo: positionTo, + callback: function (id) { + + switch (id) { + + case 'play': + MediaController.play(itemId); + break; + case 'externalplayer': + LibraryBrowser.playInExternalPlayer(itemId); + break; + case 'resume': + MediaController.play({ + ids: [itemId], + startPositionTicks: resumePositionTicks + }); + break; + case 'queue': + MediaController.queue(itemId); + break; + case 'instantmix': + MediaController.instantMix(itemId); + break; + case 'shuffle': + MediaController.shuffle(itemId); + break; + default: + break; + } + } + }); + + }); + }, + + supportsEditing: function (itemType) { + + if (itemType == "UserRootFolder" || /*itemType == "CollectionFolder" ||*/ itemType == "UserView") { + return false; + } + + return true; + }, + + getMoreCommands: function (item, user) { + + var commands = []; + + if (LibraryBrowser.supportsAddingToCollection(item)) { + commands.push('addtocollection'); + } + + if (playlistManager.supportsPlaylists(item)) { + commands.push('playlist'); + } + + if (item.Type == 'BoxSet' || item.Type == 'Playlist') { + commands.push('delete'); + } + else if (item.CanDelete) { + commands.push('delete'); + } if (user.Policy.IsAdministrator) { - commands.push('identify'); - } - } + if (LibraryBrowser.supportsEditing(item.Type)) { + commands.push('edit'); + } - return commands; - }, - - refreshItem: function (itemId) { - - ApiClient.refreshItem(itemId, { - - Recursive: true, - ImageRefreshMode: 'FullRefresh', - MetadataRefreshMode: 'FullRefresh', - ReplaceAllImages: false, - ReplaceAllMetadata: true - - }); - - Dashboard.alert(Globalize.translate('MessageRefreshQueued')); - }, - - deleteItems: function (itemIds) { - - return new Promise(function (resolve, reject) { - - var msg = Globalize.translate('ConfirmDeleteItem'); - var title = Globalize.translate('HeaderDeleteItem'); - - if (itemIds.length > 1) { - msg = Globalize.translate('ConfirmDeleteItems'); - title = Globalize.translate('HeaderDeleteItems'); + if (item.MediaType == 'Video' && item.Type != 'TvChannel' && item.Type != 'Program' && item.LocationType != 'Virtual') { + commands.push('editsubtitles'); + } + commands.push('editimages'); } - Dashboard.confirm(msg, title, function (result) { + if (user.Policy.IsAdministrator) { - if (result) { + commands.push('refresh'); + } - var promises = itemIds.map(function (itemId) { - ApiClient.deleteItem(itemId); - Events.trigger(LibraryBrowser, 'itemdeleting', [itemId]); + if (SyncManager.isAvailable(item, user)) { + commands.push('sync'); + } + + if (item.CanDownload) { + if (AppInfo.supportsDownloading) { + commands.push('download'); + } + } + + if (LibraryBrowser.canShare(item, user)) { + commands.push('share'); + } + + if (item.Type == "Movie" || + item.Type == "Trailer" || + item.Type == "Series" || + item.Type == "Game" || + item.Type == "BoxSet" || + item.Type == "Person" || + item.Type == "Book" || + item.Type == "MusicAlbum" || + item.Type == "MusicArtist") { + + if (user.Policy.IsAdministrator) { + + commands.push('identify'); + } + } + + return commands; + }, + + refreshItem: function (itemId) { + + ApiClient.refreshItem(itemId, { + + Recursive: true, + ImageRefreshMode: 'FullRefresh', + MetadataRefreshMode: 'FullRefresh', + ReplaceAllImages: false, + ReplaceAllMetadata: true + + }); + + Dashboard.alert(Globalize.translate('MessageRefreshQueued')); + }, + + deleteItems: function (itemIds) { + + return new Promise(function (resolve, reject) { + + var msg = Globalize.translate('ConfirmDeleteItem'); + var title = Globalize.translate('HeaderDeleteItem'); + + if (itemIds.length > 1) { + msg = Globalize.translate('ConfirmDeleteItems'); + title = Globalize.translate('HeaderDeleteItems'); + } + + Dashboard.confirm(msg, title, function (result) { + + if (result) { + + var promises = itemIds.map(function (itemId) { + ApiClient.deleteItem(itemId); + Events.trigger(LibraryBrowser, 'itemdeleting', [itemId]); + }); + + resolve(); + + } else { + reject(); + } + }); + }); + }, + + editImages: function (itemId) { + + require(['components/imageeditor/imageeditor'], function (ImageEditor) { + + ImageEditor.show(itemId); + }); + }, + + editSubtitles: function (itemId) { + + require(['components/subtitleeditor/subtitleeditor'], function (SubtitleEditor) { + + SubtitleEditor.show(itemId); + }); + }, + + editMetadata: function (itemId) { + + require(['components/metadataeditor/metadataeditor'], function (metadataeditor) { + + metadataeditor.show(itemId); + }); + }, + + showMoreCommands: function (positionTo, itemId, commands) { + + var items = []; + + if (commands.indexOf('addtocollection') != -1) { + items.push({ + name: Globalize.translate('ButtonAddToCollection'), + id: 'addtocollection', + ironIcon: 'add' + }); + } + + if (commands.indexOf('playlist') != -1) { + items.push({ + name: Globalize.translate('ButtonAddToPlaylist'), + id: 'playlist', + ironIcon: 'playlist-add' + }); + } + + if (commands.indexOf('delete') != -1) { + items.push({ + name: Globalize.translate('ButtonDelete'), + id: 'delete', + ironIcon: 'delete' + }); + } + + if (commands.indexOf('download') != -1) { + items.push({ + name: Globalize.translate('ButtonDownload'), + id: 'download', + ironIcon: 'file-download' + }); + } + + if (commands.indexOf('edit') != -1) { + items.push({ + name: Globalize.translate('ButtonEdit'), + id: 'edit', + ironIcon: 'mode-edit' + }); + } + + if (commands.indexOf('editimages') != -1) { + items.push({ + name: Globalize.translate('ButtonEditImages'), + id: 'editimages', + ironIcon: 'photo' + }); + } + + if (commands.indexOf('editsubtitles') != -1) { + items.push({ + name: Globalize.translate('ButtonEditSubtitles'), + id: 'editsubtitles', + ironIcon: 'closed-caption' + }); + } + + if (commands.indexOf('identify') != -1) { + items.push({ + name: Globalize.translate('ButtonIdentify'), + id: 'identify', + ironIcon: 'info' + }); + } + + if (commands.indexOf('refresh') != -1) { + items.push({ + name: Globalize.translate('ButtonRefresh'), + id: 'refresh', + ironIcon: 'refresh' + }); + } + + if (commands.indexOf('share') != -1) { + items.push({ + name: Globalize.translate('ButtonShare'), + id: 'share', + ironIcon: 'share' + }); + } + + require(['actionsheet'], function (actionsheet) { + + actionsheet.show({ + items: items, + positionTo: positionTo, + callback: function (id) { + + switch (id) { + + case 'share': + require(['sharingmanager'], function () { + SharingManager.showMenu(Dashboard.getCurrentUserId(), itemId); + }); + break; + case 'addtocollection': + require(['collectioneditor'], function (collectioneditor) { + + new collectioneditor().show([itemId]); + }); + break; + case 'playlist': + require(['playlistManager'], function (playlistManager) { + + playlistManager.showPanel([itemId]); + }); + break; + case 'delete': + LibraryBrowser.deleteItems([itemId]); + break; + case 'download': + { + var downloadHref = ApiClient.getUrl("Items/" + itemId + "/Download", { + api_key: ApiClient.accessToken() + }); + window.location.href = downloadHref; + + break; + } + case 'edit': + LibraryBrowser.editMetadata(itemId); + break; + case 'editsubtitles': + LibraryBrowser.editSubtitles(itemId); + break; + case 'editimages': + LibraryBrowser.editImages(itemId); + break; + case 'identify': + LibraryBrowser.identifyItem(itemId); + break; + case 'refresh': + ApiClient.refreshItem(itemId, { + + Recursive: true, + ImageRefreshMode: 'FullRefresh', + MetadataRefreshMode: 'FullRefresh', + ReplaceAllImages: false, + ReplaceAllMetadata: true + }); + break; + default: + break; + } + } + }); + + }); + }, + + identifyItem: function (itemId) { + + require(['components/itemidentifier/itemidentifier'], function (itemidentifier) { + + itemidentifier.show(itemId); + }); + }, + + getHref: function (item, context, topParentId) { + + var href = LibraryBrowser.getHrefInternal(item, context); + + if (context == 'tv') { + if (!topParentId) { + topParentId = LibraryMenu.getTopParentId(); + } + + if (topParentId) { + href += href.indexOf('?') == -1 ? "?topParentId=" : "&topParentId="; + href += topParentId; + } + } + + return href; + }, + + getHrefInternal: function (item, context) { + + if (!item) { + throw new Error('item cannot be null'); + } + + if (item.url) { + return item.url; + } + + // Handle search hints + var id = item.Id || item.ItemId; + + if (item.CollectionType == 'livetv') { + return 'livetv.html'; + } + + if (item.CollectionType == 'channels') { + + return 'channels.html'; + } + + if (context != 'folders') { + if (item.CollectionType == 'movies') { + return 'movies.html?topParentId=' + item.Id; + } + + if (item.CollectionType == 'boxsets') { + return 'collections.html?topParentId=' + item.Id; + } + + if (item.CollectionType == 'tvshows') { + return 'tv.html?topParentId=' + item.Id; + } + + if (item.CollectionType == 'music') { + return 'music.html?topParentId=' + item.Id; + } + + if (item.CollectionType == 'games') { + return 'gamesrecommended.html?topParentId=' + item.Id; + } + if (item.CollectionType == 'playlists') { + return 'playlists.html?topParentId=' + item.Id; + } + if (item.CollectionType == 'photos') { + return 'photos.html?topParentId=' + item.Id; + } + } + if (item.Type == 'CollectionFolder') { + return 'itemlist.html?topParentId=' + item.Id + '&parentid=' + item.Id; + } + + if (item.Type == "PhotoAlbum") { + return "itemlist.html?context=photos&parentId=" + id; + } + if (item.Type == "Playlist") { + return "itemdetails.html?id=" + id; + } + if (item.Type == "TvChannel") { + return "itemdetails.html?id=" + id; + } + if (item.Type == "Channel") { + return "channelitems.html?id=" + id; + } + if (item.Type == "ChannelFolderItem") { + return "channelitems.html?id=" + item.ChannelId + '&folderId=' + item.Id; + } + if (item.Type == "Program") { + return "itemdetails.html?id=" + id; + } + + if (item.Type == "BoxSet") { + return "itemdetails.html?id=" + id; + } + if (item.Type == "MusicAlbum") { + return "itemdetails.html?id=" + id; + } + if (item.Type == "GameSystem") { + return "itemdetails.html?id=" + id; + } + if (item.Type == "Genre") { + return "itemdetails.html?id=" + id; + } + if (item.Type == "MusicGenre") { + return "itemdetails.html?id=" + id; + } + if (item.Type == "GameGenre") { + return "itemdetails.html?id=" + id; + } + if (item.Type == "Studio") { + return "itemdetails.html?id=" + id; + } + if (item.Type == "Person") { + return "itemdetails.html?id=" + id; + } + if (item.Type == "Recording") { + return "itemdetails.html?id=" + id; + } + + if (item.Type == "MusicArtist") { + return "itemdetails.html?id=" + id; + } + + var contextSuffix = context ? ('&context=' + context) : ''; + + if (item.Type == "Series" || item.Type == "Season" || item.Type == "Episode") { + return "itemdetails.html?id=" + id + contextSuffix; + } + + if (item.IsFolder) { + return id ? "itemlist.html?parentId=" + id : "#"; + } + + return "itemdetails.html?id=" + id; + }, + + getImageUrl: function (item, type, index, options) { + + options = options || {}; + options.type = type; + options.index = index; + + if (type == 'Backdrop') { + options.tag = item.BackdropImageTags[index]; + } else if (type == 'Screenshot') { + options.tag = item.ScreenshotImageTags[index]; + } else if (type == 'Primary') { + options.tag = item.PrimaryImageTag || item.ImageTags[type]; + } else { + options.tag = item.ImageTags[type]; + } + + // For search hints + return ApiClient.getScaledImageUrl(item.Id || item.ItemId, options); + + }, + + getListViewIndex: function (item, options) { + + if (options.index == 'disc') { + + return item.ParentIndexNumber == null ? '' : Globalize.translate('ValueDiscNumber', item.ParentIndexNumber); + } + + var sortBy = (options.sortBy || '').toLowerCase(); + var code, name; + + if (sortBy.indexOf('sortname') == 0) { + + if (item.Type == 'Episode') return ''; + + // SortName + name = (item.SortName || item.Name || '?')[0].toUpperCase(); + + code = name.charCodeAt(0); + if (code < 65 || code > 90) { + return '#'; + } + + return name.toUpperCase(); + } + if (sortBy.indexOf('officialrating') == 0) { + + return item.OfficialRating || Globalize.translate('HeaderUnrated'); + } + if (sortBy.indexOf('communityrating') == 0) { + + if (item.CommunityRating == null) { + return Globalize.translate('HeaderUnrated'); + } + + return Math.floor(item.CommunityRating); + } + if (sortBy.indexOf('criticrating') == 0) { + + if (item.CriticRating == null) { + return Globalize.translate('HeaderUnrated'); + } + + return Math.floor(item.CriticRating); + } + if (sortBy.indexOf('metascore') == 0) { + + if (item.Metascore == null) { + return Globalize.translate('HeaderUnrated'); + } + + return Math.floor(item.Metascore); + } + if (sortBy.indexOf('albumartist') == 0) { + + // SortName + if (!item.AlbumArtist) return ''; + + name = item.AlbumArtist[0].toUpperCase(); + + code = name.charCodeAt(0); + if (code < 65 || code > 90) { + return '#'; + } + + return name.toUpperCase(); + } + return ''; + }, + + getUserDataCssClass: function (key) { + + if (!key) return ''; + + return 'libraryItemUserData' + key.replace(new RegExp(' ', 'g'), ''); + }, + + getListViewHtml: function (options) { + + require(['paper-icon-item', 'paper-item-body']); + + var outerHtml = ""; + + if (options.title) { + outerHtml += '

'; + outerHtml += options.title; + outerHtml += '

'; + } + + outerHtml += '
'; + + var index = 0; + var groupTitle = ''; + + outerHtml += options.items.map(function (item) { + + var html = ''; + + if (options.showIndex !== false) { + + var itemGroupTitle = LibraryBrowser.getListViewIndex(item, options); + + if (itemGroupTitle != groupTitle) { + + outerHtml += '
'; + + if (index == 0) { + html += '

'; + } + else { + html += '

'; + } + html += itemGroupTitle; + html += '

'; + + html += '
'; + + groupTitle = itemGroupTitle; + } + } + + var dataAttributes = LibraryBrowser.getItemDataAttributes(item, options, index); + + var cssClass = 'listItem'; + + var href = LibraryBrowser.getHref(item, options.context); + html += ''; + + var imgUrl; + + var downloadWidth = options.smallIcon ? 70 : 80; + // Scaling 400w episode images to 80 doesn't turn out very well + var minScale = item.Type == 'Episode' || item.Type == 'Game' || options.smallIcon ? 2 : 1.5; + + if (item.ImageTags.Primary) { + + imgUrl = ApiClient.getScaledImageUrl(item.Id, { + maxWidth: downloadWidth, + tag: item.ImageTags.Primary, + type: "Primary", + index: 0, + minScale: minScale }); - resolve(); - - } else { - reject(); } - }); - }); - }, + else if (item.AlbumId && item.AlbumPrimaryImageTag) { - editImages: function (itemId) { + imgUrl = ApiClient.getScaledImageUrl(item.AlbumId, { + type: "Primary", + maxWidth: downloadWidth, + tag: item.AlbumPrimaryImageTag, + minScale: minScale + }); - require(['components/imageeditor/imageeditor'], function (ImageEditor) { + } + else if (item.AlbumId && item.SeriesPrimaryImageTag) { - ImageEditor.show(itemId); - }); - }, + imgUrl = ApiClient.getScaledImageUrl(item.SeriesId, { + type: "Primary", + maxWidth: downloadWidth, + tag: item.SeriesPrimaryImageTag, + minScale: minScale + }); - editSubtitles: function (itemId) { + } + else if (item.ParentPrimaryImageTag) { - require(['components/subtitleeditor/subtitleeditor'], function (SubtitleEditor) { + imgUrl = ApiClient.getImageUrl(item.ParentPrimaryImageItemId, { + type: "Primary", + maxWidth: downloadWidth, + tag: item.ParentPrimaryImageTag, + minScale: minScale + }); + } - SubtitleEditor.show(itemId); - }); - }, - - editMetadata: function (itemId) { - - require(['components/metadataeditor/metadataeditor'], function (metadataeditor) { - - metadataeditor.show(itemId); - }); - }, - - showMoreCommands: function (positionTo, itemId, commands) { - - var items = []; - - if (commands.indexOf('addtocollection') != -1) { - items.push({ - name: Globalize.translate('ButtonAddToCollection'), - id: 'addtocollection', - ironIcon: 'add' - }); - } - - if (commands.indexOf('playlist') != -1) { - items.push({ - name: Globalize.translate('ButtonAddToPlaylist'), - id: 'playlist', - ironIcon: 'playlist-add' - }); - } - - if (commands.indexOf('delete') != -1) { - items.push({ - name: Globalize.translate('ButtonDelete'), - id: 'delete', - ironIcon: 'delete' - }); - } - - if (commands.indexOf('download') != -1) { - items.push({ - name: Globalize.translate('ButtonDownload'), - id: 'download', - ironIcon: 'file-download' - }); - } - - if (commands.indexOf('edit') != -1) { - items.push({ - name: Globalize.translate('ButtonEdit'), - id: 'edit', - ironIcon: 'mode-edit' - }); - } - - if (commands.indexOf('editimages') != -1) { - items.push({ - name: Globalize.translate('ButtonEditImages'), - id: 'editimages', - ironIcon: 'photo' - }); - } - - if (commands.indexOf('editsubtitles') != -1) { - items.push({ - name: Globalize.translate('ButtonEditSubtitles'), - id: 'editsubtitles', - ironIcon: 'closed-caption' - }); - } - - if (commands.indexOf('identify') != -1) { - items.push({ - name: Globalize.translate('ButtonIdentify'), - id: 'identify', - ironIcon: 'info' - }); - } - - if (commands.indexOf('refresh') != -1) { - items.push({ - name: Globalize.translate('ButtonRefresh'), - id: 'refresh', - ironIcon: 'refresh' - }); - } - - if (commands.indexOf('share') != -1) { - items.push({ - name: Globalize.translate('ButtonShare'), - id: 'share', - ironIcon: 'share' - }); - } - - require(['actionsheet'], function (actionsheet) { - - actionsheet.show({ - items: items, - positionTo: positionTo, - callback: function (id) { - - switch (id) { - - case 'share': - require(['sharingmanager'], function () { - SharingManager.showMenu(Dashboard.getCurrentUserId(), itemId); - }); - break; - case 'addtocollection': - require(['collectioneditor'], function (collectioneditor) { - - new collectioneditor().show([itemId]); - }); - break; - case 'playlist': - PlaylistManager.showPanel([itemId]); - break; - case 'delete': - LibraryBrowser.deleteItems([itemId]); - break; - case 'download': - { - var downloadHref = ApiClient.getUrl("Items/" + itemId + "/Download", { - api_key: ApiClient.accessToken() - }); - window.location.href = downloadHref; - - break; - } - case 'edit': - LibraryBrowser.editMetadata(itemId); - break; - case 'editsubtitles': - LibraryBrowser.editSubtitles(itemId); - break; - case 'editimages': - LibraryBrowser.editImages(itemId); - break; - case 'identify': - LibraryBrowser.identifyItem(itemId); - break; - case 'refresh': - ApiClient.refreshItem(itemId, { - - Recursive: true, - ImageRefreshMode: 'FullRefresh', - MetadataRefreshMode: 'FullRefresh', - ReplaceAllImages: false, - ReplaceAllMetadata: true - }); - break; - default: - break; + if (imgUrl) { + var minLazyIndex = 16; + if (options.smallIcon) { + if (index < minLazyIndex) { + html += '
'; + } else { + html += '
'; + } + } else { + if (index < minLazyIndex) { + html += '
'; + } else { + html += '
'; + } + } + } else { + if (options.smallIcon) { + html += '
'; + } else { + html += '
'; } } - }); - }); - }, + var textlines = []; - identifyItem: function (itemId) { + if (item.Type == 'Episode') { + textlines.push(item.SeriesName || ' '); + } else if (item.Type == 'MusicAlbum') { + textlines.push(item.AlbumArtist || ' '); + } - require(['components/itemidentifier/itemidentifier'], function (itemidentifier) { + var displayName = LibraryBrowser.getPosterViewDisplayName(item); - itemidentifier.show(itemId); - }); - }, + if (options.showIndexNumber && item.IndexNumber != null) { + displayName = item.IndexNumber + ". " + displayName; + } + textlines.push(displayName); - getHref: function (item, context, topParentId) { + if (item.Type == 'Audio') { + textlines.push(item.ArtistItems.map(function (a) { + return a.Name; - var href = LibraryBrowser.getHrefInternal(item, context); + }).join(', ') || ' '); + } - if (context == 'tv') { - if (!topParentId) { - topParentId = LibraryMenu.getTopParentId(); + if (item.Type == 'Game') { + textlines.push(item.GameSystem || ' '); + } + + else if (item.Type == 'MusicGenre') { + textlines.push(' '); + } + else if (item.Type == 'MusicArtist') { + textlines.push(' '); + } + else if (item.Type == 'TvChannel') { + + if (item.CurrentProgram) { + textlines.push(LibraryBrowser.getPosterViewDisplayName(item.CurrentProgram)); + } + } + else { + textlines.push(LibraryBrowser.getMiscInfoHtml(item)); + } + + if (textlines.length > 2) { + html += ''; + } else { + html += ''; + } + + var defaultAction = options.defaultAction; + if (defaultAction == 'play' || defaultAction == 'playallfromhere') { + if (item.PlayAccess != 'Full') { + defaultAction = null; + } + } + var defaultActionAttribute = defaultAction ? (' data-action="' + defaultAction + '" class="itemWithAction mediaItem clearLink"') : ' class="mediaItem clearLink"'; + html += ''; + + for (var i = 0, textLinesLength = textlines.length; i < textLinesLength; i++) { + + if (i == 0) { + html += '
'; + } else { + html += '
'; + } + html += textlines[i] || ' '; + html += '
'; + } + + //html += LibraryBrowser.getSyncIndicator(item); + + //if (item.Type == 'Series' || item.Type == 'Season' || item.Type == 'BoxSet' || item.MediaType == 'Video') { + // if (item.UserData.UnplayedItemCount) { + // //html += '' + item.UserData.UnplayedItemCount + ''; + // } else if (item.UserData.Played && item.Type != 'TvChannel') { + // html += '
'; + // } + //} + html += ''; + html += ''; + + html += ''; + html += ''; + html += LibraryBrowser.getUserDataIconsHtml(item); + html += ''; + + html += ''; + + index++; + return html; + + }).join(''); + + outerHtml += '
'; + + return outerHtml; + }, + + getItemDataAttributes: function (item, options, index) { + + var atts = []; + + var itemCommands = LibraryBrowser.getItemCommands(item, options); + + atts.push('data-itemid="' + item.Id + '"'); + atts.push('data-commands="' + itemCommands.join(',') + '"'); + + if (options.context) { + atts.push('data-context="' + (options.context || '') + '"'); } - if (topParentId) { - href += href.indexOf('?') == -1 ? "?topParentId=" : "&topParentId="; - href += topParentId; - } - } - - return href; - }, - - getHrefInternal: function (item, context) { - - if (!item) { - throw new Error('item cannot be null'); - } - - if (item.url) { - return item.url; - } - - // Handle search hints - var id = item.Id || item.ItemId; - - if (item.CollectionType == 'livetv') { - return 'livetv.html'; - } - - if (item.CollectionType == 'channels') { - - return 'channels.html'; - } - - if (context != 'folders') { - if (item.CollectionType == 'movies') { - return 'movies.html?topParentId=' + item.Id; + if (item.IsFolder) { + atts.push('data-isfolder="' + item.IsFolder + '"'); } - if (item.CollectionType == 'boxsets') { - return 'collections.html?topParentId=' + item.Id; + atts.push('data-itemtype="' + item.Type + '"'); + + if (item.MediaType) { + atts.push('data-mediatype="' + (item.MediaType || '') + '"'); } - if (item.CollectionType == 'tvshows') { - return 'tv.html?topParentId=' + item.Id; + if (item.UserData.PlaybackPositionTicks) { + atts.push('data-positionticks="' + (item.UserData.PlaybackPositionTicks || 0) + '"'); } - if (item.CollectionType == 'music') { - return 'music.html?topParentId=' + item.Id; + atts.push('data-playaccess="' + (item.PlayAccess || '') + '"'); + atts.push('data-locationtype="' + (item.LocationType || '') + '"'); + atts.push('data-index="' + index + '"'); + + if (item.AlbumId) { + atts.push('data-albumid="' + item.AlbumId + '"'); } - if (item.CollectionType == 'games') { - return 'gamesrecommended.html?topParentId=' + item.Id; - } - if (item.CollectionType == 'playlists') { - return 'playlists.html?topParentId=' + item.Id; - } - if (item.CollectionType == 'photos') { - return 'photos.html?topParentId=' + item.Id; - } - } - if (item.Type == 'CollectionFolder') { - return 'itemlist.html?topParentId=' + item.Id + '&parentid=' + item.Id; - } - - if (item.Type == "PhotoAlbum") { - return "itemlist.html?context=photos&parentId=" + id; - } - if (item.Type == "Playlist") { - return "itemdetails.html?id=" + id; - } - if (item.Type == "TvChannel") { - return "itemdetails.html?id=" + id; - } - if (item.Type == "Channel") { - return "channelitems.html?id=" + id; - } - if (item.Type == "ChannelFolderItem") { - return "channelitems.html?id=" + item.ChannelId + '&folderId=' + item.Id; - } - if (item.Type == "Program") { - return "itemdetails.html?id=" + id; - } - - if (item.Type == "BoxSet") { - return "itemdetails.html?id=" + id; - } - if (item.Type == "MusicAlbum") { - return "itemdetails.html?id=" + id; - } - if (item.Type == "GameSystem") { - return "itemdetails.html?id=" + id; - } - if (item.Type == "Genre") { - return "itemdetails.html?id=" + id; - } - if (item.Type == "MusicGenre") { - return "itemdetails.html?id=" + id; - } - if (item.Type == "GameGenre") { - return "itemdetails.html?id=" + id; - } - if (item.Type == "Studio") { - return "itemdetails.html?id=" + id; - } - if (item.Type == "Person") { - return "itemdetails.html?id=" + id; - } - if (item.Type == "Recording") { - return "itemdetails.html?id=" + id; - } - - if (item.Type == "MusicArtist") { - return "itemdetails.html?id=" + id; - } - - var contextSuffix = context ? ('&context=' + context) : ''; - - if (item.Type == "Series" || item.Type == "Season" || item.Type == "Episode") { - return "itemdetails.html?id=" + id + contextSuffix; - } - - if (item.IsFolder) { - return id ? "itemlist.html?parentId=" + id : "#"; - } - - return "itemdetails.html?id=" + id; - }, - - getImageUrl: function (item, type, index, options) { - - options = options || {}; - options.type = type; - options.index = index; - - if (type == 'Backdrop') { - options.tag = item.BackdropImageTags[index]; - } else if (type == 'Screenshot') { - options.tag = item.ScreenshotImageTags[index]; - } else if (type == 'Primary') { - options.tag = item.PrimaryImageTag || item.ImageTags[type]; - } else { - options.tag = item.ImageTags[type]; - } - - // For search hints - return ApiClient.getScaledImageUrl(item.Id || item.ItemId, options); - - }, - - getListViewIndex: function (item, options) { - - if (options.index == 'disc') { - - return item.ParentIndexNumber == null ? '' : Globalize.translate('ValueDiscNumber', item.ParentIndexNumber); - } - - var sortBy = (options.sortBy || '').toLowerCase(); - var code, name; - - if (sortBy.indexOf('sortname') == 0) { - - if (item.Type == 'Episode') return ''; - - // SortName - name = (item.SortName || item.Name || '?')[0].toUpperCase(); - - code = name.charCodeAt(0); - if (code < 65 || code > 90) { - return '#'; + if (item.ChannelId) { + atts.push('data-channelid="' + item.ChannelId + '"'); } - return name.toUpperCase(); - } - if (sortBy.indexOf('officialrating') == 0) { - - return item.OfficialRating || Globalize.translate('HeaderUnrated'); - } - if (sortBy.indexOf('communityrating') == 0) { - - if (item.CommunityRating == null) { - return Globalize.translate('HeaderUnrated'); + if (item.ArtistItems && item.ArtistItems.length) { + atts.push('data-artistid="' + item.ArtistItems[0].Id + '"'); } - return Math.floor(item.CommunityRating); - } - if (sortBy.indexOf('criticrating') == 0) { + var html = atts.join(' '); - if (item.CriticRating == null) { - return Globalize.translate('HeaderUnrated'); + if (html) { + html = ' ' + html; } - return Math.floor(item.CriticRating); - } - if (sortBy.indexOf('metascore') == 0) { + return html; + }, - if (item.Metascore == null) { - return Globalize.translate('HeaderUnrated'); + supportsAddingToCollection: function (item) { + + var invalidTypes = ['Person', 'Genre', 'MusicGenre', 'Studio', 'GameGenre', 'BoxSet', 'Playlist', 'UserView', 'CollectionFolder', 'Audio', 'Episode', 'TvChannel', 'Program', 'MusicAlbum']; + + return !item.CollectionType && invalidTypes.indexOf(item.Type) == -1 && item.MediaType != 'Photo'; + }, + + getItemCommands: function (item, options) { + + var itemCommands = []; + + //if (MediaController.canPlay(item)) { + // itemCommands.push('playmenu'); + //} + + if (LibraryBrowser.supportsEditing(item.Type)) { + itemCommands.push('edit'); } - return Math.floor(item.Metascore); - } - if (sortBy.indexOf('albumartist') == 0) { - - // SortName - if (!item.AlbumArtist) return ''; - - name = item.AlbumArtist[0].toUpperCase(); - - code = name.charCodeAt(0); - if (code < 65 || code > 90) { - return '#'; + if (item.LocalTrailerCount) { + itemCommands.push('trailer'); } - return name.toUpperCase(); - } - return ''; - }, + if (item.MediaType == "Audio" || item.Type == "MusicAlbum" || item.Type == "MusicArtist" || item.Type == "MusicGenre" || item.CollectionType == "music") { + itemCommands.push('instantmix'); + } - getUserDataCssClass: function (key) { + if (item.IsFolder || item.Type == "MusicArtist" || item.Type == "MusicGenre") { + itemCommands.push('shuffle'); + } - if (!key) return ''; + if (playlistManager.supportsPlaylists(item)) { - return 'libraryItemUserData' + key.replace(new RegExp(' ', 'g'), ''); - }, + if (options.showRemoveFromPlaylist) { + itemCommands.push('removefromplaylist'); + } else { + itemCommands.push('playlist'); + } + } - getListViewHtml: function (options) { + if (options.showAddToCollection !== false) { + if (LibraryBrowser.supportsAddingToCollection(item)) { + itemCommands.push('addtocollection'); + } + } - require(['paper-icon-item', 'paper-item-body']); + if (options.showRemoveFromCollection) { + itemCommands.push('removefromcollection'); + } - var outerHtml = ""; + if (options.playFromHere) { + itemCommands.push('playfromhere'); + itemCommands.push('queuefromhere'); + } - if (options.title) { - outerHtml += '

'; - outerHtml += options.title; - outerHtml += '

'; - } + if (item.CanDelete) { + itemCommands.push('delete'); + } - outerHtml += '
'; + if (SyncManager.isAvailable(item)) { + itemCommands.push('sync'); + } - var index = 0; - var groupTitle = ''; + if (item.Type == 'Program' && (!item.TimerId && !item.SeriesTimerId)) { - outerHtml += options.items.map(function (item) { + itemCommands.push('record'); + } + + if (item.MediaType == 'Video' && item.Type != 'TvChannel' && item.Type != 'Program' && item.LocationType != 'Virtual') { + itemCommands.push('editsubtitles'); + } + itemCommands.push('editimages'); + + return itemCommands; + }, + + screenWidth: function () { + + var screenWidth = $(window).width(); + + return screenWidth; + }, + + shapes: ['square', 'portrait', 'banner', 'smallBackdrop', 'homePageSmallBackdrop', 'backdrop', 'overflowBackdrop', 'overflowPortrait', 'overflowSquare'], + + getPostersPerRow: function (screenWidth) { + + var cache = true; + function getValue(shape) { + var div = $('
').appendTo(document.body); + var innerWidth = $('.cardImage', div).innerWidth(); + + if (!innerWidth || isNaN(innerWidth)) { + cache = false; + innerWidth = Math.min(400, screenWidth / 2); + } + + var width = screenWidth / innerWidth; + div.remove(); + return Math.floor(width); + } + + var info = {}; + + for (var i = 0, length = LibraryBrowser.shapes.length; i < length; i++) { + var currentShape = LibraryBrowser.shapes[i]; + info[currentShape] = getValue(currentShape); + } + info.cache = cache; + return info; + }, + + posterSizes: [], + + getPosterViewInfo: function () { + + var screenWidth = LibraryBrowser.screenWidth(); + + var cachedResults = LibraryBrowser.posterSizes; + + for (var i = 0, length = cachedResults.length; i < length; i++) { + + if (cachedResults[i].screenWidth == screenWidth) { + return cachedResults[i]; + } + } + + var result = LibraryBrowser.getPosterViewInfoInternal(screenWidth); + result.screenWidth = screenWidth; + + if (result.cache) { + cachedResults.push(result); + } + + return result; + }, + + getPosterViewInfoInternal: function (screenWidth) { + + var imagesPerRow = LibraryBrowser.getPostersPerRow(screenWidth); + + var result = {}; + result.screenWidth = screenWidth; + + if (!AppInfo.hasLowImageBandwidth) { + screenWidth *= 1.2; + } + + var roundTo = 100; + + for (var i = 0, length = LibraryBrowser.shapes.length; i < length; i++) { + var currentShape = LibraryBrowser.shapes[i]; + + var shapeWidth = screenWidth / imagesPerRow[currentShape]; + + if (!browserInfo.mobile) { + + shapeWidth = Math.round(shapeWidth / roundTo) * roundTo; + } + + result[currentShape + 'Width'] = Math.round(shapeWidth); + } + + result.cache = imagesPerRow.cache; + + return result; + }, + + getPosterViewHtml: function (options) { + + var items = options.items; + var currentIndexValue; + + options.shape = options.shape || "portrait"; + + var html = ""; + + var primaryImageAspectRatio = LibraryBrowser.getAveragePrimaryImageAspectRatio(items); + var isThumbAspectRatio = primaryImageAspectRatio && Math.abs(primaryImageAspectRatio - 1.777777778) < .3; + var isSquareAspectRatio = primaryImageAspectRatio && Math.abs(primaryImageAspectRatio - 1) < .33 || + primaryImageAspectRatio && Math.abs(primaryImageAspectRatio - 1.3333334) < .01; + + if (options.shape == 'auto' || options.shape == 'autohome') { + + if (isThumbAspectRatio) { + options.shape = options.shape == 'auto' ? 'backdrop' : 'backdrop'; + } else if (isSquareAspectRatio) { + options.coverImage = true; + options.shape = 'square'; + } else if (primaryImageAspectRatio && primaryImageAspectRatio > 1.9) { + options.shape = 'banner'; + options.coverImage = true; + } else if (primaryImageAspectRatio && Math.abs(primaryImageAspectRatio - 0.6666667) < .2) { + options.shape = options.shape == 'auto' ? 'portrait' : 'portrait'; + } else { + options.shape = options.defaultShape || (options.shape == 'auto' ? 'square' : 'square'); + } + } + + var posterInfo = LibraryBrowser.getPosterViewInfo(); + + var thumbWidth = posterInfo.backdropWidth; + var posterWidth = posterInfo.portraitWidth; + var squareSize = posterInfo.squareWidth; + var bannerWidth = posterInfo.bannerWidth; + + if (isThumbAspectRatio) { + posterWidth = thumbWidth; + } + else if (isSquareAspectRatio) { + posterWidth = squareSize; + } + + if (options.shape == 'overflowBackdrop') { + thumbWidth = posterInfo.overflowBackdropWidth; + } + else if (options.shape == 'overflowPortrait') { + posterWidth = posterInfo.overflowPortraitWidth; + } + else if (options.shape == 'overflowSquare') { + squareSize = posterInfo.overflowSquareWidth; + } + else if (options.shape == 'smallBackdrop') { + thumbWidth = posterInfo.smallBackdropWidth; + } + else if (options.shape == 'homePageSmallBackdrop') { + thumbWidth = posterInfo.homePageSmallBackdropWidth; + posterWidth = posterInfo.homePageSmallBackdropWidth; + } + else if (options.shape == 'detailPagePortrait') { + posterWidth = 200; + } + else if (options.shape == 'detailPageSquare') { + posterWidth = 240; + squareSize = 240; + } + else if (options.shape == 'detailPage169') { + posterWidth = 320; + thumbWidth = 320; + } + + var dateText; + var uiAspect = getDesiredAspect(options.shape); + + for (var i = 0, length = items.length; i < length; i++) { + + var item = items[i]; + + dateText = null; + + primaryImageAspectRatio = LibraryBrowser.getAveragePrimaryImageAspectRatio([item]); + + if (options.showStartDateIndex) { + + if (item.StartDate) { + try { + + dateText = LibraryBrowser.getFutureDateText(parseISO8601Date(item.StartDate, { toLocal: true }), true); + + } catch (err) { + } + } + + var newIndexValue = dateText || Globalize.translate('HeaderUnknownDate'); + + if (newIndexValue != currentIndexValue) { + + html += '

' + newIndexValue + '

'; + currentIndexValue = newIndexValue; + } + } else if (options.timeline) { + var year = item.ProductionYear || Globalize.translate('HeaderUnknownYear'); + + if (year != currentIndexValue) { + + html += '

' + year + '

'; + currentIndexValue = year; + } + } + + html += LibraryBrowser.getPosterViewItemHtml(item, i, options, primaryImageAspectRatio, thumbWidth, posterWidth, squareSize, bannerWidth, uiAspect); + } + + return html; + }, + + getPosterViewItemHtml: function (item, index, options, primaryImageAspectRatio, thumbWidth, posterWidth, squareSize, bannerWidth, uiAspect) { var html = ''; + var imgUrl = null; + var icon; + var width = null; + var height = null; - if (options.showIndex !== false) { + var forceName = false; - var itemGroupTitle = LibraryBrowser.getListViewIndex(item, options); + var enableImageEnhancers = options.enableImageEnhancers !== false; - if (itemGroupTitle != groupTitle) { + var cssClass = "card"; - outerHtml += '
'; - - if (index == 0) { - html += '

'; - } - else { - html += '

'; - } - html += itemGroupTitle; - html += '

'; - - html += '
'; - - groupTitle = itemGroupTitle; - } + if (options.fullWidthOnMobile) { + cssClass += " fullWidthCardOnMobile"; } - var dataAttributes = LibraryBrowser.getItemDataAttributes(item, options, index); + var showTitle = options.showTitle == 'auto' ? true : options.showTitle; + var coverImage = options.coverImage; - var cssClass = 'listItem'; + if (options.autoThumb && item.ImageTags && item.ImageTags.Primary && item.PrimaryImageAspectRatio && item.PrimaryImageAspectRatio >= 1.34) { - var href = LibraryBrowser.getHref(item, options.context); - html += ''; + width = posterWidth; + height = primaryImageAspectRatio ? Math.round(posterWidth / primaryImageAspectRatio) : null; - var imgUrl; + imgUrl = ApiClient.getImageUrl(item.Id, { + type: "Primary", + maxHeight: height, + maxWidth: width, + tag: item.ImageTags.Primary, + enableImageEnhancers: enableImageEnhancers + }); - var downloadWidth = options.smallIcon ? 70 : 80; - // Scaling 400w episode images to 80 doesn't turn out very well - var minScale = item.Type == 'Episode' || item.Type == 'Game' || options.smallIcon ? 2 : 1.5; + if (primaryImageAspectRatio) { + if (uiAspect) { + if (Math.abs(primaryImageAspectRatio - uiAspect) <= .2) { + coverImage = true; + } + } + } - if (item.ImageTags.Primary) { + } else if (options.autoThumb && item.ImageTags && item.ImageTags.Thumb) { imgUrl = ApiClient.getScaledImageUrl(item.Id, { - maxWidth: downloadWidth, - tag: item.ImageTags.Primary, - type: "Primary", - index: 0, - minScale: minScale + type: "Thumb", + maxWidth: thumbWidth, + tag: item.ImageTags.Thumb, + enableImageEnhancers: enableImageEnhancers }); - } - else if (item.AlbumId && item.AlbumPrimaryImageTag) { + } else if (options.preferBackdrop && item.BackdropImageTags && item.BackdropImageTags.length) { - imgUrl = ApiClient.getScaledImageUrl(item.AlbumId, { - type: "Primary", - maxWidth: downloadWidth, - tag: item.AlbumPrimaryImageTag, - minScale: minScale + imgUrl = ApiClient.getScaledImageUrl(item.Id, { + type: "Backdrop", + maxWidth: thumbWidth, + tag: item.BackdropImageTags[0], + enableImageEnhancers: enableImageEnhancers }); - } - else if (item.AlbumId && item.SeriesPrimaryImageTag) { + } else if (options.preferThumb && item.ImageTags && item.ImageTags.Thumb) { + + imgUrl = ApiClient.getScaledImageUrl(item.Id, { + type: "Thumb", + maxWidth: thumbWidth, + tag: item.ImageTags.Thumb, + enableImageEnhancers: enableImageEnhancers + }); + + } else if (options.preferBanner && item.ImageTags && item.ImageTags.Banner) { + + imgUrl = ApiClient.getScaledImageUrl(item.Id, { + type: "Banner", + maxWidth: bannerWidth, + tag: item.ImageTags.Banner, + enableImageEnhancers: enableImageEnhancers + }); + + } else if (options.preferThumb && item.SeriesThumbImageTag && options.inheritThumb !== false) { imgUrl = ApiClient.getScaledImageUrl(item.SeriesId, { - type: "Primary", - maxWidth: downloadWidth, - tag: item.SeriesPrimaryImageTag, - minScale: minScale + type: "Thumb", + maxWidth: thumbWidth, + tag: item.SeriesThumbImageTag, + enableImageEnhancers: enableImageEnhancers }); + } else if (options.preferThumb && item.ParentThumbItemId && options.inheritThumb !== false) { + + imgUrl = ApiClient.getThumbImageUrl(item.ParentThumbItemId, { + type: "Thumb", + maxWidth: thumbWidth, + enableImageEnhancers: enableImageEnhancers + }); + + } else if (options.preferThumb && item.BackdropImageTags && item.BackdropImageTags.length) { + + imgUrl = ApiClient.getScaledImageUrl(item.Id, { + type: "Backdrop", + maxWidth: thumbWidth, + tag: item.BackdropImageTags[0], + enableImageEnhancers: enableImageEnhancers + }); + + forceName = true; + + } else if (item.ImageTags && item.ImageTags.Primary) { + + width = posterWidth; + height = primaryImageAspectRatio ? Math.round(posterWidth / primaryImageAspectRatio) : null; + + imgUrl = ApiClient.getImageUrl(item.Id, { + type: "Primary", + maxHeight: height, + maxWidth: width, + tag: item.ImageTags.Primary, + enableImageEnhancers: enableImageEnhancers + }); + + if (primaryImageAspectRatio) { + if (uiAspect) { + if (Math.abs(primaryImageAspectRatio - uiAspect) <= .2) { + coverImage = true; + } + } + } } else if (item.ParentPrimaryImageTag) { imgUrl = ApiClient.getImageUrl(item.ParentPrimaryImageItemId, { type: "Primary", - maxWidth: downloadWidth, + maxWidth: posterWidth, tag: item.ParentPrimaryImageTag, - minScale: minScale + enableImageEnhancers: enableImageEnhancers }); } + else if (item.AlbumId && item.AlbumPrimaryImageTag) { - if (imgUrl) { - var minLazyIndex = 16; - if (options.smallIcon) { - if (index < minLazyIndex) { - html += '
'; - } else { - html += '
'; - } - } else { - if (index < minLazyIndex) { - html += '
'; - } else { - html += '
'; + height = squareSize; + width = primaryImageAspectRatio ? Math.round(height * primaryImageAspectRatio) : null; + + imgUrl = ApiClient.getScaledImageUrl(item.AlbumId, { + type: "Primary", + maxHeight: height, + maxWidth: width, + tag: item.AlbumPrimaryImageTag, + enableImageEnhancers: enableImageEnhancers + }); + + if (primaryImageAspectRatio) { + if (uiAspect) { + if (Math.abs(primaryImageAspectRatio - uiAspect) <= .2) { + coverImage = true; + } } } - } else { - if (options.smallIcon) { - html += '
'; - } else { - html += '
'; + } + else if (item.Type == 'Season' && item.ImageTags && item.ImageTags.Thumb) { + + imgUrl = ApiClient.getScaledImageUrl(item.Id, { + type: "Thumb", + maxWidth: thumbWidth, + tag: item.ImageTags.Thumb, + enableImageEnhancers: enableImageEnhancers + }); + + } + else if (item.BackdropImageTags && item.BackdropImageTags.length) { + + imgUrl = ApiClient.getScaledImageUrl(item.Id, { + type: "Backdrop", + maxWidth: thumbWidth, + tag: item.BackdropImageTags[0], + enableImageEnhancers: enableImageEnhancers + }); + + } else if (item.ImageTags && item.ImageTags.Thumb) { + + imgUrl = ApiClient.getScaledImageUrl(item.Id, { + type: "Thumb", + maxWidth: thumbWidth, + tag: item.ImageTags.Thumb, + enableImageEnhancers: enableImageEnhancers + }); + + } else if (item.SeriesThumbImageTag) { + + imgUrl = ApiClient.getScaledImageUrl(item.SeriesId, { + type: "Thumb", + maxWidth: thumbWidth, + tag: item.SeriesThumbImageTag, + enableImageEnhancers: enableImageEnhancers + }); + + } else if (item.ParentThumbItemId) { + + imgUrl = ApiClient.getThumbImageUrl(item, { + type: "Thumb", + maxWidth: thumbWidth, + enableImageEnhancers: enableImageEnhancers + }); + + } else if (item.MediaType == "Audio" || item.Type == "MusicAlbum" || item.Type == "MusicArtist") { + + if (item.Name && showTitle) { + icon = 'library-music'; } - } + cssClass += " defaultBackground"; - var textlines = []; + } else if (item.Type == "Recording" || item.Type == "Program" || item.Type == "TvChannel") { - if (item.Type == 'Episode') { - textlines.push(item.SeriesName || ' '); - } else if (item.Type == 'MusicAlbum') { - textlines.push(item.AlbumArtist || ' '); - } - - var displayName = LibraryBrowser.getPosterViewDisplayName(item); - - if (options.showIndexNumber && item.IndexNumber != null) { - displayName = item.IndexNumber + ". " + displayName; - } - textlines.push(displayName); - - if (item.Type == 'Audio') { - textlines.push(item.ArtistItems.map(function (a) { - return a.Name; - - }).join(', ') || ' '); - } - - if (item.Type == 'Game') { - textlines.push(item.GameSystem || ' '); - } - - else if (item.Type == 'MusicGenre') { - textlines.push(' '); - } - else if (item.Type == 'MusicArtist') { - textlines.push(' '); - } - else if (item.Type == 'TvChannel') { - - if (item.CurrentProgram) { - textlines.push(LibraryBrowser.getPosterViewDisplayName(item.CurrentProgram)); + if (item.Name && showTitle) { + icon = 'folder-open'; } - } - else { - textlines.push(LibraryBrowser.getMiscInfoHtml(item)); + + cssClass += " defaultBackground"; + } else if (item.MediaType == "Video" || item.Type == "Season" || item.Type == "Series") { + + if (item.Name && showTitle) { + icon = 'videocam'; + } + cssClass += " defaultBackground"; + } else if (item.Type == "Person") { + + if (item.Name && showTitle) { + icon = 'person'; + } + cssClass += " defaultBackground"; + } else { + if (item.Name && showTitle) { + icon = 'folder-open'; + } + cssClass += " defaultBackground"; } - if (textlines.length > 2) { - html += ''; - } else { - html += ''; + icon = item.icon || icon; + cssClass += ' ' + options.shape + 'Card'; + + var mediaSourceCount = item.MediaSourceCount || 1; + + var href = options.linkItem === false ? '#' : LibraryBrowser.getHref(item, options.context); + + if (options.showChildCountIndicator && item.ChildCount && options.showLatestItemsPopup !== false) { + cssClass += ' groupedCard'; } + if ((showTitle || options.showItemCounts) && !options.overlayText) { + cssClass += ' bottomPaddedCard'; + } + + var dataAttributes = LibraryBrowser.getItemDataAttributes(item, options, index); + var defaultAction = options.defaultAction; if (defaultAction == 'play' || defaultAction == 'playallfromhere') { if (item.PlayAccess != 'Full') { defaultAction = null; } } - var defaultActionAttribute = defaultAction ? (' data-action="' + defaultAction + '" class="itemWithAction mediaItem clearLink"') : ' class="mediaItem clearLink"'; - html += ''; + var defaultActionAttribute = defaultAction ? (' data-action="' + defaultAction + '"') : ''; - for (var i = 0, textLinesLength = textlines.length; i < textLinesLength; i++) { + // card + html += ''; - if (i == 0) { - html += '
'; - } else { - html += '
'; - } - html += textlines[i] || ' '; - html += '
'; + var style = ""; + + if (imgUrl && !options.lazy) { + style += 'background-image:url(\'' + imgUrl + '\');'; } - //html += LibraryBrowser.getSyncIndicator(item); + var imageCssClass = 'cardImage'; - //if (item.Type == 'Series' || item.Type == 'Season' || item.Type == 'BoxSet' || item.MediaType == 'Video') { - // if (item.UserData.UnplayedItemCount) { - // //html += '' + item.UserData.UnplayedItemCount + ''; - // } else if (item.UserData.Played && item.Type != 'TvChannel') { - // html += '
'; - // } - //} - html += ''; - html += ''; - - html += ''; - html += ''; - html += LibraryBrowser.getUserDataIconsHtml(item); - html += ''; - - html += ''; - - index++; - return html; - - }).join(''); - - outerHtml += '
'; - - return outerHtml; - }, - - getItemDataAttributes: function (item, options, index) { - - var atts = []; - - var itemCommands = LibraryBrowser.getItemCommands(item, options); - - atts.push('data-itemid="' + item.Id + '"'); - atts.push('data-commands="' + itemCommands.join(',') + '"'); - - if (options.context) { - atts.push('data-context="' + (options.context || '') + '"'); - } - - if (item.IsFolder) { - atts.push('data-isfolder="' + item.IsFolder + '"'); - } - - atts.push('data-itemtype="' + item.Type + '"'); - - if (item.MediaType) { - atts.push('data-mediatype="' + (item.MediaType || '') + '"'); - } - - if (item.UserData.PlaybackPositionTicks) { - atts.push('data-positionticks="' + (item.UserData.PlaybackPositionTicks || 0) + '"'); - } - - atts.push('data-playaccess="' + (item.PlayAccess || '') + '"'); - atts.push('data-locationtype="' + (item.LocationType || '') + '"'); - atts.push('data-index="' + index + '"'); - - if (item.AlbumId) { - atts.push('data-albumid="' + item.AlbumId + '"'); - } - - if (item.ChannelId) { - atts.push('data-channelid="' + item.ChannelId + '"'); - } - - if (item.ArtistItems && item.ArtistItems.length) { - atts.push('data-artistid="' + item.ArtistItems[0].Id + '"'); - } - - var html = atts.join(' '); - - if (html) { - html = ' ' + html; - } - - return html; - }, - - supportsAddingToCollection: function (item) { - - var invalidTypes = ['Person', 'Genre', 'MusicGenre', 'Studio', 'GameGenre', 'BoxSet', 'Playlist', 'UserView', 'CollectionFolder', 'Audio', 'Episode', 'TvChannel', 'Program', 'MusicAlbum']; - - return !item.CollectionType && invalidTypes.indexOf(item.Type) == -1 && item.MediaType != 'Photo'; - }, - - getItemCommands: function (item, options) { - - var itemCommands = []; - - //if (MediaController.canPlay(item)) { - // itemCommands.push('playmenu'); - //} - - if (LibraryBrowser.supportsEditing(item.Type)) { - itemCommands.push('edit'); - } - - if (item.LocalTrailerCount) { - itemCommands.push('trailer'); - } - - if (item.MediaType == "Audio" || item.Type == "MusicAlbum" || item.Type == "MusicArtist" || item.Type == "MusicGenre" || item.CollectionType == "music") { - itemCommands.push('instantmix'); - } - - if (item.IsFolder || item.Type == "MusicArtist" || item.Type == "MusicGenre") { - itemCommands.push('shuffle'); - } - - if (PlaylistManager.supportsPlaylists(item)) { - - if (options.showRemoveFromPlaylist) { - itemCommands.push('removefromplaylist'); - } else { - itemCommands.push('playlist'); - } - } - - if (options.showAddToCollection !== false) { - if (LibraryBrowser.supportsAddingToCollection(item)) { - itemCommands.push('addtocollection'); - } - } - - if (options.showRemoveFromCollection) { - itemCommands.push('removefromcollection'); - } - - if (options.playFromHere) { - itemCommands.push('playfromhere'); - itemCommands.push('queuefromhere'); - } - - if (item.CanDelete) { - itemCommands.push('delete'); - } - - if (SyncManager.isAvailable(item)) { - itemCommands.push('sync'); - } - - if (item.Type == 'Program' && (!item.TimerId && !item.SeriesTimerId)) { - - itemCommands.push('record'); - } - - if (item.MediaType == 'Video' && item.Type != 'TvChannel' && item.Type != 'Program' && item.LocationType != 'Virtual') { - itemCommands.push('editsubtitles'); - } - itemCommands.push('editimages'); - - return itemCommands; - }, - - screenWidth: function () { - - var screenWidth = $(window).width(); - - return screenWidth; - }, - - shapes: ['square', 'portrait', 'banner', 'smallBackdrop', 'homePageSmallBackdrop', 'backdrop', 'overflowBackdrop', 'overflowPortrait', 'overflowSquare'], - - getPostersPerRow: function (screenWidth) { - - var cache = true; - function getValue(shape) { - var div = $('
').appendTo(document.body); - var innerWidth = $('.cardImage', div).innerWidth(); - - if (!innerWidth || isNaN(innerWidth)) { - cache = false; - innerWidth = Math.min(400, screenWidth / 2); + if (icon) { + imageCssClass += " iconCardImage"; } - var width = screenWidth / innerWidth; - div.remove(); - return Math.floor(width); - } - - var info = {}; - - for (var i = 0, length = LibraryBrowser.shapes.length; i < length; i++) { - var currentShape = LibraryBrowser.shapes[i]; - info[currentShape] = getValue(currentShape); - } - info.cache = cache; - return info; - }, - - posterSizes: [], - - getPosterViewInfo: function () { - - var screenWidth = LibraryBrowser.screenWidth(); - - var cachedResults = LibraryBrowser.posterSizes; - - for (var i = 0, length = cachedResults.length; i < length; i++) { - - if (cachedResults[i].screenWidth == screenWidth) { - return cachedResults[i]; - } - } - - var result = LibraryBrowser.getPosterViewInfoInternal(screenWidth); - result.screenWidth = screenWidth; - - if (result.cache) { - cachedResults.push(result); - } - - return result; - }, - - getPosterViewInfoInternal: function (screenWidth) { - - var imagesPerRow = LibraryBrowser.getPostersPerRow(screenWidth); - - var result = {}; - result.screenWidth = screenWidth; - - if (!AppInfo.hasLowImageBandwidth) { - screenWidth *= 1.2; - } - - var roundTo = 100; - - for (var i = 0, length = LibraryBrowser.shapes.length; i < length; i++) { - var currentShape = LibraryBrowser.shapes[i]; - - var shapeWidth = screenWidth / imagesPerRow[currentShape]; - - if (!browserInfo.mobile) { - - shapeWidth = Math.round(shapeWidth / roundTo) * roundTo; - } - - result[currentShape + 'Width'] = Math.round(shapeWidth); - } - - result.cache = imagesPerRow.cache; - - return result; - }, - - getPosterViewHtml: function (options) { - - var items = options.items; - var currentIndexValue; - - options.shape = options.shape || "portrait"; - - var html = ""; - - var primaryImageAspectRatio = LibraryBrowser.getAveragePrimaryImageAspectRatio(items); - var isThumbAspectRatio = primaryImageAspectRatio && Math.abs(primaryImageAspectRatio - 1.777777778) < .3; - var isSquareAspectRatio = primaryImageAspectRatio && Math.abs(primaryImageAspectRatio - 1) < .33 || - primaryImageAspectRatio && Math.abs(primaryImageAspectRatio - 1.3333334) < .01; - - if (options.shape == 'auto' || options.shape == 'autohome') { - - if (isThumbAspectRatio) { - options.shape = options.shape == 'auto' ? 'backdrop' : 'backdrop'; - } else if (isSquareAspectRatio) { - options.coverImage = true; - options.shape = 'square'; - } else if (primaryImageAspectRatio && primaryImageAspectRatio > 1.9) { - options.shape = 'banner'; - options.coverImage = true; - } else if (primaryImageAspectRatio && Math.abs(primaryImageAspectRatio - 0.6666667) < .2) { - options.shape = options.shape == 'auto' ? 'portrait' : 'portrait'; - } else { - options.shape = options.defaultShape || (options.shape == 'auto' ? 'square' : 'square'); - } - } - - var posterInfo = LibraryBrowser.getPosterViewInfo(); - - var thumbWidth = posterInfo.backdropWidth; - var posterWidth = posterInfo.portraitWidth; - var squareSize = posterInfo.squareWidth; - var bannerWidth = posterInfo.bannerWidth; - - if (isThumbAspectRatio) { - posterWidth = thumbWidth; - } - else if (isSquareAspectRatio) { - posterWidth = squareSize; - } - - if (options.shape == 'overflowBackdrop') { - thumbWidth = posterInfo.overflowBackdropWidth; - } - else if (options.shape == 'overflowPortrait') { - posterWidth = posterInfo.overflowPortraitWidth; - } - else if (options.shape == 'overflowSquare') { - squareSize = posterInfo.overflowSquareWidth; - } - else if (options.shape == 'smallBackdrop') { - thumbWidth = posterInfo.smallBackdropWidth; - } - else if (options.shape == 'homePageSmallBackdrop') { - thumbWidth = posterInfo.homePageSmallBackdropWidth; - posterWidth = posterInfo.homePageSmallBackdropWidth; - } - else if (options.shape == 'detailPagePortrait') { - posterWidth = 200; - } - else if (options.shape == 'detailPageSquare') { - posterWidth = 240; - squareSize = 240; - } - else if (options.shape == 'detailPage169') { - posterWidth = 320; - thumbWidth = 320; - } - - var dateText; - var uiAspect = getDesiredAspect(options.shape); - - for (var i = 0, length = items.length; i < length; i++) { - - var item = items[i]; - - dateText = null; - - primaryImageAspectRatio = LibraryBrowser.getAveragePrimaryImageAspectRatio([item]); - - if (options.showStartDateIndex) { - - if (item.StartDate) { - try { - - dateText = LibraryBrowser.getFutureDateText(parseISO8601Date(item.StartDate, { toLocal: true }), true); - - } catch (err) { - } - } - - var newIndexValue = dateText || Globalize.translate('HeaderUnknownDate'); - - if (newIndexValue != currentIndexValue) { - - html += '

' + newIndexValue + '

'; - currentIndexValue = newIndexValue; - } - } else if (options.timeline) { - var year = item.ProductionYear || Globalize.translate('HeaderUnknownYear'); - - if (year != currentIndexValue) { - - html += '

' + year + '

'; - currentIndexValue = year; + if (coverImage) { + imageCssClass += " coveredCardImage"; + if (item.MediaType == 'Photo' || item.Type == 'PhotoAlbum' || item.Type == 'Folder') { + imageCssClass += " noScale"; } } - - html += LibraryBrowser.getPosterViewItemHtml(item, i, options, primaryImageAspectRatio, thumbWidth, posterWidth, squareSize, bannerWidth, uiAspect); - } - - return html; - }, - - getPosterViewItemHtml: function (item, index, options, primaryImageAspectRatio, thumbWidth, posterWidth, squareSize, bannerWidth, uiAspect) { - - var html = ''; - var imgUrl = null; - var icon; - var width = null; - var height = null; - - var forceName = false; - - var enableImageEnhancers = options.enableImageEnhancers !== false; - - var cssClass = "card"; - - if (options.fullWidthOnMobile) { - cssClass += " fullWidthCardOnMobile"; - } - - var showTitle = options.showTitle == 'auto' ? true : options.showTitle; - var coverImage = options.coverImage; - - if (options.autoThumb && item.ImageTags && item.ImageTags.Primary && item.PrimaryImageAspectRatio && item.PrimaryImageAspectRatio >= 1.34) { - - width = posterWidth; - height = primaryImageAspectRatio ? Math.round(posterWidth / primaryImageAspectRatio) : null; - - imgUrl = ApiClient.getImageUrl(item.Id, { - type: "Primary", - maxHeight: height, - maxWidth: width, - tag: item.ImageTags.Primary, - enableImageEnhancers: enableImageEnhancers - }); - - if (primaryImageAspectRatio) { - if (uiAspect) { - if (Math.abs(primaryImageAspectRatio - uiAspect) <= .2) { - coverImage = true; - } - } + if (options.centerImage) { + imageCssClass += " centeredCardImage"; } - } else if (options.autoThumb && item.ImageTags && item.ImageTags.Thumb) { + var dataSrc = ""; - imgUrl = ApiClient.getScaledImageUrl(item.Id, { - type: "Thumb", - maxWidth: thumbWidth, - tag: item.ImageTags.Thumb, - enableImageEnhancers: enableImageEnhancers - }); - - } else if (options.preferBackdrop && item.BackdropImageTags && item.BackdropImageTags.length) { - - imgUrl = ApiClient.getScaledImageUrl(item.Id, { - type: "Backdrop", - maxWidth: thumbWidth, - tag: item.BackdropImageTags[0], - enableImageEnhancers: enableImageEnhancers - }); - - } else if (options.preferThumb && item.ImageTags && item.ImageTags.Thumb) { - - imgUrl = ApiClient.getScaledImageUrl(item.Id, { - type: "Thumb", - maxWidth: thumbWidth, - tag: item.ImageTags.Thumb, - enableImageEnhancers: enableImageEnhancers - }); - - } else if (options.preferBanner && item.ImageTags && item.ImageTags.Banner) { - - imgUrl = ApiClient.getScaledImageUrl(item.Id, { - type: "Banner", - maxWidth: bannerWidth, - tag: item.ImageTags.Banner, - enableImageEnhancers: enableImageEnhancers - }); - - } else if (options.preferThumb && item.SeriesThumbImageTag && options.inheritThumb !== false) { - - imgUrl = ApiClient.getScaledImageUrl(item.SeriesId, { - type: "Thumb", - maxWidth: thumbWidth, - tag: item.SeriesThumbImageTag, - enableImageEnhancers: enableImageEnhancers - }); - - } else if (options.preferThumb && item.ParentThumbItemId && options.inheritThumb !== false) { - - imgUrl = ApiClient.getThumbImageUrl(item.ParentThumbItemId, { - type: "Thumb", - maxWidth: thumbWidth, - enableImageEnhancers: enableImageEnhancers - }); - - } else if (options.preferThumb && item.BackdropImageTags && item.BackdropImageTags.length) { - - imgUrl = ApiClient.getScaledImageUrl(item.Id, { - type: "Backdrop", - maxWidth: thumbWidth, - tag: item.BackdropImageTags[0], - enableImageEnhancers: enableImageEnhancers - }); - - forceName = true; - - } else if (item.ImageTags && item.ImageTags.Primary) { - - width = posterWidth; - height = primaryImageAspectRatio ? Math.round(posterWidth / primaryImageAspectRatio) : null; - - imgUrl = ApiClient.getImageUrl(item.Id, { - type: "Primary", - maxHeight: height, - maxWidth: width, - tag: item.ImageTags.Primary, - enableImageEnhancers: enableImageEnhancers - }); - - if (primaryImageAspectRatio) { - if (uiAspect) { - if (Math.abs(primaryImageAspectRatio - uiAspect) <= .2) { - coverImage = true; - } - } - } - } - else if (item.ParentPrimaryImageTag) { - - imgUrl = ApiClient.getImageUrl(item.ParentPrimaryImageItemId, { - type: "Primary", - maxWidth: posterWidth, - tag: item.ParentPrimaryImageTag, - enableImageEnhancers: enableImageEnhancers - }); - } - else if (item.AlbumId && item.AlbumPrimaryImageTag) { - - height = squareSize; - width = primaryImageAspectRatio ? Math.round(height * primaryImageAspectRatio) : null; - - imgUrl = ApiClient.getScaledImageUrl(item.AlbumId, { - type: "Primary", - maxHeight: height, - maxWidth: width, - tag: item.AlbumPrimaryImageTag, - enableImageEnhancers: enableImageEnhancers - }); - - if (primaryImageAspectRatio) { - if (uiAspect) { - if (Math.abs(primaryImageAspectRatio - uiAspect) <= .2) { - coverImage = true; - } - } - } - } - else if (item.Type == 'Season' && item.ImageTags && item.ImageTags.Thumb) { - - imgUrl = ApiClient.getScaledImageUrl(item.Id, { - type: "Thumb", - maxWidth: thumbWidth, - tag: item.ImageTags.Thumb, - enableImageEnhancers: enableImageEnhancers - }); - - } - else if (item.BackdropImageTags && item.BackdropImageTags.length) { - - imgUrl = ApiClient.getScaledImageUrl(item.Id, { - type: "Backdrop", - maxWidth: thumbWidth, - tag: item.BackdropImageTags[0], - enableImageEnhancers: enableImageEnhancers - }); - - } else if (item.ImageTags && item.ImageTags.Thumb) { - - imgUrl = ApiClient.getScaledImageUrl(item.Id, { - type: "Thumb", - maxWidth: thumbWidth, - tag: item.ImageTags.Thumb, - enableImageEnhancers: enableImageEnhancers - }); - - } else if (item.SeriesThumbImageTag) { - - imgUrl = ApiClient.getScaledImageUrl(item.SeriesId, { - type: "Thumb", - maxWidth: thumbWidth, - tag: item.SeriesThumbImageTag, - enableImageEnhancers: enableImageEnhancers - }); - - } else if (item.ParentThumbItemId) { - - imgUrl = ApiClient.getThumbImageUrl(item, { - type: "Thumb", - maxWidth: thumbWidth, - enableImageEnhancers: enableImageEnhancers - }); - - } else if (item.MediaType == "Audio" || item.Type == "MusicAlbum" || item.Type == "MusicArtist") { - - if (item.Name && showTitle) { - icon = 'library-music'; - } - cssClass += " defaultBackground"; - - } else if (item.Type == "Recording" || item.Type == "Program" || item.Type == "TvChannel") { - - if (item.Name && showTitle) { - icon = 'folder-open'; + if (options.lazy && imgUrl) { + imageCssClass += " lazy"; + dataSrc = ' data-src="' + imgUrl + '"'; } - cssClass += " defaultBackground"; - } else if (item.MediaType == "Video" || item.Type == "Season" || item.Type == "Series") { + var cardboxCssClass = 'cardBox'; - if (item.Name && showTitle) { - icon = 'videocam'; + if (options.cardLayout) { + cardboxCssClass += ' visualCardBox'; } - cssClass += " defaultBackground"; - } else if (item.Type == "Person") { + html += '
'; + html += '
'; - if (item.Name && showTitle) { - icon = 'person'; - } - cssClass += " defaultBackground"; - } else { - if (item.Name && showTitle) { - icon = 'folder-open'; - } - cssClass += " defaultBackground"; - } + html += '
'; - icon = item.icon || icon; - cssClass += ' ' + options.shape + 'Card'; + var anchorCssClass = "cardContent"; - var mediaSourceCount = item.MediaSourceCount || 1; + anchorCssClass += ' mediaItem'; - var href = options.linkItem === false ? '#' : LibraryBrowser.getHref(item, options.context); - - if (options.showChildCountIndicator && item.ChildCount && options.showLatestItemsPopup !== false) { - cssClass += ' groupedCard'; - } - - if ((showTitle || options.showItemCounts) && !options.overlayText) { - cssClass += ' bottomPaddedCard'; - } - - var dataAttributes = LibraryBrowser.getItemDataAttributes(item, options, index); - - var defaultAction = options.defaultAction; - if (defaultAction == 'play' || defaultAction == 'playallfromhere') { - if (item.PlayAccess != 'Full') { - defaultAction = null; - } - } - var defaultActionAttribute = defaultAction ? (' data-action="' + defaultAction + '"') : ''; - - // card - html += ''; - - var style = ""; - - if (imgUrl && !options.lazy) { - style += 'background-image:url(\'' + imgUrl + '\');'; - } - - var imageCssClass = 'cardImage'; - - if (icon) { - imageCssClass += " iconCardImage"; - } - - if (coverImage) { - imageCssClass += " coveredCardImage"; - if (item.MediaType == 'Photo' || item.Type == 'PhotoAlbum' || item.Type == 'Folder') { - imageCssClass += " noScale"; - } - } - if (options.centerImage) { - imageCssClass += " centeredCardImage"; - } - - var dataSrc = ""; - - if (options.lazy && imgUrl) { - imageCssClass += " lazy"; - dataSrc = ' data-src="' + imgUrl + '"'; - } - - var cardboxCssClass = 'cardBox'; - - if (options.cardLayout) { - cardboxCssClass += ' visualCardBox'; - } - html += '
'; - html += '
'; - - html += '
'; - - var anchorCssClass = "cardContent"; - - anchorCssClass += ' mediaItem'; - - if (options.defaultAction) { - anchorCssClass += ' itemWithAction'; - } - - var transition = options.transition === false || !AppInfo.enableSectionTransitions ? '' : ' data-transition="slide"'; - var onclick = item.onclick ? ' onclick="' + item.onclick + '"' : ''; - html += ''; - html += '
'; - if (icon) { - html += ''; - } - html += '
'; - - if (item.LocationType == "Virtual" || item.LocationType == "Offline") { - if (options.showLocationTypeIndicator !== false) { - html += LibraryBrowser.getOfflineIndicatorHtml(item); - } - } else if (options.showUnplayedIndicator !== false) { - html += LibraryBrowser.getPlayedIndicatorHtml(item); - } else if (options.showChildCountIndicator) { - html += LibraryBrowser.getGroupCountIndicator(item); - } - - html += LibraryBrowser.getSyncIndicator(item); - - if (mediaSourceCount > 1) { - html += '
' + mediaSourceCount + '
'; - } - - var progressHtml = options.showProgress === false || item.IsFolder ? '' : LibraryBrowser.getItemProgressBarHtml((item.Type == 'Recording' ? item : item.UserData)); - - var footerOverlayed = false; - - if (options.overlayText || (forceName && !showTitle)) { - - var footerCssClass = progressHtml ? 'cardFooter fullCardFooter' : 'cardFooter'; - - html += LibraryBrowser.getCardFooterText(item, options, showTitle, imgUrl, forceName, footerCssClass, progressHtml); - footerOverlayed = true; - } - else if (progressHtml) { - html += '
'; - html += "
"; - html += progressHtml; - html += "
"; - //cardFooter - html += "
"; - - progressHtml = ''; - } - - // cardContent - html += ''; - - if (options.overlayPlayButton && !item.IsPlaceHolder && (item.LocationType != 'Virtual' || !item.MediaType || item.Type == 'Program') && item.Type != 'Person') { - html += '
'; - } - if (options.overlayMoreButton) { - html += '
'; - } - - // cardScalable - html += '
'; - - if (!options.overlayText && !footerOverlayed) { - html += LibraryBrowser.getCardFooterText(item, options, showTitle, imgUrl, forceName, 'cardFooter outerCardFooter', progressHtml); - } - - // cardBox - html += '
'; - - // card - html += "
"; - - return html; - }, - - getCardFooterText: function (item, options, showTitle, imgUrl, forceName, footerClass, progressHtml) { - - var html = ''; - - if (options.cardLayout) { - html += '
'; - html += ''; - html += "
"; - } - - var name = options.showTitle == 'auto' && !item.IsFolder && item.MediaType == 'Photo' ? '' : LibraryBrowser.getPosterViewDisplayName(item, options.displayAsSpecial); - - if (!imgUrl && !showTitle) { - html += "
"; - html += htmlEncode(name); - html += "
"; - } - - var cssClass = options.centerText ? "cardText cardTextCentered" : "cardText"; - - var lines = []; - - if (options.showParentTitle) { - - lines.push(item.EpisodeTitle ? item.Name : (item.SeriesName || item.Album || item.AlbumArtist || item.GameSystem || "")); - } - - if (showTitle || forceName) { - - lines.push(htmlEncode(name)); - } - - if (options.showItemCounts) { - - var itemCountHtml = LibraryBrowser.getItemCountsHtml(options, item); - - lines.push(itemCountHtml); - } - - if (options.textLines) { - var additionalLines = options.textLines(item); - for (var i = 0, length = additionalLines.length; i < length; i++) { - lines.push(additionalLines[i]); - } - } - - if (options.showSongCount) { - - var songLine = ''; - - if (item.SongCount) { - songLine = item.SongCount == 1 ? - Globalize.translate('ValueOneSong') : - Globalize.translate('ValueSongCount', item.SongCount); + if (options.defaultAction) { + anchorCssClass += ' itemWithAction'; } - lines.push(songLine); - } - - if (options.showPremiereDate) { - - if (item.PremiereDate) { - try { - - lines.push(LibraryBrowser.getPremiereDateText(item)); - - } catch (err) { - lines.push(''); - - } - } else { - lines.push(''); + var transition = options.transition === false || !AppInfo.enableSectionTransitions ? '' : ' data-transition="slide"'; + var onclick = item.onclick ? ' onclick="' + item.onclick + '"' : ''; + html += ''; + html += '
'; + if (icon) { + html += ''; } - } - - if (options.showYear) { - - lines.push(item.ProductionYear || ''); - } - - if (options.showSeriesYear) { - - if (item.Status == "Continuing") { - - lines.push(Globalize.translate('ValueSeriesYearToPresent', item.ProductionYear || '')); - - } else { - lines.push(item.ProductionYear || ''); - } - - } - - if (options.showProgramAirInfo) { - - var date = parseISO8601Date(item.StartDate, { toLocal: true }); - - var text = item.StartDate ? - date.toLocaleString() : - ''; - - lines.push(text || ' '); - - lines.push(item.ChannelName || ' '); - } - - html += LibraryBrowser.getCardTextLines(lines, cssClass, !options.overlayText); - - if (options.overlayText) { - - if (progressHtml) { - html += "
"; - html += progressHtml; - html += "
"; - } - } - - if (html) { - html = '
' + html; - - //cardFooter - html += "
"; - } - - return html; - }, - - getListItemInfo: function (elem) { - - var elemWithAttributes = elem; - - while (!elemWithAttributes.getAttribute('data-itemid')) { - elemWithAttributes = elemWithAttributes.parentNode; - } - - var itemId = elemWithAttributes.getAttribute('data-itemid'); - var index = elemWithAttributes.getAttribute('data-index'); - var mediaType = elemWithAttributes.getAttribute('data-mediatype'); - - return { - id: itemId, - index: index, - mediaType: mediaType, - context: elemWithAttributes.getAttribute('data-context') - }; - }, - - getCardTextLines: function (lines, cssClass, forceLines) { - - var html = ''; - - var valid = 0; - var i, length; - - for (i = 0, length = lines.length; i < length; i++) { - - var text = lines[i]; - - if (text) { - html += "
"; - html += text; - html += "
"; - valid++; - } - } - - if (forceLines) { - while (valid < length) { - html += "
 
"; - valid++; - } - } - - return html; - }, - - getFutureDateText: function (date) { - - var weekday = []; - weekday[0] = Globalize.translate('OptionSunday'); - weekday[1] = Globalize.translate('OptionMonday'); - weekday[2] = Globalize.translate('OptionTuesday'); - weekday[3] = Globalize.translate('OptionWednesday'); - weekday[4] = Globalize.translate('OptionThursday'); - weekday[5] = Globalize.translate('OptionFriday'); - weekday[6] = Globalize.translate('OptionSaturday'); - - var day = weekday[date.getDay()]; - date = date.toLocaleDateString(); - - if (date.toLowerCase().indexOf(day.toLowerCase()) == -1) { - return day + " " + date; - } - - return date; - }, - - getPremiereDateText: function (item, date) { - - if (!date) { - - var text = ''; - - if (item.AirTime) { - text += item.AirTime; - } - - if (item.SeriesStudio) { - - if (text) { - text += " on " + item.SeriesStudio; - } else { - text += item.SeriesStudio; - } - } - - return text; - } - - var day = LibraryBrowser.getFutureDateText(date); - - if (item.AirTime) { - day += " at " + item.AirTime; - } - - if (item.SeriesStudio) { - day += " on " + item.SeriesStudio; - } - - return day; - }, - - getPosterViewDisplayName: function (item, displayAsSpecial, includeParentInfo) { - - if (!item) { - throw new Error("null item passed into getPosterViewDisplayName"); - } - - var name = item.EpisodeTitle || item.Name || ''; - - if (item.Type == "TvChannel") { - - if (item.Number) { - return item.Number + ' ' + name; - } - return name; - } - if (displayAsSpecial && item.Type == "Episode" && item.ParentIndexNumber == 0) { - - name = Globalize.translate('ValueSpecialEpisodeName', name); - - } else if (item.Type == "Episode" && item.IndexNumber != null && item.ParentIndexNumber != null) { - - var displayIndexNumber = item.IndexNumber; - - var number = "E" + displayIndexNumber; - - if (includeParentInfo !== false) { - number = "S" + item.ParentIndexNumber + ", " + number; - } - - if (item.IndexNumberEnd) { - - displayIndexNumber = item.IndexNumberEnd; - number += "-" + displayIndexNumber; - } - - name = number + " - " + name; - - } - - return name; - }, - - getOfflineIndicatorHtml: function (item) { - - if (item.LocationType == "Offline") { - return '
' + Globalize.translate('HeaderOffline') + '
'; - } - - if (item.Type == 'Episode') { - try { - - var date = parseISO8601Date(item.PremiereDate, { toLocal: true }); - - if (item.PremiereDate && (new Date().getTime() < date.getTime())) { - return '
' + Globalize.translate('HeaderUnaired') + '
'; - } - } catch (err) { - - } - - return '
' + Globalize.translate('HeaderMissing') + '
'; - } - - return ''; - }, - - getPlayedIndicatorHtml: function (item) { - - if (item.Type == "Series" || item.Type == "Season" || item.Type == "BoxSet" || item.MediaType == "Video" || item.MediaType == "Game" || item.MediaType == "Book") { - if (item.UserData.UnplayedItemCount) { - return '
' + item.UserData.UnplayedItemCount + '
'; - } - - if (item.Type != 'TvChannel') { - if (item.UserData.PlayedPercentage && item.UserData.PlayedPercentage >= 100 || (item.UserData && item.UserData.Played)) { - return '
'; - } - } - } - - return ''; - }, - - getGroupCountIndicator: function (item) { - - if (item.ChildCount) { - return '
' + item.ChildCount + '
'; - } - - return ''; - }, - - getSyncIndicator: function (item) { - - if (item.SyncStatus == 'Synced') { - - return '
'; - } - - var syncPercent = item.SyncPercent; - if (syncPercent) { - return '
'; - } - - if (item.SyncStatus == 'Queued' || item.SyncStatus == 'Converting' || item.SyncStatus == 'ReadyToTransfer' || item.SyncStatus == 'Transferring') { - - return '
'; - } - - return ''; - }, - - getAveragePrimaryImageAspectRatio: function (items) { - - var values = []; - - for (var i = 0, length = items.length; i < length; i++) { - - var ratio = items[i].PrimaryImageAspectRatio || 0; - - if (!ratio) { - continue; - } - - values[values.length] = ratio; - } - - if (!values.length) { - return null; - } - - // Use the median - values.sort(function (a, b) { return a - b; }); - - var half = Math.floor(values.length / 2); - - var result; - - if (values.length % 2) - result = values[half]; - else - result = (values[half - 1] + values[half]) / 2.0; - - // If really close to 2:3 (poster image), just return 2:3 - if (Math.abs(0.66666666667 - result) <= .15) { - return 0.66666666667; - } - - // If really close to 16:9 (episode image), just return 16:9 - if (Math.abs(1.777777778 - result) <= .2) { - return 1.777777778; - } - - // If really close to 1 (square image), just return 1 - if (Math.abs(1 - result) <= .15) { - return 1; - } - - // If really close to 4:3 (poster image), just return 2:3 - if (Math.abs(1.33333333333 - result) <= .15) { - return 1.33333333333; - } - - return result; - }, - - metroColors: ["#6FBD45", "#4BB3DD", "#4164A5", "#E12026", "#800080", "#E1B222", "#008040", "#0094FF", "#FF00C7", "#FF870F", "#7F0037"], - - getRandomMetroColor: function () { - - var index = Math.floor(Math.random() * (LibraryBrowser.metroColors.length - 1)); - - return LibraryBrowser.metroColors[index]; - }, - - getMetroColor: function (str) { - - if (str) { - var character = String(str.substr(0, 1).charCodeAt()); - var sum = 0; - for (var i = 0; i < character.length; i++) { - sum += parseInt(character.charAt(i)); - } - var index = String(sum).substr(-1); - - return LibraryBrowser.metroColors[index]; - } else { - return LibraryBrowser.getRandomMetroColor(); - } - - }, - - renderName: function (item, nameElem, linkToElement, context) { - - var name = LibraryBrowser.getPosterViewDisplayName(item, false, false); - - Dashboard.setPageTitle(name); - - if (linkToElement) { - nameElem.html('' + name + ''); - } else { - nameElem.html(name); - } - }, - - renderParentName: function (item, parentNameElem, context) { - - var html = []; - - var contextParam = context ? ('&context=' + context) : ''; - - if (item.AlbumArtists) { - html.push(LibraryBrowser.getArtistLinksHtml(item.AlbumArtists, "detailPageParentLink")); - } else if (item.ArtistItems && item.ArtistItems.length && item.Type == "MusicVideo") { - html.push(LibraryBrowser.getArtistLinksHtml(item.ArtistItems, "detailPageParentLink")); - } else if (item.SeriesName && item.Type == "Episode") { - - html.push('' + item.SeriesName + ''); - } - - if (item.SeriesName && item.Type == "Season") { - - html.push('' + item.SeriesName + ''); - - } else if (item.ParentIndexNumber != null && item.Type == "Episode") { - - html.push('' + item.SeasonName + ''); - - } else if (item.Album && item.Type == "Audio" && (item.AlbumId || item.ParentId)) { - html.push('' + item.Album + ''); - - } else if (item.Album && item.Type == "MusicVideo" && item.AlbumId) { - html.push('' + item.Album + ''); - - } else if (item.Album) { - html.push(item.Album); - } else if (item.Type == 'Program' && item.EpisodeTitle) { - html.push(item.Name); - } - - if (html.length) { - parentNameElem.show().html(html.join(' - ')); - } else { - parentNameElem.hide(); - } - }, - - renderLinks: function (linksElem, item) { - - var links = []; - - if (item.HomePageUrl) { - links.push('' + Globalize.translate('ButtonWebsite') + ''); - } - - if (item.ExternalUrls) { - - for (var i = 0, length = item.ExternalUrls.length; i < length; i++) { - - var url = item.ExternalUrls[i]; - - links.push('' + url.Name + ''); - } - } - - if (links.length) { - - var html = links.join('  /  '); - - html = Globalize.translate('ValueLinks', html); - - linksElem.innerHTML = html; - $(linksElem); - $(linksElem).show(); - - } else { - $(linksElem).hide(); - } - }, - - getDefaultPageSizeSelections: function () { - - return [20, 50, 100, 200, 300, 400, 500]; - }, - - showLayoutMenu: function (button, currentLayout) { - - // Add banner and list once all screens support them - var views = button.getAttribute('data-layouts'); - - views = views ? views.split(',') : ['List', 'Poster', 'PosterCard', 'Thumb', 'ThumbCard']; - - var menuItems = views.map(function (v) { - return { - name: Globalize.translate('Option' + v), - id: v, - ironIcon: currentLayout == v ? 'check' : null - }; - }); - - require(['actionsheet'], function (actionsheet) { - - actionsheet.show({ - items: menuItems, - positionTo: button, - callback: function (id) { - - $(button).trigger('layoutchange', [id]); - } - }); - - }); - - }, - - openViewPanel: function (btn, className) { - - $('.' + className, jQuery(btn).parents('.page')).removeClass('hide').panel('toggle'); - }, - - getQueryPagingHtml: function (options) { - - var startIndex = options.startIndex; - var limit = options.limit; - var totalRecordCount = options.totalRecordCount; - - if (limit && options.updatePageSizeSetting !== false) { - try { - appStorage.setItem(options.pageSizeKey || pageSizeKey, limit); - } catch (e) { - - } - } - - var html = ''; - - var recordsEnd = Math.min(startIndex + limit, totalRecordCount); - - // 20 is the minimum page size - var showControls = totalRecordCount > 20 || limit < totalRecordCount; - - html += '
'; - - if (showControls) { - html += ''; - - var startAtDisplay = totalRecordCount ? startIndex + 1 : 0; - html += startAtDisplay + '-' + recordsEnd + ' of ' + totalRecordCount; - - html += ''; - } - - if (showControls || options.viewButton || options.filterButton || options.sortButton || options.addLayoutButton) { - - html += '
'; - - if (showControls) { - - html += ''; - html += '= totalRecordCount ? 'disabled' : '') + '>'; - } - - if (options.addLayoutButton) { - - html += ''; - } - - if (options.sortButton) { - - html += ''; - } - - if (options.viewButton) { - - //html += ''; - var viewPanelClass = options.viewPanelClass || 'viewPanel'; - var title = options.viewIcon == 'filter-list' ? Globalize.translate('ButtonFilter') : Globalize.translate('ButtonMenu'); - html += ''; - } - - if (options.filterButton) { - - html += ''; - } - html += '
'; - if (showControls && options.showLimit) { - - var id = "selectPageSize"; - - var pageSizes = options.pageSizes || LibraryBrowser.getDefaultPageSizeSelections(); - - var optionsHtml = pageSizes.map(function (val) { - - if (limit == val) { - - return ''; - - } else { - return ''; - } - }).join(''); - - // Add styles to defeat jquery mobile - html += '
'; + if (item.LocationType == "Virtual" || item.LocationType == "Offline") { + if (options.showLocationTypeIndicator !== false) { + html += LibraryBrowser.getOfflineIndicatorHtml(item); + } + } else if (options.showUnplayedIndicator !== false) { + html += LibraryBrowser.getPlayedIndicatorHtml(item); + } else if (options.showChildCountIndicator) { + html += LibraryBrowser.getGroupCountIndicator(item); } - } - html += '
'; + html += LibraryBrowser.getSyncIndicator(item); - return html; - }, + if (mediaSourceCount > 1) { + html += '
' + mediaSourceCount + '
'; + } - showSortMenu: function (options) { + var progressHtml = options.showProgress === false || item.IsFolder ? '' : LibraryBrowser.getItemProgressBarHtml((item.Type == 'Recording' ? item : item.UserData)); - require(['paperdialoghelper', 'paper-radio-button', 'paper-radio-group'], function (paperDialogHelper) { + var footerOverlayed = false; - var dlg = paperDialogHelper.createDialog({ - removeOnClose: true, - modal: false, - entryAnimationDuration: 160, - exitAnimationDuration: 200 - }); + if (options.overlayText || (forceName && !showTitle)) { - dlg.classList.add('ui-body-a'); - dlg.classList.add('background-theme-a'); + var footerCssClass = progressHtml ? 'cardFooter fullCardFooter' : 'cardFooter'; + + html += LibraryBrowser.getCardFooterText(item, options, showTitle, imgUrl, forceName, footerCssClass, progressHtml); + footerOverlayed = true; + } + else if (progressHtml) { + html += '
'; + html += "
"; + html += progressHtml; + html += "
"; + //cardFooter + html += "
"; + + progressHtml = ''; + } + + // cardContent + html += ''; + + if (options.overlayPlayButton && !item.IsPlaceHolder && (item.LocationType != 'Virtual' || !item.MediaType || item.Type == 'Program') && item.Type != 'Person') { + html += '
'; + } + if (options.overlayMoreButton) { + html += '
'; + } + + // cardScalable + html += '
'; + + if (!options.overlayText && !footerOverlayed) { + html += LibraryBrowser.getCardFooterText(item, options, showTitle, imgUrl, forceName, 'cardFooter outerCardFooter', progressHtml); + } + + // cardBox + html += '
'; + + // card + html += "
"; + + return html; + }, + + getCardFooterText: function (item, options, showTitle, imgUrl, forceName, footerClass, progressHtml) { var html = ''; - html += '
'; - - html += '

'; - html += Globalize.translate('HeaderSortBy'); - html += '

'; - - html += ''; - for (var i = 0, length = options.items.length; i < length; i++) { - - var option = options.items[i]; - - html += '' + option.name + ''; - } - html += ''; - - html += '

'; - html += Globalize.translate('HeaderSortOrder'); - html += '

'; - html += ''; - html += '' + Globalize.translate('OptionAscending') + ''; - html += '' + Globalize.translate('OptionDescending') + ''; - html += ''; - html += '
'; - - html += '
'; - html += '' + Globalize.translate('ButtonClose') + ''; - html += '
'; - - dlg.innerHTML = html; - document.body.appendChild(dlg); - - var fireCallbackOnClose = false; - - paperDialogHelper.open(dlg).then(function () { - - if (options.callback && fireCallbackOnClose) { - options.callback(); - } - }); - - $('.groupSortBy', dlg).on('iron-select', function () { - - var newValue = this.selected.replace('_', ','); - var changed = options.query.SortBy != newValue; - - options.query.SortBy = newValue; - options.query.StartIndex = 0; - - if (options.callback && changed) { - fireCallbackOnClose = true; - } - }); - - $('.groupSortOrder', dlg).on('iron-select', function () { - - var newValue = this.selected; - var changed = options.query.SortOrder != newValue; - - options.query.SortOrder = newValue; - options.query.StartIndex = 0; - - if (options.callback && changed) { - fireCallbackOnClose = true; - } - }); - }); - }, - - getRatingHtml: function (item, metascore) { - - var html = ""; - - if (item.CommunityRating) { - - html += "
"; - html += '
'; - html += item.CommunityRating.toFixed(1); - html += '
'; - } - - if (item.CriticRating != null) { - - if (item.CriticRating >= 60) { - html += '
'; - } else { - html += '
'; + if (options.cardLayout) { + html += '
'; + html += ''; + html += "
"; } - html += '
' + item.CriticRating + '%
'; - } + var name = options.showTitle == 'auto' && !item.IsFolder && item.MediaType == 'Photo' ? '' : LibraryBrowser.getPosterViewDisplayName(item, options.displayAsSpecial); - //if (item.Metascore && metascore !== false) { + if (!imgUrl && !showTitle) { + html += "
"; + html += htmlEncode(name); + html += "
"; + } - // if (item.Metascore >= 60) { - // html += '
' + item.Metascore + '
'; - // } - // else if (item.Metascore >= 40) { - // html += '
' + item.Metascore + '
'; - // } else { - // html += '
' + item.Metascore + '
'; - // } - //} + var cssClass = options.centerText ? "cardText cardTextCentered" : "cardText"; - return html; - }, + var lines = []; - getItemProgressBarHtml: function (item) { + if (options.showParentTitle) { + lines.push(item.EpisodeTitle ? item.Name : (item.SeriesName || item.Album || item.AlbumArtist || item.GameSystem || "")); + } - if (item.Type == "Recording" && item.CompletionPercentage) { + if (showTitle || forceName) { - return ''; - } + lines.push(htmlEncode(name)); + } - var pct = item.PlayedPercentage; + if (options.showItemCounts) { - if (pct && pct < 100) { + var itemCountHtml = LibraryBrowser.getItemCountsHtml(options, item); - return ''; - } + lines.push(itemCountHtml); + } - return null; - }, + if (options.textLines) { + var additionalLines = options.textLines(item); + for (var i = 0, length = additionalLines.length; i < length; i++) { + lines.push(additionalLines[i]); + } + } - getUserDataButtonHtml: function (method, itemId, btnCssClass, icon, tooltip, style) { + if (options.showSongCount) { - var tagName = style == 'fab' ? 'paper-fab' : 'paper-icon-button'; + var songLine = ''; - return '<' + tagName + ' title="' + tooltip + '" data-itemid="' + itemId + '" icon="' + icon + '" class="' + btnCssClass + '" onclick="LibraryBrowser.' + method + '(this);return false;">'; + if (item.SongCount) { + songLine = item.SongCount == 1 ? + Globalize.translate('ValueOneSong') : + Globalize.translate('ValueSongCount', item.SongCount); + } - }, + lines.push(songLine); + } - getUserDataIconsHtml: function (item, includePlayed, style) { + if (options.showPremiereDate) { - var html = ''; + if (item.PremiereDate) { + try { - var userData = item.UserData || {}; + lines.push(LibraryBrowser.getPremiereDateText(item)); - var itemId = item.Id; + } catch (err) { + lines.push(''); - if (includePlayed !== false) { - var tooltipPlayed = Globalize.translate('TooltipPlayed'); + } + } else { + lines.push(''); + } + } - if (item.MediaType == 'Video' || item.Type == 'Series' || item.Type == 'Season' || item.Type == 'BoxSet' || item.Type == 'Playlist') { - if (item.Type != 'TvChannel') { - if (userData.Played) { - html += LibraryBrowser.getUserDataButtonHtml('markPlayed', itemId, 'btnUserItemRating btnUserItemRatingOn', 'check', tooltipPlayed, style); + if (options.showYear) { + + lines.push(item.ProductionYear || ''); + } + + if (options.showSeriesYear) { + + if (item.Status == "Continuing") { + + lines.push(Globalize.translate('ValueSeriesYearToPresent', item.ProductionYear || '')); + + } else { + lines.push(item.ProductionYear || ''); + } + + } + + if (options.showProgramAirInfo) { + + var date = parseISO8601Date(item.StartDate, { toLocal: true }); + + var text = item.StartDate ? + date.toLocaleString() : + ''; + + lines.push(text || ' '); + + lines.push(item.ChannelName || ' '); + } + + html += LibraryBrowser.getCardTextLines(lines, cssClass, !options.overlayText); + + if (options.overlayText) { + + if (progressHtml) { + html += "
"; + html += progressHtml; + html += "
"; + } + } + + if (html) { + html = '
' + html; + + //cardFooter + html += "
"; + } + + return html; + }, + + getListItemInfo: function (elem) { + + var elemWithAttributes = elem; + + while (!elemWithAttributes.getAttribute('data-itemid')) { + elemWithAttributes = elemWithAttributes.parentNode; + } + + var itemId = elemWithAttributes.getAttribute('data-itemid'); + var index = elemWithAttributes.getAttribute('data-index'); + var mediaType = elemWithAttributes.getAttribute('data-mediatype'); + + return { + id: itemId, + index: index, + mediaType: mediaType, + context: elemWithAttributes.getAttribute('data-context') + }; + }, + + getCardTextLines: function (lines, cssClass, forceLines) { + + var html = ''; + + var valid = 0; + var i, length; + + for (i = 0, length = lines.length; i < length; i++) { + + var text = lines[i]; + + if (text) { + html += "
"; + html += text; + html += "
"; + valid++; + } + } + + if (forceLines) { + while (valid < length) { + html += "
 
"; + valid++; + } + } + + return html; + }, + + getFutureDateText: function (date) { + + var weekday = []; + weekday[0] = Globalize.translate('OptionSunday'); + weekday[1] = Globalize.translate('OptionMonday'); + weekday[2] = Globalize.translate('OptionTuesday'); + weekday[3] = Globalize.translate('OptionWednesday'); + weekday[4] = Globalize.translate('OptionThursday'); + weekday[5] = Globalize.translate('OptionFriday'); + weekday[6] = Globalize.translate('OptionSaturday'); + + var day = weekday[date.getDay()]; + date = date.toLocaleDateString(); + + if (date.toLowerCase().indexOf(day.toLowerCase()) == -1) { + return day + " " + date; + } + + return date; + }, + + getPremiereDateText: function (item, date) { + + if (!date) { + + var text = ''; + + if (item.AirTime) { + text += item.AirTime; + } + + if (item.SeriesStudio) { + + if (text) { + text += " on " + item.SeriesStudio; } else { - html += LibraryBrowser.getUserDataButtonHtml('markPlayed', itemId, 'btnUserItemRating', 'check', tooltipPlayed, style); + text += item.SeriesStudio; + } + } + + return text; + } + + var day = LibraryBrowser.getFutureDateText(date); + + if (item.AirTime) { + day += " at " + item.AirTime; + } + + if (item.SeriesStudio) { + day += " on " + item.SeriesStudio; + } + + return day; + }, + + getPosterViewDisplayName: function (item, displayAsSpecial, includeParentInfo) { + + if (!item) { + throw new Error("null item passed into getPosterViewDisplayName"); + } + + var name = item.EpisodeTitle || item.Name || ''; + + if (item.Type == "TvChannel") { + + if (item.Number) { + return item.Number + ' ' + name; + } + return name; + } + if (displayAsSpecial && item.Type == "Episode" && item.ParentIndexNumber == 0) { + + name = Globalize.translate('ValueSpecialEpisodeName', name); + + } else if (item.Type == "Episode" && item.IndexNumber != null && item.ParentIndexNumber != null) { + + var displayIndexNumber = item.IndexNumber; + + var number = "E" + displayIndexNumber; + + if (includeParentInfo !== false) { + number = "S" + item.ParentIndexNumber + ", " + number; + } + + if (item.IndexNumberEnd) { + + displayIndexNumber = item.IndexNumberEnd; + number += "-" + displayIndexNumber; + } + + name = number + " - " + name; + + } + + return name; + }, + + getOfflineIndicatorHtml: function (item) { + + if (item.LocationType == "Offline") { + return '
' + Globalize.translate('HeaderOffline') + '
'; + } + + if (item.Type == 'Episode') { + try { + + var date = parseISO8601Date(item.PremiereDate, { toLocal: true }); + + if (item.PremiereDate && (new Date().getTime() < date.getTime())) { + return '
' + Globalize.translate('HeaderUnaired') + '
'; + } + } catch (err) { + + } + + return '
' + Globalize.translate('HeaderMissing') + '
'; + } + + return ''; + }, + + getPlayedIndicatorHtml: function (item) { + + if (item.Type == "Series" || item.Type == "Season" || item.Type == "BoxSet" || item.MediaType == "Video" || item.MediaType == "Game" || item.MediaType == "Book") { + if (item.UserData.UnplayedItemCount) { + return '
' + item.UserData.UnplayedItemCount + '
'; + } + + if (item.Type != 'TvChannel') { + if (item.UserData.PlayedPercentage && item.UserData.PlayedPercentage >= 100 || (item.UserData && item.UserData.Played)) { + return '
'; } } } - } - var tooltipLike = Globalize.translate('TooltipLike'); - var tooltipDislike = Globalize.translate('TooltipDislike'); + return ''; + }, - if (typeof userData.Likes == "undefined") { - html += LibraryBrowser.getUserDataButtonHtml('markDislike', itemId, 'btnUserItemRating', 'thumb-down', tooltipDislike, style); - html += LibraryBrowser.getUserDataButtonHtml('markLike', itemId, 'btnUserItemRating', 'thumb-up', tooltipLike, style); - } - else if (userData.Likes) { - html += LibraryBrowser.getUserDataButtonHtml('markDislike', itemId, 'btnUserItemRating', 'thumb-down', tooltipDislike, style); - html += LibraryBrowser.getUserDataButtonHtml('markLike', itemId, 'btnUserItemRating btnUserItemRatingOn', 'thumb-up', tooltipLike, style); - } - else { - html += LibraryBrowser.getUserDataButtonHtml('markDislike', itemId, 'btnUserItemRating btnUserItemRatingOn', 'thumb-down', tooltipDislike, style); - html += LibraryBrowser.getUserDataButtonHtml('markLike', itemId, 'btnUserItemRating', 'thumb-up', tooltipLike, style); - } + getGroupCountIndicator: function (item) { - var tooltipFavorite = Globalize.translate('TooltipFavorite'); - if (userData.IsFavorite) { + if (item.ChildCount) { + return '
' + item.ChildCount + '
'; + } - html += LibraryBrowser.getUserDataButtonHtml('markFavorite', itemId, 'btnUserItemRating btnUserItemRatingOn', 'favorite', tooltipFavorite, style); - } else { - html += LibraryBrowser.getUserDataButtonHtml('markFavorite', itemId, 'btnUserItemRating', 'favorite', tooltipFavorite, style); - } + return ''; + }, - return html; - }, + getSyncIndicator: function (item) { - markPlayed: function (link) { + if (item.SyncStatus == 'Synced') { - var id = link.getAttribute('data-itemid'); + return '
'; + } - var markAsPlayed = !link.classList.contains('btnUserItemRatingOn'); + var syncPercent = item.SyncPercent; + if (syncPercent) { + return '
'; + } - if (markAsPlayed) { - ApiClient.markPlayed(Dashboard.getCurrentUserId(), id); - link.classList.add('btnUserItemRatingOn'); - } else { - ApiClient.markUnplayed(Dashboard.getCurrentUserId(), id); - link.classList.remove('btnUserItemRatingOn'); - } - }, + if (item.SyncStatus == 'Queued' || item.SyncStatus == 'Converting' || item.SyncStatus == 'ReadyToTransfer' || item.SyncStatus == 'Transferring') { - markFavorite: function (link) { + return '
'; + } - var id = link.getAttribute('data-itemid'); + return ''; + }, - var $link = $(link); + getAveragePrimaryImageAspectRatio: function (items) { - var markAsFavorite = !$link.hasClass('btnUserItemRatingOn'); + var values = []; - ApiClient.updateFavoriteStatus(Dashboard.getCurrentUserId(), id, markAsFavorite); + for (var i = 0, length = items.length; i < length; i++) { - if (markAsFavorite) { - $link.addClass('btnUserItemRatingOn'); - } else { - $link.removeClass('btnUserItemRatingOn'); - } - }, + var ratio = items[i].PrimaryImageAspectRatio || 0; - markLike: function (link) { + if (!ratio) { + continue; + } - var id = link.getAttribute('data-itemid'); + values[values.length] = ratio; + } - var $link = $(link); + if (!values.length) { + return null; + } - if (!$link.hasClass('btnUserItemRatingOn')) { + // Use the median + values.sort(function (a, b) { return a - b; }); - ApiClient.updateUserItemRating(Dashboard.getCurrentUserId(), id, true); + var half = Math.floor(values.length / 2); - $link.addClass('btnUserItemRatingOn'); + var result; - } else { + if (values.length % 2) + result = values[half]; + else + result = (values[half - 1] + values[half]) / 2.0; - ApiClient.clearUserItemRating(Dashboard.getCurrentUserId(), id); + // If really close to 2:3 (poster image), just return 2:3 + if (Math.abs(0.66666666667 - result) <= .15) { + return 0.66666666667; + } - $link.removeClass('btnUserItemRatingOn'); - } + // If really close to 16:9 (episode image), just return 16:9 + if (Math.abs(1.777777778 - result) <= .2) { + return 1.777777778; + } - $link.prev().removeClass('btnUserItemRatingOn'); - }, + // If really close to 1 (square image), just return 1 + if (Math.abs(1 - result) <= .15) { + return 1; + } - markDislike: function (link) { + // If really close to 4:3 (poster image), just return 2:3 + if (Math.abs(1.33333333333 - result) <= .15) { + return 1.33333333333; + } - var id = link.getAttribute('data-itemid'); + return result; + }, - var $link = $(link); + metroColors: ["#6FBD45", "#4BB3DD", "#4164A5", "#E12026", "#800080", "#E1B222", "#008040", "#0094FF", "#FF00C7", "#FF870F", "#7F0037"], - if (!$link.hasClass('btnUserItemRatingOn')) { + getRandomMetroColor: function () { - ApiClient.updateUserItemRating(Dashboard.getCurrentUserId(), id, false); + var index = Math.floor(Math.random() * (LibraryBrowser.metroColors.length - 1)); - $link.addClass('btnUserItemRatingOn'); + return LibraryBrowser.metroColors[index]; + }, - } else { + getMetroColor: function (str) { - ApiClient.clearUserItemRating(Dashboard.getCurrentUserId(), id); + if (str) { + var character = String(str.substr(0, 1).charCodeAt()); + var sum = 0; + for (var i = 0; i < character.length; i++) { + sum += parseInt(character.charAt(i)); + } + var index = String(sum).substr(-1); - $link.removeClass('btnUserItemRatingOn'); - } + return LibraryBrowser.metroColors[index]; + } else { + return LibraryBrowser.getRandomMetroColor(); + } - $link.next().removeClass('btnUserItemRatingOn'); - }, + }, - renderDetailImage: function (elem, item, editable, preferThumb) { + renderName: function (item, nameElem, linkToElement, context) { - var imageTags = item.ImageTags || {}; + var name = LibraryBrowser.getPosterViewDisplayName(item, false, false); - if (item.PrimaryImageTag) { - imageTags.Primary = item.PrimaryImageTag; - } + Dashboard.setPageTitle(name); - var html = ''; + if (linkToElement) { + nameElem.html('' + name + ''); + } else { + nameElem.html(name); + } + }, - var url; - var shape = 'portrait'; + renderParentName: function (item, parentNameElem, context) { - var imageHeight = 360; - var detectRatio = false; + var html = []; - if (preferThumb && imageTags.Thumb) { + var contextParam = context ? ('&context=' + context) : ''; - url = ApiClient.getScaledImageUrl(item.Id, { - type: "Thumb", - maxHeight: imageHeight, - tag: item.ImageTags.Thumb + if (item.AlbumArtists) { + html.push(LibraryBrowser.getArtistLinksHtml(item.AlbumArtists, "detailPageParentLink")); + } else if (item.ArtistItems && item.ArtistItems.length && item.Type == "MusicVideo") { + html.push(LibraryBrowser.getArtistLinksHtml(item.ArtistItems, "detailPageParentLink")); + } else if (item.SeriesName && item.Type == "Episode") { + + html.push('' + item.SeriesName + ''); + } + + if (item.SeriesName && item.Type == "Season") { + + html.push('' + item.SeriesName + ''); + + } else if (item.ParentIndexNumber != null && item.Type == "Episode") { + + html.push('' + item.SeasonName + ''); + + } else if (item.Album && item.Type == "Audio" && (item.AlbumId || item.ParentId)) { + html.push('' + item.Album + ''); + + } else if (item.Album && item.Type == "MusicVideo" && item.AlbumId) { + html.push('' + item.Album + ''); + + } else if (item.Album) { + html.push(item.Album); + } else if (item.Type == 'Program' && item.EpisodeTitle) { + html.push(item.Name); + } + + if (html.length) { + parentNameElem.show().html(html.join(' - ')); + } else { + parentNameElem.hide(); + } + }, + + renderLinks: function (linksElem, item) { + + var links = []; + + if (item.HomePageUrl) { + links.push('' + Globalize.translate('ButtonWebsite') + ''); + } + + if (item.ExternalUrls) { + + for (var i = 0, length = item.ExternalUrls.length; i < length; i++) { + + var url = item.ExternalUrls[i]; + + links.push('' + url.Name + ''); + } + } + + if (links.length) { + + var html = links.join('  /  '); + + html = Globalize.translate('ValueLinks', html); + + linksElem.innerHTML = html; + $(linksElem); + $(linksElem).show(); + + } else { + $(linksElem).hide(); + } + }, + + getDefaultPageSizeSelections: function () { + + return [20, 50, 100, 200, 300, 400, 500]; + }, + + showLayoutMenu: function (button, currentLayout) { + + // Add banner and list once all screens support them + var views = button.getAttribute('data-layouts'); + + views = views ? views.split(',') : ['List', 'Poster', 'PosterCard', 'Thumb', 'ThumbCard']; + + var menuItems = views.map(function (v) { + return { + name: Globalize.translate('Option' + v), + id: v, + ironIcon: currentLayout == v ? 'check' : null + }; }); - shape = 'thumb'; - } - else if (imageTags.Primary) { - url = ApiClient.getScaledImageUrl(item.Id, { - type: "Primary", - maxHeight: imageHeight, - tag: item.ImageTags.Primary + require(['actionsheet'], function (actionsheet) { + + actionsheet.show({ + items: menuItems, + positionTo: button, + callback: function (id) { + + $(button).trigger('layoutchange', [id]); + } + }); + }); - detectRatio = true; - } - else if (item.BackdropImageTags && item.BackdropImageTags.length) { - url = ApiClient.getScaledImageUrl(item.Id, { - type: "Backdrop", - maxHeight: imageHeight, - tag: item.BackdropImageTags[0] + }, + + openViewPanel: function (btn, className) { + + $('.' + className, jQuery(btn).parents('.page')).removeClass('hide').panel('toggle'); + }, + + getQueryPagingHtml: function (options) { + + var startIndex = options.startIndex; + var limit = options.limit; + var totalRecordCount = options.totalRecordCount; + + if (limit && options.updatePageSizeSetting !== false) { + try { + appStorage.setItem(options.pageSizeKey || pageSizeKey, limit); + } catch (e) { + + } + } + + var html = ''; + + var recordsEnd = Math.min(startIndex + limit, totalRecordCount); + + // 20 is the minimum page size + var showControls = totalRecordCount > 20 || limit < totalRecordCount; + + html += '
'; + + if (showControls) { + html += ''; + + var startAtDisplay = totalRecordCount ? startIndex + 1 : 0; + html += startAtDisplay + '-' + recordsEnd + ' of ' + totalRecordCount; + + html += ''; + } + + if (showControls || options.viewButton || options.filterButton || options.sortButton || options.addLayoutButton) { + + html += '
'; + + if (showControls) { + + html += ''; + html += '= totalRecordCount ? 'disabled' : '') + '>'; + } + + if (options.addLayoutButton) { + + html += ''; + } + + if (options.sortButton) { + + html += ''; + } + + if (options.viewButton) { + + //html += ''; + var viewPanelClass = options.viewPanelClass || 'viewPanel'; + var title = options.viewIcon == 'filter-list' ? Globalize.translate('ButtonFilter') : Globalize.translate('ButtonMenu'); + html += ''; + } + + if (options.filterButton) { + + html += ''; + } + + html += '
'; + + if (showControls && options.showLimit) { + + var id = "selectPageSize"; + + var pageSizes = options.pageSizes || LibraryBrowser.getDefaultPageSizeSelections(); + + var optionsHtml = pageSizes.map(function (val) { + + if (limit == val) { + + return ''; + + } else { + return ''; + } + }).join(''); + + // Add styles to defeat jquery mobile + html += '
'; + } + } + + html += '
'; + + return html; + }, + + showSortMenu: function (options) { + + require(['paperdialoghelper', 'paper-radio-button', 'paper-radio-group'], function (paperDialogHelper) { + + var dlg = paperDialogHelper.createDialog({ + removeOnClose: true, + modal: false, + entryAnimationDuration: 160, + exitAnimationDuration: 200 + }); + + dlg.classList.add('ui-body-a'); + dlg.classList.add('background-theme-a'); + + var html = ''; + + html += '
'; + + html += '

'; + html += Globalize.translate('HeaderSortBy'); + html += '

'; + + html += ''; + for (var i = 0, length = options.items.length; i < length; i++) { + + var option = options.items[i]; + + html += '' + option.name + ''; + } + html += ''; + + html += '

'; + html += Globalize.translate('HeaderSortOrder'); + html += '

'; + html += ''; + html += '' + Globalize.translate('OptionAscending') + ''; + html += '' + Globalize.translate('OptionDescending') + ''; + html += ''; + html += '
'; + + html += '
'; + html += '' + Globalize.translate('ButtonClose') + ''; + html += '
'; + + dlg.innerHTML = html; + document.body.appendChild(dlg); + + var fireCallbackOnClose = false; + + paperDialogHelper.open(dlg).then(function () { + + if (options.callback && fireCallbackOnClose) { + options.callback(); + } + }); + + $('.groupSortBy', dlg).on('iron-select', function () { + + var newValue = this.selected.replace('_', ','); + var changed = options.query.SortBy != newValue; + + options.query.SortBy = newValue; + options.query.StartIndex = 0; + + if (options.callback && changed) { + fireCallbackOnClose = true; + } + }); + + $('.groupSortOrder', dlg).on('iron-select', function () { + + var newValue = this.selected; + var changed = options.query.SortOrder != newValue; + + options.query.SortOrder = newValue; + options.query.StartIndex = 0; + + if (options.callback && changed) { + fireCallbackOnClose = true; + } + }); }); - shape = 'thumb'; - } - else if (imageTags.Thumb) { + }, - url = ApiClient.getScaledImageUrl(item.Id, { - type: "Thumb", - maxHeight: imageHeight, - tag: item.ImageTags.Thumb - }); - shape = 'thumb'; - } - else if (imageTags.Disc) { + getRatingHtml: function (item, metascore) { - url = ApiClient.getScaledImageUrl(item.Id, { - type: "Disc", - maxHeight: imageHeight, - tag: item.ImageTags.Disc - }); - shape = 'square'; - } - else if (item.AlbumId && item.AlbumPrimaryImageTag) { + var html = ""; - url = ApiClient.getScaledImageUrl(item.AlbumId, { - type: "Primary", - maxHeight: imageHeight, - tag: item.AlbumPrimaryImageTag - }); - shape = 'square'; - } - else if (item.MediaType == "Audio" || item.Type == "MusicAlbum" || item.Type == "MusicGenre") { - url = "css/images/items/detail/audio.png"; - shape = 'square'; - } - else if (item.MediaType == "Game" || item.Type == "GameGenre") { - url = "css/images/items/detail/game.png"; - shape = 'square'; - } - else if (item.Type == "Person") { - url = "css/images/items/detail/person.png"; - shape = 'square'; - } - else if (item.Type == "Genre" || item.Type == "Studio") { - url = "css/images/items/detail/video.png"; - shape = 'square'; - } - else if (item.Type == "TvChannel") { - url = "css/images/items/detail/tv.png"; - shape = 'square'; - } - else { - url = "css/images/items/detail/video.png"; - shape = 'square'; - } + if (item.CommunityRating) { - html += '
'; + html += "
"; + html += '
'; + html += item.CommunityRating.toFixed(1); + html += '
'; + } - if (editable) { - html += ""; - } + if (item.CriticRating != null) { - if (detectRatio && item.PrimaryImageAspectRatio) { + if (item.CriticRating >= 60) { + html += '
'; + } else { + html += '
'; + } - if (item.PrimaryImageAspectRatio >= 1.48) { + html += '
' + item.CriticRating + '%
'; + } + + //if (item.Metascore && metascore !== false) { + + // if (item.Metascore >= 60) { + // html += '
' + item.Metascore + '
'; + // } + // else if (item.Metascore >= 40) { + // html += '
' + item.Metascore + '
'; + // } else { + // html += '
' + item.Metascore + '
'; + // } + //} + + return html; + }, + + getItemProgressBarHtml: function (item) { + + + if (item.Type == "Recording" && item.CompletionPercentage) { + + return ''; + } + + var pct = item.PlayedPercentage; + + if (pct && pct < 100) { + + return ''; + } + + return null; + }, + + getUserDataButtonHtml: function (method, itemId, btnCssClass, icon, tooltip, style) { + + var tagName = style == 'fab' ? 'paper-fab' : 'paper-icon-button'; + + return '<' + tagName + ' title="' + tooltip + '" data-itemid="' + itemId + '" icon="' + icon + '" class="' + btnCssClass + '" onclick="LibraryBrowser.' + method + '(this);return false;">'; + + }, + + getUserDataIconsHtml: function (item, includePlayed, style) { + + var html = ''; + + var userData = item.UserData || {}; + + var itemId = item.Id; + + if (includePlayed !== false) { + var tooltipPlayed = Globalize.translate('TooltipPlayed'); + + if (item.MediaType == 'Video' || item.Type == 'Series' || item.Type == 'Season' || item.Type == 'BoxSet' || item.Type == 'Playlist') { + if (item.Type != 'TvChannel') { + if (userData.Played) { + html += LibraryBrowser.getUserDataButtonHtml('markPlayed', itemId, 'btnUserItemRating btnUserItemRatingOn', 'check', tooltipPlayed, style); + } else { + html += LibraryBrowser.getUserDataButtonHtml('markPlayed', itemId, 'btnUserItemRating', 'check', tooltipPlayed, style); + } + } + } + } + + var tooltipLike = Globalize.translate('TooltipLike'); + var tooltipDislike = Globalize.translate('TooltipDislike'); + + if (typeof userData.Likes == "undefined") { + html += LibraryBrowser.getUserDataButtonHtml('markDislike', itemId, 'btnUserItemRating', 'thumb-down', tooltipDislike, style); + html += LibraryBrowser.getUserDataButtonHtml('markLike', itemId, 'btnUserItemRating', 'thumb-up', tooltipLike, style); + } + else if (userData.Likes) { + html += LibraryBrowser.getUserDataButtonHtml('markDislike', itemId, 'btnUserItemRating', 'thumb-down', tooltipDislike, style); + html += LibraryBrowser.getUserDataButtonHtml('markLike', itemId, 'btnUserItemRating btnUserItemRatingOn', 'thumb-up', tooltipLike, style); + } + else { + html += LibraryBrowser.getUserDataButtonHtml('markDislike', itemId, 'btnUserItemRating btnUserItemRatingOn', 'thumb-down', tooltipDislike, style); + html += LibraryBrowser.getUserDataButtonHtml('markLike', itemId, 'btnUserItemRating', 'thumb-up', tooltipLike, style); + } + + var tooltipFavorite = Globalize.translate('TooltipFavorite'); + if (userData.IsFavorite) { + + html += LibraryBrowser.getUserDataButtonHtml('markFavorite', itemId, 'btnUserItemRating btnUserItemRatingOn', 'favorite', tooltipFavorite, style); + } else { + html += LibraryBrowser.getUserDataButtonHtml('markFavorite', itemId, 'btnUserItemRating', 'favorite', tooltipFavorite, style); + } + + return html; + }, + + markPlayed: function (link) { + + var id = link.getAttribute('data-itemid'); + + var markAsPlayed = !link.classList.contains('btnUserItemRatingOn'); + + if (markAsPlayed) { + ApiClient.markPlayed(Dashboard.getCurrentUserId(), id); + link.classList.add('btnUserItemRatingOn'); + } else { + ApiClient.markUnplayed(Dashboard.getCurrentUserId(), id); + link.classList.remove('btnUserItemRatingOn'); + } + }, + + markFavorite: function (link) { + + var id = link.getAttribute('data-itemid'); + + var $link = $(link); + + var markAsFavorite = !$link.hasClass('btnUserItemRatingOn'); + + ApiClient.updateFavoriteStatus(Dashboard.getCurrentUserId(), id, markAsFavorite); + + if (markAsFavorite) { + $link.addClass('btnUserItemRatingOn'); + } else { + $link.removeClass('btnUserItemRatingOn'); + } + }, + + markLike: function (link) { + + var id = link.getAttribute('data-itemid'); + + var $link = $(link); + + if (!$link.hasClass('btnUserItemRatingOn')) { + + ApiClient.updateUserItemRating(Dashboard.getCurrentUserId(), id, true); + + $link.addClass('btnUserItemRatingOn'); + + } else { + + ApiClient.clearUserItemRating(Dashboard.getCurrentUserId(), id); + + $link.removeClass('btnUserItemRatingOn'); + } + + $link.prev().removeClass('btnUserItemRatingOn'); + }, + + markDislike: function (link) { + + var id = link.getAttribute('data-itemid'); + + var $link = $(link); + + if (!$link.hasClass('btnUserItemRatingOn')) { + + ApiClient.updateUserItemRating(Dashboard.getCurrentUserId(), id, false); + + $link.addClass('btnUserItemRatingOn'); + + } else { + + ApiClient.clearUserItemRating(Dashboard.getCurrentUserId(), id); + + $link.removeClass('btnUserItemRatingOn'); + } + + $link.next().removeClass('btnUserItemRatingOn'); + }, + + renderDetailImage: function (elem, item, editable, preferThumb) { + + var imageTags = item.ImageTags || {}; + + if (item.PrimaryImageTag) { + imageTags.Primary = item.PrimaryImageTag; + } + + var html = ''; + + var url; + var shape = 'portrait'; + + var imageHeight = 360; + var detectRatio = false; + + if (preferThumb && imageTags.Thumb) { + + url = ApiClient.getScaledImageUrl(item.Id, { + type: "Thumb", + maxHeight: imageHeight, + tag: item.ImageTags.Thumb + }); shape = 'thumb'; - } else if (item.PrimaryImageAspectRatio >= .85 && item.PrimaryImageAspectRatio <= 1.34) { + } + else if (imageTags.Primary) { + + url = ApiClient.getScaledImageUrl(item.Id, { + type: "Primary", + maxHeight: imageHeight, + tag: item.ImageTags.Primary + }); + detectRatio = true; + } + else if (item.BackdropImageTags && item.BackdropImageTags.length) { + + url = ApiClient.getScaledImageUrl(item.Id, { + type: "Backdrop", + maxHeight: imageHeight, + tag: item.BackdropImageTags[0] + }); + shape = 'thumb'; + } + else if (imageTags.Thumb) { + + url = ApiClient.getScaledImageUrl(item.Id, { + type: "Thumb", + maxHeight: imageHeight, + tag: item.ImageTags.Thumb + }); + shape = 'thumb'; + } + else if (imageTags.Disc) { + + url = ApiClient.getScaledImageUrl(item.Id, { + type: "Disc", + maxHeight: imageHeight, + tag: item.ImageTags.Disc + }); shape = 'square'; } - } + else if (item.AlbumId && item.AlbumPrimaryImageTag) { - html += ""; - - if (editable) { - html += "
"; - } - - var progressHtml = item.IsFolder || !item.UserData ? '' : LibraryBrowser.getItemProgressBarHtml((item.Type == 'Recording' ? item : item.UserData)); - - html += '
'; - if (progressHtml) { - html += progressHtml; - } - html += "
"; - - html += "
"; - - elem.innerHTML = html; - - if (shape == 'thumb') { - elem.classList.add('thumbDetailImageContainer'); - elem.classList.remove('portraitDetailImageContainer'); - elem.classList.remove('squareDetailImageContainer'); - } - else if (shape == 'square') { - elem.classList.remove('thumbDetailImageContainer'); - elem.classList.remove('portraitDetailImageContainer'); - elem.classList.add('squareDetailImageContainer'); - } else { - elem.classList.remove('thumbDetailImageContainer'); - elem.classList.add('portraitDetailImageContainer'); - elem.classList.remove('squareDetailImageContainer'); - } - - var img = elem.querySelector('img'); - img.onload = function () { - if (img.src.indexOf('empty.png') == -1) { - img.classList.add('loaded'); + url = ApiClient.getScaledImageUrl(item.AlbumId, { + type: "Primary", + maxHeight: imageHeight, + tag: item.AlbumPrimaryImageTag + }); + shape = 'square'; } - }; - ImageLoader.lazyImage(img, url); - }, - - refreshDetailImageUserData: function (elem, item) { - - var progressHtml = item.IsFolder || !item.UserData ? '' : LibraryBrowser.getItemProgressBarHtml((item.Type == 'Recording' ? item : item.UserData)); - - var detailImageProgressContainer = elem.querySelector('.detailImageProgressContainer'); - - detailImageProgressContainer.innerHTML = progressHtml || ''; - }, - - getDisplayTime: function (date) { - - if ((typeof date).toString().toLowerCase() === 'string') { - try { - - date = parseISO8601Date(date, { toLocal: true }); - - } catch (err) { - return date; + else if (item.MediaType == "Audio" || item.Type == "MusicAlbum" || item.Type == "MusicGenre") { + url = "css/images/items/detail/audio.png"; + shape = 'square'; + } + else if (item.MediaType == "Game" || item.Type == "GameGenre") { + url = "css/images/items/detail/game.png"; + shape = 'square'; + } + else if (item.Type == "Person") { + url = "css/images/items/detail/person.png"; + shape = 'square'; + } + else if (item.Type == "Genre" || item.Type == "Studio") { + url = "css/images/items/detail/video.png"; + shape = 'square'; + } + else if (item.Type == "TvChannel") { + url = "css/images/items/detail/tv.png"; + shape = 'square'; + } + else { + url = "css/images/items/detail/video.png"; + shape = 'square'; } - } - var lower = date.toLocaleTimeString().toLowerCase(); + html += '
'; - var hours = date.getHours(); - var minutes = date.getMinutes(); + if (editable) { + html += ""; + } - var text; + if (detectRatio && item.PrimaryImageAspectRatio) { - if (lower.indexOf('am') != -1 || lower.indexOf('pm') != -1) { + if (item.PrimaryImageAspectRatio >= 1.48) { + shape = 'thumb'; + } else if (item.PrimaryImageAspectRatio >= .85 && item.PrimaryImageAspectRatio <= 1.34) { + shape = 'square'; + } + } - var suffix = hours > 11 ? 'pm' : 'am'; + html += ""; - hours = (hours % 12) || 12; + if (editable) { + html += ""; + } - text = hours; + var progressHtml = item.IsFolder || !item.UserData ? '' : LibraryBrowser.getItemProgressBarHtml((item.Type == 'Recording' ? item : item.UserData)); - if (minutes) { + html += '
'; + if (progressHtml) { + html += progressHtml; + } + html += "
"; + + html += "
"; + + elem.innerHTML = html; + + if (shape == 'thumb') { + elem.classList.add('thumbDetailImageContainer'); + elem.classList.remove('portraitDetailImageContainer'); + elem.classList.remove('squareDetailImageContainer'); + } + else if (shape == 'square') { + elem.classList.remove('thumbDetailImageContainer'); + elem.classList.remove('portraitDetailImageContainer'); + elem.classList.add('squareDetailImageContainer'); + } else { + elem.classList.remove('thumbDetailImageContainer'); + elem.classList.add('portraitDetailImageContainer'); + elem.classList.remove('squareDetailImageContainer'); + } + + var img = elem.querySelector('img'); + img.onload = function () { + if (img.src.indexOf('empty.png') == -1) { + img.classList.add('loaded'); + } + }; + ImageLoader.lazyImage(img, url); + }, + + refreshDetailImageUserData: function (elem, item) { + + var progressHtml = item.IsFolder || !item.UserData ? '' : LibraryBrowser.getItemProgressBarHtml((item.Type == 'Recording' ? item : item.UserData)); + + var detailImageProgressContainer = elem.querySelector('.detailImageProgressContainer'); + + detailImageProgressContainer.innerHTML = progressHtml || ''; + }, + + getDisplayTime: function (date) { + + if ((typeof date).toString().toLowerCase() === 'string') { + try { + + date = parseISO8601Date(date, { toLocal: true }); + + } catch (err) { + return date; + } + } + + var lower = date.toLocaleTimeString().toLowerCase(); + + var hours = date.getHours(); + var minutes = date.getMinutes(); + + var text; + + if (lower.indexOf('am') != -1 || lower.indexOf('pm') != -1) { + + var suffix = hours > 11 ? 'pm' : 'am'; + + hours = (hours % 12) || 12; + + text = hours; + + if (minutes) { + + text += ':'; + if (minutes < 10) { + text += '0'; + } + text += minutes; + } + + text += suffix; + + } else { + text = hours + ':'; - text += ':'; if (minutes < 10) { text += '0'; } text += minutes; } - text += suffix; + return text; + }, - } else { - text = hours + ':'; + getMiscInfoHtml: function (item) { + + var miscInfo = []; + var text, date; + + if (item.IsSeries && !item.IsRepeat) { + + require(['livetvcss']); + miscInfo.push('' + Globalize.translate('LabelNewProgram') + ''); - if (minutes < 10) { - text += '0'; } - text += minutes; - } - return text; - }, + if (item.IsLive) { - getMiscInfoHtml: function (item) { + miscInfo.push('' + Globalize.translate('LabelLiveProgram') + ''); - var miscInfo = []; - var text, date; - - if (item.IsSeries && !item.IsRepeat) { - - require(['livetvcss']); - miscInfo.push('' + Globalize.translate('LabelNewProgram') + ''); - - } - - if (item.IsLive) { - - miscInfo.push('' + Globalize.translate('LabelLiveProgram') + ''); - - } - - if (item.ChannelId && item.ChannelName) { - if (item.Type == 'Program' || item.Type == 'Recording') { - miscInfo.push('' + item.ChannelName + ''); } - } - if (item.Type == "Episode" || item.MediaType == 'Photo') { + if (item.ChannelId && item.ChannelName) { + if (item.Type == 'Program' || item.Type == 'Recording') { + miscInfo.push('' + item.ChannelName + ''); + } + } - if (item.PremiereDate) { + if (item.Type == "Episode" || item.MediaType == 'Photo') { + + if (item.PremiereDate) { + + try { + date = parseISO8601Date(item.PremiereDate, { toLocal: true }); + + text = date.toLocaleDateString(); + miscInfo.push(text); + } + catch (e) { + console.log("Error parsing date: " + item.PremiereDate); + } + } + } + + if (item.StartDate) { try { - date = parseISO8601Date(item.PremiereDate, { toLocal: true }); + date = parseISO8601Date(item.StartDate, { toLocal: true }); text = date.toLocaleDateString(); miscInfo.push(text); + + if (item.Type != "Recording") { + text = LibraryBrowser.getDisplayTime(date); + miscInfo.push(text); + } } catch (e) { console.log("Error parsing date: " + item.PremiereDate); } } - } - if (item.StartDate) { + if (item.ProductionYear && item.Type == "Series") { - try { - date = parseISO8601Date(item.StartDate, { toLocal: true }); + if (item.Status == "Continuing") { + miscInfo.push(Globalize.translate('ValueSeriesYearToPresent', item.ProductionYear)); - text = date.toLocaleDateString(); - miscInfo.push(text); + } + else if (item.ProductionYear) { + + text = item.ProductionYear; + + if (item.EndDate) { + + try { + + var endYear = parseISO8601Date(item.EndDate, { toLocal: true }).getFullYear(); + + if (endYear != item.ProductionYear) { + text += "-" + parseISO8601Date(item.EndDate, { toLocal: true }).getFullYear(); + } + + } + catch (e) { + console.log("Error parsing date: " + item.EndDate); + } + } - if (item.Type != "Recording") { - text = LibraryBrowser.getDisplayTime(date); miscInfo.push(text); } } - catch (e) { - console.log("Error parsing date: " + item.PremiereDate); - } - } - if (item.ProductionYear && item.Type == "Series") { + if (item.Type != "Series" && item.Type != "Episode" && item.MediaType != 'Photo') { - if (item.Status == "Continuing") { - miscInfo.push(Globalize.translate('ValueSeriesYearToPresent', item.ProductionYear)); + if (item.ProductionYear) { - } - else if (item.ProductionYear) { - - text = item.ProductionYear; - - if (item.EndDate) { + miscInfo.push(item.ProductionYear); + } + else if (item.PremiereDate) { try { - - var endYear = parseISO8601Date(item.EndDate, { toLocal: true }).getFullYear(); - - if (endYear != item.ProductionYear) { - text += "-" + parseISO8601Date(item.EndDate, { toLocal: true }).getFullYear(); - } - + text = parseISO8601Date(item.PremiereDate, { toLocal: true }).getFullYear(); + miscInfo.push(text); } catch (e) { - console.log("Error parsing date: " + item.EndDate); + console.log("Error parsing date: " + item.PremiereDate); + } + } + } + + var minutes; + + if (item.RunTimeTicks && item.Type != "Series") { + + if (item.Type == "Audio") { + + miscInfo.push(Dashboard.getDisplayTime(item.RunTimeTicks)); + + } else { + minutes = item.RunTimeTicks / 600000000; + + minutes = minutes || 1; + + miscInfo.push(Math.round(minutes) + "min"); + } + } + + if (item.CumulativeRunTimeTicks && item.Type != "Series" && item.Type != "Season") { + + miscInfo.push(Dashboard.getDisplayTime(item.CumulativeRunTimeTicks)); + } + + if (item.OfficialRating && item.Type !== "Season" && item.Type !== "Episode") { + miscInfo.push(item.OfficialRating); + } + + if (item.IsHD) { + + miscInfo.push(Globalize.translate('LabelHDProgram')); + } + + //if (item.Audio) { + + // miscInfo.push(item.Audio); + + //} + + if (item.Video3DFormat) { + miscInfo.push("3D"); + } + + if (item.MediaType == 'Photo' && item.Width && item.Height) { + miscInfo.push(item.Width + "x" + item.Height); + } + + if (item.SeriesTimerId) { + var html = ''; + html += ''; + html += '
'; + html += '
'; + html += '
'; + html += '
'; + miscInfo.push(html); + require(['livetvcss']); + } + else if (item.TimerId) { + + var html = ''; + html += ''; + html += '
'; + html += '
'; + miscInfo.push(html); + require(['livetvcss']); + } + + return miscInfo.join('    '); + }, + + renderOverview: function (elems, item) { + + $(elems).each(function () { + var elem = this; + var overview = item.Overview || ''; + + $('a', elem).each(function () { + this.setAttribute("target", "_blank"); + }); + + if (overview) { + elem.innerHTML = overview; + + elem.classList.remove('empty'); + } else { + elem.innerHTML = ''; + + elem.classList.add('empty'); + } + }); + + }, + + renderStudios: function (elem, item, isStatic) { + + if (item.Studios && item.Studios.length && item.Type != "Series") { + + var html = ''; + + for (var i = 0, length = item.Studios.length; i < length; i++) { + + if (i > 0) { + html += '  /  '; + } + + if (isStatic) { + html += item.Studios[i].Name; + } else { + html += '' + item.Studios[i].Name + ''; } } - miscInfo.push(text); - } - } + var translationKey = item.Studios.length > 1 ? "ValueStudios" : "ValueStudio"; - if (item.Type != "Series" && item.Type != "Episode" && item.MediaType != 'Photo') { + html = Globalize.translate(translationKey, html); - if (item.ProductionYear) { + elem.show().html(html).trigger('create'); - miscInfo.push(item.ProductionYear); - } - else if (item.PremiereDate) { - - try { - text = parseISO8601Date(item.PremiereDate, { toLocal: true }).getFullYear(); - miscInfo.push(text); - } - catch (e) { - console.log("Error parsing date: " + item.PremiereDate); - } - } - } - - var minutes; - - if (item.RunTimeTicks && item.Type != "Series") { - - if (item.Type == "Audio") { - - miscInfo.push(Dashboard.getDisplayTime(item.RunTimeTicks)); } else { - minutes = item.RunTimeTicks / 600000000; - - minutes = minutes || 1; - - miscInfo.push(Math.round(minutes) + "min"); + elem.hide(); } - } + }, - if (item.CumulativeRunTimeTicks && item.Type != "Series" && item.Type != "Season") { - - miscInfo.push(Dashboard.getDisplayTime(item.CumulativeRunTimeTicks)); - } - - if (item.OfficialRating && item.Type !== "Season" && item.Type !== "Episode") { - miscInfo.push(item.OfficialRating); - } - - if (item.IsHD) { - - miscInfo.push(Globalize.translate('LabelHDProgram')); - } - - //if (item.Audio) { - - // miscInfo.push(item.Audio); - - //} - - if (item.Video3DFormat) { - miscInfo.push("3D"); - } - - if (item.MediaType == 'Photo' && item.Width && item.Height) { - miscInfo.push(item.Width + "x" + item.Height); - } - - if (item.SeriesTimerId) { - var html = ''; - html += ''; - html += '
'; - html += '
'; - html += '
'; - html += '
'; - miscInfo.push(html); - require(['livetvcss']); - } - else if (item.TimerId) { - - var html = ''; - html += ''; - html += '
'; - html += '
'; - miscInfo.push(html); - require(['livetvcss']); - } - - return miscInfo.join('    '); - }, - - renderOverview: function (elems, item) { - - $(elems).each(function () { - var elem = this; - var overview = item.Overview || ''; - - $('a', elem).each(function () { - this.setAttribute("target", "_blank"); - }); - - if (overview) { - elem.innerHTML = overview; - - elem.classList.remove('empty'); - } else { - elem.innerHTML = ''; - - elem.classList.add('empty'); - } - }); - - }, - - renderStudios: function (elem, item, isStatic) { - - if (item.Studios && item.Studios.length && item.Type != "Series") { + renderGenres: function (elem, item, limit, isStatic) { var html = ''; - for (var i = 0, length = item.Studios.length; i < length; i++) { + var genres = item.Genres || []; + + for (var i = 0, length = genres.length; i < length; i++) { + + if (limit && i >= limit) { + break; + } if (i > 0) { - html += '  /  '; + html += '  /  '; + } + + var param = item.Type == "Audio" || item.Type == "MusicArtist" || item.Type == "MusicAlbum" ? "musicgenre" : "genre"; + + if (item.MediaType == "Game") { + param = "gamegenre"; } if (isStatic) { - html += item.Studios[i].Name; + html += genres[i]; } else { - html += '' + item.Studios[i].Name + ''; + html += '' + genres[i] + ''; } } - var translationKey = item.Studios.length > 1 ? "ValueStudios" : "ValueStudio"; + elem.html(html).trigger('create'); + }, - html = Globalize.translate(translationKey, html); + renderPremiereDate: function (elem, item) { + if (item.PremiereDate) { + try { - elem.show().html(html).trigger('create'); + var date = parseISO8601Date(item.PremiereDate, { toLocal: true }); + var translationKey = new Date().getTime() > date.getTime() ? "ValuePremiered" : "ValuePremieres"; - } else { - elem.hide(); - } - }, + elem.show().html(Globalize.translate(translationKey, date.toLocaleDateString())); - renderGenres: function (elem, item, limit, isStatic) { - - var html = ''; - - var genres = item.Genres || []; - - for (var i = 0, length = genres.length; i < length; i++) { - - if (limit && i >= limit) { - break; - } - - if (i > 0) { - html += '  /  '; - } - - var param = item.Type == "Audio" || item.Type == "MusicArtist" || item.Type == "MusicAlbum" ? "musicgenre" : "genre"; - - if (item.MediaType == "Game") { - param = "gamegenre"; - } - - if (isStatic) { - html += genres[i]; + } catch (err) { + elem.hide(); + } } else { - html += '' + genres[i] + ''; - } - } - - elem.html(html).trigger('create'); - }, - - renderPremiereDate: function (elem, item) { - if (item.PremiereDate) { - try { - - var date = parseISO8601Date(item.PremiereDate, { toLocal: true }); - - var translationKey = new Date().getTime() > date.getTime() ? "ValuePremiered" : "ValuePremieres"; - - elem.show().html(Globalize.translate(translationKey, date.toLocaleDateString())); - - } catch (err) { elem.hide(); } - } else { - elem.hide(); + }, + + renderAwardSummary: function (elem, item) { + if (item.AwardSummary) { + elem.show().html(Globalize.translate('ValueAwards', item.AwardSummary)); + } else { + elem.hide(); + } + }, + + renderDetailPageBackdrop: function (page, item) { + + var screenWidth = screen.availWidth; + + var imgUrl; + var hasbackdrop = false; + + if (item.BackdropImageTags && item.BackdropImageTags.length) { + + imgUrl = ApiClient.getScaledImageUrl(item.Id, { + type: "Backdrop", + index: 0, + maxWidth: screenWidth, + tag: item.BackdropImageTags[0] + }); + + ImageLoader.lazyImage($('#itemBackdrop', page).addClass('noFade').removeClass('noBackdrop')[0], imgUrl); + hasbackdrop = true; + } + else if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) { + + imgUrl = ApiClient.getScaledImageUrl(item.ParentBackdropItemId, { + type: 'Backdrop', + index: 0, + tag: item.ParentBackdropImageTags[0], + maxWidth: screenWidth + }); + + ImageLoader.lazyImage($('#itemBackdrop', page).addClass('noFade').removeClass('noBackdrop')[0], imgUrl); + hasbackdrop = true; + } + else { + + $('#itemBackdrop', page).addClass('noBackdrop').css('background-image', 'none'); + } + + return hasbackdrop; } - }, + }; - renderAwardSummary: function (elem, item) { - if (item.AwardSummary) { - elem.show().html(Globalize.translate('ValueAwards', item.AwardSummary)); - } else { - elem.hide(); - } - }, - - renderDetailPageBackdrop: function (page, item) { - - var screenWidth = screen.availWidth; - - var imgUrl; - var hasbackdrop = false; - - if (item.BackdropImageTags && item.BackdropImageTags.length) { - - imgUrl = ApiClient.getScaledImageUrl(item.Id, { - type: "Backdrop", - index: 0, - maxWidth: screenWidth, - tag: item.BackdropImageTags[0] - }); - - ImageLoader.lazyImage($('#itemBackdrop', page).addClass('noFade').removeClass('noBackdrop')[0], imgUrl); - hasbackdrop = true; - } - else if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) { - - imgUrl = ApiClient.getScaledImageUrl(item.ParentBackdropItemId, { - type: 'Backdrop', - index: 0, - tag: item.ParentBackdropImageTags[0], - maxWidth: screenWidth - }); - - ImageLoader.lazyImage($('#itemBackdrop', page).addClass('noFade').removeClass('noBackdrop')[0], imgUrl); - hasbackdrop = true; - } - else { - - $('#itemBackdrop', page).addClass('noBackdrop').css('background-image', 'none'); - } - - return hasbackdrop; + if (libraryBrowser.enableFullPaperTabs()) { + document.documentElement.classList.add('fullPaperLibraryTabs'); + } else { + document.documentElement.classList.add('basicPaperLibraryTabs'); } - }; - if (libraryBrowser.enableFullPaperTabs()) { - document.documentElement.classList.add('fullPaperLibraryTabs'); - } else { - document.documentElement.classList.add('basicPaperLibraryTabs'); - } + return libraryBrowser; + + })(window, document, screen); + + window.LibraryBrowser = libraryBrowser; return libraryBrowser; - -})(window, document, screen); \ No newline at end of file +}); \ No newline at end of file diff --git a/dashboard-ui/scripts/librarylist.js b/dashboard-ui/scripts/librarylist.js index d2c042bff2..65cd4c8119 100644 --- a/dashboard-ui/scripts/librarylist.js +++ b/dashboard-ui/scripts/librarylist.js @@ -468,7 +468,10 @@ }); break; case 'playlist': - PlaylistManager.showPanel([itemId]); + require(['playlistManager'], function (playlistManager) { + + playlistManager.showPanel([itemId]); + }); break; case 'delete': LibraryBrowser.deleteItems([itemId]); @@ -1164,8 +1167,11 @@ hideSelections(); break; case 'playlist': - PlaylistManager.showPanel(items); - hideSelections(); + require(['playlistManager'], function (playlistManager) { + + playlistManager.showPanel(items); + hideSelections(); + }); break; case 'delete': LibraryBrowser.deleteItems(items).then(function () { diff --git a/dashboard-ui/scripts/playlistmanager.js b/dashboard-ui/scripts/playlistmanager.js index 74bfdf1a2e..8878712b4c 100644 --- a/dashboard-ui/scripts/playlistmanager.js +++ b/dashboard-ui/scripts/playlistmanager.js @@ -1,6 +1,6 @@ -(function ($, document) { +define([], function () { - window.PlaylistManager = { + return { showPanel: function (items) { @@ -17,5 +17,4 @@ return item.RunTimeTicks || item.IsFolder || item.Type == "Genre" || item.Type == "MusicGenre" || item.Type == "MusicArtist"; } }; - -})(jQuery, document); \ No newline at end of file +}); \ No newline at end of file diff --git a/dashboard-ui/scripts/site.js b/dashboard-ui/scripts/site.js index 1bb3d85f7a..cb1c78b5d9 100644 --- a/dashboard-ui/scripts/site.js +++ b/dashboard-ui/scripts/site.js @@ -1845,6 +1845,8 @@ var AppInfo = {}; paths.appStorage = apiClientBowerPath + "/appstorage"; } + paths.playlistManager = "scripts/playlistmanager"; + var sha1Path = bowerPath + "/cryptojslib/components/sha1-min"; var md5Path = bowerPath + "/cryptojslib/components/md5-min"; var shim = {}; @@ -1955,7 +1957,6 @@ var AppInfo = {}; define("localassetmanager", [apiClientBowerPath + "/localassetmanager"]); define("fileupload", [apiClientBowerPath + "/fileupload"]); } - define("apiclient-deferred", ["legacy/deferred"]); define("connectionmanager", [apiClientBowerPath + "/connectionmanager"]); define("contentuploader", [apiClientBowerPath + "/sync/contentuploader"]); @@ -2228,6 +2229,8 @@ var AppInfo = {}; deps.push('css!devices/android/android.css'); } else if (AppInfo.isNativeApp && browserInfo.safari) { deps.push('css!devices/ios/ios.css'); + } else if (AppInfo.isNativeApp && browserInfo.edge) { + deps.push('css!devices/windowsphone/wp.css'); } else if (!browserInfo.android) { deps.push('css!devices/android/android.css'); } @@ -2255,7 +2258,6 @@ var AppInfo = {}; deps.push('scripts/search'); deps.push('scripts/librarylist'); deps.push('scripts/alphapicker'); - deps.push('scripts/playlistmanager'); deps.push('scripts/sync'); deps.push('scripts/backdrops'); deps.push('scripts/librarymenu'); @@ -2279,7 +2281,6 @@ var AppInfo = {}; postInitDependencies.push('scripts/remotecontrol'); postInitDependencies.push('css!css/notifications.css'); postInitDependencies.push('css!css/chromecast.css'); - postInitDependencies.push('apiclient-deferred'); if (Dashboard.isRunningInCordova()) {