diff --git a/dashboard-ui/bower_components/emby-webcomponents/.bower.json b/dashboard-ui/bower_components/emby-webcomponents/.bower.json index 9572ade724..49d0ab880b 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/.bower.json +++ b/dashboard-ui/bower_components/emby-webcomponents/.bower.json @@ -14,12 +14,12 @@ }, "devDependencies": {}, "ignore": [], - "version": "1.4.127", - "_release": "1.4.127", + "version": "1.4.128", + "_release": "1.4.128", "_resolution": { "type": "version", - "tag": "1.4.127", - "commit": "90c7b31f36c7c56406492a2c396c879817ce0303" + "tag": "1.4.128", + "commit": "75f2667ad68265aa1f8c28127bbbeacfc22a21a6" }, "_source": "https://github.com/MediaBrowser/emby-webcomponents.git", "_target": "^1.2.0", diff --git a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css new file mode 100644 index 0000000000..ba16f68472 --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css @@ -0,0 +1,220 @@ +.card { + text-transform: none; + background-color: transparent !important; + background: none !important; + margin: 0; + padding: 0; + display: block; + color: inherit !important; + box-shadow: none !important; + outline: none !important; + cursor: pointer; + contain: style; +} + +.verticalItemsContainer .card { + contain: layout style; +} + +.card, .card:focus { + font-weight: inherit !important; +} + +button.card { + border: 0 !important; + font-size: inherit !important; + font-family: inherit !important; +} + +.cardScalable { + position: relative; +} + +.backdropCard .cardPadder, .smallBackdropCard .cardPadder, .overflowBackdropCard .cardPadder { + padding-bottom: 56.25%; +} + +.squareCard .cardPadder { + padding-bottom: 100%; +} + +.letterBoxCard .cardPadder { + padding-bottom: 75%; +} + +.portraitCard .cardPadder { + padding-bottom: 150%; +} + +.bannerCard .cardPadder { + padding-bottom: 18.5%; +} + +.card .cardBox { + padding: 0 !important; + margin: 0; + transition: none !important; + border-radius: 0 !important; + border: 3px solid transparent; + will-change: transform; + /* Needed to keep the cardOverlayTarget from showing outside the bounds while it animates */ + overflow: hidden; +} + +.round .cardBox { + border: .7em solid transparent; +} + +.round .cardImageContainer { + border: .15em solid transparent; +} + +.card:focus { + position: relative !important; + z-index: 10 !important; +} + + .card:focus .cardBox { + border-color: transparent; + } + +.cardImageContainer, .round:focus .cardImageContainer { + border-color: #fff; +} + +.round .cardBox { + transition: transform 180ms ease-out !important; + -webkit-transform-origin: center center; + transform-origin: center center; +} + +.layout-tv .round:focus .cardBox { + transform: scale(1.34, 1.34); +} + +/*.card[focused]:not(.noScale) .cardBox, .card:focus:not(.noScale) .cardBox { + animation:SHW .2s; + animation-fill-mode: both; +}*/ + +.dimunselected .card .cardImageContainer { + -webkit-filter: brightness(50%); + filter: brightness(50%); + transition: filter, -webkit-filter 600ms ease-out !important; +} + +.dimunselected .card:focus .cardImageContainer { + -webkit-filter: initial; + filter: initial; + transition: filter, -webkit-filter 600ms ease-out !important; +} + +.cardImageContainer { + background-size: contain; + background-repeat: no-repeat; + background-position: center bottom; + display: -ms-flex; + display: -webkit-flex; + display: flex; + align-items: center; + justify-content: center; + position: relative; + background-clip: content-box !important; +} + +.scalableCard .cardImageContainer { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: auto !important; + height: auto !important; +} + +.round .cardImageContainer, .round .cardImage { + border-radius: 1000px; +} + +.cardImage.coveredImage, .cardImageContainer.coveredImage, .coveredImage .cardImage { + background-size: 100% 100%; + background-position: center center; +} + +.coveredImage.noScale, .coveredImage.noScale .cardImage { + background-size: cover; +} + +.cardFooter { + padding: .25em .25em; +} + +.innerCardFooter { + background: rgba(0,0,0,.7); + position: absolute; + bottom: 0; + left: 0; + text-align: left; + z-index: 1; + overflow: hidden; + max-width: 100%; +} + +.fullInnerCardFooter { + right: 0; +} + +.cardText { + padding: .25em .35em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + + .cardText + .cardText { + padding-top: .1em; + } + +.cardText { + color: inherit; +} + +.innerCardFooter .cardText, .cardImageContainer .cardText { + color: #fff; +} + +.cardCenteredText { + white-space: normal; +} + +.cardImage { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-size: contain; + background-repeat: no-repeat; + background-position: center bottom; +} + +.cardImageIcon { + width: 12vh; + height: 12vh; + font-size: 12vh; + color: #fff; + position: relative; + top: -8%; +} + +.card .indicators { + right: .5vh; + top: .5vh; + position: absolute; + display: flex; + align-items: center; +} + +.emptyCardImageContainer { + font-size: 90%; +} diff --git a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js new file mode 100644 index 0000000000..d926d97335 --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js @@ -0,0 +1,836 @@ +define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo', 'focusManager', 'indicators', 'globalize', 'emby-button', 'css!./card'], + function (datetime, imageLoader, connectionManager, itemHelper, mediaInfo, focusManager, indicators, globalize) { + + function setShapeHorizontal(items, options) { + + var primaryImageAspectRatio = imageLoader.getPrimaryImageAspectRatio(items) || 0; + + if (primaryImageAspectRatio && primaryImageAspectRatio < .85) { + options.shape = 'portraitCard'; + + if (options.rows !== 0) { + options.rows = 2; + } + } + else if (primaryImageAspectRatio && primaryImageAspectRatio > 1.34) { + options.shape = 'backdropCard'; + + if (options.rows !== 0) { + options.rows = 3; + } + } + else { + options.shape = 'squareCard'; + + if (options.rows !== 0) { + options.rows = 3; + } + } + } + + function setShapeVertical(items, options) { + + var primaryImageAspectRatio = imageLoader.getPrimaryImageAspectRatio(items) || 0; + + if (options.preferThumb) { + options.shape = 'backdropCard'; + } + else if (primaryImageAspectRatio && primaryImageAspectRatio < .85) { + options.shape = 'portraitCard'; + } + else if (primaryImageAspectRatio && primaryImageAspectRatio > 1.34) { + options.shape = 'backdropCard'; + } + else { + options.shape = 'squareCard'; + } + } + + function setWidth(isVertical, options) { + + if (options.width) { + return; + } + + if (isVertical) { + if (options.shape == 'backdropCard') { + options.width = options.thumbWidth; + } + else if (options.shape == 'portraitCard') { + options.width = options.portraitWidth; + } + else if (options.shape == 'squareCard') { + options.width = options.squareWidth; + } + } + else { + if (options.shape == 'backdropCard') { + options.width = 500; + } + else if (options.shape == 'portraitCard') { + options.width = 243; + } + else if (options.shape == 'squareCard') { + options.width = 242; + } + } + } + + function buildCardsHtml(items, options) { + + var apiClient = connectionManager.currentApiClient(); + + var html = buildCardsHtmlInternal(items, apiClient, options); + + return html; + } + + function buildCardsHtmlInternal(items, apiClient, options) { + + var isVertical; + + if (options.shape == 'autoVertical') { + isVertical = true; + setShapeVertical(items, options); + } + else if (options.shape == 'auto') { + setShapeHorizontal(items, options); + } + + setWidth(isVertical, options); + + if (options.indexBy == 'Genres') { + return buildCardsByGenreHtmlInternal(items, apiClient, options); + } + + var className = 'card'; + + if (options.shape) { + className += ' ' + options.shape; + } + + var html = ''; + var itemsInRow = 0; + + var currentIndexValue; + var hasOpenRow; + var hasOpenSection; + + for (var i = 0, length = items.length; i < length; i++) { + + var item = items[i]; + + if (options.indexBy) { + var newIndexValue = ''; + + if (options.indexBy == 'PremiereDate') { + if (item.PremiereDate) { + try { + + newIndexValue = getDisplayDateText(datetime.parseISO8601Date(item.PremiereDate)); + + } catch (err) { + } + } + } + + else if (options.indexBy == 'Genres') { + newIndexValue = item.Name; + } + + else if (options.indexBy == 'ProductionYear') { + newIndexValue = item.ProductionYear; + } + + else if (options.indexBy == 'CommunityRating') { + newIndexValue = item.CommunityRating ? (Math.floor(item.CommunityRating) + (item.CommunityRating % 1 >= .5 ? .5 : 0)) + '+' : null; + } + + if (newIndexValue != currentIndexValue) { + + if (hasOpenRow) { + html += ''; + hasOpenRow = false; + itemsInRow = 0; + } + + if (hasOpenSection) { + + html += ''; + + if (isVertical) { + html += ''; + } + hasOpenSection = false; + } + + if (isVertical) { + html += '
'; + } else { + html += '
'; + } + if (isVertical) { + html += '

' + newIndexValue + '

'; + } else { + html += '
' + newIndexValue + '
'; + } + if (isVertical) { + html += '
'; + } + currentIndexValue = newIndexValue; + hasOpenSection = true; + } + } + + if (options.rows && itemsInRow == 0) { + + if (hasOpenRow) { + html += '
'; + hasOpenRow = false; + } + + html += '
'; + hasOpenRow = true; + } + + var cardClass = className; + html += buildCard(i, item, apiClient, options, cardClass); + + itemsInRow++; + + if (options.rows && itemsInRow >= options.rows) { + html += '
'; + hasOpenRow = false; + itemsInRow = 0; + } + } + + if (hasOpenRow) { + html += '
'; + } + + if (hasOpenSection) { + html += '
'; + + if (isVertical) { + html += ''; + } + } + + return html; + } + + function buildCardsByGenreHtmlInternal(items, apiClient, options) { + + var className = 'card'; + + if (options.shape) { + className += ' ' + options.shape; + } + + var html = ''; + + var loopItems = options.genres; + + for (var i = 0, length = loopItems.length; i < length; i++) { + + var item = loopItems[i]; + + var genreLower = item.Name.toLowerCase(); + var renderItems = items.filter(function (currentItem) { + + return currentItem.Genres.filter(function (g) { + + return g.toLowerCase() == genreLower; + + }).length > 0; + }); + + if (!renderItems.length) { + continue; + } + + html += '
'; + html += '
' + item.Name + '
'; + + var showMoreButton = false; + if (renderItems.length > options.indexLimit) { + renderItems.length = Math.min(renderItems.length, options.indexLimit); + showMoreButton = true; + } + + var itemsInRow = 0; + var hasOpenRow = false; + var hasOpenSection = false; + + html += renderItems.map(function (renderItem) { + + var currentItemHtml = ''; + + if (options.rows && itemsInRow == 0) { + + if (hasOpenRow) { + currentItemHtml += '
'; + hasOpenRow = false; + } + + currentItemHtml += '
'; + hasOpenRow = true; + } + + var cardClass = className; + currentItemHtml += buildCard(i, renderItem, apiClient, options, cardClass); + + itemsInRow++; + + if (options.rows && itemsInRow >= options.rows) { + currentItemHtml += '
'; + hasOpenRow = false; + itemsInRow = 0; + } + + return currentItemHtml; + + }).join(''); + + + if (showMoreButton) { + html += '
'; + html += ''; + html += '
'; + } + + html += ''; + html += ''; + } + + return html; + } + + function getDisplayDateText(date) { + + var weekday = []; + weekday[0] = globalize.translate('core#OptionSunday'); + weekday[1] = globalize.translate('core#OptionMonday'); + weekday[2] = globalize.translate('core#OptionTuesday'); + weekday[3] = globalize.translate('core#OptionWednesday'); + weekday[4] = globalize.translate('core#OptionThursday'); + weekday[5] = globalize.translate('core#OptionFriday'); + weekday[6] = globalize.translate('core#OptionSaturday'); + + var day = weekday[date.getDay()]; + date = date.toLocaleDateString(); + + if (date.toLowerCase().indexOf(day.toLowerCase()) == -1) { + return day + " " + date; + } + + return date; + } + + 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; + } + } + return null; + } + + function getCardImageUrl(item, apiClient, options) { + + var width = options.width; + var height = null; + var primaryImageAspectRatio = imageLoader.getPrimaryImageAspectRatio([item]); + var forceName = false; + var imgUrl = null; + var coverImage = false; + + if (options.preferThumb && item.ImageTags && item.ImageTags.Thumb) { + + imgUrl = apiClient.getScaledImageUrl(item.Id, { + type: "Thumb", + maxWidth: width, + tag: item.ImageTags.Thumb + }); + + } else if (options.preferBanner && item.ImageTags && item.ImageTags.Banner) { + + imgUrl = apiClient.getScaledImageUrl(item.Id, { + type: "Banner", + maxWidth: width, + tag: item.ImageTags.Banner + }); + + } else if (options.preferThumb && item.SeriesThumbImageTag && options.inheritThumb !== false) { + + imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { + type: "Thumb", + maxWidth: width, + tag: item.SeriesThumbImageTag + }); + + } else if (options.preferThumb && item.ParentThumbItemId && options.inheritThumb !== false) { + + imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, { + type: "Thumb", + maxWidth: width, + tag: item.ParentThumbImageTag + }); + + } else if (options.preferThumb && item.BackdropImageTags && item.BackdropImageTags.length) { + + imgUrl = apiClient.getScaledImageUrl(item.Id, { + type: "Backdrop", + maxWidth: width, + tag: item.BackdropImageTags[0] + }); + + forceName = true; + + } else if (item.ImageTags && item.ImageTags.Primary) { + + height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; + + imgUrl = apiClient.getImageUrl(item.Id, { + type: "Primary", + maxHeight: height, + maxWidth: width, + tag: item.ImageTags.Primary + }); + + if (options.preferThumb && options.showTitle !== false) { + forceName = true; + } + + if (primaryImageAspectRatio) { + var uiAspect = getDesiredAspect(options.shape); + if (uiAspect) { + coverImage = Math.abs(primaryImageAspectRatio - uiAspect) <= .2; + } + } + + } else if (item.PrimaryImageTag) { + + height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; + + imgUrl = apiClient.getImageUrl(item.Id || item.ItemId, { + type: "Primary", + maxHeight: height, + maxWidth: width, + tag: item.PrimaryImageTag + }); + + if (options.preferThumb && options.showTitle !== false) { + forceName = true; + } + + if (primaryImageAspectRatio) { + var uiAspect = getDesiredAspect(options.shape); + if (uiAspect) { + coverImage = Math.abs(primaryImageAspectRatio - uiAspect) <= .2; + } + } + } + else if (item.ParentPrimaryImageTag) { + + imgUrl = apiClient.getImageUrl(item.ParentPrimaryImageItemId, { + type: "Primary", + maxWidth: width, + tag: item.ParentPrimaryImageTag + }); + } + else if (item.AlbumId && item.AlbumPrimaryImageTag) { + + width = primaryImageAspectRatio ? Math.round(height * primaryImageAspectRatio) : null; + + imgUrl = apiClient.getScaledImageUrl(item.AlbumId, { + type: "Primary", + maxHeight: height, + maxWidth: width, + tag: item.AlbumPrimaryImageTag + }); + + if (primaryImageAspectRatio) { + var uiAspect = getDesiredAspect(options.shape); + if (uiAspect) { + coverImage = Math.abs(primaryImageAspectRatio - uiAspect) <= .2; + } + } + } + else if (item.Type == 'Season' && item.ImageTags && item.ImageTags.Thumb) { + + imgUrl = apiClient.getScaledImageUrl(item.Id, { + type: "Thumb", + maxWidth: width, + tag: item.ImageTags.Thumb + }); + + } + else if (item.BackdropImageTags && item.BackdropImageTags.length) { + + imgUrl = apiClient.getScaledImageUrl(item.Id, { + type: "Backdrop", + maxWidth: width, + tag: item.BackdropImageTags[0] + }); + + } else if (item.ImageTags && item.ImageTags.Thumb) { + + imgUrl = apiClient.getScaledImageUrl(item.Id, { + type: "Thumb", + maxWidth: width, + tag: item.ImageTags.Thumb + }); + + } else if (item.SeriesThumbImageTag) { + + imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { + type: "Thumb", + maxWidth: width, + tag: item.SeriesThumbImageTag + }); + + } else if (item.ParentThumbItemId) { + + imgUrl = apiClient.getThumbImageUrl(item.ParentThumbItemId, { + type: "Thumb", + maxWidth: width, + tag: item.ParentThumbImageTag + }); + + } + + return { + imgUrl: imgUrl, + forceName: forceName, + coverImage: coverImage + }; + } + + function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + function buildCard(index, item, apiClient, options, className) { + + className += " itemAction"; + + if (options.scalable) { + className += " scalableCard"; + } + + var imgInfo = getCardImageUrl(item, apiClient, options); + var imgUrl = imgInfo.imgUrl; + + var cardImageContainerClass = 'cardImageContainer'; + if (options.coverImage || imgInfo.coverImage) { + cardImageContainerClass += ' coveredImage'; + + if (item.MediaType == 'Photo' || item.Type == 'PhotoAlbum' || item.Type == 'Folder') { + cardImageContainerClass += ' noScale'; + } + } + + if (!imgUrl) { + cardImageContainerClass += ' emptyCardImageContainer defaultCardColor' + getRandomInt(1, 5); + } + + var separateCardBox = options.scalable; + + if (!separateCardBox) { + cardImageContainerClass += " cardBox"; + } + + // cardBox can be it's own separate element if an outer footer is ever needed + var cardImageContainerOpen = imgUrl ? ('
') : ('
'); + var cardImageContainerClose = '
'; + + if (separateCardBox) { + cardImageContainerOpen = '
' + cardImageContainerOpen; + cardImageContainerClose += '
'; + } + + var indicatorsHtml = ''; + + indicatorsHtml += indicators.getTimerIndicator(item); + + if (options.showGroupCount) { + + indicatorsHtml += indicators.getChildCountIndicatorHtml(item, { + minCount: 1 + }); + } + else { + indicatorsHtml += indicators.getPlayedIndicatorHtml(item); + } + + if (indicatorsHtml) { + cardImageContainerOpen += '
' + indicatorsHtml + '
'; + } + + var showTitle = options.showTitle || imgInfo.forceName || item.Type == 'PhotoAlbum'; + var showParentTitle = options.showParentTitle || (imgInfo.forceName && item.Type == 'Episode'); + + if (!imgUrl) { + var defaultName = item.EpisodeTitle ? item.Name : itemHelper.getDisplayName(item); + cardImageContainerOpen += '
' + defaultName + '
'; + } + + var nameHtml = ''; + + if (showParentTitle) { + nameHtml += '
' + (item.EpisodeTitle ? item.Name : (item.SeriesName || item.Album || item.AlbumArtist || item.GameSystem || "")) + '
'; + } + + if (showTitle) { + var nameClass = 'cardText'; + nameHtml += '
' + itemHelper.getDisplayName(item) + '
'; + } + + var innerCardFooterClass = 'innerCardFooter'; + var progressHtml = indicators.getProgressBarHtml(item); + + if (progressHtml) { + nameHtml += progressHtml; + innerCardFooterClass += " fullInnerCardFooter"; + } + + var innerCardFooter = ''; + + if (nameHtml && imgUrl) { + innerCardFooter += '
'; + innerCardFooter += nameHtml; + innerCardFooter += '
'; + } + + var data = ''; + + var action = options.action || 'link'; + + var tagName = 'button'; + + var prefix = (item.SortName || item.Name || '')[0]; + + if (prefix) { + prefix = prefix.toUpperCase(); + } + + var timerAttributes = ''; + if (item.TimerId) { + timerAttributes += ' data-timerid="' + item.TimerId + '"'; + } + if (item.SeriesTimerId) { + timerAttributes += ' data-seriestimerid="' + item.SeriesTimerId + '"'; + } + + var positionTicksData = item.UserData && item.UserData.PlaybackPositionTicks ? (' data-positionticks="' + item.UserData.PlaybackPositionTicks + '"') : ''; + var collectionIdData = options.collectionId ? (' data-collectionid="' + options.collectionId + '"') : ''; + var playlistIdData = options.playlistId ? (' data-playlistid="' + options.playlistId + '"') : ''; + + return '\ +<' + tagName + ' data-index="' + index + '"' + timerAttributes + ' data-action="' + action + '" data-isfolder="' + (item.IsFolder || false) + '" data-serverid="' + (item.ServerId) + '" data-id="' + (item.Id || item.ItemId) + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '"' + positionTicksData + collectionIdData + playlistIdData + ' data-prefix="' + prefix + '" class="' + className + '"> \ +' + cardImageContainerOpen + innerCardFooter + data + cardImageContainerClose + '\ +'; + } + + function buildCards(items, options) { + + // Abort if the container has been disposed + if (!document.body.contains(options.itemsContainer)) { + return; + } + + if (options.parentContainer) { + if (items.length) { + options.parentContainer.classList.remove('hide'); + } else { + options.parentContainer.classList.add('hide'); + return; + } + } + + var apiClient = connectionManager.currentApiClient(); + + var html = buildCardsHtmlInternal(items, apiClient, options); + + if (html) { + + if (options.itemsContainer.cardBuilderHtml != html) { + options.itemsContainer.innerHTML = html; + + if (items.length < 50) { + options.itemsContainer.cardBuilderHtml = html; + } else { + options.itemsContainer.cardBuilderHtml = null; + } + } + + imageLoader.lazyChildren(options.itemsContainer); + } else { + + options.itemsContainer.innerHTML = html; + options.itemsContainer.cardBuilderHtml = null; + } + + if (options.autoFocus) { + focusManager.autoFocus(options.itemsContainer, true); + } + + if (options.indexBy == 'Genres') { + options.itemsContainer.addEventListener('click', onItemsContainerClick); + } + } + + function parentWithClass(elem, className) { + + while (!elem.classList || !elem.classList.contains(className)) { + elem = elem.parentNode; + + if (!elem) { + return null; + } + } + + return elem; + } + + function onItemsContainerClick(e) { + + var listItemsMoreButton = parentWithClass(e.target, 'listItemsMoreButton'); + + if (listItemsMoreButton) { + + var value = listItemsMoreButton.getAttribute('data-indexvalue'); + var parentid = listItemsMoreButton.getAttribute('data-parentid'); + + Emby.Page.showGenre({ + ParentId: parentid, + Id: value + }); + } + } + + function ensureIndicators(card, indicatorsElem) { + + if (indicatorsElem) { + return indicatorsElem; + } + + indicatorsElem = card.querySelector('.indicators'); + + if (!indicatorsElem) { + + var cardImageContainer = card.querySelector('.cardImageContainer'); + indicatorsElem = document.createElement('div'); + indicatorsElem.classList.add('indicators'); + cardImageContainer.appendChild(indicatorsElem); + } + + return indicatorsElem; + } + + function updateUserData(card, userData) { + + var type = card.getAttribute('data-type'); + var enableCountIndicator = type == 'Series' || type == 'BoxSet' || type == 'Season'; + var indicatorsElem; + + if (userData.Played) { + + var playedIndicator = card.querySelector('.playedIndicator'); + + if (!playedIndicator) { + + playedIndicator = document.createElement('div'); + playedIndicator.classList.add('playedIndicator'); + indicatorsElem = ensureIndicators(card, indicatorsElem); + indicatorsElem.appendChild(playedIndicator); + } + playedIndicator.innerHTML = 'check'; + } else { + + var playedIndicator = card.querySelector('.playedIndicator'); + if (playedIndicator) { + + playedIndicator.parentNode.removeChild(playedIndicator); + } + } + if (userData.UnplayedItemCount) { + var countIndicator = card.querySelector('.countIndicator'); + + if (!countIndicator) { + + countIndicator = document.createElement('div'); + countIndicator.classList.add('countIndicator'); + indicatorsElem = ensureIndicators(card, indicatorsElem); + indicatorsElem.appendChild(countIndicator); + } + countIndicator.innerHTML = userData.UnplayedItemCount; + } else if (enableCountIndicator) { + + var countIndicator = card.querySelector('.countIndicator'); + if (countIndicator) { + + countIndicator.parentNode.removeChild(countIndicator); + } + } + + var progressHtml = indicators.getProgressBarHtml({ + Type: type, + UserData: userData, + MediaType: 'Video' + }); + + if (progressHtml) { + + var itemProgressBar = card.querySelector('.itemProgressBar'); + + if (!itemProgressBar) { + itemProgressBar = document.createElement('div'); + itemProgressBar.classList.add('itemProgressBar'); + + var innerCardFooter = card.querySelector('.innerCardFooter'); + if (!innerCardFooter) { + innerCardFooter = document.createElement('div'); + innerCardFooter.classList.add('innerCardFooter'); + var cardImageContainer = card.querySelector('.cardImageContainer'); + cardImageContainer.appendChild(innerCardFooter); + } + innerCardFooter.appendChild(itemProgressBar); + } + + itemProgressBar.innerHTML = progressHtml; + } + else { + + var itemProgressBar = card.querySelector('.itemProgressBar'); + if (itemProgressBar) { + itemProgressBar.parentNode.removeChild(itemProgressBar); + } + } + } + + function onUserDataChanged(userData) { + + var cards = document.querySelectorAll('.card[data-id="' + userData.ItemId + '"]'); + + for (var i = 0, length = cards.length; i < length; i++) { + updateUserData(cards[i], userData); + } + } + + return { + buildCardsHtml: buildCardsHtml, + buildCards: buildCards, + onUserDataChanged: onUserDataChanged + }; + }); \ No newline at end of file diff --git a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/chaptercardbuilder.js b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/chaptercardbuilder.js new file mode 100644 index 0000000000..b7f20c9fe4 --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/chaptercardbuilder.js @@ -0,0 +1,115 @@ +define(['datetime', 'imageLoader', 'itemShortcuts'], function (datetime, imageLoader, itemShortcuts) { + + function buildChapterCardsHtml(item, chapters, options) { + + var className = 'card scalableCard itemAction chapterCard'; + + var mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || []; + var videoStream = mediaStreams.filter(function (i) { + return i.Type == 'Video'; + })[0] || {}; + + var shape = 'backdropCard'; + + if (videoStream.Width && videoStream.Height) { + + if ((videoStream.Width / videoStream.Height) <= 1.34) { + shape = 'squareCard'; + } + } + + className += ' ' + shape; + + if (options.block || options.rows) { + className += ' block'; + } + + var html = ''; + var itemsInRow = 0; + + for (var i = 0, length = chapters.length; i < length; i++) { + + if (options.rows && itemsInRow == 0) { + html += '
'; + } + + var chapter = chapters[i]; + + html += buildChapterCard(item, chapter, options, className); + itemsInRow++; + + if (options.rows && itemsInRow >= options.rows) { + itemsInRow = 0; + html += '
'; + } + } + + return html; + } + + function buildChapterCard(item, chapter, options, className) { + + var imgUrl = chapter.images ? chapter.images.primary : ''; + + var cardImageContainerClass = 'cardImageContainer'; + if (options.coverImage) { + cardImageContainerClass += ' coveredImage'; + } + var dataAttributes = ' data-action="play" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-positionticks="' + chapter.StartPositionTicks + '"'; + var cardImageContainer = imgUrl ? ('
') : ('
'); + + var nameHtml = ''; + nameHtml += '
' + chapter.Name + '
'; + nameHtml += '
' + datetime.getDisplayRunningTime(chapter.StartPositionTicks) + '
'; + + var html = '\ +
\ +' + ; + + return html; + } + + function buildChapterCards(item, chapters, options) { + + // Abort if the container has been disposed + if (!document.body.contains(options.parentContainer)) { + return; + } + + if (options.parentContainer) { + if (chapters.length) { + options.parentContainer.classList.remove('hide'); + } else { + options.parentContainer.classList.add('hide'); + return; + } + } + + var html = buildChapterCardsHtml(item, chapters, options); + + options.itemsContainer.innerHTML = html; + + imageLoader.lazyChildren(options.itemsContainer); + + itemShortcuts.off(options.itemsContainer); + itemShortcuts.on(options.itemsContainer); + } + + return { + buildChapterCards: buildChapterCards + }; + +}); \ No newline at end of file diff --git a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/peoplecardbuilder.js b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/peoplecardbuilder.js new file mode 100644 index 0000000000..d468eb266b --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/peoplecardbuilder.js @@ -0,0 +1,110 @@ +define(['imageLoader', 'itemShortcuts'], function (imageLoader, itemShortcuts) { + + function buildPeopleCardsHtml(people, options) { + + var className = 'card portraitCard personCard'; + + if (options.block || options.rows) { + className += ' block'; + } + + var html = ''; + var itemsInRow = 0; + + var serverId = options.serverId; + + for (var i = 0, length = people.length; i < length; i++) { + + if (options.rows && itemsInRow == 0) { + html += '
'; + } + + var person = people[i]; + + html += buildPersonCard(person, serverId, options, className); + itemsInRow++; + + if (options.rows && itemsInRow >= options.rows) { + itemsInRow = 0; + html += '
'; + } + } + + return html; + } + + function buildPersonCard(person, serverId, options, className) { + + className += " itemAction scalableCard"; + + var imgUrl = person.images ? person.images.primary : ''; + + var cardImageContainerClass = 'cardImageContainer'; + if (options.coverImage) { + cardImageContainerClass += ' coveredImage'; + } + var cardImageContainer = imgUrl ? ('
') : ('
'); + + var nameHtml = ''; + nameHtml += '
' + person.Name + '
'; + + if (person.Role) { + nameHtml += '
as ' + person.Role + '
'; + } + else if (person.Type) { + nameHtml += '
' + Globalize.translate('core#' + person.Type) + '
'; + } else { + nameHtml += '
 
'; + } + + var html = '\ +
\ +' + ; + + return html; + } + + function buildPeopleCards(items, options) { + + // Abort if the container has been disposed + if (!document.body.contains(options.parentContainer)) { + return; + } + + if (options.parentContainer) { + if (items.length) { + options.parentContainer.classList.remove('hide'); + } else { + options.parentContainer.classList.add('hide'); + return; + } + } + + var html = buildPeopleCardsHtml(items, options); + + options.itemsContainer.innerHTML = html; + + imageLoader.lazyChildren(options.itemsContainer); + + itemShortcuts.off(options.itemsContainer); + itemShortcuts.on(options.itemsContainer); + } + + return { + buildPeopleCards: buildPeopleCards + }; + +}); \ No newline at end of file diff --git a/dashboard-ui/bower_components/emby-webcomponents/listview/listview.js b/dashboard-ui/bower_components/emby-webcomponents/listview/listview.js index dc8c88f898..ec64b305aa 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/listview/listview.js +++ b/dashboard-ui/bower_components/emby-webcomponents/listview/listview.js @@ -196,9 +196,8 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan var positionTicksData = item.UserData && item.UserData.PlaybackPositionTicks ? (' data-positionticks="' + item.UserData.PlaybackPositionTicks + '"') : ''; var collectionIdData = options.collectionId ? (' data-collectionid="' + options.collectionId + '"') : ''; var playlistIdData = options.playlistId ? (' data-playlistid="' + options.playlistId + '"') : ''; - var seriesIdData = item.SeriesId ? (' data-seriesid="' + item.SeriesId + '"') : ''; - html += '<' + outerTagName + ' class="' + cssClass + '" data-index="' + i + '"' + playlistItemId + ' data-action="' + action + '" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-mediatype="' + item.MediaType + '" data-type="' + item.Type + '"' + positionTicksData + collectionIdData + playlistIdData + seriesIdData + '>'; + html += '<' + outerTagName + ' class="' + cssClass + '" data-index="' + i + '"' + playlistItemId + ' data-action="' + action + '" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-mediatype="' + item.MediaType + '" data-type="' + item.Type + '"' + positionTicksData + collectionIdData + playlistIdData + '>'; if (!clickEntireItem && options.dragHandle) { html += ''; diff --git a/dashboard-ui/bower_components/emby-webcomponents/playmenu.js b/dashboard-ui/bower_components/emby-webcomponents/playmenu.js index 9f0d1a8531..72552cade0 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/playmenu.js +++ b/dashboard-ui/bower_components/emby-webcomponents/playmenu.js @@ -15,20 +15,13 @@ define(['actionsheet', 'datetime', 'playbackManager', 'globalize', 'appSettings' var resumePositionTicks = item.UserData ? item.UserData.PlaybackPositionTicks : null; var showExternalPlayer = isMobileApp && mediaType == 'Video' && !isFolder && appSettings.enableExternalPlayers(); - var playableItemId = itemType == 'Program' ? channelId : itemId; if (!resumePositionTicks && mediaType != "Audio" && !isFolder && !showExternalPlayer) { - if (itemType == 'Program') { - playbackManager.play({ - ids: [channelId], - serverId: serverId - }); - } else { - playbackManager.play({ - items: [item] - }); - } + playbackManager.play({ + ids: [playableItemId], + serverId: serverId + }); return; } diff --git a/dashboard-ui/bower_components/polymer/.bower.json b/dashboard-ui/bower_components/polymer/.bower.json index 5320b592cc..cad9543436 100644 --- a/dashboard-ui/bower_components/polymer/.bower.json +++ b/dashboard-ui/bower_components/polymer/.bower.json @@ -31,14 +31,14 @@ "web-component-tester": "*" }, "private": true, - "homepage": "https://github.com/Polymer/polymer", + "homepage": "https://github.com/polymer/polymer", "_release": "1.6.0", "_resolution": { "type": "version", "tag": "v1.6.0", "commit": "8715c83bf04a228de00ec662ed43eb6141e61b91" }, - "_source": "git://github.com/Polymer/polymer.git", + "_source": "git://github.com/polymer/polymer.git", "_target": "^1.1.0", - "_originalSource": "Polymer/polymer" + "_originalSource": "polymer/polymer" } \ No newline at end of file diff --git a/dashboard-ui/scripts/librarybrowser.js b/dashboard-ui/scripts/librarybrowser.js index 40eea361ec..5150c2f2d5 100644 --- a/dashboard-ui/scripts/librarybrowser.js +++ b/dashboard-ui/scripts/librarybrowser.js @@ -802,13 +802,6 @@ }); } - if (item.SeriesId) { - atts.push({ - name: 'seriesid', - value: item.SeriesId - }); - } - if (options.collectionId) { atts.push({ name: 'collectionid', diff --git a/dashboard-ui/scripts/site.js b/dashboard-ui/scripts/site.js index f1474dd6e6..91f2a54f58 100644 --- a/dashboard-ui/scripts/site.js +++ b/dashboard-ui/scripts/site.js @@ -1429,6 +1429,11 @@ var AppInfo = {}; define("backdrop", [embyWebComponentsBowerPath + "/backdrop/backdrop"], returnFirstDependency); define("fetchHelper", [embyWebComponentsBowerPath + "/fetchhelper"], returnFirstDependency); + define("cardStyle", ['css!' + embyWebComponentsBowerPath + "/cardbuilder/card"], returnFirstDependency); + define("cardBuilder", [embyWebComponentsBowerPath + "/cardbuilder/cardbuilder"], returnFirstDependency); + define("peoplecardbuilder", [embyWebComponentsBowerPath + "/cardbuilder/peoplecardbuilder"], returnFirstDependency); + define("chaptercardbuilder", [embyWebComponentsBowerPath + "/cardbuilder/chaptercardbuilder"], returnFirstDependency); + define("tvguide", [embyWebComponentsBowerPath + "/guide/guide", 'embyRouter'], returnFirstDependency); define("voiceDialog", [embyWebComponentsBowerPath + "/voice/voicedialog"], returnFirstDependency); define("voiceReceiver", [embyWebComponentsBowerPath + "/voice/voicereceiver"], returnFirstDependency);