mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
Merge branch 'master' of https://github.com/niklasvh/html2canvas
Conflicts: build/html2canvas.min.js dist/html2canvas.js src/core.js
This commit is contained in:
commit
52c669fe5b
@ -10,6 +10,7 @@
|
||||
"boss": true,
|
||||
"eqnull": true,
|
||||
"browser": true,
|
||||
"indent": 4,
|
||||
"globals": {
|
||||
"jQuery": true
|
||||
},
|
||||
|
@ -25,7 +25,7 @@ module.exports = function(grunt) {
|
||||
src: [
|
||||
'src/promise.js', 'src/fallback.js', 'src/**/*.js'
|
||||
],
|
||||
dest: 'build/<%= pkg.name %>.js'
|
||||
dest: 'dist/<%= pkg.name %>.js'
|
||||
},
|
||||
options:{
|
||||
banner: meta.banner + meta.pre,
|
||||
@ -71,7 +71,7 @@ module.exports = function(grunt) {
|
||||
uglify: {
|
||||
dist: {
|
||||
src: ['<%= concat.dist.dest %>'],
|
||||
dest: 'build/<%= pkg.name %>.min.js'
|
||||
dest: 'dist/<%= pkg.name %>.min.js'
|
||||
},
|
||||
options: {
|
||||
banner: meta.banner
|
||||
|
@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "html2canvas",
|
||||
"version": "0.4.1",
|
||||
"version": "0.5.0-alpha",
|
||||
"description": "Screenshots with JavaScript",
|
||||
"main": "build/html2canvas.js",
|
||||
"main": "dist/html2canvas.js",
|
||||
"ignore": [
|
||||
"tests",
|
||||
".travis.yml"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
8
build/html2canvas.min.js
vendored
8
build/html2canvas.min.js
vendored
File diff suppressed because one or more lines are too long
41
build/html2canvas.js → dist/html2canvas.js
vendored
41
build/html2canvas.js → dist/html2canvas.js
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
html2canvas 0.5.0-rc1 <http://html2canvas.hertzen.com>
|
||||
html2canvas 0.5.0-alpha <http://html2canvas.hertzen.com>
|
||||
Copyright (c) 2014 Niklas von Hertzen
|
||||
|
||||
Released under MIT License
|
||||
@ -47,6 +47,7 @@ window.html2canvas = function(nodeList, options) {
|
||||
}
|
||||
|
||||
options.async = typeof(options.async) === "undefined" ? true : options.async;
|
||||
options.allowTaint = typeof(options.allowTaint) === "undefined" ? false : options.allowTaint;
|
||||
options.removeContainer = typeof(options.removeContainer) === "undefined" ? true : options.removeContainer;
|
||||
|
||||
var node = ((nodeList === undefined) ? [document.documentElement] : ((nodeList.length) ? nodeList : [nodeList]))[0];
|
||||
@ -72,7 +73,7 @@ function renderDocument(document, options, windowWidth, windowHeight) {
|
||||
var bounds = getBounds(node);
|
||||
var width = options.type === "view" ? Math.min(bounds.width, windowWidth) : documentWidth(clonedWindow.document);
|
||||
var height = options.type === "view" ? Math.min(bounds.height, windowHeight) : documentHeight(clonedWindow.document);
|
||||
var renderer = new CanvasRenderer(width, height, imageLoader);
|
||||
var renderer = new CanvasRenderer(width, height, imageLoader, options);
|
||||
var parser = new NodeParser(node, renderer, support, imageLoader, options);
|
||||
return parser.ready.then(function() {
|
||||
log("Finished rendering");
|
||||
@ -263,6 +264,7 @@ function ImageContainer(src, cors) {
|
||||
this.src = src;
|
||||
this.image = new Image();
|
||||
var self = this;
|
||||
this.tainted = null;
|
||||
this.promise = new Promise(function(resolve, reject) {
|
||||
self.image.onload = resolve;
|
||||
self.image.onerror = reject;
|
||||
@ -1083,7 +1085,7 @@ NodeParser.prototype.paintNode = function(container) {
|
||||
case "IMG":
|
||||
var imageContainer = this.images.get(container.node.src);
|
||||
if (imageContainer) {
|
||||
this.renderer.renderImage(container, bounds, borderData, imageContainer.image);
|
||||
this.renderer.renderImage(container, bounds, borderData, imageContainer);
|
||||
} else {
|
||||
log("Error loading <img>", container.node.src);
|
||||
}
|
||||
@ -1538,13 +1540,14 @@ function ProxyImageContainer(src, proxy) {
|
||||
|
||||
var proxyImageCount = 0;
|
||||
|
||||
function Renderer(width, height, images) {
|
||||
function Renderer(width, height, images, options) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.images = images;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
Renderer.prototype.renderImage = function(container, bounds, borderData, image) {
|
||||
Renderer.prototype.renderImage = function(container, bounds, borderData, imageContainer) {
|
||||
var paddingLeft = container.cssInt('paddingLeft'),
|
||||
paddingTop = container.cssInt('paddingTop'),
|
||||
paddingRight = container.cssInt('paddingRight'),
|
||||
@ -1552,11 +1555,11 @@ Renderer.prototype.renderImage = function(container, bounds, borderData, image)
|
||||
borders = borderData.borders;
|
||||
|
||||
this.drawImage(
|
||||
image,
|
||||
imageContainer,
|
||||
0,
|
||||
0,
|
||||
image.width,
|
||||
image.height,
|
||||
imageContainer.image.width,
|
||||
imageContainer.image.height,
|
||||
bounds.left + paddingLeft + borders[3].width,
|
||||
bounds.top + paddingTop + borders[0].width,
|
||||
bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight),
|
||||
@ -1649,6 +1652,7 @@ function CanvasRenderer(width, height) {
|
||||
this.canvas.width = width;
|
||||
this.canvas.height = height;
|
||||
this.ctx = this.canvas.getContext("2d");
|
||||
this.taintCtx = document.createElement("canvas").getContext("2d");
|
||||
this.ctx.textBaseline = "bottom";
|
||||
this.variables = {};
|
||||
log("Initialized CanvasRenderer");
|
||||
@ -1670,8 +1674,25 @@ CanvasRenderer.prototype.drawShape = function(shape, color) {
|
||||
this.setFillStyle(color).fill();
|
||||
};
|
||||
|
||||
CanvasRenderer.prototype.drawImage = function(image, sx, sy, sw, sh, dx, dy, dw, dh) {
|
||||
this.ctx.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);
|
||||
CanvasRenderer.prototype.taints = function(imageContainer) {
|
||||
if (imageContainer.tainted === null) {
|
||||
this.taintCtx.drawImage(imageContainer.image, 0, 0);
|
||||
try {
|
||||
this.taintCtx.getImageData(0, 0, 1, 1);
|
||||
imageContainer.tainted = false;
|
||||
} catch(e) {
|
||||
this.taintCtx = document.createElement("canvas").getContext("2d");
|
||||
imageContainer.tainted = true;
|
||||
}
|
||||
}
|
||||
|
||||
return imageContainer.tainted;
|
||||
};
|
||||
|
||||
CanvasRenderer.prototype.drawImage = function(imageContainer, sx, sy, sw, sh, dx, dy, dw, dh) {
|
||||
if (!this.taints(imageContainer)) {
|
||||
this.ctx.drawImage(imageContainer.image, sx, sy, sw, sh, dx, dy, dw, dh);
|
||||
}
|
||||
};
|
||||
|
||||
CanvasRenderer.prototype.clip = function(shape, callback, context) {
|
8
dist/html2canvas.min.js
vendored
Normal file
8
dist/html2canvas.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -171,7 +171,7 @@
|
||||
<p style="color: black; font-size: 1em; line-height: 1.3em; clear: both">
|
||||
This is a nonsensical document, but syntactically valid HTML 4.0. All 100% conformant CSS1 agents should be able to render the document elements above this paragraph <b>indistinguishably</b> (to the pixel) from this reference rendering, (except font rasterization and form widgets). All discrepancies should be traceable to CSS1 implementation shortcomings. Once you have finished evaluating this test, you can return to the <A HREF="sec5526c.htm" style="text-decoration:none">parent page</A>.
|
||||
</p>
|
||||
<script type="text/javascript" src="../build/html2canvas.js"></script>
|
||||
<script type="text/javascript" src="../dist/html2canvas.js"></script>
|
||||
<script type="text/javascript">
|
||||
html2canvas(document.body, {
|
||||
onrendered: function(canvas) {
|
||||
|
@ -53,7 +53,7 @@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="../build/html2canvas.js"></script>
|
||||
<script type="text/javascript" src="../dist/html2canvas.js"></script>
|
||||
<script type="text/javascript">
|
||||
html2canvas(document.body, {
|
||||
onrendered: function(canvas) {
|
||||
|
@ -2,7 +2,7 @@
|
||||
"title": "html2canvas",
|
||||
"name": "html2canvas",
|
||||
"description": "Screenshots with JavaScript",
|
||||
"version": "0.5.0-rc1",
|
||||
"version": "0.5.0-alpha",
|
||||
"author": {
|
||||
"name": "Niklas von Hertzen",
|
||||
"email": "niklasvh@gmail.com",
|
||||
@ -20,7 +20,7 @@
|
||||
"url": "https://github.com/niklasvh/html2canvas/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"baconjs": "0.7.11",
|
||||
"baconjs": "^0.7.11",
|
||||
"base64-arraybuffer": ">= 0.1.0",
|
||||
"grunt": "^0.4.5",
|
||||
"grunt-contrib-concat": "*",
|
||||
@ -31,7 +31,7 @@
|
||||
"grunt-contrib-watch": "~0.5.1",
|
||||
"lodash": "^2.4.1",
|
||||
"png-js": ">= 0.1.1",
|
||||
"wd": "0.2.21"
|
||||
"wd": "^0.2.21"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt travis --verbose"
|
||||
|
@ -8,6 +8,7 @@ window.html2canvas = function(nodeList, options) {
|
||||
}
|
||||
|
||||
options.async = typeof(options.async) === "undefined" ? true : options.async;
|
||||
options.allowTaint = typeof(options.allowTaint) === "undefined" ? false : options.allowTaint;
|
||||
options.removeContainer = typeof(options.removeContainer) === "undefined" ? true : options.removeContainer;
|
||||
|
||||
var node = ((nodeList === undefined) ? [document.documentElement] : ((nodeList.length) ? nodeList : [nodeList]))[0];
|
||||
@ -33,7 +34,7 @@ function renderDocument(document, options, windowWidth, windowHeight) {
|
||||
var bounds = getBounds(node);
|
||||
var width = options.type === "view" ? Math.min(bounds.width, windowWidth) : documentWidth(clonedWindow.document);
|
||||
var height = options.type === "view" ? Math.min(bounds.height, windowHeight) : documentHeight(clonedWindow.document);
|
||||
var renderer = new CanvasRenderer(width, height, imageLoader);
|
||||
var renderer = new CanvasRenderer(width, height, imageLoader, options);
|
||||
var parser = new NodeParser(node, renderer, support, imageLoader, options);
|
||||
return parser.ready.then(function() {
|
||||
log("Finished rendering");
|
||||
|
@ -2,6 +2,7 @@ function ImageContainer(src, cors) {
|
||||
this.src = src;
|
||||
this.image = new Image();
|
||||
var self = this;
|
||||
this.tainted = null;
|
||||
this.promise = new Promise(function(resolve, reject) {
|
||||
self.image.onload = resolve;
|
||||
self.image.onerror = reject;
|
||||
|
@ -254,7 +254,7 @@ NodeParser.prototype.paintNode = function(container) {
|
||||
case "IMG":
|
||||
var imageContainer = this.images.get(container.node.src);
|
||||
if (imageContainer) {
|
||||
this.renderer.renderImage(container, bounds, borderData, imageContainer.image);
|
||||
this.renderer.renderImage(container, bounds, borderData, imageContainer);
|
||||
} else {
|
||||
log("Error loading <img>", container.node.src);
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
function Renderer(width, height, images) {
|
||||
function Renderer(width, height, images, options) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.images = images;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
Renderer.prototype.renderImage = function(container, bounds, borderData, image) {
|
||||
Renderer.prototype.renderImage = function(container, bounds, borderData, imageContainer) {
|
||||
var paddingLeft = container.cssInt('paddingLeft'),
|
||||
paddingTop = container.cssInt('paddingTop'),
|
||||
paddingRight = container.cssInt('paddingRight'),
|
||||
@ -12,11 +13,11 @@ Renderer.prototype.renderImage = function(container, bounds, borderData, image)
|
||||
borders = borderData.borders;
|
||||
|
||||
this.drawImage(
|
||||
image,
|
||||
imageContainer,
|
||||
0,
|
||||
0,
|
||||
image.width,
|
||||
image.height,
|
||||
imageContainer.image.width,
|
||||
imageContainer.image.height,
|
||||
bounds.left + paddingLeft + borders[3].width,
|
||||
bounds.top + paddingTop + borders[0].width,
|
||||
bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight),
|
||||
|
@ -4,6 +4,7 @@ function CanvasRenderer(width, height) {
|
||||
this.canvas.width = width;
|
||||
this.canvas.height = height;
|
||||
this.ctx = this.canvas.getContext("2d");
|
||||
this.taintCtx = document.createElement("canvas").getContext("2d");
|
||||
this.ctx.textBaseline = "bottom";
|
||||
this.variables = {};
|
||||
log("Initialized CanvasRenderer");
|
||||
@ -25,8 +26,25 @@ CanvasRenderer.prototype.drawShape = function(shape, color) {
|
||||
this.setFillStyle(color).fill();
|
||||
};
|
||||
|
||||
CanvasRenderer.prototype.drawImage = function(image, sx, sy, sw, sh, dx, dy, dw, dh) {
|
||||
this.ctx.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);
|
||||
CanvasRenderer.prototype.taints = function(imageContainer) {
|
||||
if (imageContainer.tainted === null) {
|
||||
this.taintCtx.drawImage(imageContainer.image, 0, 0);
|
||||
try {
|
||||
this.taintCtx.getImageData(0, 0, 1, 1);
|
||||
imageContainer.tainted = false;
|
||||
} catch(e) {
|
||||
this.taintCtx = document.createElement("canvas").getContext("2d");
|
||||
imageContainer.tainted = true;
|
||||
}
|
||||
}
|
||||
|
||||
return imageContainer.tainted;
|
||||
};
|
||||
|
||||
CanvasRenderer.prototype.drawImage = function(imageContainer, sx, sy, sw, sh, dx, dy, dw, dh) {
|
||||
if (!this.taints(imageContainer)) {
|
||||
this.ctx.drawImage(imageContainer.image, sx, sy, sw, sh, dx, dy, dw, dh);
|
||||
}
|
||||
};
|
||||
|
||||
CanvasRenderer.prototype.clip = function(shape, callback, context) {
|
||||
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* jQuery helper plugin for examples and tests
|
||||
*/
|
||||
(function( $ ){
|
||||
$.fn.html2canvas = function(options) {
|
||||
if (options && options.profile && window.console && window.console.profile && window.location.search !== "?selenium2") {
|
||||
window.console.profile();
|
||||
}
|
||||
var date = new Date(),
|
||||
$message = null,
|
||||
timeoutTimer = false,
|
||||
timer = date.getTime();
|
||||
options = options || {};
|
||||
|
||||
var promise = html2canvas(this, options);
|
||||
promise.catch(function(err) {
|
||||
console.log("html2canvas threw an error", err);
|
||||
});
|
||||
|
||||
promise.then(function(canvas) {
|
||||
var $canvas = $(canvas),
|
||||
finishTime = new Date();
|
||||
|
||||
if (options && options.profile && window.console && window.console.profileEnd) {
|
||||
window.console.profileEnd();
|
||||
}
|
||||
$canvas.addClass("html2canvas")
|
||||
.css({
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0
|
||||
}).appendTo(document.body);
|
||||
|
||||
if (window.location.search !== "?selenium") {
|
||||
$canvas.siblings().toggle();
|
||||
$(window).click(function(){
|
||||
$canvas.toggle().siblings().toggle();
|
||||
throwMessage("Canvas Render " + ($canvas.is(':visible') ? "visible" : "hidden"));
|
||||
});
|
||||
throwMessage('Screenshot created in '+ ((finishTime.getTime()-timer)) + " ms<br />",4000);
|
||||
} else {
|
||||
$canvas.css('display', 'none');
|
||||
}
|
||||
// test if canvas is read-able
|
||||
try {
|
||||
$canvas[0].toDataURL();
|
||||
} catch(e) {
|
||||
if ($canvas[0].nodeName.toLowerCase() === "canvas") {
|
||||
// TODO, maybe add a bit less offensive way to present this, but still something that can easily be noticed
|
||||
window.alert("Canvas is tainted, unable to read data");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function throwMessage(msg,duration){
|
||||
window.clearTimeout(timeoutTimer);
|
||||
timeoutTimer = window.setTimeout(function(){
|
||||
$message.fadeOut(function(){
|
||||
$message.remove();
|
||||
$message = null;
|
||||
});
|
||||
},duration || 2000);
|
||||
if ($message)
|
||||
$message.remove();
|
||||
$message = $('<div />').html(msg).css({
|
||||
margin:0,
|
||||
padding:10,
|
||||
background: "#000",
|
||||
opacity:0.7,
|
||||
position:"fixed",
|
||||
top:10,
|
||||
right:10,
|
||||
fontFamily: 'Tahoma',
|
||||
color:'#fff',
|
||||
fontSize:12,
|
||||
borderRadius:12,
|
||||
width:'auto',
|
||||
height:'auto',
|
||||
textAlign:'center',
|
||||
textDecoration:'none',
|
||||
display:'none'
|
||||
}).appendTo(document.body).fadeIn();
|
||||
log(msg);
|
||||
}
|
||||
};
|
||||
})( jQuery );
|
105
tests/test.js
105
tests/test.js
@ -7,21 +7,100 @@
|
||||
*/
|
||||
var h2cSelector, h2cOptions;
|
||||
(function(document, window) {
|
||||
var srcStart = '<script type="text/javascript" src="', scrEnd = '"></script>';
|
||||
|
||||
document.write(srcStart + '/tests/assets/jquery-1.6.2.js' + scrEnd);
|
||||
document.write(srcStart + '/tests/assets/jquery.plugin.html2canvas.js' + scrEnd);
|
||||
var html2canvas = ['log', 'nodecontainer', 'stackingcontext', 'textcontainer', 'support', 'imagecontainer', 'dummyimagecontainer', 'proxyimagecontainer', 'gradientcontainer', 'lineargradientcontainer', 'webkitgradientcontainer',
|
||||
'imageloader', 'nodeparser', 'font', 'fontmetrics', 'core', 'renderer', 'promise', 'renderers/canvas'], i;
|
||||
if (window.location.search === "?selenium") {
|
||||
document.write(srcStart + '/build/html2canvas.js' + scrEnd);
|
||||
} else {
|
||||
for (i = 0; i < html2canvas.length; ++i) {
|
||||
document.write(srcStart + '/src/' + html2canvas[i] + '.js?' + Math.random() + scrEnd);
|
||||
}
|
||||
function appendScript(src) {
|
||||
document.write('<script type="text/javascript" src="' + src + '.js?' + Math.random() + '"></script>');
|
||||
}
|
||||
|
||||
var sources = ['log', 'nodecontainer', 'stackingcontext', 'textcontainer', 'support', 'imagecontainer', 'dummyimagecontainer', 'proxyimagecontainer', 'gradientcontainer',
|
||||
'lineargradientcontainer', 'webkitgradientcontainer', 'imageloader', 'nodeparser', 'font', 'fontmetrics', 'core', 'renderer', 'promise', 'renderers/canvas'];
|
||||
|
||||
['/tests/assets/jquery-1.6.2'].concat(window.location.search === "?selenium" ? ['/dist/html2canvas'] : sources.map(function(src) { return '/src/' + src; })).forEach(appendScript);
|
||||
|
||||
window.onload = function() {
|
||||
(function( $ ){
|
||||
$.fn.html2canvas = function(options) {
|
||||
if (options && options.profile && window.console && window.console.profile && window.location.search !== "?selenium2") {
|
||||
window.console.profile();
|
||||
}
|
||||
var date = new Date(),
|
||||
$message = null,
|
||||
timeoutTimer = false,
|
||||
timer = date.getTime();
|
||||
options = options || {};
|
||||
|
||||
var promise = html2canvas(this, options);
|
||||
promise['catch'](function(err) {
|
||||
console.log("html2canvas threw an error", err);
|
||||
});
|
||||
|
||||
promise.then(function(canvas) {
|
||||
var $canvas = $(canvas),
|
||||
finishTime = new Date();
|
||||
|
||||
if (options && options.profile && window.console && window.console.profileEnd) {
|
||||
window.console.profileEnd();
|
||||
}
|
||||
$canvas.addClass("html2canvas")
|
||||
.css({
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0
|
||||
}).appendTo(document.body);
|
||||
|
||||
if (window.location.search !== "?selenium") {
|
||||
$canvas.siblings().toggle();
|
||||
$(window).click(function(){
|
||||
$canvas.toggle().siblings().toggle();
|
||||
throwMessage("Canvas Render " + ($canvas.is(':visible') ? "visible" : "hidden"));
|
||||
});
|
||||
throwMessage('Screenshot created in '+ ((finishTime.getTime()-timer)) + " ms<br />",4000);
|
||||
} else {
|
||||
$canvas.css('display', 'none');
|
||||
}
|
||||
// test if canvas is read-able
|
||||
try {
|
||||
$canvas[0].toDataURL();
|
||||
} catch(e) {
|
||||
if ($canvas[0].nodeName.toLowerCase() === "canvas") {
|
||||
// TODO, maybe add a bit less offensive way to present this, but still something that can easily be noticed
|
||||
window.alert("Canvas is tainted, unable to read data");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function throwMessage(msg,duration){
|
||||
window.clearTimeout(timeoutTimer);
|
||||
timeoutTimer = window.setTimeout(function(){
|
||||
$message.fadeOut(function(){
|
||||
$message.remove();
|
||||
$message = null;
|
||||
});
|
||||
},duration || 2000);
|
||||
if ($message)
|
||||
$message.remove();
|
||||
$message = $('<div />').html(msg).css({
|
||||
margin:0,
|
||||
padding:10,
|
||||
background: "#000",
|
||||
opacity:0.7,
|
||||
position:"fixed",
|
||||
top:10,
|
||||
right:10,
|
||||
fontFamily: 'Tahoma',
|
||||
color:'#fff',
|
||||
fontSize:12,
|
||||
borderRadius:12,
|
||||
width:'auto',
|
||||
height:'auto',
|
||||
textAlign:'center',
|
||||
textDecoration:'none',
|
||||
display:'none'
|
||||
}).appendTo(document.body).fadeIn();
|
||||
log(msg);
|
||||
}
|
||||
};
|
||||
})(jQuery);
|
||||
|
||||
h2cSelector = [document.documentElement];
|
||||
|
||||
if (window.setUp) {
|
||||
@ -29,9 +108,7 @@ var h2cSelector, h2cOptions;
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
|
||||
$(h2cSelector).html2canvas($.extend({
|
||||
flashcanvas: "../external/flashcanvas.min.js",
|
||||
logging: true,
|
||||
profile: true,
|
||||
proxy: "http://html2canvas.appspot.com/query",
|
||||
|
Loading…
Reference in New Issue
Block a user