diff options
Diffstat (limited to 'catapult/third_party/polymer/components/iron-image/iron-image.html')
-rwxr-xr-x | catapult/third_party/polymer/components/iron-image/iron-image.html | 403 |
1 files changed, 403 insertions, 0 deletions
diff --git a/catapult/third_party/polymer/components/iron-image/iron-image.html b/catapult/third_party/polymer/components/iron-image/iron-image.html new file mode 100755 index 00000000..bf774d6c --- /dev/null +++ b/catapult/third_party/polymer/components/iron-image/iron-image.html @@ -0,0 +1,403 @@ +<!-- +@license +Copyright (c) 2015 The Polymer Project Authors. All rights reserved. +This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt +The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt +The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt +Code distributed by Google as part of the polymer project is also +subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt +--> + +<link rel="import" href="../polymer/polymer.html"> +<link rel="import" href="../iron-flex-layout/iron-flex-layout.html"> + +<!-- +`iron-image` is an element for displaying an image that provides useful sizing and +preloading options not found on the standard `<img>` tag. + +The `sizing` option allows the image to be either cropped (`cover`) or +letterboxed (`contain`) to fill a fixed user-size placed on the element. + +The `preload` option prevents the browser from rendering the image until the +image is fully loaded. In the interim, either the element's CSS `background-color` +can be be used as the placeholder, or the `placeholder` property can be +set to a URL (preferably a data-URI, for instant rendering) for an +placeholder image. + +The `fade` option (only valid when `preload` is set) will cause the placeholder +image/color to be faded out once the image is rendered. + +Examples: + + Basically identical to `<img src="...">` tag: + + <iron-image src="http://lorempixel.com/400/400"></iron-image> + + Will letterbox the image to fit: + + <iron-image style="width:400px; height:400px;" sizing="contain" + src="http://lorempixel.com/600/400"></iron-image> + + Will crop the image to fit: + + <iron-image style="width:400px; height:400px;" sizing="cover" + src="http://lorempixel.com/600/400"></iron-image> + + Will show light-gray background until the image loads: + + <iron-image style="width:400px; height:400px; background-color: lightgray;" + sizing="cover" preload src="http://lorempixel.com/600/400"></iron-image> + + Will show a base-64 encoded placeholder image until the image loads: + + <iron-image style="width:400px; height:400px;" placeholder="data:image/gif;base64,..." + sizing="cover" preload src="http://lorempixel.com/600/400"></iron-image> + + Will fade the light-gray background out once the image is loaded: + + <iron-image style="width:400px; height:400px; background-color: lightgray;" + sizing="cover" preload fade src="http://lorempixel.com/600/400"></iron-image> + +Custom property | Description | Default +----------------|-------------|---------- +`--iron-image-placeholder` | Mixin applied to #placeholder | `{}` +`--iron-image-width` | Sets the width of the wrapped image | `auto` +`--iron-image-height` | Sets the height of the wrapped image | `auto` + +@group Iron Elements +@element iron-image +@demo demo/index.html +--> + +<dom-module id="iron-image"> + <template> + <style> + :host { + display: inline-block; + overflow: hidden; + position: relative; + } + + #sizedImgDiv { + @apply(--layout-fit); + + display: none; + } + + #img { + display: block; + width: var(--iron-image-width, auto); + height: var(--iron-image-height, auto); + } + + :host([sizing]) #sizedImgDiv { + display: block; + } + + :host([sizing]) #img { + display: none; + } + + #placeholder { + @apply(--layout-fit); + + background-color: inherit; + opacity: 1; + + @apply(--iron-image-placeholder); + } + + #placeholder.faded-out { + transition: opacity 0.5s linear; + opacity: 0; + } + </style> + + <div id="sizedImgDiv" + role="img" + hidden$="[[_computeImgDivHidden(sizing)]]" + aria-hidden$="[[_computeImgDivARIAHidden(alt)]]" + aria-label$="[[_computeImgDivARIALabel(alt, src)]]"></div> + <img id="img" alt$="[[alt]]" hidden$="[[_computeImgHidden(sizing)]]"> + <div id="placeholder" + hidden$="[[_computePlaceholderHidden(preload, fade, loading, loaded)]]" + class$="[[_computePlaceholderClassName(preload, fade, loading, loaded)]]"></div> + </template> + + <script> + Polymer({ + is: 'iron-image', + + properties: { + /** + * The URL of an image. + */ + src: { + observer: '_srcChanged', + type: String, + value: '' + }, + + /** + * A short text alternative for the image. + */ + alt: { + type: String, + value: null + }, + + /** + * When true, the image is prevented from loading and any placeholder is + * shown. This may be useful when a binding to the src property is known to + * be invalid, to prevent 404 requests. + */ + preventLoad: { + type: Boolean, + value: false, + observer: '_preventLoadChanged' + }, + + /** + * Sets a sizing option for the image. Valid values are `contain` (full + * aspect ratio of the image is contained within the element and + * letterboxed) or `cover` (image is cropped in order to fully cover the + * bounds of the element), or `null` (default: image takes natural size). + */ + sizing: { + type: String, + value: null, + reflectToAttribute: true + }, + + /** + * When a sizing option is used (`cover` or `contain`), this determines + * how the image is aligned within the element bounds. + */ + position: { + type: String, + value: 'center' + }, + + /** + * When `true`, any change to the `src` property will cause the `placeholder` + * image to be shown until the new image has loaded. + */ + preload: { + type: Boolean, + value: false + }, + + /** + * This image will be used as a background/placeholder until the src image has + * loaded. Use of a data-URI for placeholder is encouraged for instant rendering. + */ + placeholder: { + type: String, + value: null, + observer: '_placeholderChanged' + }, + + /** + * When `preload` is true, setting `fade` to true will cause the image to + * fade into place. + */ + fade: { + type: Boolean, + value: false + }, + + /** + * Read-only value that is true when the image is loaded. + */ + loaded: { + notify: true, + readOnly: true, + type: Boolean, + value: false + }, + + /** + * Read-only value that tracks the loading state of the image when the `preload` + * option is used. + */ + loading: { + notify: true, + readOnly: true, + type: Boolean, + value: false + }, + + /** + * Read-only value that indicates that the last set `src` failed to load. + */ + error: { + notify: true, + readOnly: true, + type: Boolean, + value: false + }, + + /** + * Can be used to set the width of image (e.g. via binding); size may also be + * set via CSS. + */ + width: { + observer: '_widthChanged', + type: Number, + value: null + }, + + /** + * Can be used to set the height of image (e.g. via binding); size may also be + * set via CSS. + * + * @attribute height + * @type number + * @default null + */ + height: { + observer: '_heightChanged', + type: Number, + value: null + }, + }, + + observers: [ + '_transformChanged(sizing, position)' + ], + + ready: function() { + var img = this.$.img; + + img.onload = function() { + if (this.$.img.src !== this._resolveSrc(this.src)) return; + + this._setLoading(false); + this._setLoaded(true); + this._setError(false); + }.bind(this); + + img.onerror = function() { + if (this.$.img.src !== this._resolveSrc(this.src)) return; + + this._reset(); + + this._setLoading(false); + this._setLoaded(false); + this._setError(true); + }.bind(this); + + this._resolvedSrc = ''; + }, + + _load: function(src) { + if (src) { + this.$.img.src = src; + } else { + this.$.img.removeAttribute('src'); + } + this.$.sizedImgDiv.style.backgroundImage = src ? 'url("' + src + '")' : ''; + + this._setLoading(!!src); + this._setLoaded(false); + this._setError(false); + }, + + _reset: function() { + this.$.img.removeAttribute('src'); + this.$.sizedImgDiv.style.backgroundImage = ''; + + this._setLoading(false); + this._setLoaded(false); + this._setError(false); + }, + + _computePlaceholderHidden: function() { + return !this.preload || (!this.fade && !this.loading && this.loaded); + }, + + _computePlaceholderClassName: function() { + return (this.preload && this.fade && !this.loading && this.loaded) ? 'faded-out' : ''; + }, + + _computeImgDivHidden: function() { + return !this.sizing; + }, + + _computeImgDivARIAHidden: function() { + return this.alt === '' ? 'true' : undefined; + }, + + _computeImgDivARIALabel: function() { + if (this.alt !== null) { + return this.alt; + } + + // Polymer.ResolveUrl.resolveUrl will resolve '' relative to a URL x to + // that URL x, but '' is the default for src. + if (this.src === '') { + return ''; + } + + var pathComponents = (new URL(this._resolveSrc(this.src))).pathname.split("/"); + return pathComponents[pathComponents.length - 1]; + }, + + _computeImgHidden: function() { + return !!this.sizing; + }, + + _widthChanged: function() { + this.style.width = isNaN(this.width) ? this.width : this.width + 'px'; + }, + + _heightChanged: function() { + this.style.height = isNaN(this.height) ? this.height : this.height + 'px'; + }, + + _preventLoadChanged: function() { + if (this.preventLoad || this.loaded) return; + + this._reset(); + this._load(this.src); + }, + + _srcChanged: function(newSrc, oldSrc) { + var newResolvedSrc = this._resolveSrc(newSrc); + if (newResolvedSrc === this._resolvedSrc) return; + this._resolvedSrc = newResolvedSrc; + + this._reset(); + if (!this.preventLoad) { + this._load(newSrc); + } + }, + + _placeholderChanged: function() { + this.$.placeholder.style.backgroundImage = + this.placeholder ? 'url("' + this.placeholder + '")' : ''; + }, + + _transformChanged: function() { + var sizedImgDivStyle = this.$.sizedImgDiv.style; + var placeholderStyle = this.$.placeholder.style; + + sizedImgDivStyle.backgroundSize = + placeholderStyle.backgroundSize = + this.sizing; + + sizedImgDivStyle.backgroundPosition = + placeholderStyle.backgroundPosition = + this.sizing ? this.position : ''; + + sizedImgDivStyle.backgroundRepeat = + placeholderStyle.backgroundRepeat = + this.sizing ? 'no-repeat' : ''; + }, + + _resolveSrc: function(testSrc) { + return Polymer.ResolveUrl.resolveUrl(testSrc, this.ownerDocument.baseURI); + } + }); + </script> +</dom-module> |