2017-07-29 05:07:42 +03:00
|
|
|
/* @flow */
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
import type Options from './index';
|
|
|
|
import type Logger from './Logger';
|
|
|
|
|
2017-08-03 15:57:55 +03:00
|
|
|
export type ImageElement = Image | HTMLCanvasElement;
|
2017-08-03 19:00:02 +03:00
|
|
|
type ImageCache = {[string]: Promise<?ImageElement>};
|
2017-07-29 05:07:42 +03:00
|
|
|
|
|
|
|
export default class ImageLoader {
|
|
|
|
origin: string;
|
|
|
|
options: Options;
|
|
|
|
_link: HTMLAnchorElement;
|
|
|
|
cache: ImageCache;
|
|
|
|
logger: Logger;
|
2017-08-03 15:57:55 +03:00
|
|
|
_index: number;
|
2017-08-06 12:53:38 +03:00
|
|
|
_window: WindowProxy;
|
2017-07-29 05:07:42 +03:00
|
|
|
|
2017-08-06 12:53:38 +03:00
|
|
|
constructor(options: Options, logger: Logger, window: WindowProxy) {
|
2017-07-29 05:07:42 +03:00
|
|
|
this.options = options;
|
2017-08-06 12:53:38 +03:00
|
|
|
this._window = window;
|
2017-07-29 05:07:42 +03:00
|
|
|
this.origin = this.getOrigin(window.location.href);
|
|
|
|
this.cache = {};
|
|
|
|
this.logger = logger;
|
2017-08-03 15:57:55 +03:00
|
|
|
this._index = 0;
|
2017-07-29 05:07:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
loadImage(src: string): ?string {
|
|
|
|
if (this.hasImageInCache(src)) {
|
|
|
|
return src;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.options.allowTaint === true || this.isInlineImage(src) || this.isSameOrigin(src)) {
|
|
|
|
return this.addImage(src, src);
|
|
|
|
} else if (typeof this.options.proxy === 'string' && !this.isSameOrigin(src)) {
|
|
|
|
// TODO proxy
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-03 15:57:55 +03:00
|
|
|
loadCanvas(node: HTMLCanvasElement): string {
|
|
|
|
const key = String(this._index++);
|
|
|
|
this.cache[key] = Promise.resolve(node);
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
2017-07-29 05:07:42 +03:00
|
|
|
isInlineImage(src: string): boolean {
|
|
|
|
return /data:image\/.*;base64,/i.test(src);
|
|
|
|
}
|
|
|
|
|
|
|
|
hasImageInCache(key: string): boolean {
|
|
|
|
return typeof this.cache[key] !== 'undefined';
|
|
|
|
}
|
|
|
|
|
|
|
|
addImage(key: string, src: string): string {
|
|
|
|
if (__DEV__) {
|
|
|
|
this.logger.log(`Added image ${key.substring(0, 256)}`);
|
|
|
|
}
|
|
|
|
this.cache[key] = new Promise((resolve, reject) => {
|
|
|
|
const img = new Image();
|
|
|
|
img.onload = () => resolve(img);
|
|
|
|
img.onerror = reject;
|
|
|
|
img.src = src;
|
|
|
|
if (img.complete === true) {
|
|
|
|
resolve(img);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
|
|
|
isSameOrigin(url: string): boolean {
|
|
|
|
return this.getOrigin(url) === this.origin;
|
|
|
|
}
|
|
|
|
|
|
|
|
getOrigin(url: string): string {
|
2017-08-06 12:53:38 +03:00
|
|
|
const link = this._link || (this._link = this._window.document.createElement('a'));
|
2017-07-29 05:07:42 +03:00
|
|
|
link.href = url;
|
|
|
|
link.href = link.href; // IE9, LOL! - http://jsfiddle.net/niklasvh/2e48b/
|
|
|
|
return link.protocol + link.hostname + link.port;
|
|
|
|
}
|
|
|
|
|
|
|
|
ready(): Promise<ImageStore> {
|
|
|
|
const keys = Object.keys(this.cache);
|
2017-08-03 19:00:02 +03:00
|
|
|
return Promise.all(
|
|
|
|
keys.map(str =>
|
|
|
|
this.cache[str].catch(e => {
|
|
|
|
if (__DEV__) {
|
|
|
|
this.logger.log(`Unable to load image`, e);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
})
|
|
|
|
)
|
|
|
|
).then(images => {
|
2017-07-29 05:07:42 +03:00
|
|
|
if (__DEV__) {
|
|
|
|
this.logger.log('Finished loading images', images);
|
|
|
|
}
|
|
|
|
return new ImageStore(keys, images);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export class ImageStore {
|
|
|
|
_keys: Array<string>;
|
2017-08-03 19:00:02 +03:00
|
|
|
_images: Array<?ImageElement>;
|
2017-07-29 05:07:42 +03:00
|
|
|
|
2017-08-03 19:00:02 +03:00
|
|
|
constructor(keys: Array<string>, images: Array<?ImageElement>) {
|
2017-07-29 05:07:42 +03:00
|
|
|
this._keys = keys;
|
|
|
|
this._images = images;
|
|
|
|
}
|
|
|
|
|
2017-08-03 15:57:55 +03:00
|
|
|
get(key: string): ?ImageElement {
|
2017-07-29 05:07:42 +03:00
|
|
|
const index = this._keys.indexOf(key);
|
|
|
|
return index === -1 ? null : this._images[index];
|
|
|
|
}
|
|
|
|
}
|