diff --git a/src/assets/css/librarybrowser.css b/src/assets/css/librarybrowser.css index 88598fb94d..460585ae61 100644 --- a/src/assets/css/librarybrowser.css +++ b/src/assets/css/librarybrowser.css @@ -24,10 +24,6 @@ padding-top: 7em !important; } -.layout-mobile .libraryPage { - padding-top: 4em !important; -} - .itemDetailPage { padding-top: 0 !important; } @@ -164,6 +160,7 @@ display: flex; flex-direction: column; contain: layout style paint; + transition: background ease-in-out 0.5s; } .hiddenViewMenuBar .skinHeader { @@ -438,12 +435,14 @@ background-repeat: no-repeat; background-position: center; background-attachment: fixed; - height: 50vh; + height: 40vh; position: relative; + animation: backdrop-fadein 800ms ease-in normal both; } .layout-mobile .itemBackdrop { background-attachment: scroll; + height: 26.5vh; } .layout-desktop .itemBackdrop::after, @@ -463,10 +462,20 @@ .detailPageContent { display: flex; flex-direction: column; - padding-left: 2%; + padding-left: 32.45vw; padding-right: 2%; } +.layout-mobile .detailPageContent { + padding-left: 5%; + padding-right: 5%; +} + +.layout-desktop .detailPageContent .emby-scroller, +.layout-tv .detailPageContent .emby-scroller { + margin-left: 0; +} + .layout-desktop .noBackdrop .detailPageContent, .layout-tv .noBackdrop .detailPageContent { margin-top: 2.5em; @@ -477,6 +486,10 @@ margin-top: 0; } +.detailSectionContent a { + color: inherit; +} + .personBackdrop { background-size: contain; } @@ -495,7 +508,23 @@ .parentName { display: block; - margin-bottom: 0.5em; + margin: 0 0 0; +} + +.layout-mobile .parentName { + margin: 0.6em 0 0; +} + +.musicParentName { + margin: 0.15em 0 0.2em; +} + +.layout-mobile .musicParentName { + margin: -0.25em 0 0.25em; +} + +.layout-mobile .itemExternalLinks { + display: none; } .mainDetailButtons { @@ -503,8 +532,6 @@ -webkit-box-align: center; -webkit-align-items: center; align-items: center; - -webkit-flex-wrap: wrap; - flex-wrap: wrap; margin: 1em 0; } @@ -520,6 +547,35 @@ font-weight: 600; } +.itemName.originalTitle { + margin: 0.2em 0 0.2em; +} + +.itemName.parentNameLast { + margin: 0 0 0; +} + +.layout-mobile .itemName.parentNameLast { + margin: 0.4em 0 0.4em; +} + +.layout-mobile h1.itemName, +.layout-mobile h1.parentName { + font-size: 1.6em; +} + +.itemName.parentNameLast.withOriginalTitle { + margin: 0 0 0; +} + +.layout-mobile .itemName.parentNameLast.withOriginalTitle { + margin: 0.6em 0 0; +} + +.layout-mobile .itemName.originalTitle { + margin: 0.5em 0 0.5em; +} + .nameContainer { display: flex; flex-direction: column; @@ -546,6 +602,19 @@ text-align: center; } +.layout-mobile .mainDetailButtons { + margin-top: 1em; + margin-bottom: 0.5em; +} + +.subtitle { + margin: 0.15em 0 0.2em; +} + +.layout-mobile .subtitle { + margin: 0.2em 0 0.2em; +} + .detailPagePrimaryContainer { display: flex; align-items: center; @@ -556,7 +625,7 @@ .layout-mobile .detailPagePrimaryContainer { display: block; position: relative; - top: 0; + padding: 0.5em 3.3% 0.5em; } .layout-tv #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer, @@ -566,13 +635,14 @@ padding-left: 32.45vw; } -.layout-desktop .detailSticky, -.layout-tv .detailSticky { +.layout-desktop .detailRibbon, +.layout-tv .detailRibbon { margin-top: -7.2em; + height: 7.18em; } -.layout-desktop .noBackdrop .detailSticky, -.layout-tv .noBackdrop .detailSticky { +.layout-desktop .noBackdrop .detailRibbon, +.layout-tv .noBackdrop .detailRibbon { margin-top: 0; } @@ -584,6 +654,9 @@ white-space: nowrap; text-overflow: ellipsis; text-align: left; + min-width: 0; + max-width: 100%; + overflow: hidden; } .layout-mobile .infoText { @@ -594,13 +667,29 @@ margin: 1.25em 0; } -.detailImageContainer { - position: relative; - margin-top: -25vh; - margin-bottom: 10vh; +.layout-mobile .detailPageSecondaryContainer { + margin: 1em 0; +} + +.layout-mobile .detailImageContainer { + display: none; +} + +.detailImageContainer .card { + position: absolute; + top: 50%; float: left; width: 25vw; z-index: 3; + transform: translateY(-50%); +} + +.detailImageContainer .card.backdropCard { + top: 35%; +} + +.detailImageContainer .card.squareCard { + top: 40%; } .layout-desktop .noBackdrop .detailImageContainer, @@ -613,11 +702,11 @@ } .detailLogo { - width: 30vw; - height: 25vh; + width: 25vw; + height: 16vh; position: absolute; top: 10vh; - right: 20vw; + right: 25vw; background-size: contain; } @@ -657,14 +746,19 @@ div.itemDetailGalleryLink.defaultCardBackground { position: relative; } - .layout-desktop .detailPageWrapperContainer, - .layout-tv .detailPageWrapperContainer { - margin-top: 7.2em; + .layout-desktop .itemBackdrop, + .layout-tv .itemBackdrop { + height: 40vh; } - .layout-tv #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer, - .layout-desktop #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer { - padding-left: 3.3%; + .layout-desktop .detailPageWrapperContainer, + .layout-tv .detailPageWrapperContainer { + margin-top: 0.1em; + } + + .layout-desktop .detailImageContainer .card, + .layout-tv .detailImageContainer .card { + top: 10%; } .btnPlaySimple { @@ -680,12 +774,12 @@ div.itemDetailGalleryLink.defaultCardBackground { .emby-button.detailFloatingButton { position: absolute; - background-color: rgba(0, 0, 0, 0.5) !important; - z-index: 1; - top: 50%; - left: 50%; + background-color: rgba(0, 0, 0, 0.5); + z-index: 3; + top: 100%; + left: 90%; margin: -2.2em 0 0 -2.2em; - padding: 0.4em !important; + padding: 0.4em; color: rgba(255, 255, 255, 0.76); } @@ -695,16 +789,12 @@ div.itemDetailGalleryLink.defaultCardBackground { @media all and (max-width: 62.5em) { .parentName { - margin-bottom: 1em; + margin-bottom: 0; } .itemDetailPage { padding-top: 0 !important; } - - .detailimg-hidemobile { - display: none; - } } @media all and (min-width: 31.25em) { @@ -868,6 +958,10 @@ div.itemDetailGalleryLink.defaultCardBackground { } } +.detailVerticalSection .emby-scrollbuttons { + padding-top: 0.4em; +} + .layout-tv .detailVerticalSection { margin-bottom: 3.4em !important; } @@ -956,6 +1050,10 @@ div.itemDetailGalleryLink.defaultCardBackground { margin-bottom: 2.7em; } +.layout-mobile .verticalSection-extrabottompadding { + margin-bottom: 1em; +} + .sectionTitleButton, .sectionTitleIconButton { margin-right: 0 !important; @@ -981,7 +1079,13 @@ div.itemDetailGalleryLink.defaultCardBackground { div:not(.sectionTitleContainer-cards) > .sectionTitle-cards { margin: 0; - padding-top: 1.25em; + padding-top: 0.5em; + padding-bottom: 0.2em; +} + +.layout-mobile :not(.sectionTitleContainer-cards) > .sectionTitle-cards { + margin: 0; + padding-top: 0.5em; } .sectionTitleButton { @@ -1134,6 +1238,12 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards { .trackSelections .selectContainer .selectLabel { margin: 0 0.2em 0 0; + line-height: 1.75; +} + +.layout-mobile .detailsGroupItem .label, +.layout-mobile .trackSelections .selectContainer .selectLabel { + flex-basis: 4.5em; } .trackSelections .selectContainer .detailTrackSelect { diff --git a/src/components/actionSheet/actionSheet.js b/src/components/actionSheet/actionSheet.js index c56f42a9d9..2e22111945 100644 --- a/src/components/actionSheet/actionSheet.js +++ b/src/components/actionSheet/actionSheet.js @@ -16,7 +16,7 @@ function getOffsets(elems) { return results; } - for (let elem of elems) { + for (const elem of elems) { let box = elem.getBoundingClientRect(); results.push({ @@ -135,7 +135,7 @@ export function show(options) { let renderIcon = false; let icons = []; let itemIcon; - for (let item of options.items) { + for (const item of options.items) { itemIcon = item.icon || (item.selected ? 'check' : null); diff --git a/src/components/cardbuilder/cardBuilder.js b/src/components/cardbuilder/cardBuilder.js index 52d5ed202a..6b37e023b9 100644 --- a/src/components/cardbuilder/cardBuilder.js +++ b/src/components/cardbuilder/cardBuilder.js @@ -1310,7 +1310,7 @@ import 'programStyles'; } const mediaSourceCount = item.MediaSourceCount || 1; - if (mediaSourceCount > 1) { + if (mediaSourceCount > 1 && options.disableIndicators !== true) { innerCardFooter += '
' + mediaSourceCount + '
'; } @@ -1391,34 +1391,36 @@ import 'programStyles'; cardBoxClose = ''; cardScalableClose = ''; - let indicatorsHtml = ''; + if (options.disableIndicators !== true) { + let indicatorsHtml = ''; - if (options.missingIndicator !== false) { - indicatorsHtml += indicators.getMissingIndicator(item); - } + if (options.missingIndicator !== false) { + indicatorsHtml += indicators.getMissingIndicator(item); + } - indicatorsHtml += indicators.getSyncIndicator(item); - indicatorsHtml += indicators.getTimerIndicator(item); + indicatorsHtml += indicators.getSyncIndicator(item); + indicatorsHtml += indicators.getTimerIndicator(item); - indicatorsHtml += indicators.getTypeIndicator(item); + indicatorsHtml += indicators.getTypeIndicator(item); - if (options.showGroupCount) { + if (options.showGroupCount) { - indicatorsHtml += indicators.getChildCountIndicatorHtml(item, { - minCount: 1 - }); - } else { - indicatorsHtml += indicators.getPlayedIndicatorHtml(item); - } + indicatorsHtml += indicators.getChildCountIndicatorHtml(item, { + minCount: 1 + }); + } else { + indicatorsHtml += indicators.getPlayedIndicatorHtml(item); + } - if (item.Type === 'CollectionFolder' || item.CollectionType) { - const refreshClass = item.RefreshProgress ? '' : ' class="hide"'; - indicatorsHtml += '
'; - requireRefreshIndicator(); - } + if (item.Type === 'CollectionFolder' || item.CollectionType) { + const refreshClass = item.RefreshProgress ? '' : ' class="hide"'; + indicatorsHtml += '
'; + requireRefreshIndicator(); + } - if (indicatorsHtml) { - cardImageContainerOpen += '
' + indicatorsHtml + '
'; + if (indicatorsHtml) { + cardImageContainerOpen += '
' + indicatorsHtml + '
'; + } } if (!imgUrl) { @@ -1467,7 +1469,7 @@ import 'programStyles'; let additionalCardContent = ''; if (layoutManager.desktop) { - additionalCardContent += getHoverMenuHtml(item, action); + additionalCardContent += getHoverMenuHtml(item, action, options); } return '<' + tagName + ' data-index="' + index + '"' + timerAttributes + actionAttribute + ' data-isfolder="' + (item.IsFolder || false) + '" data-serverid="' + (item.ServerId || options.serverId) + '" data-id="' + (item.Id || item.ItemId) + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + positionTicksData + collectionIdData + playlistIdData + contextData + parentIdData + ' data-prefix="' + prefix + '" class="' + className + '">' + cardImageContainerOpen + innerCardFooter + cardImageContainerClose + overlayButtons + additionalCardContent + cardScalableClose + outerCardFooter + cardBoxClose + ''; @@ -1477,9 +1479,10 @@ import 'programStyles'; * Generates HTML markup for the card overlay. * @param {object} item - Item used to generate the card overlay. * @param {string} action - Action assigned to the overlay. + * @param {Array} options - Card builder options. * @returns {string} HTML markup of the card overlay. */ - function getHoverMenuHtml(item, action) { + function getHoverMenuHtml(item, action, options) { let html = ''; html += '
'; @@ -1494,12 +1497,12 @@ import 'programStyles'; const userData = item.UserData || {}; - if (itemHelper.canMarkPlayed(item)) { + if (itemHelper.canMarkPlayed(item) && !options.disableHoverMenu) { require(['emby-playstatebutton']); html += ''; } - if (itemHelper.canRate(item)) { + if (itemHelper.canRate(item) && !options.disableHoverMenu) { const likes = userData.Likes == null ? '' : userData.Likes; @@ -1507,7 +1510,9 @@ import 'programStyles'; html += ''; } - html += ''; + if (!options.disableHoverMenu) { + html += ''; + } html += '
'; html += ''; diff --git a/src/components/groupedcards.js b/src/components/groupedcards.js index 602c4310f4..5f23d8bb18 100644 --- a/src/components/groupedcards.js +++ b/src/components/groupedcards.js @@ -22,7 +22,7 @@ define(['dom', 'appRouter', 'connectionManager'], function (dom, appRouter, conn return void appRouter.showItem(items[0]); } - var url = 'itemdetails.html?id=' + itemId + '&serverId=' + serverId; + var url = 'details?id=' + itemId + '&serverId=' + serverId; Dashboard.navigate(url); }); e.stopPropagation(); diff --git a/src/components/images/imageLoader.js b/src/components/images/imageLoader.js index f7183515c5..ddf1183797 100644 --- a/src/components/images/imageLoader.js +++ b/src/components/images/imageLoader.js @@ -212,8 +212,15 @@ import 'css!./style'; } } + export function setLazyImage(element, url) { + element.classList.add('lazy'); + element.setAttribute('data-src', url); + lazyImage(element); + } + /* eslint-enable indent */ export default { + serLazyImage: setLazyImage, fillImages: fillImages, fillImage: fillImage, lazyImage: lazyImage, diff --git a/src/components/itemHelper.js b/src/components/itemHelper.js index b18f37110c..3508866bdb 100644 --- a/src/components/itemHelper.js +++ b/src/components/itemHelper.js @@ -1,14 +1,12 @@ define(['apphost', 'globalize'], function (appHost, globalize) { 'use strict'; - function getDisplayName(item, options) { + function getDisplayName(item, options = {}) { if (!item) { throw new Error('null item passed into getDisplayName'); } - options = options || {}; - if (item.Type === 'Timer') { item = item.ProgramInfo || item; } diff --git a/src/components/listview/listview.js b/src/components/listview/listview.js index 42f32ba794..b2fa2d6971 100644 --- a/src/components/listview/listview.js +++ b/src/components/listview/listview.js @@ -125,10 +125,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan var largeTitleTagName = layoutManager.tv ? 'h2' : 'div'; - for (var i = 0, length = textlines.length; i < length; i++) { - - var text = textlines[i]; - + for (const [i, text] of textlines.entries()) { if (!text) { continue; } @@ -434,8 +431,6 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan html += '
'; - const moreIcon = 'more_vert'; - html += getTextLinesHtml(textlines, isLargeStyle); if (options.mediaInfo !== false) { @@ -486,10 +481,6 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan html += ''; } - if (options.moreButton !== false) { - html += ''; - } - if (options.infoButton) { html += ''; } @@ -503,14 +494,18 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan var userData = item.UserData || {}; var likes = userData.Likes == null ? '' : userData.Likes; - if (itemHelper.canMarkPlayed(item)) { + if (itemHelper.canMarkPlayed(item) && options.enablePlayedButton !== false) { html += ''; } - if (itemHelper.canRate(item)) { + if (itemHelper.canRate(item) && options.enableRatingButton !== false) { html += ''; } } + + if (options.moreButton !== false) { + html += ''; + } } html += '
'; diff --git a/src/components/mediainfo/mediainfo.css b/src/components/mediainfo/mediainfo.css index 1883b78726..508c9d96ad 100644 --- a/src/components/mediainfo/mediainfo.css +++ b/src/components/mediainfo/mediainfo.css @@ -41,6 +41,8 @@ width: auto !important; height: auto !important; font-size: 1.4em; + margin-right: 0.125em; + color: #f2b01e; } .mediaInfoCriticRating { diff --git a/src/components/remotecontrol/remotecontrol.js b/src/components/remotecontrol/remotecontrol.js index b1d7471331..d620ea5d1e 100644 --- a/src/components/remotecontrol/remotecontrol.js +++ b/src/components/remotecontrol/remotecontrol.js @@ -122,10 +122,10 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL var artistName; if (item.ArtistItems != null) { artistName = item.ArtistItems[0].Name; - context.querySelector('.nowPlayingAlbum').innerHTML = '${albumName}`; - context.querySelector('.nowPlayingArtist').innerHTML = '${artistName}`; - context.querySelector('.contextMenuAlbum').innerHTML = ' ` + globalize.translate('ViewAlbum') + ''; - context.querySelector('.contextMenuArtist').innerHTML = ' ` + globalize.translate('ViewArtist') + ''; + context.querySelector('.nowPlayingAlbum').innerHTML = '${albumName}`; + context.querySelector('.nowPlayingArtist').innerHTML = '${artistName}`; + context.querySelector('.contextMenuAlbum').innerHTML = ' ` + globalize.translate('ViewAlbum') + ''; + context.querySelector('.contextMenuArtist').innerHTML = ' ` + globalize.translate('ViewArtist') + ''; } else { artistName = item.Artists; context.querySelector('.nowPlayingAlbum').innerHTML = albumName; @@ -136,12 +136,12 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL } else if (item.Type == 'Episode') { if (item.SeasonName != null) { var seasonName = item.SeasonName; - context.querySelector('.nowPlayingSeason').innerHTML = '${seasonName}`; + context.querySelector('.nowPlayingSeason').innerHTML = '${seasonName}`; } if (item.SeriesName != null) { var seriesName = item.SeriesName; if (item.SeriesId != null) { - context.querySelector('.nowPlayingSerie').innerHTML = '${seriesName}`; + context.querySelector('.nowPlayingSerie').innerHTML = '${seriesName}`; } else { context.querySelector('.nowPlayingSerie').innerHTML = seriesName; } diff --git a/src/itemdetails.html b/src/controllers/itemDetails/index.html similarity index 73% rename from src/itemdetails.html rename to src/controllers/itemDetails/index.html index 44ca561d40..ddb7be3aec 100644 --- a/src/itemdetails.html +++ b/src/controllers/itemDetails/index.html @@ -1,8 +1,5 @@ -
+
-
@@ -15,94 +12,75 @@
- - - - - - - - - - - - - -
@@ -110,7 +88,7 @@
-
+
@@ -124,6 +102,11 @@
+ +
+
+
+
@@ -164,15 +147,15 @@
-

${HeaderSchedule}

-
+

${HeaderSchedule}

+
-
+
-

${HeaderNextUp}

-
+

${HeaderNextUp}

+
@@ -180,64 +163,64 @@
-

+

-
+
-

${HeaderAdditionalParts}

-
+

${HeaderAdditionalParts}

+
-
-

+
+

-
-

+
+

-

${HeaderCastCrew}

+

${HeaderCastCrew}

-

${HeaderUpcomingOnTV}

-
+

${HeaderUpcomingOnTV}

+
-

${HeaderSpecialFeatures}

-
+

${HeaderSpecialFeatures}

+
-

${HeaderMusicVideos}

-
+

${HeaderMusicVideos}

+
-
-

${HeaderScenes}

+
+

${HeaderScenes}

-
-

${HeaderMoreLikeThis}

+
+

${HeaderMoreLikeThis}

diff --git a/src/controllers/itemDetails.js b/src/controllers/itemDetails/index.js similarity index 83% rename from src/controllers/itemDetails.js rename to src/controllers/itemDetails/index.js index c9b6b7fc1c..45c43c19be 100644 --- a/src/controllers/itemDetails.js +++ b/src/controllers/itemDetails/index.js @@ -28,15 +28,11 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti } function hideAll(page, className, show) { - var i; - var length; - var elems = page.querySelectorAll('.' + className); - - for (i = 0, length = elems.length; i < length; i++) { + for (const elem of page.querySelectorAll('.' + className)) { if (show) { - elems[i].classList.remove('hide'); + elem.classList.remove('hide'); } else { - elems[i].classList.add('hide'); + elem.classList.add('hide'); } } } @@ -51,7 +47,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti positionTo: button, cancelTimer: false, record: false, - deleteItem: true === item.IsFolder, + deleteItem: item.CanDelete === true, shuffle: false, instantMix: false, user: user, @@ -75,7 +71,9 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti moreButton: false, recordButton: false }); - return html += '
'; + html += '
'; + + return html; } function renderSeriesTimerSchedule(page, apiClient, seriesTimerId) { @@ -143,9 +141,13 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti var mediaSources = item.MediaSources; instance._currentPlaybackMediaSources = mediaSources; + page.querySelector('.trackSelections').classList.remove('hide'); + select.setLabel(globalize.translate('LabelVersion')); + var currentValue = select.value; + var selectedId = mediaSources[0].Id; select.innerHTML = mediaSources.map(function (v) { var selected = v.Id === selectedId ? ' selected' : ''; @@ -172,7 +174,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti return m.Id === mediaSourceId; })[0]; var tracks = mediaSource.MediaStreams.filter(function (m) { - return 'Video' === m.Type; + return m.Type === 'Video'; }); var select = page.querySelector('.selectVideo'); select.setLabel(globalize.translate('LabelVideo')); @@ -242,12 +244,24 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti select.setLabel(globalize.translate('LabelSubtitles')); var selectedId = null == mediaSource.DefaultSubtitleStreamIndex ? -1 : mediaSource.DefaultSubtitleStreamIndex; - if (tracks.length) { + var videoTracks = mediaSource.MediaStreams.filter(function (m) { + return 'Video' === m.Type; + }); + + // This only makes sence on Video items + if (videoTracks.length) { var selected = -1 === selectedId ? ' selected' : ''; select.innerHTML = '' + tracks.map(function (v) { selected = v.Index === selectedId ? ' selected' : ''; return ''; }).join(''); + + if (tracks.length > 1) { + select.removeAttribute('disabled'); + } else { + select.setAttribute('disabled', 'disabled'); + } + page.querySelector('.selectSubtitlesContainer').classList.remove('hide'); } else { select.innerHTML = ''; @@ -278,7 +292,15 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti var enableShuffle = item.IsFolder || -1 !== ['MusicAlbum', 'MusicGenre', 'MusicArtist'].indexOf(item.Type); hideAll(page, 'btnShuffle', enableShuffle); canPlay = true; - hideAll(page, 'btnResume', item.UserData && item.UserData.PlaybackPositionTicks > 0); + + const isResumable = item.UserData && item.UserData.PlaybackPositionTicks > 0; + hideAll(page, 'btnResume', isResumable); + + if (isResumable) { + for (const elem of page.querySelectorAll('.btnPlay')) { + elem.querySelector('.detailButton-icon').classList.replace('play_arrow', 'replay'); + } + } } else { hideAll(page, 'btnPlay'); hideAll(page, 'btnResume'); @@ -324,8 +346,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti function getArtistLinksHtml(artists, serverId, context) { var html = []; - for (var i = 0, length = artists.length; i < length; i++) { - var artist = artists[i]; + for (const artist of artists) { var href = appRouter.getRouteUrl(artist, { context: context, itemType: 'MusicArtist', @@ -333,10 +354,18 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti }); html.push('' + artist.Name + ''); } + html = html.join(' / '); - return html = html.join(' / '); + return html; } - function renderName(item, container, isStatic, context) { + + /** + * Renders the item's name block + * @param {Object} item - Item used to render the name. + * @param {HTMLDivElement} container - Container to render the information into. + * @param {Object} context - Application context. + */ + function renderName(item, container, context) { var parentRoute; var parentNameHtml = []; var parentNameLast = false; @@ -410,16 +439,12 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti if (parentNameLast) { // Music if (layoutManager.mobile) { - html = '

' + parentNameHtml.join('
') + '

'; + html = '

' + parentNameHtml.join('
') + '

'; } else { - html = '

' + parentNameHtml.join(' - ') + '

'; + html = '

' + parentNameHtml.join(' - ') + '

'; } } else { - if (layoutManager.mobile) { - html = '

' + parentNameHtml.join('
') + '

'; - } else { - html = '

' + tvShowHtml + '

'; - } + html = '

' + tvShowHtml + '

'; } } @@ -428,17 +453,19 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti }); if (html && !parentNameLast) { - if (!layoutManager.mobile && tvSeasonHtml) { - html += '

' + tvSeasonHtml + ' - ' + name + '

'; + if (tvSeasonHtml) { + html += '

' + tvSeasonHtml + ' - ' + name + '

'; } else { - html += '

' + name + '

'; + html += '

' + name + '

'; } + } else if (item.OriginalTitle && item.OriginalTitle != item.Name) { + html = '

' + name + '

' + html; } else { - html = '

' + name + '

' + html; + html = '

' + name + '

' + html; } if (item.OriginalTitle && item.OriginalTitle != item.Name) { - html += '

' + item.OriginalTitle + '

'; + html += '

' + item.OriginalTitle + '

'; } container.innerHTML = html; @@ -470,43 +497,18 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti var imgUrl; var hasbackdrop = false; var itemBackdropElement = page.querySelector('#itemBackdrop'); - var usePrimaryImage = item.MediaType === 'Video' && item.Type !== 'Movie' && item.Type !== 'Trailer' || - item.MediaType && item.MediaType !== 'Video' || - item.Type === 'MusicAlbum' || - item.Type === 'Person'; if (!layoutManager.mobile && !userSettings.detailsBanner()) { return false; } - if ('Program' === item.Type && item.ImageTags && item.ImageTags.Thumb) { - imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: 'Thumb', - maxWidth: dom.getScreenWidth(), - index: 0, - tag: item.ImageTags.Thumb - }); - page.classList.remove('noBackdrop'); - imageLoader.lazyImage(itemBackdropElement, imgUrl); - hasbackdrop = true; - } else if (usePrimaryImage && item.ImageTags && item.ImageTags.Primary) { - imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: 'Primary', - maxWidth: dom.getScreenWidth(), - index: 0, - tag: item.ImageTags.Primary - }); - page.classList.remove('noBackdrop'); - imageLoader.lazyImage(itemBackdropElement, imgUrl); - hasbackdrop = true; - } else if (item.BackdropImageTags && item.BackdropImageTags.length) { + if (item.BackdropImageTags && item.BackdropImageTags.length) { imgUrl = apiClient.getScaledImageUrl(item.Id, { type: 'Backdrop', maxWidth: dom.getScreenWidth(), index: 0, tag: item.BackdropImageTags[0] }); - page.classList.remove('noBackdrop'); imageLoader.lazyImage(itemBackdropElement, imgUrl); hasbackdrop = true; } else if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) { @@ -516,50 +518,35 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti index: 0, tag: item.ParentBackdropImageTags[0] }); - page.classList.remove('noBackdrop'); - imageLoader.lazyImage(itemBackdropElement, imgUrl); - hasbackdrop = true; - } else if (item.ImageTags && item.ImageTags.Thumb) { - imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: 'Thumb', - maxWidth: dom.getScreenWidth(), - index: 0, - tag: item.ImageTags.Thumb - }); - page.classList.remove('noBackdrop'); imageLoader.lazyImage(itemBackdropElement, imgUrl); hasbackdrop = true; } else { itemBackdropElement.style.backgroundImage = ''; } - if ('Person' === item.Type) { - // FIXME: This hides the backdrop on all persons to fix a margin issue. Ideally, a proper fix should be made. - page.classList.add('noBackdrop'); - itemBackdropElement.classList.add('personBackdrop'); - } else { - itemBackdropElement.classList.remove('personBackdrop'); - } - return hasbackdrop; } function reloadFromItem(instance, page, params, item, user) { - var context = params.context; - page.querySelector('.detailPagePrimaryContainer').classList.add('detailSticky'); + const apiClient = connectionManager.getApiClient(item.ServerId); - renderName(item, page.querySelector('.nameContainer'), false, context); - var apiClient = connectionManager.getApiClient(item.ServerId); - renderSeriesTimerEditor(page, item, apiClient, user); - renderTimerEditor(page, item, apiClient, user); - renderImage(page, item, apiClient, user); - renderLogo(page, item, apiClient); Emby.Page.setTitle(''); - setInitialCollapsibleState(page, item, apiClient, context, user); - renderDetails(page, item, apiClient, context); - renderTrackSelections(page, instance, item); + + // Start rendering the artwork first + renderImage(page, item); + renderLogo(page, item, apiClient); renderBackdrop(item); renderDetailPageBackdrop(page, item, apiClient); + + // Render the main information for the item + page.querySelector('.detailPagePrimaryContainer').classList.add('detailRibbon'); + renderName(item, page.querySelector('.nameContainer'), params.context); + renderDetails(page, item, apiClient, params.context); + renderTrackSelections(page, instance, item); + + renderSeriesTimerEditor(page, item, apiClient, user); + renderTimerEditor(page, item, apiClient, user); + setInitialCollapsibleState(page, item, apiClient, params.context, user); var canPlay = reloadPlayButtons(page, item); if ((item.LocalTrailerCount || item.RemoteTrailers && item.RemoteTrailers.length) && -1 !== playbackManager.getSupportedCommands().indexOf('PlayTrailers')) { @@ -570,12 +557,6 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti setTrailerButtonVisibility(page, item); - if (item.CanDelete && !item.IsFolder) { - hideAll(page, 'btnDeleteItem', true); - } else { - hideAll(page, 'btnDeleteItem'); - } - if ('Program' !== item.Type || canPlay) { hideAll(page, 'mainDetailButtons', true); } else { @@ -667,18 +648,15 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti } function renderLogo(page, item, apiClient) { - var url = logoImageUrl(item, apiClient, { - maxWidth: 400 - }); var detailLogo = page.querySelector('.detailLogo'); + var url = logoImageUrl(item, apiClient, {}); + if (!layoutManager.mobile && !userSettings.enableBackdrops()) { detailLogo.classList.add('hide'); } else if (url) { detailLogo.classList.remove('hide'); - detailLogo.classList.add('lazy'); - detailLogo.setAttribute('data-src', url); - imageLoader.lazyImage(detailLogo); + imageLoader.setLazyImage(detailLogo, url); } else { detailLogo.classList.add('hide'); } @@ -704,172 +682,60 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti } } - function renderLinks(linksElem, item) { - var html = []; + function renderLinks(page, item) { + var externalLinksElem = page.querySelector('.itemExternalLinks'); var links = []; if (!layoutManager.tv && item.HomePageUrl) { - links.push('' + globalize.translate('ButtonWebsite') + ''); + 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 + ''); + for (const url of item.ExternalUrls) { + links.push(`${url.Name}`); } } + var html = []; if (links.length) { html.push(links.join(', ')); } - linksElem.innerHTML = html.join(', '); + externalLinksElem.innerHTML = html.join(', '); if (html.length) { - linksElem.classList.remove('hide'); + externalLinksElem.classList.remove('hide'); } else { - linksElem.classList.add('hide'); + externalLinksElem.classList.add('hide'); } } - function renderDetailImage(page, elem, item, apiClient, editable, imageLoader, indicators) { - if ('SeriesTimer' === item.Type || 'Program' === item.Type) { - editable = false; - } + function renderDetailImage(elem, item, imageLoader) { + const itemArray = []; + itemArray.push(item); + const cardHtml = cardBuilder.getCardsHtml(itemArray, { + shape: 'auto', + showTitle: false, + centerText: true, + overlayText: false, + transition: false, + disableIndicators: true, + disableHoverMenu: true, + overlayPlayButton: true, + width: dom.getWindowSize().innerWidth * 0.25 + }); - elem.classList.add('detailimg-hidemobile'); + elem.innerHTML = cardHtml; - var imageTags = item.ImageTags || {}; - - if (item.PrimaryImageTag) { - imageTags.Primary = item.PrimaryImageTag; - } - - var url; - var html = ''; - var shape = 'portrait'; - var detectRatio = false; - - /* In the following section, getScreenWidth() is multiplied by 0.5 as the posters - are 25vw and we need double the resolution to counter Skia's scaling. */ - // TODO: Find a reliable way to get the poster width - if (imageTags.Primary) { - url = apiClient.getScaledImageUrl(item.Id, { - type: 'Primary', - maxWidth: Math.round(dom.getScreenWidth() * 0.5), - tag: item.ImageTags.Primary - }); - detectRatio = true; - } else if (item.BackdropImageTags && item.BackdropImageTags.length) { - url = apiClient.getScaledImageUrl(item.Id, { - type: 'Backdrop', - maxWidth: Math.round(dom.getScreenWidth() * 0.5), - tag: item.BackdropImageTags[0] - }); - shape = 'thumb'; - } else if (imageTags.Thumb) { - url = apiClient.getScaledImageUrl(item.Id, { - type: 'Thumb', - maxWidth: Math.round(dom.getScreenWidth() * 0.5), - tag: item.ImageTags.Thumb - }); - shape = 'thumb'; - } else if (imageTags.Disc) { - url = apiClient.getScaledImageUrl(item.Id, { - type: 'Disc', - maxWidth: Math.round(dom.getScreenWidth() * 0.5), - tag: item.ImageTags.Disc - }); - shape = 'square'; - } else if (item.AlbumId && item.AlbumPrimaryImageTag) { - url = apiClient.getScaledImageUrl(item.AlbumId, { - type: 'Primary', - maxWidth: Math.round(dom.getScreenWidth() * 0.5), - tag: item.AlbumPrimaryImageTag - }); - shape = 'square'; - } else if (item.SeriesId && item.SeriesPrimaryImageTag) { - url = apiClient.getScaledImageUrl(item.SeriesId, { - type: 'Primary', - maxWidth: Math.round(dom.getScreenWidth() * 0.5), - tag: item.SeriesPrimaryImageTag - }); - } else if (item.ParentPrimaryImageItemId && item.ParentPrimaryImageTag) { - url = apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, { - type: 'Primary', - maxWidth: Math.round(dom.getScreenWidth() * 0.5), - tag: item.ParentPrimaryImageTag - }); - } - - if (editable && url === undefined) { - html += ""; - } else if (!editable && url === undefined) { - html += "'; - } - - var progressHtml = item.IsFolder || !item.UserData ? '' : indicators.getProgressBarHtml(item); - html += '
'; - - if (progressHtml) { - html += progressHtml; - } - - html += '
'; - elem.innerHTML = html; - - if (detectRatio && item.PrimaryImageAspectRatio) { - if (item.PrimaryImageAspectRatio >= 1.48) { - shape = 'thumb'; - } else if (item.PrimaryImageAspectRatio >= 0.85 && item.PrimaryImageAspectRatio <= 1.34) { - shape = 'square'; - } - } - - if ('thumb' == shape) { - elem.classList.add('thumbDetailImageContainer'); - elem.classList.remove('portraitDetailImageContainer'); - elem.classList.remove('squareDetailImageContainer'); - } else if ('square' == shape) { - 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'); - } - - if (url) { - imageLoader.lazyImage(elem.querySelector('img'), url); - } + imageLoader.lazyChildren(elem); } - function renderImage(page, item, apiClient, user) { + function renderImage(page, item) { renderDetailImage( - page, page.querySelector('.detailImageContainer'), item, - apiClient, - user.Policy.IsAdministrator && 'Photo' != item.MediaType, - imageLoader, - indicators + imageLoader ); } @@ -985,54 +851,41 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti } } - function renderOverview(elems, item) { - for (var i = 0, length = elems.length; i < length; i++) { - var elem = elems[i]; + function renderOverview(page, item) { + for (const overviewElemnt of page.querySelectorAll('.overview')) { var overview = item.Overview || ''; if (overview) { - elem.innerHTML = overview; - elem.classList.remove('hide'); - elem.classList.add('detail-clamp-text'); + overviewElemnt.innerHTML = overview; + overviewElemnt.classList.remove('hide'); + overviewElemnt.classList.add('detail-clamp-text'); // Grab the sibling element to control the expand state - var expandButton = elem.parentElement.querySelector('.overview-expand'); + var expandButton = overviewElemnt.parentElement.querySelector('.overview-expand'); // Detect if we have overflow of text. Based on this StackOverflow answer // https://stackoverflow.com/a/35157976 - if (Math.abs(elem.scrollHeight - elem.offsetHeight) > 2) { + if (Math.abs(overviewElemnt.scrollHeight - overviewElemnt.offsetHeight) > 2) { expandButton.classList.remove('hide'); } else { expandButton.classList.add('hide'); } - expandButton.addEventListener('click', toggleLineClamp.bind(null, elem)); + expandButton.addEventListener('click', toggleLineClamp.bind(null, overviewElemnt)); - var anchors = elem.querySelectorAll('a'); - - for (var j = 0, length2 = anchors.length; j < length2; j++) { - anchors[j].setAttribute('target', '_blank'); + for (const anchor of overviewElemnt.querySelectorAll('a')) { + anchor.setAttribute('target', '_blank'); } } else { - elem.innerHTML = ''; - elem.classList.add('hide'); + overviewElemnt.innerHTML = ''; + overviewElemnt.classList.add('hide'); } } } - function renderGenres(page, item, context) { - context = context || inferContext(item); - var type; + function renderGenres(page, item, context = inferContext(item)) { var genres = item.GenreItems || []; - - switch (context) { - case 'music': - type = 'MusicGenre'; - break; - - default: - type = 'Genre'; - } + var type = context === 'music' ? 'MusicGenre' : 'Genre'; var html = genres.map(function (p) { return '' + p.Name + ''; + }) + '">' + person.Name + ''; + }).join(', '); + + var writersLabel = page.querySelector('.writersLabel'); + writersLabel.innerHTML = globalize.translate(writers.length > 1 ? 'Writers' : 'Writer'); + var writersValue = page.querySelector('.writers'); + writersValue.innerHTML = html; + + var writersGroup = page.querySelector('.writersGroup'); + if (writers.length) { + writersGroup.classList.remove('hide'); + } else { + writersGroup.classList.add('hide'); + } + } + + function renderDirector(page, item, context) { + var directors = (item.People || []).filter(function (person) { + return person.Type === 'Director'; + }); + + var html = directors.map(function (person) { + return '' + person.Name + ''; }).join(', '); var directorsLabel = page.querySelector('.directorsLabel'); @@ -1086,13 +969,39 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti } } - function renderDetails(page, item, apiClient, context, isStatic) { - renderSimilarItems(page, item, context); - renderMoreFromSeason(page, item, apiClient); - renderMoreFromArtist(page, item, apiClient); - renderDirector(page, item, context); - renderGenres(page, item, context); - renderChannelGuide(page, apiClient, item); + function renderMiscInfo(page, item) { + const primaryItemMiscInfo = page.querySelectorAll('.itemMiscInfo-primary'); + + for (const miscInfo of primaryItemMiscInfo) { + mediaInfo.fillPrimaryMediaInfo(miscInfo, item, { + interactive: true, + episodeTitle: false, + subtitles: false + }); + + if (miscInfo.innerHTML && 'SeriesTimer' !== item.Type) { + miscInfo.classList.remove('hide'); + } else { + miscInfo.classList.add('hide'); + } + } + + const secondaryItemMiscInfo = page.querySelectorAll('.itemMiscInfo-secondary'); + + for (const miscInfo of secondaryItemMiscInfo) { + mediaInfo.fillSecondaryMediaInfo(miscInfo, item, { + interactive: true + }); + + if (miscInfo.innerHTML && 'SeriesTimer' !== item.Type) { + miscInfo.classList.remove('hide'); + } else { + miscInfo.classList.add('hide'); + } + } + } + + function renderTagline(page, item) { var taglineElement = page.querySelector('.tagline'); if (item.Taglines && item.Taglines.length) { @@ -1101,44 +1010,21 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti } else { taglineElement.classList.add('hide'); } + } - var overview = page.querySelector('.overview'); - var externalLinksElem = page.querySelector('.itemExternalLinks'); - - renderOverview([overview], item); - - var i; - var itemMiscInfo; - itemMiscInfo = page.querySelectorAll('.itemMiscInfo-primary'); - for (i = 0; i < itemMiscInfo.length; i++) { - mediaInfo.fillPrimaryMediaInfo(itemMiscInfo[i], item, { - interactive: true, - episodeTitle: false, - subtitles: false - }); - - if (itemMiscInfo[i].innerHTML && 'SeriesTimer' !== item.Type) { - itemMiscInfo[i].classList.remove('hide'); - } else { - itemMiscInfo[i].classList.add('hide'); - } - } - - itemMiscInfo = page.querySelectorAll('.itemMiscInfo-secondary'); - for (i = 0; i < itemMiscInfo.length; i++) { - mediaInfo.fillSecondaryMediaInfo(itemMiscInfo[i], item, { - interactive: true - }); - - if (itemMiscInfo[i].innerHTML && 'SeriesTimer' !== item.Type) { - itemMiscInfo[i].classList.remove('hide'); - } else { - itemMiscInfo[i].classList.add('hide'); - } - } - + function renderDetails(page, item, apiClient, context, isStatic) { + renderSimilarItems(page, item, context); + renderMoreFromSeason(page, item, apiClient); + renderMoreFromArtist(page, item, apiClient); + renderDirector(page, item, context); + renderWriter(page, item, context); + renderGenres(page, item, context); + renderChannelGuide(page, apiClient, item); + renderTagline(page, item); + renderOverview(page, item); + renderMiscInfo(page, item); reloadUserDataButtons(page, item); - renderLinks(externalLinksElem, item); + renderLinks(page, item); renderTags(page, item); renderSeriesAirTime(page, item, isStatic); } @@ -1426,8 +1312,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti action: 'playallfromhere', image: false, artist: 'auto', - containerAlbumArtists: item.AlbumArtists, - addToListButton: true + containerAlbumArtists: item.AlbumArtists }); isList = true; } else if ('Series' == item.Type) { @@ -1469,11 +1354,12 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti items: result.Items, showIndexNumber: false, enableOverview: true, + enablePlayedButton: layoutManager.mobile ? false : true, + infoButton: layoutManager.mobile ? false : true, imageSize: 'large', enableSideMediaInfo: false, highlight: false, action: layoutManager.tv ? 'resume' : 'none', - infoButton: true, imagePlayButton: true, includeParentInfoInTitle: false }); @@ -1500,6 +1386,9 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti childrenItemsContainer.classList.remove('vertical-list'); } } + if (layoutManager.mobile) { + childrenItemsContainer.classList.remove('padded-right'); + } childrenItemsContainer.innerHTML = html; imageLoader.lazyChildren(childrenItemsContainer); if ('BoxSet' == item.Type) { @@ -1701,12 +1590,10 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti } function renderCollectionItems(page, parentItem, types, items) { + page.querySelector('.collectionItems').classList.remove('hide'); page.querySelector('.collectionItems').innerHTML = ''; - var i; - var length; - for (i = 0, length = types.length; i < length; i++) { - var type = types[i]; + for (const type of types) { var typeItems = filterItemsByCollectionItemType(items, type); if (typeItems.length) { @@ -1739,8 +1626,8 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti renderChildren(page, parentItem); }; - for (i = 0, length = containers.length; i < length; i++) { - containers[i].notifyRefreshNeeded = notifyRefreshNeeded; + for (const container of containers) { + container.notifyRefreshNeeded = notifyRefreshNeeded; } // if nothing in the collection can be played hide play and shuffle buttons @@ -1876,7 +1763,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti function renderCast(page, item) { var people = (item.People || []).filter(function (p) { - return 'Director' !== p.Type; + return p.Type === 'Actor'; }); if (!people.length) { @@ -1905,12 +1792,10 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti } function bindAll(view, selector, eventName, fn) { - var i; - var length; var elems = view.querySelectorAll(selector); - for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener(eventName, fn); + for (const elem of elems) { + elem.addEventListener(eventName, fn); } } @@ -1923,13 +1808,14 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti return function (view, params) { function reload(instance, page, params) { loading.show(); + var apiClient = params.serverId ? connectionManager.getApiClient(params.serverId) : ApiClient; - var promises = [getPromise(apiClient, params), apiClient.getCurrentUser()]; - Promise.all(promises).then(function (responses) { - var item = responses[0]; - var user = responses[1]; + + Promise.all([getPromise(apiClient, params), apiClient.getCurrentUser()]).then(([item, user]) => { currentItem = item; reloadFromItem(instance, page, params, item, user); + }).catch((error) => { + console.error('failed to get item or current user: ', error); }); } @@ -1980,7 +1866,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti }); } - playItem(item, item.UserData && 'resume' === mode ? item.UserData.PlaybackPositionTicks : 0); + playItem(item, item.UserData && mode === 'resume' ? item.UserData.PlaybackPositionTicks : 0); } function onPlayClick() { @@ -1995,15 +1881,6 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti playbackManager.shuffle(currentItem); } - function onDeleteClick() { - require(['deleteHelper'], function (deleteHelper) { - deleteHelper.deleteItem({ - item: currentItem, - navigate: true - }); - }); - } - function onCancelSeriesTimerClick() { require(['recordingHelper'], function (recordingHelper) { recordingHelper.cancelSeriesTimerWithConfirmation(currentItem.Id, currentItem.ServerId).then(function () { @@ -2092,7 +1969,6 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti bindAll(view, '.btnPlayTrailer', 'click', onPlayTrailerClick); bindAll(view, '.btnCancelSeriesTimer', 'click', onCancelSeriesTimerClick); bindAll(view, '.btnCancelTimer', 'click', onCancelTimerClick); - bindAll(view, '.btnDeleteItem', 'click', onDeleteClick); bindAll(view, '.btnDownload', 'click', onDownloadClick); view.querySelector('.trackSelections').addEventListener('submit', onTrackSelectionsSubmit); view.querySelector('.btnSplitVersions').addEventListener('click', function () { @@ -2125,9 +2001,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti view.addEventListener('viewshow', function (e) { var page = this; - if (layoutManager.mobile) { - libraryMenu.setTransparentMenu(true); - } + libraryMenu.setTransparentMenu(true); if (e.detail.isRestored) { if (currentItem) { diff --git a/src/elements/emby-scrollbuttons/emby-scrollbuttons.css b/src/elements/emby-scrollbuttons/emby-scrollbuttons.css index b2e0d3bc23..5af739bac1 100644 --- a/src/elements/emby-scrollbuttons/emby-scrollbuttons.css +++ b/src/elements/emby-scrollbuttons/emby-scrollbuttons.css @@ -6,7 +6,7 @@ justify-content: center; min-width: 104px; min-height: 24px; - padding-top: 1.25em; + padding-top: 0.85em; z-index: 1; color: #fff; display: flex; diff --git a/src/scripts/dom.js b/src/scripts/dom.js index a3d157f337..080bff66ae 100644 --- a/src/scripts/dom.js +++ b/src/scripts/dom.js @@ -211,7 +211,7 @@ 'MozAnimation': 'animationend', 'WebkitAnimation': 'webkitAnimationEnd' }; - for (let t in animations) { + for (const t in animations) { if (el.style[t] !== undefined) { _animationEvent = animations[t]; return animations[t]; @@ -251,7 +251,7 @@ 'MozTransition': 'transitionend', 'WebkitTransition': 'webkitTransitionEnd' }; - for (let t in transitions) { + for (const t in transitions) { if (el.style[t] !== undefined) { _transitionEvent = transitions[t]; return transitions[t]; diff --git a/src/scripts/itembynamedetailpage.js b/src/scripts/itembynamedetailpage.js index 44eca55589..fd29724225 100644 --- a/src/scripts/itembynamedetailpage.js +++ b/src/scripts/itembynamedetailpage.js @@ -71,12 +71,12 @@ define(['connectionManager', 'listView', 'cardBuilder', 'imageLoader', 'libraryB html += '
'; html += '
'; - html += '

'; + html += '

'; html += section.name; html += '

'; html += ''; html += '
'; - html += '
'; + html += '
'; html += '
'; return html += '
'; }).join(''); diff --git a/src/scripts/routes.js b/src/scripts/routes.js index b5bb04683b..ab12b53abf 100644 --- a/src/scripts/routes.js +++ b/src/scripts/routes.js @@ -15,7 +15,7 @@ define([ 'detailtablecss'], function () { function defineRoute(newRoute) { - var path = newRoute.path; + var path = newRoute.alias ? newRoute.alias : newRoute.path; console.debug('defining route: ' + path); newRoute.dictionary = 'core'; Emby.Page.addRoute(path, newRoute); @@ -240,8 +240,9 @@ define([ transition: 'fade' }); defineRoute({ - path: '/itemdetails.html', - controller: 'itemDetails', + alias: '/details', + path: '/controllers/itemDetails/index.html', + controller: 'itemDetails/index', autoFocus: false, transition: 'fade' }); diff --git a/src/scripts/site.js b/src/scripts/site.js index 27818f34b2..ddadad4c80 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -1038,7 +1038,7 @@ var AppInfo = {}; } if ('SeriesTimer' == itemType) { - return 'itemdetails.html?seriesTimerId=' + id + '&serverId=' + serverId; + return 'details?seriesTimerId=' + id + '&serverId=' + serverId; } if ('livetv' == item.CollectionType) { @@ -1108,13 +1108,13 @@ var AppInfo = {}; var itemTypes = ['Playlist', 'TvChannel', 'Program', 'BoxSet', 'MusicAlbum', 'MusicGenre', 'Person', 'Recording', 'MusicArtist']; if (itemTypes.indexOf(itemType) >= 0) { - return 'itemdetails.html?id=' + id + '&serverId=' + serverId; + return 'details?id=' + id + '&serverId=' + serverId; } var contextSuffix = context ? '&context=' + context : ''; if ('Series' == itemType || 'Season' == itemType || 'Episode' == itemType) { - return 'itemdetails.html?id=' + id + contextSuffix + '&serverId=' + serverId; + return 'details?id=' + id + contextSuffix + '&serverId=' + serverId; } if (item.IsFolder) { @@ -1125,7 +1125,7 @@ var AppInfo = {}; return '#'; } - return 'itemdetails.html?id=' + id + '&serverId=' + serverId; + return 'details?id=' + id + '&serverId=' + serverId; }; appRouter.showItem = showItem; diff --git a/src/strings/en-us.json b/src/strings/en-us.json index a73167da79..acd038adb0 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -1535,6 +1535,7 @@ "Whitelist": "Whitelist", "WizardCompleted": "That's all we need for now. Jellyfin has begun collecting information about your media library. Check out some of our apps, and then click Finish to view the Dashboard.", "Writer": "Writer", + "Writers": "Writers", "XmlDocumentAttributeListHelp": "These attributes are applied to the root element of every XML response.", "XmlTvKidsCategoriesHelp": "Programs with these categories will be displayed as programs for children. Separate multiple with '|'.", "XmlTvMovieCategoriesHelp": "Programs with these categories will be displayed as movies. Separate multiple with '|'.", diff --git a/src/themes/appletv/theme.css b/src/themes/appletv/theme.css index bf6f6c2a51..0c7a462f02 100644 --- a/src/themes/appletv/theme.css +++ b/src/themes/appletv/theme.css @@ -227,7 +227,7 @@ html { color: #fff !important; } -.detailSticky { +.detailRibbon { background: #303030; background: -webkit-gradient(linear, left top, right top, from(#bcbcbc), color-stop(#a7b4b7), color-stop(#beb5a5), color-stop(#adbec2), to(#b9c7cb)); background: -webkit-linear-gradient(left, #bcbcbc, #a7b4b7, #beb5a5, #adbec2, #b9c7cb); @@ -257,11 +257,6 @@ html { background: #fff; } -.mediaInfoTimerIcon, -.starIcon { - color: #cb272a; -} - .emby-input, .emby-textarea { color: inherit; diff --git a/src/themes/blueradiance/theme.css b/src/themes/blueradiance/theme.css index 08ab576aa3..0d0446157f 100644 --- a/src/themes/blueradiance/theme.css +++ b/src/themes/blueradiance/theme.css @@ -223,7 +223,7 @@ html { color: #fff !important; } -.detailSticky { +.detailRibbon { background: #303030; background: -webkit-gradient(linear, left top, right top, from(#291a31), color-stop(#033664), color-stop(#011432), color-stop(#141a3a), to(#291a31)); background: -webkit-linear-gradient(left, #291a31, #033664, #011432, #141a3a, #291a31); @@ -261,11 +261,6 @@ html { background: rgba(170, 170, 190, 0.2); } -.mediaInfoTimerIcon, -.starIcon { - color: #cb272a; -} - .emby-input, .emby-textarea { color: inherit; diff --git a/src/themes/dark/theme.css b/src/themes/dark/theme.css index a32e606386..5c12389a1f 100644 --- a/src/themes/dark/theme.css +++ b/src/themes/dark/theme.css @@ -203,11 +203,11 @@ html { background: rgba(30, 30, 30, 0.9); } -.detailSticky { +.detailRibbon { background: rgba(32, 32, 32, 0.8); } -.noBackdrop .detailSticky { +.noBackdrop .detailRibbon { background: #202020; } @@ -236,11 +236,6 @@ html { background: rgba(170, 170, 190, 0.2); } -.mediaInfoTimerIcon, -.starIcon { - color: #cb272a; -} - .emby-input, .emby-textarea { color: inherit; @@ -453,3 +448,8 @@ html { .metadataSidebarIcon { color: #00a4dc; } + +.emby-button.detailFloatingButton { + background-color: #00a4dc; + color: #fff; +} diff --git a/src/themes/light/theme.css b/src/themes/light/theme.css index acea3f1d68..c178537042 100644 --- a/src/themes/light/theme.css +++ b/src/themes/light/theme.css @@ -221,7 +221,7 @@ html { color: #fff !important; } -.detailSticky { +.detailRibbon { background-color: #303030; color: #ccc; color: rgba(255, 255, 255, 0.87); @@ -250,11 +250,6 @@ html { background: #fff; } -.mediaInfoTimerIcon, -.starIcon { - color: #cb272a; -} - .emby-input, .emby-textarea { color: inherit; diff --git a/src/themes/purplehaze/theme.css b/src/themes/purplehaze/theme.css index a311fd3104..025e7901be 100644 --- a/src/themes/purplehaze/theme.css +++ b/src/themes/purplehaze/theme.css @@ -307,7 +307,7 @@ a[data-role=button] { color: #f8f8fe !important; } -.detailSticky { +.detailRibbon { background: #000420; background: -moz-linear-gradient(left, #000420 0%, #06256f 18%, #2b052b 38%, #2b052b 68%, #06256f 81%, #000420 100%); background: -webkit-linear-gradient(left, #000420 0%, #06256f 18%, #2b052b 38%, #2b052b 68%, #06256f 81%, #000420 100%); @@ -344,11 +344,6 @@ a[data-role=button] { background: rgba(170, 170, 190, 0.2); } -.mediaInfoTimerIcon, -.starIcon { - color: #f2b01e; -} - .emby-input, .emby-textarea { color: inherit; diff --git a/src/themes/wmc/theme.css b/src/themes/wmc/theme.css index 97c08caf80..cd9e6bc16e 100644 --- a/src/themes/wmc/theme.css +++ b/src/themes/wmc/theme.css @@ -209,7 +209,7 @@ html { color: #fff !important; } -.detailSticky { +.detailRibbon { background-color: #081b3b; } @@ -243,11 +243,6 @@ html { background: rgba(170, 170, 190, 0.2); } -.mediaInfoTimerIcon, -.starIcon { - color: #cb272a; -} - .emby-input, .emby-textarea { color: inherit;