1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

use shared image loader

This commit is contained in:
Luke Pulverenti 2016-01-16 13:29:08 -05:00
parent 08d07100ef
commit 000727d782
17 changed files with 570 additions and 347 deletions

View file

@ -16,12 +16,12 @@
}, },
"devDependencies": {}, "devDependencies": {},
"ignore": [], "ignore": [],
"version": "1.0.25", "version": "1.0.26",
"_release": "1.0.25", "_release": "1.0.26",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "1.0.25", "tag": "1.0.26",
"commit": "f2e83b0e30527b5182ceb043d170ad7188368245" "commit": "6fe8727397b13e87e3afaeee600f600269e0ee18"
}, },
"_source": "git://github.com/MediaBrowser/Emby.ApiClient.Javascript.git", "_source": "git://github.com/MediaBrowser/Emby.ApiClient.Javascript.git",
"_target": "~1.0.3", "_target": "~1.0.3",

View file

@ -748,44 +748,38 @@
console.log('Begin getConnectServers'); console.log('Begin getConnectServers');
return new Promise(function (resolve, reject) { if (!credentials.ConnectAccessToken || !credentials.ConnectUserId) {
return Promise.resolve([]);
}
if (!credentials.ConnectAccessToken || !credentials.ConnectUserId) { var url = "https://connect.emby.media/service/servers?userId=" + credentials.ConnectUserId;
resolve([]);
return; 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; }).then(function (servers) {
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([]);
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 = { var info = {
Id: foundServer.Id, Id: foundServer.Id,
LocalAddress: foundServer.Address, LocalAddress: convertEndpointAddressToManualAddress(foundServer) || foundServer.Address,
Name: foundServer.Name, Name: foundServer.Name,
ManualAddress: convertEndpointAddressToManualAddress(foundServer),
DateLastLocalConnection: new Date().getTime() DateLastLocalConnection: new Date().getTime()
}; };
@ -1467,13 +1460,10 @@
self.getRegistrationInfo = function (feature, apiClient) { self.getRegistrationInfo = function (feature, apiClient) {
if (isConnectUserSupporter()) { if (isConnectUserSupporter()) {
return new Promise(function (resolve, reject) { return Promise.resolve({
Name: feature,
resolve({ IsRegistered: true,
Name: feature, IsTrial: false
IsRegistered: true,
IsTrial: false
});
}); });
} }

View file

@ -15,12 +15,12 @@
}, },
"devDependencies": {}, "devDependencies": {},
"ignore": [], "ignore": [],
"version": "1.0.18", "version": "1.0.20",
"_release": "1.0.18", "_release": "1.0.20",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "1.0.18", "tag": "1.0.20",
"commit": "a251227c4635bcac732075e494b2d8a4e7956d26" "commit": "b88c3533403d7fc921adb381c81917c80d9c4e77"
}, },
"_source": "git://github.com/MediaBrowser/emby-webcomponents.git", "_source": "git://github.com/MediaBrowser/emby-webcomponents.git",
"_target": "~1.0.0", "_target": "~1.0.0",

View file

@ -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
};
});

View file

@ -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
};
});

View file

@ -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;
});
}
};
});

View file

@ -29,14 +29,14 @@
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
}, },
"ignore": [], "ignore": [],
"homepage": "https://github.com/polymerelements/iron-behaviors", "homepage": "https://github.com/PolymerElements/iron-behaviors",
"_release": "1.0.12", "_release": "1.0.12",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.0.12", "tag": "v1.0.12",
"commit": "657f526a2382a659cdf4e13be87ecc89261588a3" "commit": "657f526a2382a659cdf4e13be87ecc89261588a3"
}, },
"_source": "git://github.com/polymerelements/iron-behaviors.git", "_source": "git://github.com/PolymerElements/iron-behaviors.git",
"_target": "^1.0.0", "_target": "^1.0.0",
"_originalSource": "polymerelements/iron-behaviors" "_originalSource": "PolymerElements/iron-behaviors"
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "paper-input", "name": "paper-input",
"version": "1.1.4", "version": "1.1.5",
"description": "Material design text fields", "description": "Material design text fields",
"authors": [ "authors": [
"The Polymer Authors" "The Polymer Authors"
@ -44,14 +44,14 @@
"iron-validator-behavior": "PolymerElements/iron-validator-behavior#^1.0.0", "iron-validator-behavior": "PolymerElements/iron-validator-behavior#^1.0.0",
"paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0", "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
"test-fixture": "PolymerElements/test-fixture#^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" "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
}, },
"_release": "1.1.4", "_release": "1.1.5",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.1.4", "tag": "v1.1.5",
"commit": "8ca01ac3cafc61abd980d262875ffca0c79640fa" "commit": "0aa8318b5e026688f94c78c7673acabf5bad0f17"
}, },
"_source": "git://github.com/polymerelements/paper-input.git", "_source": "git://github.com/polymerelements/paper-input.git",
"_target": "^1.0.9", "_target": "^1.0.9",

View file

@ -1,6 +1,6 @@
{ {
"name": "paper-input", "name": "paper-input",
"version": "1.1.4", "version": "1.1.5",
"description": "Material design text fields", "description": "Material design text fields",
"authors": [ "authors": [
"The Polymer Authors" "The Polymer Authors"
@ -44,7 +44,7 @@
"iron-validator-behavior": "PolymerElements/iron-validator-behavior#^1.0.0", "iron-validator-behavior": "PolymerElements/iron-validator-behavior#^1.0.0",
"paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0", "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
"test-fixture": "PolymerElements/test-fixture#^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" "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
} }
} }

View file

@ -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 `<label>`'s content and `hidden` property, e.g. * The label for this input. If you're using PaperInputBehavior to
* implement your own paper-input-like element, bind this to
* `<label>`'s content and `hidden` property, e.g.
* `<label hidden$="[[!label]]">[[label]]</label>` in your `template` * `<label hidden$="[[!label]]">[[label]]</label>` in your `template`
*/ */
label: { label: {
@ -40,7 +42,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, },
/** /**
* The value for this input. Bind this to the `<input is="iron-input">`'s `bindValue` * The value for this input. If you're using PaperInputBehavior to
* implement your own paper-input-like element, bind this to
* the `<input is="iron-input">`'s `bindValue`
* property, or the value property of your input that is `notify:true`. * property, or the value property of your input that is `notify:true`.
*/ */
value: { value: {
@ -49,8 +53,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, },
/** /**
* Set to true to disable this input. Bind this to both the `<paper-input-container>`'s * Set to true to disable this input. If you're using PaperInputBehavior to
* and the input's `disabled` property. * implement your own paper-input-like element, bind this to
* both the `<paper-input-container>`'s and the input's `disabled` property.
*/ */
disabled: { disabled: {
type: Boolean, type: Boolean,
@ -58,8 +63,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, },
/** /**
* Returns true if the value is invalid. Bind this to both the `<paper-input-container>`'s * Returns true if the value is invalid. If you're using PaperInputBehavior to
* and the input's `invalid` property. * implement your own paper-input-like element, bind this to both the
* `<paper-input-container>`'s and the input's `invalid` property.
* *
* If `autoValidate` is true, the `invalid` attribute is managed automatically, * If `autoValidate` is true, the `invalid` attribute is managed automatically,
* which can clobber attempts to manage it manually. * which can clobber attempts to manage it manually.
@ -71,48 +77,55 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, },
/** /**
* Set to true to prevent the user from entering invalid input. Bind this to the * Set to true to prevent the user from entering invalid input. If you're
* `<input is="iron-input">`'s `preventInvalidInput` property. * using PaperInputBehavior to implement your own paper-input-like element,
* bind this to `<input is="iron-input">`'s `preventInvalidInput` property.
*/ */
preventInvalidInput: { preventInvalidInput: {
type: Boolean type: Boolean
}, },
/** /**
* Set this to specify the pattern allowed by `preventInvalidInput`. Bind this to the * Set this to specify the pattern allowed by `preventInvalidInput`. If
* `<input is="iron-input">`'s `allowedPattern` property. * you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `allowedPattern`
* property.
*/ */
allowedPattern: { allowedPattern: {
type: String type: String
}, },
/** /**
* The type of the input. The supported types are `text`, `number` and `password`. Bind this * The type of the input. The supported types are `text`, `number` and `password`.
* to the `<input is="iron-input">`'s `type` property. * If you're using PaperInputBehavior to implement your own paper-input-like element,
* bind this to the `<input is="iron-input">`'s `type` property.
*/ */
type: { type: {
type: String type: String
}, },
/** /**
* The datalist of the input (if any). This should match the id of an existing `<datalist>`. Bind this * The datalist of the input (if any). This should match the id of an existing `<datalist>`.
* to the `<input is="iron-input">`'s `list` property. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `list` property.
*/ */
list: { list: {
type: String type: String
}, },
/** /**
* A pattern to validate the `input` with. Bind this to the `<input is="iron-input">`'s * A pattern to validate the `input` with. If you're using PaperInputBehavior to
* `pattern` property. * implement your own paper-input-like element, bind this to
* the `<input is="iron-input">`'s `pattern` property.
*/ */
pattern: { pattern: {
type: String type: String
}, },
/** /**
* Set to true to mark the input as required. Bind this to the `<input is="iron-input">`'s * Set to true to mark the input as required. If you're using PaperInputBehavior to
* `required` property. * implement your own paper-input-like element, bind this to
* the `<input is="iron-input">`'s `required` property.
*/ */
required: { required: {
type: Boolean, type: Boolean,
@ -120,8 +133,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, },
/** /**
* The error message to display when the input is invalid. Bind this to the * The error message to display when the input is invalid. If you're using
* `<paper-input-error>`'s content, if using. * PaperInputBehavior to implement your own paper-input-like element,
* bind this to the `<paper-input-error>`'s content, if using.
*/ */
errorMessage: { errorMessage: {
type: String type: String
@ -136,8 +150,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, },
/** /**
* Set to true to disable the floating label. Bind this to the `<paper-input-container>`'s * Set to true to disable the floating label. If you're using PaperInputBehavior to
* `noLabelFloat` property. * implement your own paper-input-like element, bind this to
* the `<paper-input-container>`'s `noLabelFloat` property.
*/ */
noLabelFloat: { noLabelFloat: {
type: Boolean, type: Boolean,
@ -145,8 +160,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, },
/** /**
* Set to true to always float the label. Bind this to the `<paper-input-container>`'s * Set to true to always float the label. If you're using PaperInputBehavior to
* `alwaysFloatLabel` property. * implement your own paper-input-like element, bind this to
* the `<paper-input-container>`'s `alwaysFloatLabel` property.
*/ */
alwaysFloatLabel: { alwaysFloatLabel: {
type: Boolean, type: Boolean,
@ -154,8 +170,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, },
/** /**
* Set to true to auto-validate the input value. Bind this to the `<paper-input-container>`'s * Set to true to auto-validate the input value. If you're using PaperInputBehavior to
* `autoValidate` property. * implement your own paper-input-like element, bind this to
* the `<paper-input-container>`'s `autoValidate` property.
*/ */
autoValidate: { autoValidate: {
type: Boolean, type: Boolean,
@ -163,8 +180,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, },
/** /**
* Name of the validator to use. Bind this to the `<input is="iron-input">`'s `validator` * Name of the validator to use. If you're using PaperInputBehavior to
* property. * implement your own paper-input-like element, bind this to
* the `<input is="iron-input">`'s `validator` property.
*/ */
validator: { validator: {
type: String type: String
@ -173,7 +191,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
// HTMLInputElement attributes for binding if needed // HTMLInputElement attributes for binding if needed
/** /**
* Bind this to the `<input is="iron-input">`'s `autocomplete` property. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `autocomplete` property.
*/ */
autocomplete: { autocomplete: {
type: String, type: String,
@ -181,29 +200,34 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, },
/** /**
* Bind this to the `<input is="iron-input">`'s `autofocus` property. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `autofocus` property.
*/ */
autofocus: { autofocus: {
type: Boolean type: Boolean
}, },
/** /**
* Bind this to the `<input is="iron-input">`'s `inputmode` property. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `inputmode` property.
*/ */
inputmode: { inputmode: {
type: String type: String
}, },
/** /**
* Bind this to the `<input is="iron-input">`'s `minlength` property. * The minimum length of the input value.
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `minlength` property.
*/ */
minlength: { minlength: {
type: Number type: Number
}, },
/** /**
* The maximum length of the input value. Bind this to the `<input is="iron-input">`'s * The maximum length of the input value.
* `maxlength` property. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `maxlength` property.
*/ */
maxlength: { maxlength: {
type: Number type: Number
@ -211,7 +235,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
/** /**
* The minimum (numeric or date-time) input value. * The minimum (numeric or date-time) input value.
* Bind this to the `<input is="iron-input">`'s `min` property. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `min` property.
*/ */
min: { min: {
type: String type: String
@ -220,7 +245,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
/** /**
* The maximum (numeric or date-time) input value. * The maximum (numeric or date-time) input value.
* Can be a String (e.g. `"2000-1-1"`) or a Number (e.g. `2`). * Can be a String (e.g. `"2000-1-1"`) or a Number (e.g. `2`).
* Bind this to the `<input is="iron-input">`'s `max` property. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `max` property.
*/ */
max: { max: {
type: String type: String
@ -228,14 +254,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
/** /**
* Limits the numeric or date-time increments. * Limits the numeric or date-time increments.
* Bind this to the `<input is="iron-input">`'s `step` property. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `step` property.
*/ */
step: { step: {
type: String type: String
}, },
/** /**
* Bind this to the `<input is="iron-input">`'s `name` property. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `name` property.
*/ */
name: { name: {
type: String type: String
@ -251,7 +279,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, },
/** /**
* Bind this to the `<input is="iron-input">`'s `readonly` property. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `readonly` property.
*/ */
readonly: { readonly: {
type: Boolean, type: Boolean,
@ -259,7 +288,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, },
/** /**
* Bind this to the `<input is="iron-input">`'s `size` property. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `size` property.
*/ */
size: { size: {
type: Number type: Number
@ -268,7 +298,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
// Nonstandard attributes for binding if needed // Nonstandard attributes for binding if needed
/** /**
* Bind this to the `<input is="iron-input">`'s `autocapitalize` property. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `autocapitalize` property.
*/ */
autocapitalize: { autocapitalize: {
type: String, type: String,
@ -276,7 +307,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, },
/** /**
* Bind this to the `<input is="iron-input">`'s `autocorrect` property. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `autocorrect` property.
*/ */
autocorrect: { autocorrect: {
type: String, type: String,
@ -284,28 +316,36 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, },
/** /**
* Bind this to the `<input is="iron-input">`'s `autosave` property, used with type=search. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `autosave` property,
* used with type=search.
*/ */
autosave: { autosave: {
type: String type: String
}, },
/** /**
* Bind this to the `<input is="iron-input">`'s `results` property, used with type=search. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `results` property,
* used with type=search.
*/ */
results: { results: {
type: Number type: Number
}, },
/** /**
* Bind this to the `<input is="iron-input">`'s `accept` property, used with type=file. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `accept` property,
* used with type=file.
*/ */
accept: { accept: {
type: String type: String
}, },
/** /**
* Bind this to the `<input is="iron-input">`'s `multiple` property, used with type=file. * If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the`<input is="iron-input">`'s `multiple` property,
* used with type=file.
*/ */
multiple: { multiple: {
type: Boolean type: Boolean
@ -354,8 +394,20 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
return this.inputElement; return this.inputElement;
}, },
registered: function() {
// These types have some default placeholder text; overlapping
// the label on top of it looks terrible. Auto-float the label in this case.
this._typesThatHaveText = ["date", "datetime", "datetime-local", "month",
"time", "week", "file"];
},
attached: function() { attached: function() {
this._updateAriaLabelledBy(); this._updateAriaLabelledBy();
if (this.inputElement &&
this._typesThatHaveText.indexOf(this.inputElement.type) !== -1) {
this.alwaysFloatLabel = true;
}
}, },
_appendStringWithSpace: function(str, more) { _appendStringWithSpace: function(str, more) {

View file

@ -39,9 +39,10 @@ for `suffix`).
</paper-input> </paper-input>
A `paper-input` can use the native `type=search` or `type=file` features. A `paper-input` can use the native `type=search` or `type=file` features.
However, since we can't control the native styling of the input, in these cases However, since we can't control the native styling of the input (search icon,
it's recommended to use a placeholder text, or `always-float-label`, file button, date placeholder, etc.), in these cases the label will be
as to not overlap the native UI (search icon, file button, etc.). automatically floated. The `placeholder` attribute can still be used for
additional informational text.
<paper-input label="search!" type="search" <paper-input label="search!" type="search"
placeholder="search for cats" autosave="test" results="5"> placeholder="search for cats" autosave="test" results="5">
@ -100,6 +101,7 @@ style this element.
aria-labelledby$="[[_ariaLabelledBy]]" aria-labelledby$="[[_ariaLabelledBy]]"
aria-describedby$="[[_ariaDescribedBy]]" aria-describedby$="[[_ariaDescribedBy]]"
disabled$="[[disabled]]" disabled$="[[disabled]]"
title$="[[title]]"
bind-value="{{value}}" bind-value="{{value}}"
invalid="{{invalid}}" invalid="{{invalid}}"
prevent-invalid-input="[[preventInvalidInput]]" prevent-invalid-input="[[preventInvalidInput]]"

View file

@ -70,7 +70,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
</template> </template>
</test-fixture> </test-fixture>
<test-fixture id="required-char-counter"> <test-fixture id="required-char-counter">
<template> <template>
<paper-input auto-validate char-counter required error-message="error"></paper-input> <paper-input auto-validate char-counter required error-message="error"></paper-input>
@ -95,6 +94,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
</template> </template>
</test-fixture> </test-fixture>
<test-fixture id="date">
<template>
<paper-input label="foo" type="date"></paper-input>
</template>
</test-fixture>
<letters-only></letters-only> <letters-only></letters-only>
<test-fixture id="validator"> <test-fixture id="validator">
@ -121,6 +126,18 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
assert.ok(floatingLabel); assert.ok(floatingLabel);
}); });
test('special types autofloat the label', function() {
var input = fixture('date');
// Browsers that don't support special <input> types like `date` fallback
// to `text`, so make sure to only test if type is still preserved after
// the element is attached.
if (input.inputElement.type === "date") {
assert.equal(input.alwaysFloatLabel, true);
var floatingLabel = Polymer.dom(Polymer.dom(input.root).querySelector('paper-input-container').root).querySelector('.label-is-floating');
assert.ok(floatingLabel);
}
});
test('always-float-label attribute works without placeholder', function() { test('always-float-label attribute works without placeholder', function() {
var input = fixture('always-float-label'); var input = fixture('always-float-label');
var container = Polymer.dom(input.root).querySelector('paper-input-container'); var container = Polymer.dom(input.root).querySelector('paper-input-container');

View file

@ -32,14 +32,14 @@
"iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0" "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0"
}, },
"ignore": [], "ignore": [],
"homepage": "https://github.com/polymerelements/paper-ripple", "homepage": "https://github.com/PolymerElements/paper-ripple",
"_release": "1.0.5", "_release": "1.0.5",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.0.5", "tag": "v1.0.5",
"commit": "d72e7a9a8ab518b901ed18dde492df3b87a93be5" "commit": "d72e7a9a8ab518b901ed18dde492df3b87a93be5"
}, },
"_source": "git://github.com/polymerelements/paper-ripple.git", "_source": "git://github.com/PolymerElements/paper-ripple.git",
"_target": "^1.0.0", "_target": "^1.0.0",
"_originalSource": "polymerelements/paper-ripple" "_originalSource": "PolymerElements/paper-ripple"
} }

View file

@ -24,14 +24,14 @@
"web-component-tester": "*" "web-component-tester": "*"
}, },
"private": true, "private": true,
"homepage": "https://github.com/polymer/polymer", "homepage": "https://github.com/Polymer/polymer",
"_release": "1.2.3", "_release": "1.2.3",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.2.3", "tag": "v1.2.3",
"commit": "aa535d1675342007cbf64dc9c66497cf74cbc616" "commit": "aa535d1675342007cbf64dc9c66497cf74cbc616"
}, },
"_source": "git://github.com/polymer/polymer.git", "_source": "git://github.com/Polymer/polymer.git",
"_target": "^1.0.0", "_target": "^1.0.0",
"_originalSource": "polymer/polymer" "_originalSource": "Polymer/polymer"
} }

View file

@ -1,185 +0,0 @@
(function () {
function setImageIntoElement(elem, url) {
if (elem.tagName !== "IMG") {
elem.style.backgroundImage = "url('" + url + "')";
} else {
elem.setAttribute("src", url);
}
if (browserInfo.chrome && !browserInfo.mobile) {
if (!elem.classList.contains('noFade')) {
fadeIn(elem, 1);
}
}
}
function fadeIn(elem, iterations) {
var keyframes = [
{ opacity: '0', offset: 0 },
{ opacity: '1', offset: 1 }];
var timing = { duration: 200, iterations: iterations };
return elem.animate(keyframes, timing);
}
// Request Quota (only for File System API)
var requestedBytes = 1024 * 1024 * 600; // MB
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;
});
});
});
var fileSystem;
function imageFileStore() {
var self = this;
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);
}
self.getImageUrl = function (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);
});
});
};
self.setImageInto = function (elem, url) {
self.getImageUrl(url).then(function (localUrl) {
setImageIntoElement(elem, localUrl);
}, function () {
setImageIntoElement(elem, url);
});
};
window.ImageStore = self;
}
require(['cryptojs-md5'], function () {
new imageFileStore();
});
})();

View file

@ -1849,6 +1849,14 @@ var AppInfo = {};
connectservice: apiClientBowerPath + '/connectservice' connectservice: apiClientBowerPath + '/connectservice'
}; };
if (navigator.webkitPersistentStorage) {
paths.imageloader = embyWebComponentsBowerPath + "/images/persistentimageloader";
} else if (Dashboard.isRunningInCordova()) {
paths.imageloader = 'cordova/imagestore';
} else {
paths.imageloader = embyWebComponentsBowerPath + "/images/basicimageloader";
}
paths.hlsjs = bowerPath + "/hls.js/dist/hls.min"; paths.hlsjs = bowerPath + "/hls.js/dist/hls.min";
if (Dashboard.isRunningInCordova()) { if (Dashboard.isRunningInCordova()) {
@ -2262,13 +2270,6 @@ var AppInfo = {};
var postInitDependencies = []; var postInitDependencies = [];
if (navigator.webkitPersistentStorage) {
postInitDependencies.push('components/imagestore');
}
else if (Dashboard.isRunningInCordova()) {
postInitDependencies.push('cordova/imagestore');
}
postInitDependencies.push('scripts/thememediaplayer'); postInitDependencies.push('scripts/thememediaplayer');
postInitDependencies.push('scripts/remotecontrol'); postInitDependencies.push('scripts/remotecontrol');
postInitDependencies.push('css!css/notifications.css'); postInitDependencies.push('css!css/notifications.css');
@ -2396,7 +2397,7 @@ var AppInfo = {};
var keys = []; var keys = [];
keys.push(navigator.userAgent); keys.push(navigator.userAgent);
keys.push((navigator.cpuClass || "")); keys.push((navigator.cpuClass || ""));
keys.push(new Date().getTime());
var randomId = CryptoJS.SHA1(keys.join('|')).toString(); var randomId = CryptoJS.SHA1(keys.join('|')).toString();
appStorage.setItem('_deviceId', randomId); appStorage.setItem('_deviceId', randomId);
onDeviceAdAcquired(randomId); onDeviceAdAcquired(randomId);

View file

@ -1,4 +1,4 @@
define(['visibleinviewport'], function (visibleInViewport) { define(['visibleinviewport', 'imageloader'], function (visibleInViewport, imageLoader) {
var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel'); var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel');
var thresholdX = screen.availWidth; var thresholdX = screen.availWidth;
@ -11,11 +11,27 @@
function fillImage(elem) { function fillImage(elem) {
var source = elem.getAttribute('data-src'); var source = elem.getAttribute('data-src');
if (source) { if (source) {
ImageStore.setImageInto(elem, source); imageLoader.loadImage(elem, source).then(fadeIn);
elem.setAttribute("data-src", ''); elem.setAttribute("data-src", '');
} }
} }
function fadeIn(elem) {
if (!browserInfo.animate || browserInfo.mobile) {
return;
}
if (elem.classList.contains('noFade')) {
return;
}
var keyframes = [
{ opacity: '0', offset: 0 },
{ opacity: '1', offset: 1 }];
var timing = { duration: 300, iterations: 1 };
elem.animate(keyframes, timing);
}
function cancelAll(tokens) { function cancelAll(tokens) {
for (var i = 0, length = tokens.length; i < length; i++) { for (var i = 0, length = tokens.length; i < length; i++) {
@ -90,11 +106,7 @@
for (var i = 0, length = elems.length; i < length; i++) { for (var i = 0, length = elems.length; i < length; i++) {
var elem = elems[0]; var elem = elems[0];
var source = elem.getAttribute('data-src'); fillImage(elem);
if (source) {
ImageStore.setImageInto(elem, source);
elem.setAttribute("data-src", '');
}
} }
} }
@ -109,36 +121,6 @@
fillImages([elem]); fillImages([elem]);
} }
function setImageIntoElement(elem, url) {
if (elem.tagName !== "IMG") {
elem.style.backgroundImage = "url('" + url + "')";
} else {
elem.setAttribute("src", url);
}
if (browserInfo.animate && !browserInfo.mobile) {
if (!elem.classList.contains('noFade')) {
fadeIn(elem, 1);
}
}
}
function fadeIn(elem, iterations) {
var keyframes = [
{ opacity: '0', offset: 0 },
{ opacity: '1', offset: 1 }];
var timing = { duration: 200, iterations: iterations };
return elem.animate(keyframes, timing);
}
window.ImageStore = {
setImageInto: setImageIntoElement
};
window.ImageLoader = { window.ImageLoader = {
fillImages: fillImages, fillImages: fillImages,
lazyImage: lazyImage, lazyImage: lazyImage,