html2canvas
Version:
Screenshots with JavaScript
271 lines (240 loc) • 10.4 kB
JavaScript
'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);
}
});
};