diff --git a/src/Core.js b/src/Core.js index a5b4356..f50a6f5 100644 --- a/src/Core.js +++ b/src/Core.js @@ -7,216 +7,196 @@ html2canvas; function h2clog(a) { - if (_html2canvas.logging && window.console && window.console.log) { - window.console.log(a); - } + if (_html2canvas.logging && window.console && window.console.log) { + window.console.log(a); + } } _html2canvas.Util = {}; _html2canvas.Util.backgroundImage = function (src) { - if (/data:image\/.*;base64,/i.test( src ) || /^(-webkit|-moz|linear-gradient|-o-)/.test( src )) { - return src; - } - - if (src.toLowerCase().substr( 0, 5 ) === 'url("') { - src = src.substr( 5 ); - src = src.substr( 0, src.length - 2 ); - } else { - src = src.substr( 4 ); - src = src.substr( 0, src.length - 1 ); - } - + if (/data:image\/.*;base64,/i.test( src ) || /^(-webkit|-moz|linear-gradient|-o-)/.test( src )) { return src; + } + + if (src.toLowerCase().substr( 0, 5 ) === 'url("') { + src = src.substr( 5 ); + src = src.substr( 0, src.length - 2 ); + } else { + src = src.substr( 4 ); + src = src.substr( 0, src.length - 1 ); + } + + return src; }; _html2canvas.Util.Bounds = function getBounds (el) { - var clientRect, - bounds = {}; + var clientRect, + bounds = {}; - if (el.getBoundingClientRect){ - clientRect = el.getBoundingClientRect(); + if (el.getBoundingClientRect){ + clientRect = el.getBoundingClientRect(); - // TODO add scroll position to bounds, so no scrolling of window necessary - bounds.top = clientRect.top; - bounds.bottom = clientRect.bottom || (clientRect.top + clientRect.height); - bounds.left = clientRect.left; + // TODO add scroll position to bounds, so no scrolling of window necessary + bounds.top = clientRect.top; + bounds.bottom = clientRect.bottom || (clientRect.top + clientRect.height); + bounds.left = clientRect.left; - // older IE doesn't have width/height, but top/bottom instead - bounds.width = clientRect.width || (clientRect.right - clientRect.left); - bounds.height = clientRect.height || (clientRect.bottom - clientRect.top); + // older IE doesn't have width/height, but top/bottom instead + bounds.width = clientRect.width || (clientRect.right - clientRect.left); + bounds.height = clientRect.height || (clientRect.bottom - clientRect.top); - return bounds; + return bounds; - } + } }; _html2canvas.Util.getCSS = function (el, attribute) { - // return $(el).css(attribute); + // return $(el).css(attribute); - var val; + var val; - function toPX( attribute, val ) { - var rsLeft = el.runtimeStyle && el.runtimeStyle[ attribute ], - left, - style = el.style; + function toPX( attribute, val ) { + var rsLeft = el.runtimeStyle && el.runtimeStyle[ attribute ], + left, + style = el.style; - // Check if we are not dealing with pixels, (Opera has issues with this) - // Ported from jQuery css.js - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + // Check if we are not dealing with pixels, (Opera has issues with this) + // Ported from jQuery css.js + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels - if ( !/^-?[0-9]+\.?[0-9]*(?:px)?$/i.test( val ) && /^-?\d/.test( val ) ) { + if ( !/^-?[0-9]+\.?[0-9]*(?:px)?$/i.test( val ) && /^-?\d/.test( val ) ) { - // Remember the original values - left = style.left; + // Remember the original values + left = style.left; - // Put in the new values to get a computed value out - if ( rsLeft ) { - el.runtimeStyle.left = el.currentStyle.left; - } - style.left = attribute === "fontSize" ? "1em" : (val || 0); - val = style.pixelLeft + "px"; + // Put in the new values to get a computed value out + if ( rsLeft ) { + el.runtimeStyle.left = el.currentStyle.left; + } + style.left = attribute === "fontSize" ? "1em" : (val || 0); + val = style.pixelLeft + "px"; - // Revert the changed values - style.left = left; - if ( rsLeft ) { - el.runtimeStyle.left = rsLeft; - } - - } - - if (!/^(thin|medium|thick)$/i.test( val )) { - return Math.round(parseFloat( val )) + "px"; - } - - return val; + // Revert the changed values + style.left = left; + if ( rsLeft ) { + el.runtimeStyle.left = rsLeft; + } } - - if ( window.getComputedStyle ) { - if ( previousElement !== el ) { - computedCSS = document.defaultView.getComputedStyle(el, null); - } - val = computedCSS[ attribute ]; - - if ( attribute === "backgroundPosition" ) { - - val = (val.split(",")[0] || "0 0").split(" "); - - val[ 0 ] = ( val[0].indexOf( "%" ) === -1 ) ? toPX( attribute + "X", val[ 0 ] ) : val[ 0 ]; - val[ 1 ] = ( val[1] === undefined ) ? val[0] : val[1]; // IE 9 doesn't return double digit always - val[ 1 ] = ( val[1].indexOf( "%" ) === -1 ) ? toPX( attribute + "Y", val[ 1 ] ) : val[ 1 ]; - } else if ( /border(Top|Bottom)(Left|Right)Radius/.test( attribute) ) { - var arr = val.split(" "); - if ( arr.length <= 1 ) { - arr[ 1 ] = arr[ 0 ]; - } - arr[ 0 ] = parseInt( arr[ 0 ], 10 ); - arr[ 1 ] = parseInt( arr[ 1 ], 10 ); - val = arr; - } - - } else if ( el.currentStyle ) { - // IE 9> - if (attribute === "backgroundPosition") { - // Older IE uses -x and -y - val = [ toPX( attribute + "X", el.currentStyle[ attribute + "X" ] ), toPX( attribute + "Y", el.currentStyle[ attribute + "Y" ] ) ]; - } else { - - val = toPX( attribute, el.currentStyle[ attribute ] ); - - if (/^(border)/i.test( attribute ) && /^(medium|thin|thick)$/i.test( val )) { - switch (val) { - case "thin": - val = "1px"; - break; - case "medium": - val = "0px"; // this is wrong, it should be 3px but IE uses medium for no border as well.. TODO find a work around - break; - case "thick": - val = "5px"; - break; - } - } - } - - - + if (!/^(thin|medium|thick)$/i.test( val )) { + return Math.round(parseFloat( val )) + "px"; } - - - return val; + } -//return $(el).css(attribute); + if ( window.getComputedStyle ) { + if ( previousElement !== el ) { + computedCSS = document.defaultView.getComputedStyle(el, null); + } + val = computedCSS[ attribute ]; + if ( attribute === "backgroundPosition" ) { + val = (val.split(",")[0] || "0 0").split(" "); + + val[ 0 ] = ( val[0].indexOf( "%" ) === -1 ) ? toPX( attribute + "X", val[ 0 ] ) : val[ 0 ]; + val[ 1 ] = ( val[1] === undefined ) ? val[0] : val[1]; // IE 9 doesn't return double digit always + val[ 1 ] = ( val[1].indexOf( "%" ) === -1 ) ? toPX( attribute + "Y", val[ 1 ] ) : val[ 1 ]; + } else if ( /border(Top|Bottom)(Left|Right)Radius/.test( attribute) ) { + var arr = val.split(" "); + if ( arr.length <= 1 ) { + arr[ 1 ] = arr[ 0 ]; + } + arr[ 0 ] = parseInt( arr[ 0 ], 10 ); + arr[ 1 ] = parseInt( arr[ 1 ], 10 ); + val = arr; + } + + } else if ( el.currentStyle ) { + // IE 9> + if (attribute === "backgroundPosition") { + // Older IE uses -x and -y + val = [ toPX( attribute + "X", el.currentStyle[ attribute + "X" ] ), toPX( attribute + "Y", el.currentStyle[ attribute + "Y" ] ) ]; + } else { + + val = toPX( attribute, el.currentStyle[ attribute ] ); + + if (/^(border)/i.test( attribute ) && /^(medium|thin|thick)$/i.test( val )) { + switch (val) { + case "thin": + val = "1px"; + break; + case "medium": + val = "0px"; // this is wrong, it should be 3px but IE uses medium for no border as well.. TODO find a work around + break; + case "thick": + val = "5px"; + break; + } + } + } + } + + return val; }; _html2canvas.Util.BackgroundPosition = function ( el, bounds, image ) { - // TODO add support for multi image backgrounds + // TODO add support for multi image backgrounds - var bgposition = _html2canvas.Util.getCSS( el, "backgroundPosition" ) , - topPos, - left, - percentage, - val; + var bgposition = _html2canvas.Util.getCSS( el, "backgroundPosition" ) , + topPos, + left, + percentage, + val; - if (bgposition.length === 1){ - val = bgposition; + if (bgposition.length === 1){ + val = bgposition; - bgposition = []; + bgposition = []; - bgposition[0] = val; - bgposition[1] = val; - } + bgposition[0] = val; + bgposition[1] = val; + } + if (bgposition[0].toString().indexOf("%") !== -1){ + percentage = (parseFloat(bgposition[0])/100); + left = ((bounds.width * percentage)-(image.width*percentage)); + } else { + left = parseInt(bgposition[0],10); + } + if (bgposition[1].toString().indexOf("%") !== -1){ + percentage = (parseFloat(bgposition[1])/100); + topPos = ((bounds.height * percentage)-(image.height*percentage)); + } else { + topPos = parseInt(bgposition[1],10); + } - if (bgposition[0].toString().indexOf("%") !== -1){ - percentage = (parseFloat(bgposition[0])/100); - left = ((bounds.width * percentage)-(image.width*percentage)); - - }else{ - left = parseInt(bgposition[0],10); - } - - if (bgposition[1].toString().indexOf("%") !== -1){ - - percentage = (parseFloat(bgposition[1])/100); - topPos = ((bounds.height * percentage)-(image.height*percentage)); - }else{ - topPos = parseInt(bgposition[1],10); - } - - - - - return { - top: topPos, - left: left - }; - + return { + top: topPos, + left: left + }; }; _html2canvas.Util.Extend = function (options, defaults) { - for (var key in options) { - if (options.hasOwnProperty(key)) { - defaults[key] = options[key]; - } + for (var key in options) { + if (options.hasOwnProperty(key)) { + defaults[key] = options[key]; } - return defaults; + } + return defaults; }; @@ -229,43 +209,43 @@ _html2canvas.Util.Extend = function (options, defaults) { _html2canvas.Util.Children = function( elem ) { - var children; - try { + var children; + try { - children = (elem.nodeName && elem.nodeName.toUpperCase() === "IFRAME") ? - elem.contentDocument || elem.contentWindow.document : (function( array ){ - var ret = []; + children = (elem.nodeName && elem.nodeName.toUpperCase() === "IFRAME") ? + elem.contentDocument || elem.contentWindow.document : (function( array ){ + var ret = []; - if ( array !== null ) { + if ( array !== null ) { - (function( first, second ) { - var i = first.length, - j = 0; - - if ( typeof second.length === "number" ) { - for ( var l = second.length; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - })( ret, array ); + (function( first, second ) { + var i = first.length, + j = 0; + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; } - return ret; - })( elem.childNodes ); + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } - } catch (ex) { - h2clog("html2canvas.Util.Children failed with exception: " + ex.message); - children = []; - } - return children; + first.length = i; + + return first; + })( ret, array ); + + } + + return ret; + })( elem.childNodes ); + + } catch (ex) { + h2clog("html2canvas.Util.Children failed with exception: " + ex.message); + children = []; + } + return children; }; diff --git a/src/Renderer.js b/src/Renderer.js index 25abb00..edf4d90 100644 --- a/src/Renderer.js +++ b/src/Renderer.js @@ -1,66 +1,58 @@ _html2canvas.Renderer = function(parseQueue, options){ - var queue = [], renderer; - function sortZ(zStack){ - var subStacks = [], - stackValues = [], - zStackChildren = zStack.children, - s, - i, - stackLen, - zValue, - zLen, - stackChild, - b, - subStackLen; + function createRenderQueue(parseQueue) { + var queue = []; + var sortZ = function(zStack){ + var subStacks = [], + stackValues = []; - for (s = 0, zLen = zStackChildren.length; s < zLen; s+=1){ - - stackChild = zStackChildren[s]; - - if (stackChild.children && stackChild.children.length > 0){ - subStacks.push(stackChild); - stackValues.push(stackChild.zindex); - }else{ - queue.push(stackChild); - } - - } - - stackValues.sort(function(a, b) { - return a - b; - }); - - for (i = 0, stackLen = stackValues.length; i < stackLen; i+=1){ - zValue = stackValues[i]; - for (b = 0, subStackLen = subStacks.length; b <= subStackLen; b+=1){ - - if (subStacks[b].zindex === zValue){ - stackChild = subStacks.splice(b, 1); - sortZ(stackChild[0]); - break; - + zStack.children.forEach(function(stackChild) { + if (stackChild.children && stackChild.children.length > 0){ + subStacks.push(stackChild); + stackValues.push(stackChild.zindex); + } else { + queue.push(stackChild); } - } + }); + + stackValues.sort(function(a, b) { + return a - b; + }); + + stackValues.forEach(function(zValue) { + var index; + + subStacks.some(function(stack, i){ + index = i; + return (stack.zindex === zValue); + }); + sortZ(subStacks.splice(index, 1)[0]); + + }); + }; + + sortZ(parseQueue.zIndex); + + return queue; + } + + function getRenderer(rendererName) { + var renderer; + + if (typeof options.renderer === "string" && _html2canvas.Renderer[rendererName] !== undefined) { + renderer = _html2canvas.Renderer[rendererName](options); + } else if (typeof rendererName === "function") { + renderer = rendererName(options); + } else { + throw new Error("Unknown renderer"); } + if ( typeof renderer._create !== "function" ) { + throw new Error("Invalid renderer defined"); + } + return renderer; } - sortZ(parseQueue.zIndex); - - if (typeof options.renderer === "string" && _html2canvas.Renderer[options.renderer] !== undefined) { - renderer = _html2canvas.Renderer[options.renderer](options); - } else if (typeof options.renderer === "function") { - renderer = options.renderer(options); - } else { - throw new Error("Unknown renderer"); - } - - if ( typeof renderer._create !== "function" ) { - throw new Error("Invalid renderer defined"); - } - - return renderer._create( parseQueue, options, document, queue, _html2canvas ); - + return getRenderer(options.renderer)._create(parseQueue, options, document, createRenderQueue(parseQueue), _html2canvas); };