From ad1f82dbaf1602c4de871ecdad98d63e174ddf34 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 16 Jan 2016 13:29:08 -0500 Subject: [PATCH] use shared image loader --- .../emby-apiclient/.bower.json | 8 +- .../emby-apiclient/connectionmanager.js | 74 +++---- .../emby-webcomponents/.bower.json | 8 +- .../images/basicimageloader.js | 25 +++ .../emby-webcomponents/images/imagehelper.js | 175 +++++++++++++++++ .../images/persistentimageloader.js | 164 ++++++++++++++++ .../iron-behaviors/.bower.json | 6 +- .../bower_components/paper-input/.bower.json | 10 +- .../bower_components/paper-input/bower.json | 4 +- .../paper-input/paper-input-behavior.html | 146 +++++++++----- .../paper-input/paper-input.html | 8 +- .../paper-input/test/paper-input.html | 19 +- .../bower_components/paper-ripple/.bower.json | 6 +- .../bower_components/polymer/.bower.json | 6 +- dashboard-ui/components/imagestore.js | 185 ------------------ dashboard-ui/scripts/site.js | 17 +- .../thirdparty/jquery.unveil-custom.js | 56 ++---- 17 files changed, 570 insertions(+), 347 deletions(-) create mode 100644 dashboard-ui/bower_components/emby-webcomponents/images/basicimageloader.js create mode 100644 dashboard-ui/bower_components/emby-webcomponents/images/imagehelper.js create mode 100644 dashboard-ui/bower_components/emby-webcomponents/images/persistentimageloader.js delete mode 100644 dashboard-ui/components/imagestore.js diff --git a/dashboard-ui/bower_components/emby-apiclient/.bower.json b/dashboard-ui/bower_components/emby-apiclient/.bower.json index 0a72e4c328..7aa03d96c4 100644 --- a/dashboard-ui/bower_components/emby-apiclient/.bower.json +++ b/dashboard-ui/bower_components/emby-apiclient/.bower.json @@ -16,12 +16,12 @@ }, "devDependencies": {}, "ignore": [], - "version": "1.0.25", - "_release": "1.0.25", + "version": "1.0.26", + "_release": "1.0.26", "_resolution": { "type": "version", - "tag": "1.0.25", - "commit": "f2e83b0e30527b5182ceb043d170ad7188368245" + "tag": "1.0.26", + "commit": "6fe8727397b13e87e3afaeee600f600269e0ee18" }, "_source": "git://github.com/MediaBrowser/Emby.ApiClient.Javascript.git", "_target": "~1.0.3", diff --git a/dashboard-ui/bower_components/emby-apiclient/connectionmanager.js b/dashboard-ui/bower_components/emby-apiclient/connectionmanager.js index efa177a53b..e1de391585 100644 --- a/dashboard-ui/bower_components/emby-apiclient/connectionmanager.js +++ b/dashboard-ui/bower_components/emby-apiclient/connectionmanager.js @@ -748,44 +748,38 @@ console.log('Begin getConnectServers'); - return new Promise(function (resolve, reject) { + if (!credentials.ConnectAccessToken || !credentials.ConnectUserId) { + return Promise.resolve([]); + } - if (!credentials.ConnectAccessToken || !credentials.ConnectUserId) { - resolve([]); - return; + var url = "https://connect.emby.media/service/servers?userId=" + credentials.ConnectUserId; + + return ajax({ + type: "GET", + url: url, + dataType: "json", + headers: { + "X-Application": appName + "/" + appVersion, + "X-Connect-UserToken": credentials.ConnectAccessToken } - var url = "https://connect.emby.media/service/servers?userId=" + credentials.ConnectUserId; - - ajax({ - type: "GET", - url: url, - dataType: "json", - headers: { - "X-Application": appName + "/" + appVersion, - "X-Connect-UserToken": credentials.ConnectAccessToken - } - - }).then(function (servers) { - - servers = servers.map(function (i) { - return { - ExchangeToken: i.AccessKey, - ConnectServerId: i.Id, - Id: i.SystemId, - Name: i.Name, - RemoteAddress: i.Url, - LocalAddress: i.LocalAddress, - UserLinkType: (i.UserType || '').toLowerCase() == "guest" ? "Guest" : "LinkedUser" - }; - }); - - resolve(servers); - - }, function () { - resolve([]); + }).then(function (servers) { + return servers.map(function (i) { + return { + ExchangeToken: i.AccessKey, + ConnectServerId: i.Id, + Id: i.SystemId, + Name: i.Name, + RemoteAddress: i.Url, + LocalAddress: i.LocalAddress, + UserLinkType: (i.UserType || '').toLowerCase() == "guest" ? "Guest" : "LinkedUser" + }; }); + + }, function () { + return []; + }); } @@ -858,9 +852,8 @@ var info = { Id: foundServer.Id, - LocalAddress: foundServer.Address, + LocalAddress: convertEndpointAddressToManualAddress(foundServer) || foundServer.Address, Name: foundServer.Name, - ManualAddress: convertEndpointAddressToManualAddress(foundServer), DateLastLocalConnection: new Date().getTime() }; @@ -1467,13 +1460,10 @@ self.getRegistrationInfo = function (feature, apiClient) { if (isConnectUserSupporter()) { - return new Promise(function (resolve, reject) { - - resolve({ - Name: feature, - IsRegistered: true, - IsTrial: false - }); + return Promise.resolve({ + Name: feature, + IsRegistered: true, + IsTrial: false }); } diff --git a/dashboard-ui/bower_components/emby-webcomponents/.bower.json b/dashboard-ui/bower_components/emby-webcomponents/.bower.json index 5ff3c5d040..e144b18851 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/.bower.json +++ b/dashboard-ui/bower_components/emby-webcomponents/.bower.json @@ -15,12 +15,12 @@ }, "devDependencies": {}, "ignore": [], - "version": "1.0.18", - "_release": "1.0.18", + "version": "1.0.20", + "_release": "1.0.20", "_resolution": { "type": "version", - "tag": "1.0.18", - "commit": "a251227c4635bcac732075e494b2d8a4e7956d26" + "tag": "1.0.20", + "commit": "b88c3533403d7fc921adb381c81917c80d9c4e77" }, "_source": "git://github.com/MediaBrowser/emby-webcomponents.git", "_target": "~1.0.0", diff --git a/dashboard-ui/bower_components/emby-webcomponents/images/basicimageloader.js b/dashboard-ui/bower_components/emby-webcomponents/images/basicimageloader.js new file mode 100644 index 0000000000..a981713a94 --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/images/basicimageloader.js @@ -0,0 +1,25 @@ +define([], function () { + + function loadImage(elem, url) { + + if (elem.tagName !== "IMG") { + + var tmp = new Image(); + + tmp.onload = function () { + elem.style.backgroundImage = "url('" + url + "')"; + }; + tmp.src = url; + + } else { + elem.setAttribute("src", url); + } + + return Promise.resolve(elem); + } + + return { + loadImage: loadImage + }; + +}); \ No newline at end of file diff --git a/dashboard-ui/bower_components/emby-webcomponents/images/imagehelper.js b/dashboard-ui/bower_components/emby-webcomponents/images/imagehelper.js new file mode 100644 index 0000000000..8548fe58a6 --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/images/imagehelper.js @@ -0,0 +1,175 @@ +define(['visibleinviewport', 'imageloader'], function (visibleinviewport, imageLoader) { + + var thresholdX = screen.availWidth; + var thresholdY = screen.availHeight; + + var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel'); + + function isVisible(elem) { + return visibleinviewport(elem, true, thresholdX, thresholdY); + } + + function fillImage(elem) { + var source = elem.getAttribute('data-src'); + if (source) { + imageLoader.loadImage(elem, source); + elem.setAttribute("data-src", ''); + } + } + + function cancelAll(tokens) { + for (var i = 0, length = tokens.length; i < length; i++) { + + tokens[i] = true; + } + } + + function unveilElements(images) { + + if (!images.length) { + return; + } + + var cancellationTokens = []; + function unveilInternal(tokenIndex) { + + var remaining = []; + var anyFound = false; + var out = false; + + // TODO: This out construct assumes left to right, top to bottom + + for (var i = 0, length = images.length; i < length; i++) { + + if (cancellationTokens[tokenIndex]) { + return; + } + var img = images[i]; + if (!out && isVisible(img)) { + anyFound = true; + fillImage(img); + } else { + + if (anyFound) { + out = true; + } + remaining.push(img); + } + } + + images = remaining; + + if (!images.length) { + document.removeEventListener('focus', unveil, true); + document.removeEventListener('scroll', unveil, true); + document.removeEventListener(wheelEvent, unveil, true); + window.removeEventListener('resize', unveil, true); + } + } + + function unveil() { + + cancelAll(cancellationTokens); + + var index = cancellationTokens.length; + cancellationTokens.length++; + + setTimeout(function () { + unveilInternal(index); + }, 1); + } + + document.addEventListener('scroll', unveil, true); + document.addEventListener('focus', unveil, true); + document.addEventListener(wheelEvent, unveil, true); + window.addEventListener('resize', unveil, true); + + unveil(); + } + + function fillImages(elems) { + + for (var i = 0, length = elems.length; i < length; i++) { + var elem = elems[0]; + var source = elem.getAttribute('data-src'); + if (source) { + ImageStore.setImageInto(elem, source); + elem.setAttribute("data-src", ''); + } + } + } + + function lazyChildren(elem) { + + unveilElements(elem.getElementsByClassName('lazy')); + } + + function lazyImage(elem, url) { + + elem.setAttribute('data-src', url); + fillImages([elem]); + } + + function getPrimaryImageAspectRatio(items) { + + var values = []; + + for (var i = 0, length = items.length; i < length; i++) { + + var ratio = items[i].PrimaryImageAspectRatio || 0; + + if (!ratio) { + continue; + } + + values[values.length] = ratio; + } + + if (!values.length) { + return null; + } + + // Use the median + values.sort(function (a, b) { return a - b; }); + + var half = Math.floor(values.length / 2); + + var result; + + if (values.length % 2) + result = values[half]; + else + result = (values[half - 1] + values[half]) / 2.0; + + // If really close to 2:3 (poster image), just return 2:3 + var aspect2x3 = 2 / 3; + if (Math.abs(aspect2x3 - result) <= .15) { + return aspect2x3; + } + + // If really close to 16:9 (episode image), just return 16:9 + var aspect16x9 = 16 / 9; + if (Math.abs(aspect16x9 - result) <= .2) { + return aspect16x9; + } + + // If really close to 1 (square image), just return 1 + if (Math.abs(1 - result) <= .15) { + return 1; + } + + // If really close to 4:3 (poster image), just return 2:3 + var aspect4x3 = 4 / 3; + if (Math.abs(aspect4x3 - result) <= .15) { + return aspect4x3; + } + + return result; + } + + return { + lazyChildren: lazyChildren, + getPrimaryImageAspectRatio: getPrimaryImageAspectRatio + }; + +}); \ No newline at end of file diff --git a/dashboard-ui/bower_components/emby-webcomponents/images/persistentimageloader.js b/dashboard-ui/bower_components/emby-webcomponents/images/persistentimageloader.js new file mode 100644 index 0000000000..1cbcb640b0 --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/images/persistentimageloader.js @@ -0,0 +1,164 @@ +define(['cryptojs-md5'], function () { + + function setImageIntoElement(elem, url) { + + if (elem.tagName !== "IMG") { + + elem.style.backgroundImage = "url('" + url + "')"; + + } else { + elem.setAttribute("src", url); + } + } + + // Request Quota (only for File System API) + var requestedBytes = 1024 * 1024 * 1500; + var imageCacheDirectoryEntry; + var imageCacheFolder = 'images'; + + function createDir(rootDirEntry, folders, callback, errorCallback) { + // Throw out './' or '/' and move on to prevent something like '/foo/.//bar'. + if (folders[0] == '.' || folders[0] == '') { + folders = folders.slice(1); + } + rootDirEntry.getDirectory(folders[0], { create: true }, function (dirEntry) { + // Recursively add the new subfolder (if we still have another to create). + if (folders.length > 1) { + createDir(dirEntry, folders.slice(1), callback, errorCallback); + } else { + callback(dirEntry); + } + }, errorCallback); + } + + navigator.webkitPersistentStorage.requestQuota( + requestedBytes, function (grantedBytes) { + + var requestMethod = window.webkitRequestFileSystem || window.requestFileSystem; + + requestMethod(PERSISTENT, grantedBytes, function (fs) { + + fileSystem = fs; + + createDir(fileSystem.root, imageCacheFolder.split('/'), function (dirEntry) { + + imageCacheDirectoryEntry = dirEntry; + + }); + + }); + + }); + + function getCacheKey(url) { + + // Try to strip off the domain to share the cache between local and remote connections + var index = url.indexOf('://'); + + if (index != -1) { + url = url.substring(index + 3); + + index = url.indexOf('/'); + + if (index != -1) { + url = url.substring(index + 1); + } + + } + + return CryptoJS.MD5(url).toString(); + } + + function downloadToFile(url, dir, filename, callback, errorCallback) { + + console.log('Downloading ' + url); + + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.responseType = "arraybuffer"; + + xhr.onload = function (e) { + if (this.status == 200) { + writeData(dir, filename, this.getResponseHeader('Content-Type'), this.response, callback, errorCallback); + } else { + errorCallback(); + } + } + + xhr.send(); + } + + function writeData(dir, filename, fileType, data, callback, errorCallback) { + + dir.getFile(filename, { create: true }, function (fileEntry) { + + // Create a FileWriter object for our FileEntry (log.txt). + fileEntry.createWriter(function (fileWriter) { + + fileWriter.onwriteend = function (e) { + callback(fileEntry); + }; + + fileWriter.onerror = errorCallback; + + // Create a new Blob and write it to log.txt. + var blob = new Blob([data], { type: fileType }); + + fileWriter.write(blob); + + }, errorCallback); + + }, errorCallback); + } + + function getImageUrl(originalUrl) { + + return new Promise(function (resolve, reject) { + + if (originalUrl.indexOf('tag=') != -1) { + originalUrl += "&accept=webp"; + } + + var key = getCacheKey(originalUrl); + + var fileEntryCallback = function (fileEntry) { + resolve(fileEntry.toURL()); + }; + + var errorCallback = function (e) { + console.log('Imagestore error: ' + e.name); + reject(); + }; + + if (!fileSystem || !imageCacheDirectoryEntry) { + errorCallback(''); + return; + } + + var path = '/' + imageCacheFolder + "/" + key; + + fileSystem.root.getFile(path, { create: false }, fileEntryCallback, function () { + + downloadToFile(originalUrl, imageCacheDirectoryEntry, key, fileEntryCallback, errorCallback); + }); + }); + } + + var fileSystem; + + return { + loadImage: function (elem, url) { + + return getImageUrl(url).then(function (localUrl) { + + setImageIntoElement(elem, localUrl); + return elem; + + }, function () { + setImageIntoElement(elem, url); + return elem; + }); + } + }; + +}); \ No newline at end of file diff --git a/dashboard-ui/bower_components/iron-behaviors/.bower.json b/dashboard-ui/bower_components/iron-behaviors/.bower.json index 17f68b3351..db08f2170c 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.12", "_resolution": { "type": "version", "tag": "v1.0.12", "commit": "657f526a2382a659cdf4e13be87ecc89261588a3" }, - "_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 diff --git a/dashboard-ui/bower_components/paper-input/.bower.json b/dashboard-ui/bower_components/paper-input/.bower.json index 99d82dd61d..0216a6c581 100644 --- a/dashboard-ui/bower_components/paper-input/.bower.json +++ b/dashboard-ui/bower_components/paper-input/.bower.json @@ -1,6 +1,6 @@ { "name": "paper-input", - "version": "1.1.4", + "version": "1.1.5", "description": "Material design text fields", "authors": [ "The Polymer Authors" @@ -44,14 +44,14 @@ "iron-validator-behavior": "PolymerElements/iron-validator-behavior#^1.0.0", "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0", "test-fixture": "PolymerElements/test-fixture#^1.0.0", - "web-component-tester": "Polymer/web-component-tester#^3.4.0", + "web-component-tester": "^4.0.0", "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" }, - "_release": "1.1.4", + "_release": "1.1.5", "_resolution": { "type": "version", - "tag": "v1.1.4", - "commit": "8ca01ac3cafc61abd980d262875ffca0c79640fa" + "tag": "v1.1.5", + "commit": "0aa8318b5e026688f94c78c7673acabf5bad0f17" }, "_source": "git://github.com/polymerelements/paper-input.git", "_target": "^1.0.9", diff --git a/dashboard-ui/bower_components/paper-input/bower.json b/dashboard-ui/bower_components/paper-input/bower.json index 22775b8851..99a9b83b38 100644 --- a/dashboard-ui/bower_components/paper-input/bower.json +++ b/dashboard-ui/bower_components/paper-input/bower.json @@ -1,6 +1,6 @@ { "name": "paper-input", - "version": "1.1.4", + "version": "1.1.5", "description": "Material design text fields", "authors": [ "The Polymer Authors" @@ -44,7 +44,7 @@ "iron-validator-behavior": "PolymerElements/iron-validator-behavior#^1.0.0", "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0", "test-fixture": "PolymerElements/test-fixture#^1.0.0", - "web-component-tester": "Polymer/web-component-tester#^3.4.0", + "web-component-tester": "^4.0.0", "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" } } diff --git a/dashboard-ui/bower_components/paper-input/paper-input-behavior.html b/dashboard-ui/bower_components/paper-input/paper-input-behavior.html index f41669c7e9..3edbb79ca9 100644 --- a/dashboard-ui/bower_components/paper-input/paper-input-behavior.html +++ b/dashboard-ui/bower_components/paper-input/paper-input-behavior.html @@ -32,7 +32,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN */ /** - * The label for this input. Bind this to `