mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-22 05:21:52 +08:00
perf(img): load through webworkers, lazy load viewable imgs
This commit is contained in:
224
src/components/img/img-loader.ts
Normal file
224
src/components/img/img-loader.ts
Normal file
@ -0,0 +1,224 @@
|
||||
import { removeArrayItem } from '../../util/util';
|
||||
|
||||
|
||||
export class ImgLoader {
|
||||
private wkr: Worker;
|
||||
private callbacks: Function[] = [];
|
||||
private ids = 0;
|
||||
|
||||
load(src: string, cache: boolean, callback: Function) {
|
||||
if (src) {
|
||||
(<any>callback).id = this.ids++;
|
||||
this.callbacks.push(callback);
|
||||
this.worker().postMessage(JSON.stringify({
|
||||
id: (<any>callback).id,
|
||||
src: src,
|
||||
cache: cache
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
cancelLoad(callback: Function) {
|
||||
removeArrayItem(this.callbacks, callback);
|
||||
}
|
||||
|
||||
abort(src: string) {
|
||||
if (src) {
|
||||
this.worker().postMessage(JSON.stringify({
|
||||
src: src,
|
||||
type: 'abort'
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private worker() {
|
||||
if (!this.wkr) {
|
||||
// create a blob from the inline worker string
|
||||
const workerBlob = new Blob([INLINE_WORKER]);
|
||||
|
||||
// obtain a blob URL reference to our worker 'file'.
|
||||
const blobURL = window.URL.createObjectURL(workerBlob);
|
||||
|
||||
// create the worker
|
||||
this.wkr = new Worker(blobURL);
|
||||
|
||||
// create worker onmessage handler
|
||||
this.wkr.onmessage = (ev: MessageEvent) => {
|
||||
// we got something back from the web worker
|
||||
// let's emit this out to everyone listening
|
||||
const msg: ImgResponseMessage = JSON.parse(ev.data);
|
||||
const callback = this.callbacks.find(cb => (<any>cb).id === msg.id);
|
||||
if (callback) {
|
||||
callback(msg);
|
||||
removeArrayItem(this.callbacks, callback);
|
||||
}
|
||||
};
|
||||
|
||||
// create worker onerror handler
|
||||
this.wkr.onerror = (ev: ErrorEvent) => {
|
||||
console.error(`ImgLoader, worker ${ev.type} ${ev.message ? ev.message : ''}`);
|
||||
this.callbacks.length = 0;
|
||||
this.wkr.terminate();
|
||||
this.wkr = null;
|
||||
};
|
||||
}
|
||||
|
||||
// return that hard worker
|
||||
return this.wkr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
const INLINE_WORKER = `/** minify-start **/
|
||||
|
||||
(function(){
|
||||
|
||||
var imgs = [];
|
||||
var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
var cacheLimit = 1381855 * 10;
|
||||
|
||||
onmessage = function(msg) {
|
||||
var msgData = JSON.parse(msg.data);
|
||||
var id = msgData.id;
|
||||
var src = msgData.src;
|
||||
var imgData;
|
||||
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
if (imgs[i].s === src) {
|
||||
imgData = imgs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (msgData.type === 'abort') {
|
||||
if (imgData && imgData.x) {
|
||||
imgData.x.abort();
|
||||
imgData.x = null;
|
||||
}
|
||||
|
||||
} else if (msgData.cache && imgData && imgData.d) {
|
||||
postMessage(JSON.stringify({
|
||||
id: id,
|
||||
src: src,
|
||||
status: 200,
|
||||
data: imgData.d,
|
||||
len: imgData.l
|
||||
}));
|
||||
|
||||
} else {
|
||||
if (imgData && imgData.x && imgData.x.readyState !== 4) {
|
||||
imgData.x.addEventListener('load', function(ev) {
|
||||
onXhrLoad(id, src, imgData, ev);
|
||||
});
|
||||
imgData.x.addEventListener('error', function(e) {
|
||||
onXhrError(id, src, imgData, e);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!imgData) {
|
||||
imgData = { s: src, c: msgData.cache };
|
||||
imgs.push(imgData);
|
||||
}
|
||||
|
||||
imgData.x = new XMLHttpRequest();
|
||||
imgData.x.open('GET', src, true);
|
||||
imgData.x.responseType = 'arraybuffer';
|
||||
imgData.x.addEventListener('load', function(ev) {
|
||||
onXhrLoad(id, src, imgData, ev);
|
||||
});
|
||||
imgData.x.addEventListener('error', function(e) {
|
||||
onXhrError(id, src, imgData, e);
|
||||
});
|
||||
imgData.x.send();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function onXhrLoad(id, src, imgData, ev) {
|
||||
var rsp = {
|
||||
id: id,
|
||||
src: src,
|
||||
status: ev.target.status,
|
||||
data: null,
|
||||
len: 0
|
||||
};
|
||||
|
||||
if (ev.target.status === 200) {
|
||||
setData(rsp, ev.target.getResponseHeader('Content-Type'), ev.target.response);
|
||||
rsp.len = rsp.data.length;
|
||||
}
|
||||
|
||||
postMessage(JSON.stringify(rsp));
|
||||
|
||||
if (imgData.x.status === 200 && imgData.c) {
|
||||
imgData.d = rsp.data;
|
||||
imgData.l = rsp.len;
|
||||
|
||||
var cacheSize = 0;
|
||||
for (var i = imgs.length - 1; i >= 0; i--) {
|
||||
cacheSize += imgs[i].l;
|
||||
if (cacheSize > cacheLimit) {
|
||||
imgs.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function onXhrError(id, src, imgData, e) {
|
||||
postMessage(JSON.stringify({
|
||||
id: id,
|
||||
src: src,
|
||||
status: 510,
|
||||
msg: e.message + '' + e.stack
|
||||
}));
|
||||
imgData.x = null;
|
||||
};
|
||||
|
||||
|
||||
function setData(rsp, contentType, arrayBuffer) {
|
||||
rsp.data = 'data:' + contentType + ';base64,';
|
||||
|
||||
var bytes = new Uint8Array(arrayBuffer);
|
||||
var byteLength = bytes.byteLength;
|
||||
var byteRemainder = byteLength % 3;
|
||||
var mainLength = byteLength - byteRemainder;
|
||||
var i, a, b, c, d, chunk;
|
||||
|
||||
for (i = 0; i < mainLength; i = i + 3) {
|
||||
chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
|
||||
a = (chunk & 16515072) >> 18;
|
||||
b = (chunk & 258048) >> 12;
|
||||
c = (chunk & 4032) >> 6;
|
||||
d = chunk & 63;
|
||||
rsp.data += encodings[a] + encodings[b] + encodings[c] + encodings[d];
|
||||
}
|
||||
|
||||
if (byteRemainder === 1) {
|
||||
chunk = bytes[mainLength];
|
||||
a = (chunk & 252) >> 2;
|
||||
b = (chunk & 3) << 4;
|
||||
rsp.data += encodings[a] + encodings[b] + '==';
|
||||
|
||||
} else if (byteRemainder === 2) {
|
||||
chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1];
|
||||
a = (chunk & 64512) >> 10;
|
||||
b = (chunk & 1008) >> 4;
|
||||
c = (chunk & 15) << 2;
|
||||
rsp.data += encodings[a] + encodings[b] + encodings[c] + '=';
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
/** minify-end **/`;
|
||||
|
||||
|
||||
export interface ImgResponseMessage {
|
||||
id: number;
|
||||
src: string;
|
||||
status?: number;
|
||||
data?: string;
|
||||
msg?: string;
|
||||
}
|
@ -3,32 +3,29 @@
|
||||
// Img
|
||||
// --------------------------------------------------
|
||||
|
||||
ion-img {
|
||||
position: relative;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
/// @prop - Color of the image when it hasn't fully loaded yet
|
||||
$img-placeholder-background: #eee !default;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
ion-img {
|
||||
display: inline-block;
|
||||
|
||||
min-width: 20px;
|
||||
min-height: 20px;
|
||||
|
||||
background: $img-placeholder-background;
|
||||
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
ion-img img {
|
||||
flex-shrink: 0;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
ion-img .img-placeholder {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
background: #eee;
|
||||
|
||||
transition: opacity 200ms;
|
||||
ion-img.img-unloaded img {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ion-img.img-loaded .img-placeholder {
|
||||
opacity: 0;
|
||||
ion-img.img-loaded img {
|
||||
display: block;
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { Component, Input, HostBinding, ElementRef, ChangeDetectionStrategy, ViewEncapsulation, NgZone } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, Input, NgZone, OnDestroy, Optional, Renderer, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
import { nativeRaf } from '../../util/dom';
|
||||
import { isPresent } from '../../util/util';
|
||||
import { Content } from '../content/content';
|
||||
import { DomController } from '../../util/dom-controller';
|
||||
import { ImgLoader, ImgResponseMessage } from './img-loader';
|
||||
import { isPresent, isTrueProperty } from '../../util/util';
|
||||
import { Platform } from '../../platform/platform';
|
||||
|
||||
|
||||
@ -10,128 +12,268 @@ import { Platform } from '../../platform/platform';
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ion-img',
|
||||
template:
|
||||
'<div class="img-placeholder" [style.height]="_h" [style.width]="_w"></div>',
|
||||
template: '<img>',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class Img {
|
||||
_src: string = '';
|
||||
_normalizeSrc: string = '';
|
||||
_imgs: HTMLImageElement[] = [];
|
||||
_w: string;
|
||||
_h: string;
|
||||
_enabled: boolean = true;
|
||||
_init: boolean;
|
||||
export class Img implements OnDestroy {
|
||||
/** @internal */
|
||||
_src: string;
|
||||
/** @internal */
|
||||
_requestingSrc: string;
|
||||
/** @internal */
|
||||
_renderedSrc: string;
|
||||
/** @internal */
|
||||
_tmpDataUri: string;
|
||||
/** @internal */
|
||||
_cache: boolean = true;
|
||||
/** @internal */
|
||||
_lazy: boolean = true;
|
||||
/** @internal */
|
||||
_ww: boolean = true;
|
||||
/** @internal */
|
||||
_cb: Function;
|
||||
/** @internal */
|
||||
_bounds: any;
|
||||
/** @internal */
|
||||
_rect: any;
|
||||
/** @internal */
|
||||
_w: string = '';
|
||||
/** @internal */
|
||||
_h: string = '';
|
||||
/** @internal */
|
||||
_wQ: string = '';
|
||||
/** @internal */
|
||||
_hQ: string = '';
|
||||
|
||||
constructor(private _elementRef: ElementRef, private _platform: Platform, private _zone: NgZone) {}
|
||||
/** @private */
|
||||
canRequest: boolean;
|
||||
/** @private */
|
||||
canRender: boolean;
|
||||
|
||||
|
||||
constructor(
|
||||
private _ldr: ImgLoader,
|
||||
private _elementRef: ElementRef,
|
||||
private _renderer: Renderer,
|
||||
private _platform: Platform,
|
||||
private _zone: NgZone,
|
||||
@Optional() private _content: Content,
|
||||
private _dom: DomController
|
||||
) {
|
||||
if (!this._content) {
|
||||
console.warn(`ion-img can only be used within an ion-content`);
|
||||
} else {
|
||||
this._content.addImg(this);
|
||||
}
|
||||
this._isLoaded(false);
|
||||
}
|
||||
|
||||
@Input()
|
||||
set src(val: string) {
|
||||
let tmpImg = new Image();
|
||||
tmpImg.src = isPresent(val) ? val : '';
|
||||
get src(): string {
|
||||
return this._src;
|
||||
}
|
||||
set src(newSrc: string) {
|
||||
if (newSrc !== this._src) {
|
||||
this.reset();
|
||||
|
||||
this._src = isPresent(val) ? val : '';
|
||||
this._normalizeSrc = tmpImg.src;
|
||||
// update to the new src
|
||||
this._src = newSrc;
|
||||
|
||||
if (this._init) {
|
||||
this._update();
|
||||
// reset any existing datauri we might be holding onto
|
||||
this._tmpDataUri = null;
|
||||
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this._init = true;
|
||||
this._update();
|
||||
reset() {
|
||||
if (this._requestingSrc) {
|
||||
// abort any active requests
|
||||
console.debug(`abortRequest ${this._requestingSrc} ${Date.now()}`);
|
||||
this._ldr.abort(this._requestingSrc);
|
||||
this._requestingSrc = null;
|
||||
}
|
||||
if (this._renderedSrc) {
|
||||
// clear out the currently rendered img
|
||||
console.debug(`clearRender ${this._renderedSrc} ${Date.now()}`);
|
||||
this._renderedSrc = null;
|
||||
this._isLoaded(false);
|
||||
}
|
||||
}
|
||||
|
||||
_update() {
|
||||
if (this._enabled && this._src !== '') {
|
||||
// actively update the image
|
||||
update() {
|
||||
if (this._src && this._content.isImgsRefreshable()) {
|
||||
if (this.canRequest && (this._src !== this._renderedSrc && this._src !== this._requestingSrc) && !this._tmpDataUri) {
|
||||
console.debug(`request ${this._src} ${Date.now()}`);
|
||||
this._requestingSrc = this._src;
|
||||
|
||||
for (var i = this._imgs.length - 1; i >= 0; i--) {
|
||||
if (this._imgs[i].src === this._normalizeSrc) {
|
||||
// this is the active image
|
||||
if (this._imgs[i].complete) {
|
||||
this._loaded(true);
|
||||
}
|
||||
this._cb = (msg: ImgResponseMessage) => {
|
||||
this._loadResponse(msg);
|
||||
};
|
||||
|
||||
} else {
|
||||
// no longer the active image
|
||||
if (this._imgs[i].parentElement) {
|
||||
this._imgs[i].parentElement.removeChild(this._imgs[i]);
|
||||
}
|
||||
this._imgs.splice(i, 1);
|
||||
}
|
||||
this._ldr.load(this._src, this._cache, this._cb);
|
||||
this._setDims();
|
||||
}
|
||||
|
||||
if (!this._imgs.length) {
|
||||
this._zone.runOutsideAngular(() => {
|
||||
let img = new Image();
|
||||
img.style.width = this._width;
|
||||
img.style.height = this._height;
|
||||
|
||||
if (isPresent(this.alt)) {
|
||||
img.alt = this.alt;
|
||||
if (this.canRender && this._tmpDataUri && this._src !== this._renderedSrc) {
|
||||
// we can render and we have a datauri to render
|
||||
this._renderedSrc = this._src;
|
||||
this._setDims();
|
||||
this._dom.write(() => {
|
||||
if (this._tmpDataUri) {
|
||||
console.debug(`render ${this._src} ${Date.now()}`);
|
||||
this._isLoaded(true);
|
||||
this._srcAttr(this._tmpDataUri);
|
||||
this._tmpDataUri = null;
|
||||
}
|
||||
if (isPresent(this.title)) {
|
||||
img.title = this.title;
|
||||
}
|
||||
|
||||
img.addEventListener('load', () => {
|
||||
if (img.src === this._normalizeSrc) {
|
||||
this._elementRef.nativeElement.appendChild(img);
|
||||
nativeRaf(() => {
|
||||
this._update();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
img.src = this._src;
|
||||
|
||||
this._imgs.push(img);
|
||||
this._loaded(false);
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
// do not actively update the image
|
||||
if (!this._imgs.some(img => img.src === this._normalizeSrc)) {
|
||||
this._loaded(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_loaded(isLoaded: boolean) {
|
||||
this._elementRef.nativeElement.classList[isLoaded ? 'add' : 'remove']('img-loaded');
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_loadResponse(msg: ImgResponseMessage) {
|
||||
this._requestingSrc = null;
|
||||
|
||||
if (msg.status === 200) {
|
||||
// success :)
|
||||
this._tmpDataUri = msg.data;
|
||||
this.update();
|
||||
|
||||
} else {
|
||||
// error :(
|
||||
console.error(`img, status: ${msg.status} ${msg.msg}`);
|
||||
this._renderedSrc = this._tmpDataUri = null;
|
||||
this._dom.write(() => {
|
||||
this._isLoaded(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
enable(shouldEnable: boolean) {
|
||||
this._enabled = shouldEnable;
|
||||
this._update();
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_isLoaded(isLoaded: boolean) {
|
||||
const renderer = this._renderer;
|
||||
const ele = this._elementRef.nativeElement;
|
||||
renderer.setElementClass(ele, 'img-loaded', isLoaded);
|
||||
renderer.setElementClass(ele, 'img-unloaded', !isLoaded);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_srcAttr(srcAttr: string) {
|
||||
const imgEle = this._elementRef.nativeElement.firstChild;
|
||||
const renderer = this._renderer;
|
||||
|
||||
renderer.setElementAttribute(imgEle, 'src', srcAttr);
|
||||
renderer.setElementAttribute(imgEle, 'alt', this.alt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
get top(): number {
|
||||
const bounds = this._getBounds();
|
||||
return bounds && bounds.top || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
get bottom(): number {
|
||||
const bounds = this._getBounds();
|
||||
return bounds && bounds.bottom || 0;
|
||||
}
|
||||
|
||||
private _getBounds() {
|
||||
if (this._bounds) {
|
||||
return this._bounds;
|
||||
}
|
||||
if (!this._rect) {
|
||||
this._rect = (<HTMLElement>this._elementRef.nativeElement).getBoundingClientRect();
|
||||
console.debug(`img, ${this._src}, read, ${this._rect.top} - ${this._rect.bottom}`);
|
||||
}
|
||||
return this._rect;
|
||||
}
|
||||
|
||||
@Input()
|
||||
set bounds(b: any) {
|
||||
if (isPresent(b)) {
|
||||
this._bounds = b;
|
||||
}
|
||||
}
|
||||
|
||||
@Input()
|
||||
get lazyLoad(): boolean {
|
||||
return this._lazy;
|
||||
}
|
||||
set lazyLoad(val: boolean) {
|
||||
this._lazy = isTrueProperty(val);
|
||||
}
|
||||
|
||||
@Input()
|
||||
get webWorker(): boolean {
|
||||
return this._ww;
|
||||
}
|
||||
set webWorker(val: boolean) {
|
||||
this._ww = isTrueProperty(val);
|
||||
}
|
||||
|
||||
@Input()
|
||||
get cache(): boolean {
|
||||
return this._cache;
|
||||
}
|
||||
set cache(val: boolean) {
|
||||
this._cache = isTrueProperty(val);
|
||||
}
|
||||
|
||||
@Input()
|
||||
set width(val: string | number) {
|
||||
this._w = getUnitValue(val);
|
||||
this._wQ = getUnitValue(val);
|
||||
this._setDims();
|
||||
}
|
||||
|
||||
@Input()
|
||||
set height(val: string | number) {
|
||||
this._h = getUnitValue(val);
|
||||
this._hQ = getUnitValue(val);
|
||||
this._setDims();
|
||||
}
|
||||
|
||||
@Input() alt: string;
|
||||
_setDims() {
|
||||
if (this.canRender && (this._w !== this._wQ || this._h !== this._hQ)) {
|
||||
var wrapperEle: HTMLImageElement = this._elementRef.nativeElement;
|
||||
var renderer = this._renderer;
|
||||
|
||||
@Input() title: string;
|
||||
|
||||
@HostBinding('style.width')
|
||||
get _width(): string {
|
||||
return isPresent(this._w) ? this._w : '';
|
||||
this._dom.write(() => {
|
||||
if (this._w !== this._wQ) {
|
||||
this._w = this._wQ;
|
||||
renderer.setElementStyle(wrapperEle, 'width', this._w);
|
||||
}
|
||||
if (this._h !== this._hQ) {
|
||||
this._h = this._hQ;
|
||||
renderer.setElementStyle(wrapperEle, 'height', this._h);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@HostBinding('style.height')
|
||||
get _height(): string {
|
||||
return isPresent(this._h) ? this._h : '';
|
||||
/**
|
||||
* Set the `alt` attribute on the inner `img` element.
|
||||
*/
|
||||
@Input() alt: string = '';
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ngOnDestroy() {
|
||||
this._ldr.cancelLoad(this._cb);
|
||||
this._cb = null;
|
||||
this._content && this._content.removeImg(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
76
src/components/img/test/basic/main.html
Normal file
76
src/components/img/test/basic/main.html
Normal file
@ -0,0 +1,76 @@
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Img: Basic</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
|
||||
|
||||
<ion-content>
|
||||
|
||||
<ion-list>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-avatar item-left>
|
||||
<ion-img></ion-img>
|
||||
</ion-avatar>
|
||||
|
||||
Unloaded Avatar
|
||||
|
||||
<ion-avatar item-right>
|
||||
<ion-img></ion-img>
|
||||
</ion-avatar>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-avatar item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/blues-brothers.jpg"></ion-img>
|
||||
</ion-avatar>
|
||||
|
||||
Loaded Avatar
|
||||
|
||||
<ion-avatar item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bueller.jpg"></ion-img>
|
||||
</ion-avatar>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Unloaded Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/delorean.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Loaded Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/batmobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
</ion-list>
|
||||
|
||||
<div padding>
|
||||
Default ion-img w/in content, display: inline-block.
|
||||
<ion-img alt="Smokey" width="220" height="165" src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
has width, height and alt set.
|
||||
</div>
|
||||
|
||||
</ion-content>
|
82
src/components/img/test/img.spec.ts
Normal file
82
src/components/img/test/img.spec.ts
Normal file
@ -0,0 +1,82 @@
|
||||
import { ElementRef, Renderer } from '@angular/core';
|
||||
import { Content } from '../../content/content';
|
||||
import { Img } from '../img';
|
||||
import { ImgLoader } from '../img-loader';
|
||||
import { mockContent, MockDomController, mockElementRef, mockPlatform, mockRenderer, mockZone } from '../../../util/mock-providers';
|
||||
import { Platform } from '../../../platform/platform';
|
||||
|
||||
|
||||
fdescribe('Img', () => {
|
||||
|
||||
describe('reset', () => {
|
||||
|
||||
it('should clear rendering src', () => {
|
||||
spyOn(img, '_isLoaded');
|
||||
img._renderedSrc = '_renderedSrc.jpg';
|
||||
img.reset();
|
||||
expect(img._isLoaded).toHaveBeenCalledWith(false);
|
||||
expect(img._renderedSrc).toEqual(null);
|
||||
});
|
||||
|
||||
it('should abort requesting src', () => {
|
||||
spyOn(ldr, 'abort');
|
||||
img._requestingSrc = '_requestingSrc.jpg';
|
||||
img.reset();
|
||||
expect(ldr.abort).toHaveBeenCalledWith('_requestingSrc.jpg');
|
||||
expect(img._requestingSrc).toEqual(null);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('src setter', () => {
|
||||
|
||||
it('should abort request if already requesting', () => {
|
||||
spyOn(img, 'reset');
|
||||
img._requestingSrc = 'requesting.jpg';
|
||||
img._tmpDataUri = 'tmpDatauri.jpg';
|
||||
|
||||
img.src = 'image.jpg';
|
||||
|
||||
expect(img.reset).toHaveBeenCalled();
|
||||
expect(img.src).toEqual('image.jpg');
|
||||
expect(img._tmpDataUri).toEqual(null);
|
||||
});
|
||||
|
||||
it('should set src', () => {
|
||||
spyOn(img, 'update');
|
||||
img.src = 'image.jpg';
|
||||
expect(img.src).toEqual('image.jpg');
|
||||
expect(img.update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('src getter', () => {
|
||||
|
||||
it('should get src if set', () => {
|
||||
img._src = 'loaded.jpg';
|
||||
expect(img.src).toEqual('loaded.jpg');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
let img: Img;
|
||||
let ldr: ImgLoader;
|
||||
let elementRef: ElementRef;
|
||||
let renderer: Renderer;
|
||||
let platform: Platform;
|
||||
let content: Content;
|
||||
let dom: MockDomController;
|
||||
|
||||
beforeEach(() => {
|
||||
content = mockContent();
|
||||
ldr = new ImgLoader();
|
||||
elementRef = mockElementRef();
|
||||
renderer = mockRenderer();
|
||||
platform = mockPlatform();
|
||||
dom = new MockDomController();
|
||||
img = new Img(ldr, elementRef, renderer, platform, mockZone(), content, dom);
|
||||
});
|
||||
|
||||
});
|
35
src/components/img/test/lazy-load/app-module.ts
Normal file
35
src/components/img/test/lazy-load/app-module.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { Component, NgModule } from '@angular/core';
|
||||
import { IonicApp, IonicModule } from '../../../..';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: 'main.html'
|
||||
})
|
||||
export class E2EPage {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
template: '<ion-nav [root]="root"></ion-nav>'
|
||||
})
|
||||
export class E2EApp {
|
||||
root = E2EPage;
|
||||
}
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
E2EApp,
|
||||
E2EPage
|
||||
],
|
||||
imports: [
|
||||
IonicModule.forRoot(E2EApp)
|
||||
],
|
||||
bootstrap: [IonicApp],
|
||||
entryComponents: [
|
||||
E2EApp,
|
||||
E2EPage
|
||||
]
|
||||
})
|
||||
export class AppModule {}
|
686
src/components/img/test/lazy-load/main.html
Normal file
686
src/components/img/test/lazy-load/main.html
Normal file
@ -0,0 +1,686 @@
|
||||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>Img: Lazy Load</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
|
||||
|
||||
<ion-content>
|
||||
|
||||
<ion-list>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/batmobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/delorean.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/eleanor.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/ghostbusters.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/knight-rider.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/mirth-mobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/batmobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/delorean.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/eleanor.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/ghostbusters.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/knight-rider.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/mirth-mobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/batmobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/delorean.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/eleanor.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/ghostbusters.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/knight-rider.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/mirth-mobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/batmobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/delorean.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/eleanor.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/ghostbusters.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/knight-rider.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/mirth-mobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/batmobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/delorean.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/eleanor.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/ghostbusters.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/knight-rider.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/mirth-mobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/batmobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/delorean.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/eleanor.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/ghostbusters.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/knight-rider.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/mirth-mobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/batmobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/delorean.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/eleanor.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/ghostbusters.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/knight-rider.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/mirth-mobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/batmobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/delorean.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/eleanor.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/ghostbusters.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/knight-rider.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/mirth-mobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/batmobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/delorean.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/eleanor.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/ghostbusters.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/knight-rider.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/mirth-mobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/batmobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/delorean.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/eleanor.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/ghostbusters.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/knight-rider.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/mirth-mobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/batmobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/delorean.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/eleanor.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/ghostbusters.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/knight-rider.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/mirth-mobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/batmobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/delorean.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/eleanor.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/ghostbusters.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/knight-rider.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
<ion-thumbnail item-left>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/mirth-mobile.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
Thumbnail
|
||||
|
||||
<ion-thumbnail item-right>
|
||||
<ion-img src="http://localhost:8000/dist/e2e/img/img/bandit.jpg"></ion-img>
|
||||
</ion-thumbnail>
|
||||
|
||||
</ion-item>
|
||||
|
||||
</ion-list>
|
||||
|
||||
</ion-content>
|
@ -16,10 +16,10 @@ $item-ios-paragraph-font-size: 1.4rem !default;
|
||||
$item-ios-paragraph-text-color: #8e9093 !default;
|
||||
|
||||
/// @prop - Size of the avatar in the item
|
||||
$item-ios-avatar-size: 3.6rem !default;
|
||||
$item-ios-avatar-size: 36px !default;
|
||||
|
||||
/// @prop - Size of the thumbnail in the item
|
||||
$item-ios-thumbnail-size: 5.6rem !default;
|
||||
$item-ios-thumbnail-size: 56px !default;
|
||||
|
||||
/// @prop - Shows the detail arrow icon on an item
|
||||
$item-ios-detail-push-show: true !default;
|
||||
@ -133,16 +133,6 @@ $item-ios-sliding-content-background: $list-ios-background-color !default;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.item-ios ion-avatar[item-left],
|
||||
.item-ios ion-thumbnail[item-left] {
|
||||
margin: ($item-ios-padding-right / 2) $item-ios-padding-right ($item-ios-padding-right / 2) 0;
|
||||
}
|
||||
|
||||
.item-ios ion-avatar[item-right],
|
||||
.item-ios ion-thumbnail[item-right] {
|
||||
margin: ($item-ios-padding-right / 2);
|
||||
}
|
||||
|
||||
.item-ios .item-button {
|
||||
padding: 0 .5em;
|
||||
|
||||
@ -156,26 +146,52 @@ $item-ios-sliding-content-background: $list-ios-background-color !default;
|
||||
padding: 0 1px;
|
||||
}
|
||||
|
||||
.item-ios ion-avatar[item-left],
|
||||
.item-ios ion-thumbnail[item-left] {
|
||||
margin: ($item-ios-padding-right / 2) $item-ios-padding-right ($item-ios-padding-right / 2) 0;
|
||||
}
|
||||
|
||||
.item-ios ion-avatar[item-right],
|
||||
.item-ios ion-thumbnail[item-right] {
|
||||
margin: ($item-ios-padding-right / 2);
|
||||
}
|
||||
|
||||
|
||||
// iOS Item Avatar
|
||||
// --------------------------------------------------
|
||||
|
||||
.item-ios ion-avatar {
|
||||
min-width: $item-ios-avatar-size;
|
||||
min-height: $item-ios-avatar-size;
|
||||
}
|
||||
|
||||
.item-ios ion-avatar img {
|
||||
max-width: $item-ios-avatar-size;
|
||||
max-height: $item-ios-avatar-size;
|
||||
.item-ios ion-avatar ion-img {
|
||||
width: $item-ios-avatar-size;
|
||||
height: $item-ios-avatar-size;
|
||||
|
||||
border-radius: $item-ios-avatar-size / 2;
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.item-ios ion-avatar img {
|
||||
width: $item-ios-avatar-size;
|
||||
height: $item-ios-avatar-size;
|
||||
}
|
||||
|
||||
|
||||
// iOS Item Thumbnail
|
||||
// --------------------------------------------------
|
||||
|
||||
.item-ios ion-thumbnail {
|
||||
min-width: $item-ios-thumbnail-size;
|
||||
min-height: $item-ios-thumbnail-size;
|
||||
}
|
||||
|
||||
.item-ios ion-thumbnail ion-img,
|
||||
.item-ios ion-thumbnail img {
|
||||
max-width: $item-ios-thumbnail-size;
|
||||
max-height: $item-ios-thumbnail-size;
|
||||
width: $item-ios-thumbnail-size;
|
||||
height: $item-ios-thumbnail-size;
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,10 +16,10 @@ $item-md-paragraph-text-color: #666 !default;
|
||||
$item-md-font-size: 1.6rem !default;
|
||||
|
||||
/// @prop - Size of the avatar in the item
|
||||
$item-md-avatar-size: 4rem !default;
|
||||
$item-md-avatar-size: 40px !default;
|
||||
|
||||
/// @prop - Size of the thumbnail in the item
|
||||
$item-md-thumbnail-size: 8rem !default;
|
||||
$item-md-thumbnail-size: 80px !default;
|
||||
|
||||
/// @prop - Shows the detail arrow icon on an item
|
||||
$item-md-detail-push-show: false !default;
|
||||
@ -178,26 +178,42 @@ $item-md-sliding-content-background: $list-md-background-color !default;
|
||||
margin: ($item-md-padding-right / 2);
|
||||
}
|
||||
|
||||
|
||||
// Material Design Item Avatar
|
||||
// --------------------------------------------------
|
||||
|
||||
.item-md ion-avatar {
|
||||
min-width: $item-md-avatar-size;
|
||||
min-height: $item-md-avatar-size;
|
||||
}
|
||||
|
||||
.item-md ion-avatar img {
|
||||
max-width: $item-md-avatar-size;
|
||||
max-height: $item-md-avatar-size;
|
||||
.item-md ion-avatar ion-img {
|
||||
width: $item-md-avatar-size;
|
||||
height: $item-md-avatar-size;
|
||||
|
||||
border-radius: $item-md-avatar-size / 2;
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.item-ios ion-avatar img {
|
||||
width: $item-md-avatar-size;
|
||||
height: $item-md-avatar-size;
|
||||
}
|
||||
|
||||
|
||||
// Material Design Item Thumbnail
|
||||
// --------------------------------------------------
|
||||
|
||||
.item-md ion-thumbnail {
|
||||
min-width: $item-md-thumbnail-size;
|
||||
min-height: $item-md-thumbnail-size;
|
||||
}
|
||||
|
||||
.item-md ion-thumbnail ion-img,
|
||||
.item-md ion-thumbnail img {
|
||||
max-width: $item-md-thumbnail-size;
|
||||
max-height: $item-md-thumbnail-size;
|
||||
width: $item-md-thumbnail-size;
|
||||
height: $item-md-thumbnail-size;
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,10 +22,10 @@ $item-wp-paragraph-text-color: #666 !default;
|
||||
$item-wp-font-size: 1.6rem !default;
|
||||
|
||||
/// @prop - Size of the avatar in the item
|
||||
$item-wp-avatar-size: 4rem !default;
|
||||
$item-wp-avatar-size: 40px !default;
|
||||
|
||||
/// @prop - Size of the thumbnail in the item
|
||||
$item-wp-thumbnail-size: 8rem !default;
|
||||
$item-wp-thumbnail-size: 80px !default;
|
||||
|
||||
/// @prop - Shows the detail arrow icon on an item
|
||||
$item-wp-detail-push-show: false !default;
|
||||
@ -188,26 +188,42 @@ $item-wp-sliding-content-background: $list-wp-background-color !default;
|
||||
margin: ($item-wp-padding-right / 2);
|
||||
}
|
||||
|
||||
|
||||
// Windows Item Avatar
|
||||
// --------------------------------------------------
|
||||
|
||||
.item-wp ion-avatar {
|
||||
min-width: $item-wp-avatar-size;
|
||||
min-height: $item-wp-avatar-size;
|
||||
}
|
||||
|
||||
.item-wp ion-avatar img {
|
||||
max-width: $item-wp-avatar-size;
|
||||
max-height: $item-wp-avatar-size;
|
||||
.item-wp ion-avatar ion-img {
|
||||
overflow: hidden;
|
||||
|
||||
width: $item-wp-avatar-size;
|
||||
height: $item-wp-avatar-size;
|
||||
|
||||
border-radius: $item-wp-avatar-size / 2;
|
||||
}
|
||||
|
||||
.item-wp ion-avatar img {
|
||||
width: $item-wp-avatar-size;
|
||||
height: $item-wp-avatar-size;
|
||||
}
|
||||
|
||||
|
||||
// Windows Item Thumbnail
|
||||
// --------------------------------------------------
|
||||
|
||||
.item-wp ion-thumbnail {
|
||||
min-width: $item-wp-thumbnail-size;
|
||||
min-height: $item-wp-thumbnail-size;
|
||||
}
|
||||
|
||||
.item-wp ion-thumbnail ion-img,
|
||||
.item-wp ion-thumbnail img {
|
||||
max-width: $item-wp-thumbnail-size;
|
||||
max-height: $item-wp-thumbnail-size;
|
||||
width: $item-wp-thumbnail-size;
|
||||
height: $item-wp-thumbnail-size;
|
||||
}
|
||||
|
||||
|
||||
|
@ -19,6 +19,7 @@ import { Events, setupProvideEvents } from './util/events';
|
||||
import { Form } from './util/form';
|
||||
import { GestureController } from './gestures/gesture-controller';
|
||||
import { Haptic } from './util/haptic';
|
||||
import { ImgLoader } from './components/img/img-loader';
|
||||
import { IonicGestureConfig } from './gestures/gesture-config';
|
||||
import { Keyboard } from './util/keyboard';
|
||||
import { LoadingController } from './components/loading/loading';
|
||||
@ -55,6 +56,7 @@ export { Config, setupConfig, ConfigToken } from './config/config';
|
||||
export { DomController } from './util/dom-controller';
|
||||
export { Platform, setupPlatform, UserAgentToken, DocumentDirToken, DocLangToken, NavigatorPlatformToken } from './platform/platform';
|
||||
export { Haptic } from './util/haptic';
|
||||
export { ImgLoader } from './components/img/img-loader';
|
||||
export { QueryParams, setupQueryParams, UrlToken } from './platform/query-params';
|
||||
export { DeepLinker } from './navigation/deep-linker';
|
||||
export { NavController } from './navigation/nav-controller';
|
||||
@ -174,6 +176,7 @@ export class IonicModule {
|
||||
Form,
|
||||
GestureController,
|
||||
Haptic,
|
||||
ImgLoader,
|
||||
Keyboard,
|
||||
LoadingController,
|
||||
Location,
|
||||
|
Reference in New Issue
Block a user