From 86c1ee16015f80f64ae5fc2f2eb66afe22a2c72b Mon Sep 17 00:00:00 2001 From: MoyuScript Date: Fri, 29 Jul 2011 22:55:01 +0300 Subject: [PATCH] added support for form element text value rendering --- build.xml | 1 + build/html2canvas.js | 257 +++++++++++++++++++++++++-------------- build/html2canvas.min.js | 15 ++- src/Draw.js | 77 ++++++++---- src/Forms.js | 38 ++++++ src/LICENSE | 2 +- src/Text.js | 106 ++++++++-------- src/Util.js | 34 +++--- 8 files changed, 344 insertions(+), 186 deletions(-) create mode 100644 src/Forms.js diff --git a/build.xml b/build.xml index bd606d0..653faf5 100644 --- a/build.xml +++ b/build.xml @@ -21,6 +21,7 @@ + diff --git a/build/html2canvas.js b/build/html2canvas.js index 6fcb747..3316a01 100644 --- a/build/html2canvas.js +++ b/build/html2canvas.js @@ -1,5 +1,5 @@ /* - * html2canvas v0.26 + * html2canvas v0.27 * Copyright (c) 2011 Niklas von Hertzen. All rights reserved. * http://www.twitter.com/niklasvh * @@ -737,7 +737,7 @@ html2canvas.prototype.newElement = function(el,parentStack){ stack.clip.width = stack.clip.width-(borders[1].width); stack.clip.height = stack.clip.height-(borders[2].width); } -*/ + */ if (this.ignoreRe.test(el.nodeName) && this.opts.iframeDefault != "transparent"){ if (this.opts.iframeDefault=="default"){ bgcolor = "#efefef"; @@ -780,26 +780,59 @@ html2canvas.prototype.newElement = function(el,parentStack){ this.drawBackground(el,bgbounds,ctx); } - if (el.nodeName=="IMG"){ - image = _.loadImage(_.getAttr(el,'src')); - if (image){ - // console.log(image.width); - this.drawImage( - ctx, - image, - 0, //sx - 0, //sy - image.width, //sw - image.height, //sh - x+parseInt(_.getCSS(el,'padding-left'),10) + borders[3].width, //dx - y+parseInt(_.getCSS(el,'padding-top'),10) + borders[0].width, // dy - bounds.width - (borders[1].width + borders[3].width + parseInt(_.getCSS(el,'padding-left'),10) + parseInt(_.getCSS(el,'padding-right'),10)), //dw - bounds.height - (borders[0].width + borders[2].width + parseInt(_.getCSS(el,'padding-top'),10) + parseInt(_.getCSS(el,'padding-bottom'),10)) //dh - ); + switch(el.nodeName){ + case "IMG": + image = _.loadImage(_.getAttr(el,'src')); + if (image){ + // console.log(image.width); + this.drawImage( + ctx, + image, + 0, //sx + 0, //sy + image.width, //sw + image.height, //sh + x+parseInt(_.getCSS(el,'padding-left'),10) + borders[3].width, //dx + y+parseInt(_.getCSS(el,'padding-top'),10) + borders[0].width, // dy + bounds.width - (borders[1].width + borders[3].width + parseInt(_.getCSS(el,'padding-left'),10) + parseInt(_.getCSS(el,'padding-right'),10)), //dw + bounds.height - (borders[0].width + borders[2].width + parseInt(_.getCSS(el,'padding-top'),10) + parseInt(_.getCSS(el,'padding-bottom'),10)) //dh + ); - }else { - this.log("Error loading :" + _.getAttr(el,'src')); - } + }else { + this.log("Error loading :" + _.getAttr(el,'src')); + } + break; + case "INPUT": + // TODO add all relevant type's, i.e. HTML5 new stuff + // todo add support for placeholder attribute for browsers which support it + if (/^(text|url|email|submit|button|reset)$/.test(el.type) && el.value.length > 0){ + + this.renderFormValue(el,bounds,stack); + + + /* + this just doesn't work well enough + + this.newText(el,{ + nodeValue:el.value, + splitText: function(){ + return this; + }, + formValue:true + },stack); + */ + } + break; + case "TEXTAREA": + if (el.value.length > 0){ + this.renderFormValue(el,bounds,stack); + } + break; + case "SELECT": + if (el.options.length > 0){ + this.renderFormValue(el,bounds,stack); + } + break; } @@ -816,8 +849,8 @@ html2canvas.prototype.newElement = function(el,parentStack){ /* - * Function to draw the text on the canvas - */ +* Function to draw the text on the canvas +*/ html2canvas.prototype.printText = function(currentText,x,y,ctx){ if (this.trim(currentText).length>0){ @@ -852,6 +885,44 @@ html2canvas.prototype.drawImage = function(ctx,image,sx,sy,sw,sh,dx,dy,dw,dh){ ); this.numDraws++; +} +html2canvas.prototype.renderFormValue = function(el,bounds,stack){ + + var valueWrap = document.createElement('valuewrap'), + _ = this; + + this.each(['lineHeight','textAlign','fontFamily','color','fontSize','paddingLeft','paddingTop','width','height','border','borderLeftWidth','borderTopWidth'],function(i,style){ + valueWrap.style[style] = _.getCSS(el,style); + }); + + valueWrap.style.borderColor = "black"; + valueWrap.style.borderStyle = "solid"; + valueWrap.style.display = "block"; + valueWrap.style.position = "absolute"; + if (/^(submit|reset|button|text|password)$/.test(el.type) || el.nodeName == "SELECT"){ + valueWrap.style.lineHeight = _.getCSS(el,"height"); + } + + + valueWrap.style.top = bounds.top+"px"; + valueWrap.style.left = bounds.left+"px"; + if (el.nodeName == "SELECT"){ + // TODO increase accuracy of text position + var textValue = el.options[el.selectedIndex].text; + } else{ + var textValue = el.value; + + } + var textNode = document.createTextNode(textValue); + + valueWrap.appendChild(textNode); + $('body').append(valueWrap); + + this.newText(el,textNode,stack); + + $(valueWrap).remove(); + + } /* * Function to find all images from and background-image @@ -1331,7 +1402,7 @@ html2canvas.prototype.setContextVariable = function(ctx,variable,value){ } -html2canvas.prototype.newText = function(el,textNode,stack){ +html2canvas.prototype.newText = function(el,textNode,stack,form){ var ctx = stack.ctx; var family = this.getCSS(el,"font-family"); var size = this.getCSS(el,"font-size"); @@ -1346,7 +1417,7 @@ html2canvas.prototype.newText = function(el,textNode,stack){ var letter_spacing = this.getCSS(el,"letter-spacing"); - + // apply text-transform:ation to the text textNode.nodeValue = this.textTransform(textNode.nodeValue,this.getCSS(el,"text-transform")); var text = this.trim(textNode.nodeValue); @@ -1400,79 +1471,81 @@ html2canvas.prototype.newText = function(el,textNode,stack){ } */ - - - var oldTextNode = textNode; - for(var c=0;c + * html2canvas v0.27 * Copyright (c) 2011 Niklas von Hertzen. All rights reserved. * http://www.twitter.com/niklasvh * @@ -24,8 +24,11 @@ html2canvas.prototype.getBorderData=function(a){var b=[],c=this;this.each(["top" html2canvas.prototype.drawBorders=function(a,b,c,d){var e=c.left,f=c.top,h=c.width,i=c.height,g=this.getBorderData(a),j=this;this.each(g,function(a,c){if(c.width>0){var n=e,o=f,m=h,p=i-g[2].width;switch(a){case 0:p=g[0].width;break;case 1:n=e+h-g[1].width;m=g[1].width;break;case 2:o=o+i-g[2].width;p=g[2].width;break;case 3:m=g[3].width}m={left:n,top:o,width:m,height:p};d&&(m=j.clipBounds(m,d));m.width>0&&m.height>0&&j.newRect(b,n,o,m.width,m.height,c.color)}});return g}; html2canvas.prototype.newElement=function(a,b){var c=this.getBounds(a),d=c.left,e=c.top,f=c.width,h=c.height,i;i=this.getCSS(a,"background-color");var g=this.getCSS(a,"position"),b=b||{},j=this.formatZ(this.getCSS(a,"zIndex"),g,b.zIndex,a.parentNode),k=this.getCSS(a,"opacity"),l={ctx:new this.storageContext,zIndex:j,opacity:k*b.opacity,cssPosition:g};if(b.clip)l.clip=$.extend({},b.clip),l.clip.height-=b.borders[2].width;if(this.opts.useOverflow&&/(hidden|scroll|auto)/.test(this.getCSS(a,"overflow"))&& !/(BODY)/i.test(a.nodeName))l.clip=l.clip?this.clipBounds(l.clip,c):c;g=this.contextStacks.push(l);j=this.contextStacks[g-1].ctx;this.setContextVariable(j,"globalAlpha",l.opacity);k=this.drawBorders(a,j,c);l.borders=k;this.ignoreRe.test(a.nodeName)&&this.opts.iframeDefault!="transparent"&&(i=this.opts.iframeDefault=="default"?"#efefef":this.opts.iframeDefault);f={left:d+k[3].width,top:e+k[0].width,width:f-(k[1].width+k[3].width),height:h-(k[0].width+k[2].width)};l.clip&&(f=this.clipBounds(f,l.clip)); -f.height>0&&f.width>0&&(this.newRect(j,f.left,f.top,f.width,f.height,i),this.drawBackground(a,f,j));a.nodeName=="IMG"&&((i=this.loadImage(this.getAttr(a,"src")))?this.drawImage(j,i,0,0,i.width,i.height,d+parseInt(this.getCSS(a,"padding-left"),10)+k[3].width,e+parseInt(this.getCSS(a,"padding-top"),10)+k[0].width,c.width-(k[1].width+k[3].width+parseInt(this.getCSS(a,"padding-left"),10)+parseInt(this.getCSS(a,"padding-right"),10)),c.height-(k[0].width+k[2].width+parseInt(this.getCSS(a,"padding-top"), -10)+parseInt(this.getCSS(a,"padding-bottom"),10))):this.log("Error loading :"+this.getAttr(a,"src")));return this.contextStacks[g-1]};html2canvas.prototype.printText=function(a,b,c,d){this.trim(a).length>0&&(d.fillText(a,b,c),this.numDraws++)};html2canvas.prototype.newRect=function(a,b,c,d,e,f){f!="transparent"&&(this.setContextVariable(a,"fillStyle",f),a.fillRect(b,c,d,e),this.numDraws++)};html2canvas.prototype.drawImage=function(a,b,c,d,e,f,h,i,g,j){a.drawImage(b,c,d,e,f,h,i,g,j);this.numDraws++}; +f.height>0&&f.width>0&&(this.newRect(j,f.left,f.top,f.width,f.height,i),this.drawBackground(a,f,j));switch(a.nodeName){case "IMG":(i=this.loadImage(this.getAttr(a,"src")))?this.drawImage(j,i,0,0,i.width,i.height,d+parseInt(this.getCSS(a,"padding-left"),10)+k[3].width,e+parseInt(this.getCSS(a,"padding-top"),10)+k[0].width,c.width-(k[1].width+k[3].width+parseInt(this.getCSS(a,"padding-left"),10)+parseInt(this.getCSS(a,"padding-right"),10)),c.height-(k[0].width+k[2].width+parseInt(this.getCSS(a,"padding-top"), +10)+parseInt(this.getCSS(a,"padding-bottom"),10))):this.log("Error loading :"+this.getAttr(a,"src"));break;case "INPUT":/^(text|url|email|submit|button|reset)$/.test(a.type)&&a.value.length>0&&this.renderFormValue(a,c,l);break;case "TEXTAREA":a.value.length>0&&this.renderFormValue(a,c,l);break;case "SELECT":a.options.length>0&&this.renderFormValue(a,c,l)}return this.contextStacks[g-1]};html2canvas.prototype.printText=function(a,b,c,d){this.trim(a).length>0&&(d.fillText(a,b,c),this.numDraws++)}; +html2canvas.prototype.newRect=function(a,b,c,d,e,f){f!="transparent"&&(this.setContextVariable(a,"fillStyle",f),a.fillRect(b,c,d,e),this.numDraws++)};html2canvas.prototype.drawImage=function(a,b,c,d,e,f,h,i,g,j){a.drawImage(b,c,d,e,f,h,i,g,j);this.numDraws++}; +html2canvas.prototype.renderFormValue=function(a,b,c){var d=document.createElement("valuewrap"),e=this;this.each(["lineHeight","textAlign","fontFamily","color","fontSize","paddingLeft","paddingTop","width","height","border","borderLeftWidth","borderTopWidth"],function(b,c){d.style[c]=e.getCSS(a,c)});d.style.borderColor="black";d.style.borderStyle="solid";d.style.display="block";d.style.position="absolute";if(/^(submit|reset|button|text|password)$/.test(a.type)||a.nodeName=="SELECT")d.style.lineHeight= +e.getCSS(a,"height");d.style.top=b.top+"px";d.style.left=b.left+"px";b=document.createTextNode(a.nodeName=="SELECT"?a.options[a.selectedIndex].text:a.value);d.appendChild(b);$("body").append(d);this.newText(a,b,c);$(d).remove()}; html2canvas.prototype.getImages=function(a){var b=this;this.ignoreRe.test(a.nodeName)||this.each($(a).contents(),function(a,d){RegExp("("+this.ignoreElements+")").test(d.nodeName)||b.getImages(d)});if(a.nodeType==1||typeof a.nodeType=="undefined")(a=this.getCSS(a,"background-image"))&&a!="1"&&a!="none"&&a.substring(0,7)!="-webkit"&&a.substring(0,3)!="-o-"&&a.substring(0,4)!="-moz"&&this.preloadImage(this.backgroundImageUrl(a))}; html2canvas.prototype.loadImage=function(a){a=this.getIndex(this.images,a);return a!=-1?this.images[a+1]:!1};html2canvas.prototype.preloadImage=function(a){if(this.getIndex(this.images,a)==-1)if(this.isSameOrigin(a)){this.images.push(a);var b=new Image,c=this;$(b).load(function(){c.imagesLoaded++;c.start()});b.onerror=function(){c.images.splice(c.images.indexOf(b.src),2);c.start()};b.src=a;this.images.push(b)}else this.opts.proxyUrl&&(this.images.push(a),b=new Image,this.proxyGetImage(a,b),this.images.push(b))}; html2canvas.prototype.proxyGetImage=function(a,b){var c=this,d=document.createElement("a");d.href=a;a=d.href;$.ajax({data:{xhr2:!1,url:a},url:this.opts.proxyUrl,dataType:"jsonp",success:function(d){d.substring(0,6)=="error:"?(c.images.splice(c.images.indexOf(a),2),c.start(),c.log("Proxy was unable to load "+a+" "+d)):(b.onload=function(){c.imagesLoaded++;c.start()},b.src=d)},error:function(){c.images.splice(c.images.indexOf(a),2);c.start()}})}; @@ -44,7 +47,7 @@ padding:0});e.appendChild(document.createTextNode("Hidden Text"));c.appendChild( html2canvas.prototype.textTransform=function(a,b){switch(b){case "lowercase":return a.toLowerCase();case "capitalize":return a.replace(/(^|\s|:|-|\(|\))([a-z])/g,function(a,b,e){return b+e.toUpperCase()});case "uppercase":return a.toUpperCase();default:return a}};html2canvas.prototype.trim=function(a){return a.replace(/^\s*/,"").replace(/\s*$/,"")}; html2canvas.prototype.parseElement=function(a,b){var c=this;this.each(a.children,function(a,e){c.parsing(e,b)});this.log("Render queue stored");this.opts.storageReady(this);this.finish()};html2canvas.prototype.parsing=function(a,b){if(this.getCSS(a,"display")!="none"&&this.getCSS(a,"visibility")!="hidden"){var c=this,b=this.newElement(a,b)||b;this.ignoreRe.test(a.nodeName)||this.each(this.contentsInZ(a),function(d,e){e.nodeType==1?c.parsing(e,b):e.nodeType==3&&c.newText(a,e,b)})}}; html2canvas.prototype.log=function(a){this.opts.logging&&this.opts.logger(a)};html2canvas.prototype.withinBounds=function(a,b){return!a?!0:(a.left<=b.left||b.left+b.width:" + _.getAttr(el,'src')); - } + }else { + this.log("Error loading :" + _.getAttr(el,'src')); + } + break; + case "INPUT": + // TODO add all relevant type's, i.e. HTML5 new stuff + // todo add support for placeholder attribute for browsers which support it + if (/^(text|url|email|submit|button|reset)$/.test(el.type) && el.value.length > 0){ + + this.renderFormValue(el,bounds,stack); + + + /* + this just doesn't work well enough + + this.newText(el,{ + nodeValue:el.value, + splitText: function(){ + return this; + }, + formValue:true + },stack); + */ + } + break; + case "TEXTAREA": + if (el.value.length > 0){ + this.renderFormValue(el,bounds,stack); + } + break; + case "SELECT": + if (el.options.length > 0){ + this.renderFormValue(el,bounds,stack); + } + break; } @@ -142,8 +175,8 @@ html2canvas.prototype.newElement = function(el,parentStack){ /* - * Function to draw the text on the canvas - */ +* Function to draw the text on the canvas +*/ html2canvas.prototype.printText = function(currentText,x,y,ctx){ if (this.trim(currentText).length>0){ diff --git a/src/Forms.js b/src/Forms.js new file mode 100644 index 0000000..1db5d0b --- /dev/null +++ b/src/Forms.js @@ -0,0 +1,38 @@ +html2canvas.prototype.renderFormValue = function(el,bounds,stack){ + + var valueWrap = document.createElement('valuewrap'), + _ = this; + + this.each(['lineHeight','textAlign','fontFamily','color','fontSize','paddingLeft','paddingTop','width','height','border','borderLeftWidth','borderTopWidth'],function(i,style){ + valueWrap.style[style] = _.getCSS(el,style); + }); + + valueWrap.style.borderColor = "black"; + valueWrap.style.borderStyle = "solid"; + valueWrap.style.display = "block"; + valueWrap.style.position = "absolute"; + if (/^(submit|reset|button|text|password)$/.test(el.type) || el.nodeName == "SELECT"){ + valueWrap.style.lineHeight = _.getCSS(el,"height"); + } + + + valueWrap.style.top = bounds.top+"px"; + valueWrap.style.left = bounds.left+"px"; + if (el.nodeName == "SELECT"){ + // TODO increase accuracy of text position + var textValue = el.options[el.selectedIndex].text; + } else{ + var textValue = el.value; + + } + var textNode = document.createTextNode(textValue); + + valueWrap.appendChild(textNode); + $('body').append(valueWrap); + + this.newText(el,textNode,stack); + + $(valueWrap).remove(); + + +} \ No newline at end of file diff --git a/src/LICENSE b/src/LICENSE index bcbbc57..9d3cb4b 100644 --- a/src/LICENSE +++ b/src/LICENSE @@ -1,5 +1,5 @@ /* - * html2canvas v0.26 + * html2canvas v0.27 * Copyright (c) 2011 Niklas von Hertzen. All rights reserved. * http://www.twitter.com/niklasvh * diff --git a/src/Text.js b/src/Text.js index cdfe5f5..84f17a3 100644 --- a/src/Text.js +++ b/src/Text.js @@ -1,5 +1,5 @@ -html2canvas.prototype.newText = function(el,textNode,stack){ +html2canvas.prototype.newText = function(el,textNode,stack,form){ var ctx = stack.ctx; var family = this.getCSS(el,"font-family"); var size = this.getCSS(el,"font-size"); @@ -14,7 +14,7 @@ html2canvas.prototype.newText = function(el,textNode,stack){ var letter_spacing = this.getCSS(el,"letter-spacing"); - + // apply text-transform:ation to the text textNode.nodeValue = this.textTransform(textNode.nodeValue,this.getCSS(el,"text-transform")); var text = this.trim(textNode.nodeValue); @@ -68,79 +68,81 @@ html2canvas.prototype.newText = function(el,textNode,stack){ } */ - - - var oldTextNode = textNode; - for(var c=0;c