From 6503c7c6f8fc7e038978ee1092e0accd3fa4366d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 29 Jul 2016 15:51:58 -0400 Subject: [PATCH] update components --- .../emby-webcomponents/cardbuilder/card.css | 44 +- .../cardbuilder/cardbuilder.js | 483 ++++++++++++++++-- .../iron-behaviors/.bower.json | 6 +- 3 files changed, 488 insertions(+), 45 deletions(-) diff --git a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css index 6e3fdbad82..a1abbb6e9a 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css +++ b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css @@ -103,6 +103,21 @@ button.cardContent { transform: scale(1.34, 1.34); } +.bottomPaddedCard .cardBox:not(.visualCardBox) { + margin-bottom: 1em; +} + +.hiddenScrollX .bottomPaddedCard .cardBox, .smoothScrollX .bottomPaddedCard .cardBox { + margin-bottom: 0; +} + +.btnCardOptions { + text-align: right; + float: right; + padding: 5px 0 2px; + margin: 0 !important; +} + /*.card[focused]:not(.noScale) .cardBox, .card:focus:not(.noScale) .cardBox { animation:SHW .2s; animation-fill-mode: both; @@ -123,7 +138,7 @@ button.cardContent { .cardImageContainer { background-size: contain; background-repeat: no-repeat; - background-position: center bottom; + background-position: center center; display: -ms-flex; display: -webkit-flex; display: flex; @@ -164,7 +179,7 @@ button.cardContent { opacity: .6; } -.card:not(.round) .cardFooter { +.card:not(.round) .cardFooter:not(.transparent) { -moz-box-shadow: 0 2px 4px rgba(0,0,0,0.1); -ms-box-shadow: 0 2px 4px rgba(0,0,0,0.1); -webkit-box-shadow: 0 2px 4px rgba(0,0,0,0.1); @@ -204,6 +219,10 @@ button.cardContent { color: #fff; } +.cardTextCentered { + text-align: center; +} + .cardCenteredText { white-space: normal; } @@ -244,6 +263,7 @@ button.cardContent { bottom: 0; right: 0; margin: 0 .25em .25em 0; + z-index: 1; } .cardOverlayButton:hover { @@ -255,6 +275,26 @@ button.cardContent { font-size: 90%; } +.defaultCardColor1 { + background-color: #009688; +} + +.defaultCardColor2 { + background-color: #D32F2F; +} + +.defaultCardColor3 { + background-color: #0288D1; +} + +.defaultCardColor4 { + background-color: #388E3C; +} + +.defaultCardColor5 { + background-color: #F57F17; +} + .scalableCard.personCard { width: 14.285714285714285714285714285714%; } diff --git a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js index 8565518e59..318094d044 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js +++ b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js @@ -1,10 +1,43 @@ -define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo', 'focusManager', 'indicators', 'globalize', 'browser', 'layoutManager', 'emby-button', 'css!./card', 'paper-icon-button-light', 'clearButtonStyle'], - function (datetime, imageLoader, connectionManager, itemHelper, mediaInfo, focusManager, indicators, globalize, browser, layoutManager) { +define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo', 'focusManager', 'indicators', 'globalize', 'browser', 'layoutManager', 'apphost', 'emby-button', 'css!./card', 'paper-icon-button-light', 'clearButtonStyle'], + function (datetime, imageLoader, connectionManager, itemHelper, mediaInfo, focusManager, indicators, globalize, browser, layoutManager, appHost) { + + // 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; + + /** + * 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, '>'); + } function getCardsHtml(items, options) { var apiClient = connectionManager.currentApiClient(); + if (arguments.length == 1) { + + options = arguments[0]; + items = options.items; + } + var html = buildCardsHtmlInternal(items, apiClient, options); return html; @@ -394,7 +427,37 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo var imgUrl = null; var coverImage = false; - if (options.preferThumb && item.ImageTags && item.ImageTags.Thumb) { + 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.getScaledImageUrl(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 (options.autoThumb && item.ImageTags && item.ImageTags.Thumb) { + + imgUrl = ApiClient.getScaledImageUrl(item.Id, { + type: "Thumb", + maxWidth: thumbWidth, + tag: item.ImageTags.Thumb, + enableImageEnhancers: enableImageEnhancers + }); + + } else if (options.preferThumb && item.ImageTags && item.ImageTags.Thumb) { imgUrl = apiClient.getScaledImageUrl(item.Id, { type: "Thumb", @@ -560,15 +623,347 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo return Math.floor(Math.random() * (max - min + 1)) + min; } + function getCardTextLines(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; + } + + function getCardFooterText(item, options, showTitle, imgUrl, footerClass, progressHtml, isOuterFooter) { + + var html = ''; + + var showOtherText = isOuterFooter ? !options.overlayText : options.overlayText; + + if (isOuterFooter && options.cardLayout && !layoutManager.tv) { + var moreIcon = appHost.moreIcon == 'dots-horiz' ? '' : ''; + html += ''; + } + + var cssClass = options.centerText && !options.cardLayout ? "cardText cardTextCentered" : "cardText"; + + var lines = []; + + if (showOtherText) { + var parentTitleUnderneath = item.Type == 'MusicAlbum' || item.Type == 'Audio' || item.Type == 'MusicVideo'; + if (options.showParentTitle && !parentTitleUnderneath) { + + if (isOuterFooter && item.Type == 'Episode' && item.SeriesName && item.SeriesId) { + + lines.push(getTextActionButton({ + Id: item.SeriesId, + Name: item.SeriesName, + Type: 'Series', + IsFolder: true + })); + } + else { + + lines.push(item.EpisodeTitle ? item.Name : (item.SeriesName || item.Album || item.AlbumArtist || item.GameSystem || "")); + } + } + } + + if (showTitle) { + + var name = options.showTitle == 'auto' && !item.IsFolder && item.MediaType == 'Photo' ? '' : itemHelper.getDisplayName(item); + + lines.push(htmlEncode(name)); + } + + if (showOtherText) { + if (options.showParentTitle && parentTitleUnderneath) { + + if (isOuterFooter && item.AlbumArtists && item.AlbumArtists.length) { + item.AlbumArtists[0].Type = 'MusicArtist'; + item.AlbumArtists[0].IsFolder = true; + lines.push(getTextActionButton(item.AlbumArtists[0])); + } else { + lines.push(item.EpisodeTitle ? item.Name : (item.SeriesName || item.Album || item.AlbumArtist || item.GameSystem || "")); + } + } + + if (options.showItemCounts) { + + var itemCountHtml = 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); + } + + lines.push(songLine); + } + + if (options.showPremiereDate) { + + if (item.PremiereDate) { + try { + + lines.push(getPremiereDateText(item)); + + } catch (err) { + lines.push(''); + + } + } else { + lines.push(''); + } + } + + if (options.showYear) { + + lines.push(item.ProductionYear || ''); + } + + if (options.showChannelName) { + + lines.push(item.ChannelName || ''); + } + + if (options.showAirTime) { + + var airTimeText; + if (item.StartDate) { + + try { + var date = datetime.parseISO8601Date(item.StartDate); + + airTimeText = date.toLocaleDateString(); + + airTimeText += ', ' + datetime.getDisplayTime(date); + + if (item.EndDate) { + date = datetime.parseISO8601Date(item.EndDate); + airTimeText += ' - ' + datetime.getDisplayTime(date); + } + } + catch (e) { + console.log("Error parsing date: " + item.PremiereDate); + } + } + + lines.push(airTimeText || ''); + } + + if (item.Type == 'TvChannel') { + + if (item.CurrentProgram) { + lines.push(itemHelper.getDisplayName(item.CurrentProgram)); + } else { + lines.push(''); + } + } + + if (options.showSeriesYear) { + + if (item.Status == "Continuing") { + + lines.push(globalize.translate('ValueSeriesYearToPresent', item.ProductionYear || '')); + + } else { + lines.push(item.ProductionYear || ''); + } + + } + + if (options.showProgramAirInfo) { + + var date = datetime.parseISO8601Date(item.StartDate, true); + + var text = item.StartDate ? + date.toLocaleString() : + ''; + + lines.push(text || ' '); + + lines.push(item.ChannelName || ' '); + } + } + + html += getCardTextLines(lines, cssClass, !options.overlayText); + + if (progressHtml) { + html += progressHtml; + } + + if (html) { + html = '
' + html; + + //cardFooter + html += "
"; + } + + return html; + } + + function getTextActionButton(item, text) { + + if (!text) { + text = itemHelper.getDisplayName(item); + } + + var html = ''; + + return html; + } + + function getItemCountsHtml(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 (item.Type == 'Genre' || item.Type == 'Studio') { + + 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); + } + + 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); + } + if (item.GameCount) { + + childText = item.GameCount == 1 ? + globalize.translate('ValueOneGame') : + globalize.translate('ValueGameCount', item.GameCount); + + counts.push(childText); + } + + } else if (item.Type == 'GameGenre') { + + if (item.GameCount) { + + childText = item.GameCount == 1 ? + globalize.translate('ValueOneGame') : + globalize.translate('ValueGameCount', item.GameCount); + + counts.push(childText); + } + } else if (item.Type == 'MusicGenre' || options.context == "MusicArtist") { + + 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(' • '); + } + function buildCard(index, item, apiClient, options, className) { var action = options.action || 'link'; - if (layoutManager.tv) { - className += " itemAction"; - } - - if (options.scalable) { + var scalable = options.scalable !== false; + if (scalable) { className += " scalableCard"; } @@ -588,7 +983,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo cardImageContainerClass += ' emptyCardImageContainer defaultCardColor' + getRandomInt(1, 5); } - var separateCardBox = options.scalable; + var separateCardBox = scalable; if (!separateCardBox) { cardImageContainerClass += " cardBox"; @@ -635,63 +1030,60 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo cardImageContainerOpen += '
' + indicatorsHtml + '
'; } - var showTitle = options.showTitle || imgInfo.forceName || item.Type == 'PhotoAlbum'; - var showParentTitle = options.showParentTitle || (imgInfo.forceName && item.Type == 'Episode'); + var forceName = imgInfo.forceName; + + var showTitle = options.showTitle == 'auto' ? true : (options.showTitle || item.Type == 'PhotoAlbum' || item.Type == 'Folder'); + + if (forceName && !options.cardLayout) { + showTitle = false; + } if (!imgUrl) { var defaultName = item.EpisodeTitle ? item.Name : itemHelper.getDisplayName(item); cardImageContainerOpen += '
' + defaultName + '
'; } - var enableOuterFooter = options.overlayText === false; - 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) { - innerCardFooterClass += " fullInnerCardFooter"; - } - var innerCardFooter = ''; - if (imgUrl && (progressHtml || (nameHtml && !enableOuterFooter))) { - innerCardFooter += '
'; + var footerOverlayed = false; - if (!enableOuterFooter) { - innerCardFooter += nameHtml; - } + if (options.overlayText) { + + var footerCssClass = progressHtml ? 'innerCardFooter fullInnerCardFooter' : 'innerCardFooter'; + innerCardFooter += getCardFooterText(item, options, showTitle, imgUrl, footerCssClass, progressHtml, false); + footerOverlayed = true; + } + else if (progressHtml) { + innerCardFooter += '
'; innerCardFooter += progressHtml; innerCardFooter += '
'; + + progressHtml = ''; } var outerCardFooter = ''; - if (nameHtml && enableOuterFooter) { - outerCardFooter += '
'; - outerCardFooter += nameHtml; - outerCardFooter += '
'; + if (!options.overlayText && !footerOverlayed) { + var footerCssClass = options.cardLayout ? 'cardFooter' : 'cardFooter transparent'; + outerCardFooter = getCardFooterText(item, options, showTitle, imgUrl, footerCssClass, progressHtml, true); } var overlayButtons = ''; - if (!layoutManager.tv) { + if (!layoutManager.tv && scalable) { if (options.overlayPlayButton && !item.IsPlaceHolder && (item.LocationType != 'Virtual' || !item.MediaType || item.Type == 'Program') && item.Type != 'Person' && item.PlayAccess == 'Full') { overlayButtons += ''; } if (options.overlayMoreButton) { - overlayButtons += ''; + + var moreIcon = appHost.moreIcon == 'dots-horiz' ? '' : ''; + + overlayButtons += ''; } } - var tagName = layoutManager.tv ? 'button' : 'div'; + var tagName = layoutManager.tv || !scalable ? 'button' : 'div'; var prefix = (item.SortName || item.Name || '')[0]; @@ -711,7 +1103,18 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo var collectionIdData = options.collectionId ? (' data-collectionid="' + options.collectionId + '"') : ''; var playlistIdData = options.playlistId ? (' data-playlistid="' + options.playlistId + '"') : ''; - var actionAttribute = layoutManager.tv ? (' data-action="' + action + '"') : ''; + var actionAttribute; + + if (tagName == 'button') { + className += " itemAction"; + actionAttribute = ' data-action="' + action + '"'; + } else { + actionAttribute = ''; + } + + if (outerCardFooter && !options.cardLayout) { + className += ' bottomPaddedCard'; + } return '\ <' + tagName + ' data-index="' + index + '"' + timerAttributes + actionAttribute + ' 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 + '"> \ diff --git a/dashboard-ui/bower_components/iron-behaviors/.bower.json b/dashboard-ui/bower_components/iron-behaviors/.bower.json index dac19e56be..c7dc4d6af0 100644 --- a/dashboard-ui/bower_components/iron-behaviors/.bower.json +++ b/dashboard-ui/bower_components/iron-behaviors/.bower.json @@ -29,14 +29,14 @@ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" }, "ignore": [], - "homepage": "https://github.com/PolymerElements/iron-behaviors", + "homepage": "https://github.com/polymerelements/iron-behaviors", "_release": "1.0.17", "_resolution": { "type": "version", "tag": "v1.0.17", "commit": "ef8e89b5f0aa4e8a6b51ca6491ea453bf395f94f" }, - "_source": "git://github.com/PolymerElements/iron-behaviors.git", + "_source": "git://github.com/polymerelements/iron-behaviors.git", "_target": "^1.0.0", - "_originalSource": "PolymerElements/iron-behaviors" + "_originalSource": "polymerelements/iron-behaviors" } \ No newline at end of file