html2canvas/src/imageloader.js
2014-09-27 23:03:57 +03:00

138 lines
5.0 KiB
JavaScript

function ImageLoader(options, support) {
this.link = null;
this.options = options;
this.support = support;
this.origin = window.location.protocol + window.location.hostname + window.location.port;
}
ImageLoader.prototype.findImages = function(nodes) {
var images = [];
nodes.reduce(function(imageNodes, container) {
switch(container.node.nodeName) {
case "IMG":
return imageNodes.concat([{
args: [container.node.src],
method: "url"
}]);
case "svg":
case "IFRAME":
return imageNodes.concat([{
args: [container.node],
method: container.node.nodeName
}]);
}
return imageNodes;
}, []).forEach(this.addImage(images, this.loadImage), this);
return images;
};
ImageLoader.prototype.findBackgroundImage = function(images, container) {
container.parseBackgroundImages().filter(this.hasImageBackground).forEach(this.addImage(images, this.loadImage), this);
return images;
};
ImageLoader.prototype.addImage = function(images, callback) {
return function(newImage) {
newImage.args.forEach(function(image) {
if (!this.imageExists(images, image)) {
images.splice(0, 0, callback.call(this, newImage));
log('Added image #' + (images.length), typeof(image) === "string" ? image.substring(0, 100) : image);
}
}, this);
};
};
ImageLoader.prototype.hasImageBackground = function(imageData) {
return imageData.method !== "none";
};
ImageLoader.prototype.loadImage = function(imageData) {
if (imageData.method === "url") {
var src = imageData.args[0];
if (this.isSVG(src) && !this.support.svg && !this.options.allowTaint) {
return new SVGContainer(src);
} else if (src.match(/data:image\/.*;base64,/i)) {
return new ImageContainer(src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, ''), false);
} else if (this.isSameOrigin(src) || this.options.allowTaint === true || this.isSVG(src)) {
return new ImageContainer(src, false);
} else if (this.support.cors && !this.options.allowTaint && this.options.useCORS) {
return new ImageContainer(src, true);
} else if (this.options.proxy) {
return new ProxyImageContainer(src, this.options.proxy);
} else {
return new DummyImageContainer(src);
}
} else if (imageData.method === "linear-gradient") {
return new LinearGradientContainer(imageData);
} else if (imageData.method === "gradient") {
return new WebkitGradientContainer(imageData);
} else if (imageData.method === "svg") {
return new SVGNodeContainer(imageData.args[0], this.support.svg);
} else if (imageData.method === "IFRAME") {
return new FrameContainer(imageData.args[0], this.isSameOrigin(imageData.args[0].src), this.options);
} else {
return new DummyImageContainer(imageData);
}
};
ImageLoader.prototype.isSVG = function(src) {
return (/(.+).svg$/i.test(src)) || SVGContainer.prototype.isInline(src);
};
ImageLoader.prototype.imageExists = function(images, src) {
return images.some(function(image) {
return image.src === src;
});
};
ImageLoader.prototype.isSameOrigin = function(url) {
var link = this.link || (this.link = document.createElement("a"));
link.href = url;
link.href = link.href; // IE9, LOL! - http://jsfiddle.net/niklasvh/2e48b/
var origin = link.protocol + link.hostname + link.port;
return (origin === this.origin);
};
ImageLoader.prototype.getPromise = function(container) {
return this.timeout(container, this.options.imageTimeout)['catch'](function() {
var dummy = new DummyImageContainer(container.src);
return dummy.promise.then(function(image) {
container.image = image;
});
});
};
ImageLoader.prototype.get = function(src) {
var found = null;
return this.images.some(function(img) {
return (found = img).src === src;
}) ? found : null;
};
ImageLoader.prototype.fetch = function(nodes) {
this.images = nodes.reduce(bind(this.findBackgroundImage, this), this.findImages(nodes));
this.images.forEach(function(image, index) {
image.promise.then(function() {
log("Succesfully loaded image #"+ (index+1), image);
}, function(e) {
log("Failed loading image #"+ (index+1), image, e);
});
});
this.ready = Promise.all(this.images.map(this.getPromise, this));
log("Finished searching images");
return this;
};
ImageLoader.prototype.timeout = function(container, timeout) {
var timer;
return Promise.race([container.promise, new Promise(function(res, reject) {
timer = setTimeout(function() {
log("Timed out loading image", container);
reject(container);
}, timeout);
})]).then(function(container) {
clearTimeout(timer);
return container;
});
};