UNPKG

html2canvas

Version:
271 lines (240 loc) 10.4 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.ResourceStore = undefined; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _Feature = require('./Feature'); var _Feature2 = _interopRequireDefault(_Feature); var _Proxy = require('./Proxy'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var ResourceLoader = function () { function ResourceLoader(options, logger, window) { _classCallCheck(this, ResourceLoader); this.options = options; this._window = window; this.origin = this.getOrigin(window.location.href); this.cache = {}; this.logger = logger; this._index = 0; } _createClass(ResourceLoader, [{ key: 'loadImage', value: function loadImage(src) { var _this = this; if (this.hasResourceInCache(src)) { return src; } if (isBlobImage(src)) { this.cache[src] = _loadImage(src, this.options.imageTimeout || 0); return src; } if (!isSVG(src) || _Feature2.default.SUPPORT_SVG_DRAWING) { if (this.options.allowTaint === true || isInlineImage(src) || this.isSameOrigin(src)) { return this.addImage(src, src, false); } else if (!this.isSameOrigin(src)) { if (typeof this.options.proxy === 'string') { this.cache[src] = (0, _Proxy.Proxy)(src, this.options).then(function (src) { return _loadImage(src, _this.options.imageTimeout || 0); }); return src; } else if (this.options.useCORS === true && _Feature2.default.SUPPORT_CORS_IMAGES) { return this.addImage(src, src, true); } } } } }, { key: 'inlineImage', value: function inlineImage(src) { var _this2 = this; if (isInlineImage(src)) { return _loadImage(src, this.options.imageTimeout || 0); } if (this.hasResourceInCache(src)) { return this.cache[src]; } if (!this.isSameOrigin(src) && typeof this.options.proxy === 'string') { return this.cache[src] = (0, _Proxy.Proxy)(src, this.options).then(function (src) { return _loadImage(src, _this2.options.imageTimeout || 0); }); } return this.xhrImage(src); } }, { key: 'xhrImage', value: function xhrImage(src) { var _this3 = this; this.cache[src] = new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status !== 200) { reject('Failed to fetch image ' + src.substring(0, 256) + ' with status code ' + xhr.status); } else { var reader = new FileReader(); reader.addEventListener('load', function () { // $FlowFixMe var result = reader.result; resolve(result); }, false); reader.addEventListener('error', function (e) { return reject(e); }, false); reader.readAsDataURL(xhr.response); } } }; xhr.responseType = 'blob'; if (_this3.options.imageTimeout) { var timeout = _this3.options.imageTimeout; xhr.timeout = timeout; xhr.ontimeout = function () { return reject(process.env.NODE_ENV !== 'production' ? 'Timed out (' + timeout + 'ms) fetching ' + src.substring(0, 256) : ''); }; } xhr.open('GET', src, true); xhr.send(); }).then(function (src) { return _loadImage(src, _this3.options.imageTimeout || 0); }); return this.cache[src]; } }, { key: 'loadCanvas', value: function loadCanvas(node) { var key = String(this._index++); this.cache[key] = Promise.resolve(node); return key; } }, { key: 'hasResourceInCache', value: function hasResourceInCache(key) { return typeof this.cache[key] !== 'undefined'; } }, { key: 'addImage', value: function addImage(key, src, useCORS) { var _this4 = this; if (process.env.NODE_ENV !== 'production') { this.logger.log('Added image ' + key.substring(0, 256)); } var imageLoadHandler = function imageLoadHandler(supportsDataImages) { return new Promise(function (resolve, reject) { var img = new Image(); img.onload = function () { return resolve(img); }; //ios safari 10.3 taints canvas with data urls unless crossOrigin is set to anonymous if (!supportsDataImages || useCORS) { img.crossOrigin = 'anonymous'; } img.onerror = reject; img.src = src; if (img.complete === true) { // Inline XML images may fail to parse, throwing an Error later on setTimeout(function () { resolve(img); }, 500); } if (_this4.options.imageTimeout) { var timeout = _this4.options.imageTimeout; setTimeout(function () { return reject(process.env.NODE_ENV !== 'production' ? 'Timed out (' + timeout + 'ms) fetching ' + src.substring(0, 256) : ''); }, timeout); } }); }; this.cache[key] = isInlineBase64Image(src) && !isSVG(src) ? // $FlowFixMe _Feature2.default.SUPPORT_BASE64_DRAWING(src).then(imageLoadHandler) : imageLoadHandler(true); return key; } }, { key: 'isSameOrigin', value: function isSameOrigin(url) { return this.getOrigin(url) === this.origin; } }, { key: 'getOrigin', value: function getOrigin(url) { var link = this._link || (this._link = this._window.document.createElement('a')); link.href = url; link.href = link.href; // IE9, LOL! - http://jsfiddle.net/niklasvh/2e48b/ return link.protocol + link.hostname + link.port; } }, { key: 'ready', value: function ready() { var _this5 = this; var keys = Object.keys(this.cache); var values = keys.map(function (str) { return _this5.cache[str].catch(function (e) { if (process.env.NODE_ENV !== 'production') { _this5.logger.log('Unable to load image', e); } return null; }); }); return Promise.all(values).then(function (images) { if (process.env.NODE_ENV !== 'production') { _this5.logger.log('Finished loading ' + images.length + ' images', images); } return new ResourceStore(keys, images); }); } }]); return ResourceLoader; }(); exports.default = ResourceLoader; var ResourceStore = exports.ResourceStore = function () { function ResourceStore(keys, resources) { _classCallCheck(this, ResourceStore); this._keys = keys; this._resources = resources; } _createClass(ResourceStore, [{ key: 'get', value: function get(key) { var index = this._keys.indexOf(key); return index === -1 ? null : this._resources[index]; } }]); return ResourceStore; }(); var INLINE_SVG = /^data:image\/svg\+xml/i; var INLINE_BASE64 = /^data:image\/.*;base64,/i; var INLINE_IMG = /^data:image\/.*/i; var isInlineImage = function isInlineImage(src) { return INLINE_IMG.test(src); }; var isInlineBase64Image = function isInlineBase64Image(src) { return INLINE_BASE64.test(src); }; var isBlobImage = function isBlobImage(src) { return src.substr(0, 4) === 'blob'; }; var isSVG = function isSVG(src) { return src.substr(-3).toLowerCase() === 'svg' || INLINE_SVG.test(src); }; var _loadImage = function _loadImage(src, timeout) { return new Promise(function (resolve, reject) { var img = new Image(); img.onload = function () { return resolve(img); }; img.onerror = reject; img.src = src; if (img.complete === true) { // Inline XML images may fail to parse, throwing an Error later on setTimeout(function () { resolve(img); }, 500); } if (timeout) { setTimeout(function () { return reject(process.env.NODE_ENV !== 'production' ? 'Timed out (' + timeout + 'ms) loading image' : ''); }, timeout); } }); };