Repository: sjhewitt/glitch.js
Branch: gh-pages
Commit: 01cb997e5c18
Files: 8
Total size: 112.9 KB
Directory structure:
gitextract_z_57uipc/
├── examples.html
├── index.html
├── javascripts/
│ ├── html2canvas.js
│ └── main.js
├── nojquery.html
├── params.json
└── stylesheets/
├── pygment_trac.css
└── stylesheet.css
================================================
FILE CONTENTS
================================================
================================================
FILE: examples.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen" />
<link rel="stylesheet" type="text/css" href="stylesheets/pygment_trac.css" media="screen" />
<!-- <link rel="stylesheet" type="text/css" href="stylesheets/print.css" media="print" /> -->
<title>Glitch.js by sjhewitt</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/sjhewitt/glitch.js/master/glitch.js"></script>
<script src="javascripts/html2canvas.js"></script>
</head>
<body>
<div class="outer-container">
<header>
<div class="container">
<h1><a href="index.html">Glitch.js</a></h1>
<h2>Glitched DOM elements</h2>
</div>
</header>
<div class="container">
<div id="example1" class="example">
<h1>Glitch an image</h1>
<img class="source" src="images/Lenna.png" style="width: 100%;" />
<div class="middle"><button class="btn">Glitch</button></div>
<div class="target"></div>
</div>
<script>
$("#example1 button").click(function(){
$("#example1 .source").glitch(function(canvas){
$("#example1 .target").html(canvas);
});
})
</script>
<div id="example2" class="example">
<h1>Glitch some HTML elements</h1>
<div class="source">
<h2 style="background: #238aa1;">Header Element</h2>
<div>
<input type="text" value="input text" />
</div>
<ul>
<li>List Element 1</li>
<li>List Element 2</li>
<li>List Element 3</li>
<li>List Element 4</li>
</ul>
<button class="btn">Button with rounded corners</button>
</div>
<div class="middle"><button class="btn">Glitch</button></div>
<div class="target"></div>
</div>
<script>
var example2 = false;
$("#example2 button").click(function(){
if(!example2) {
example2 = $("#example2 .source");
} else {
$("#example2 canvas").replaceWith(example2);
}
example2.glitch();
})
</script>
<div id="example3" class="example">
<h1>HTML and cross-domain images</h1>
<div class="source" style="background: #aaa; border: 5px solid green;">
<h2 style="background: #238aa1;">Header Element</h2>
<div>
<input type="text" value="input text" />
</div>
<div style="display: inline-block; background-image: url(http://www.google.com/logos/2011/gregormendel11-res.jpg); width: 256px; height: 341px;">
<p style="text-align: center; color: red;">And some text on top of it</p>
</div>
</div>
<div class="middle"><button class="btn">Glitch</button></div>
<div class="target"></div>
</div>
<script>
var example3 = false;
$("#example3 button").click(function(){
if(!example3) {
example3 = $("#example3 .source");
} else {
$("#example3 canvas").replaceWith(example3);
}
example3.glitch();
})
</script>
<style type="text/css">
#example4 .source {
background: #4a3b9c;
border: 5px solid green;
height: 300px;
overflow: auto;
}
#example4 h2 {
background: #238aa1;
}
</style>
<div id="example4" class="example">
<h1>Glitch Transition</h1>
<div class="source">
<h2>Page 1</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
<div class="middle"><button class="btn">Glitch</button></div>
<div class="target"></div>
</div>
<script>
$(function(){
var example4a = $("#example4 .source");
var example4b = $("<div class='source'><h2>Page 2</h2><p>Beard flexitarian semiotics tofu retro. Synth sustainable accusamus hoodie, scenester retro wayfarers occupy. Twee ea marfa nesciunt pickled pork belly. Pop-up fugiat squid, aute brunch viral fingerstache american apparel et cupidatat placeat butcher etsy art party. Mlkshk sriracha delectus, dreamcatcher occaecat freegan esse placeat fugiat williamsburg aliquip nisi cred retro jean shorts. Stumptown mixtape gastropub, you probably haven't heard of them master cleanse laboris sunt scenester post-ironic dreamcatcher ex. Williamsburg sriracha cray high life cillum.</p></div>");
$("#example4 button").click(function(){
if(example4a[0].parentNode) {
example4a.glitch(example4b, {
effect: "slide"
});
} else {
example4b.glitch(example4a);
}
});
});
</script>
<style type="text/css">
#example5 .source {
background: #4a3b9c;
border: 5px solid green;
}
#example5 h2 {
background: #238aa1;
}
</style>
<div id="example5" class="example">
<h1>Glitch Transition (different size elements)</h1>
<div class="source">
<h2>Page 1</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
<div class="middle"><button class="btn">Glitch</button></div>
<div class="target"></div>
</div>
<script>
$(function(){
var example5a = $("#example5 .source");
var example5b = $("<div class='source'><h2>Page 2</h2><p>Beard flexitarian semiotics tofu retro. Synth sustainable accusamus hoodie, scenester retro wayfarers occupy. Twee ea marfa nesciunt pickled pork belly. Pop-up fugiat squid, aute brunch viral fingerstache american apparel et cupidatat placeat butcher etsy art party. Mlkshk sriracha delectus, dreamcatcher occaecat freegan esse placeat fugiat williamsburg aliquip nisi cred retro jean shorts. Stumptown mixtape gastropub, you probably haven't heard of them master cleanse laboris sunt scenester post-ironic dreamcatcher ex. Williamsburg sriracha cray high life cillum.</p></div>").width(400);
$("#example5 button").click(function(){
if(example5a[0].parentNode) {
glitch.transition(example5a, example5b);
} else {
glitch.transition(example5b, example5a, {
effect: "slide"
});
}
});
});
</script>
<div id="wholePage" class="example centered">
<h1>Now glitch the whole page</h1>
<div class="middle">
<button class="btn">GLITCH!!</button>
</div>
</div>
<script>
$("#wholePage button").click(function(){
window.oldContent = $(".outer-container");
glitch.transition(
window.oldContent,
$("<div class='outer-container'><div class=\"container middle\"><button id=\"restore\" class='btn'>Restore</button></div></div>"),
{
effect: "slide"
});
})
</script>
</div>
</div>
<script>
$("body").on("click", "#restore", function(){
glitch.transition($(".outer-container"), window.oldContent);
});
</script>
</body>
</html>
================================================
FILE: index.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen" />
<link rel="stylesheet" type="text/css" href="stylesheets/pygment_trac.css" media="screen" />
<!-- <link rel="stylesheet" type="text/css" href="stylesheets/print.css" media="print" /> -->
<title>Glitch.js by sjhewitt</title>
</head>
<body>
<div class="outer-container">
<header>
<div class="container">
<div id="glitch-header">
<h1>Glitch.js</h1>
<h2>Glitched DOM elements</h2>
</div>
<section id="downloads">
<a href="https://github.com/sjhewitt/glitch.js/zipball/master" class="btn">Download as .zip</a>
<a href="https://github.com/sjhewitt/glitch.js/tarball/master" class="btn">Download as .tar.gz</a>
<a href="https://github.com/sjhewitt/glitch.js" class="btn btn-github"><span class="icon"></span>View on GitHub</a>
</section>
</div>
</header>
<div class="container">
<section id="main_content">
<h3>Welcome to Glitch.js</h3>
<p>More info coming soon</p>
<p>Until then, check out the <a href="http://blog.sjhewitt.co.uk/2012/07/javascript-glitch-effect-glitch-js/">blog post</a> and <a href="examples.html">examples</a></p>
<img src="images/lena-glitch.png" />
</section>
</div>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="https://raw.github.com/sjhewitt/glitch.js/master/glitch.js"></script>
<script src="javascripts/html2canvas.js"></script>
<script src="javascripts/main.js"></script>
</body>
</html>
================================================
FILE: javascripts/html2canvas.js
================================================
/**
@license html2canvas v0.34 <http://html2canvas.hertzen.com>
Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
http://www.twitter.com/niklasvh
Released under MIT License
*/
(function(window, document, undefined){
/*
html2canvas v0.34 <http://html2canvas.hertzen.com>
Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
http://www.twitter.com/niklasvh
Released under MIT License
*/
"use strict";
var _html2canvas = {},
previousElement,
computedCSS,
html2canvas;
function h2clog(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 );
}
return src;
};
function adjustBounds(el, box) {
var win = document.defaultView;
var doc = el.ownerDocument;
var body = doc.body;
var docElem = doc.documentElement;
var clientTop = docElem.clientTop || body.clientTop || 0;
var clientLeft = docElem.clientLeft || body.clientLeft || 0;
var scrollTop = win.pageYOffset || docElem.scrollTop;
var scrollLeft = win.pageXOffset || docElem.scrollLeft;
var top = box.top + scrollTop - clientTop;
var left = box.left + scrollLeft - clientLeft;
return {
top: top,
left: left,
bottom: top + box.height,
height: box.height,
width: box.width
};
}
_html2canvas.Util.Bounds = function getBounds (el) {
var clientRect,
bounds = {};
if (el.getBoundingClientRect){
return adjustBounds(el, el.getBoundingClientRect());
}
};
_html2canvas.Util.getCSS = function (el, attribute) {
// return $(el).css(attribute);
var val;
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
// 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 ) ) {
// 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";
// 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;
}
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 ( 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;
//return $(el).css(attribute);
};
_html2canvas.Util.BackgroundPosition = function ( el, bounds, image ) {
// TODO add support for multi image backgrounds
var bgposition = _html2canvas.Util.getCSS( el, "backgroundPosition" ) ,
topPos,
left,
percentage,
val;
if (bgposition.length === 1){
val = bgposition;
bgposition = [];
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);
}
return {
top: topPos,
left: left
};
};
_html2canvas.Util.Extend = function (options, defaults) {
for (var key in options) {
if (options.hasOwnProperty(key)) {
defaults[key] = options[key];
}
}
return defaults;
};
/*
* Derived from jQuery.contents()
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/
_html2canvas.Util.Children = function( elem ) {
var children;
try {
children = (elem.nodeName && elem.nodeName.toUpperCase() === "IFRAME") ?
elem.contentDocument || elem.contentWindow.document : (function( array ){
var ret = [];
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 );
}
return ret;
})( elem.childNodes );
} catch (ex) {
h2clog("html2canvas.Util.Children failed with exception: " + ex.message);
children = [];
}
return children;
};
/*
html2canvas v0.34 <http://html2canvas.hertzen.com>
Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
http://www.twitter.com/niklasvh
Contributor(s):
Niklas von Hertzen <http://www.twitter.com/niklasvh>
André Fiedler <http://www.twitter.com/sonnenkiste>
Released under MIT License
*/
(function(){
_html2canvas.Generate = {};
var reGradients = [
/^(-webkit-linear-gradient)\(([a-z\s]+)([\w\d\.\s,%\(\)]+)\)$/,
/^(-o-linear-gradient)\(([a-z\s]+)([\w\d\.\s,%\(\)]+)\)$/,
/^(-webkit-gradient)\((linear|radial),\s((?:\d{1,3}%?)\s(?:\d{1,3}%?),\s(?:\d{1,3}%?)\s(?:\d{1,3}%?))([\w\d\.\s,%\(\)-]+)\)$/,
/^(-moz-linear-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?))([\w\d\.\s,%\(\)]+)\)$/,
/^(-webkit-radial-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?)),\s(\w+)\s([a-z-]+)([\w\d\.\s,%\(\)]+)\)$/,
/^(-moz-radial-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?)),\s(\w+)\s?([a-z-]*)([\w\d\.\s,%\(\)]+)\)$/,
/^(-o-radial-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?)),\s(\w+)\s([a-z-]+)([\w\d\.\s,%\(\)]+)\)$/
];
/*
* TODO: Add IE10 vendor prefix (-ms) support
* TODO: Add W3C gradient (linear-gradient) support
* TODO: Add old Webkit -webkit-gradient(radial, ...) support
* TODO: Maybe some RegExp optimizations are possible ;o)
*/
_html2canvas.Generate.parseGradient = function(css, bounds) {
var gradient, i, len = reGradients.length, m1, stop, m2, m2Len, step, m3;
for(i = 0; i < len; i+=1){
m1 = css.match(reGradients[i]);
if(m1) break;
}
if(m1) {
switch(m1[1]) {
case '-webkit-linear-gradient':
case '-o-linear-gradient':
gradient = {
type: 'linear',
x0: null,
y0: null,
x1: null,
y1: null,
colorStops: []
};
// get coordinates
m2 = m1[2].match(/\w+/g);
if(m2){
m2Len = m2.length;
for(i = 0; i < m2Len; i+=1){
switch(m2[i]) {
case 'top':
gradient.y0 = 0;
gradient.y1 = bounds.height;
break;
case 'right':
gradient.x0 = bounds.width;
gradient.x1 = 0;
break;
case 'bottom':
gradient.y0 = bounds.height;
gradient.y1 = 0;
break;
case 'left':
gradient.x0 = 0;
gradient.x1 = bounds.width;
break;
}
}
}
if(gradient.x0 === null && gradient.x1 === null){ // center
gradient.x0 = gradient.x1 = bounds.width / 2;
}
if(gradient.y0 === null && gradient.y1 === null){ // center
gradient.y0 = gradient.y1 = bounds.height / 2;
}
// get colors and stops
m2 = m1[3].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)(?:\s\d{1,3}(?:%|px))?)+/g);
if(m2){
m2Len = m2.length;
step = 1 / Math.max(m2Len - 1, 1);
for(i = 0; i < m2Len; i+=1){
m3 = m2[i].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%|px)?/);
if(m3[2]){
stop = parseFloat(m3[2]);
if(m3[3] === '%'){
stop /= 100;
} else { // px - stupid opera
stop /= bounds.width;
}
} else {
stop = i * step;
}
gradient.colorStops.push({
color: m3[1],
stop: stop
});
}
}
break;
case '-webkit-gradient':
gradient = {
type: m1[2] === 'radial' ? 'circle' : m1[2], // TODO: Add radial gradient support for older mozilla definitions
x0: 0,
y0: 0,
x1: 0,
y1: 0,
colorStops: []
};
// get coordinates
m2 = m1[3].match(/(\d{1,3})%?\s(\d{1,3})%?,\s(\d{1,3})%?\s(\d{1,3})%?/);
if(m2){
gradient.x0 = (m2[1] * bounds.width) / 100;
gradient.y0 = (m2[2] * bounds.height) / 100;
gradient.x1 = (m2[3] * bounds.width) / 100;
gradient.y1 = (m2[4] * bounds.height) / 100;
}
// get colors and stops
m2 = m1[4].match(/((?:from|to|color-stop)\((?:[0-9\.]+,\s)?(?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)\))+/g);
if(m2){
m2Len = m2.length;
for(i = 0; i < m2Len; i+=1){
m3 = m2[i].match(/(from|to|color-stop)\(([0-9\.]+)?(?:,\s)?((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\)/);
stop = parseFloat(m3[2]);
if(m3[1] === 'from') stop = 0.0;
if(m3[1] === 'to') stop = 1.0;
gradient.colorStops.push({
color: m3[3],
stop: stop
});
}
}
break;
case '-moz-linear-gradient':
gradient = {
type: 'linear',
x0: 0,
y0: 0,
x1: 0,
y1: 0,
colorStops: []
};
// get coordinates
m2 = m1[2].match(/(\d{1,3})%?\s(\d{1,3})%?/);
// m2[1] == 0% -> left
// m2[1] == 50% -> center
// m2[1] == 100% -> right
// m2[2] == 0% -> top
// m2[2] == 50% -> center
// m2[2] == 100% -> bottom
if(m2){
gradient.x0 = (m2[1] * bounds.width) / 100;
gradient.y0 = (m2[2] * bounds.height) / 100;
gradient.x1 = bounds.width - gradient.x0;
gradient.y1 = bounds.height - gradient.y0;
}
// get colors and stops
m2 = m1[3].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)(?:\s\d{1,3}%)?)+/g);
if(m2){
m2Len = m2.length;
step = 1 / Math.max(m2Len - 1, 1);
for(i = 0; i < m2Len; i+=1){
m3 = m2[i].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%)?/);
if(m3[2]){
stop = parseFloat(m3[2]);
if(m3[3]){ // percentage
stop /= 100;
}
} else {
stop = i * step;
}
gradient.colorStops.push({
color: m3[1],
stop: stop
});
}
}
break;
case '-webkit-radial-gradient':
case '-moz-radial-gradient':
case '-o-radial-gradient':
gradient = {
type: 'circle',
x0: 0,
y0: 0,
x1: bounds.width,
y1: bounds.height,
cx: 0,
cy: 0,
rx: 0,
ry: 0,
colorStops: []
};
// center
m2 = m1[2].match(/(\d{1,3})%?\s(\d{1,3})%?/);
if(m2){
gradient.cx = (m2[1] * bounds.width) / 100;
gradient.cy = (m2[2] * bounds.height) / 100;
}
// size
m2 = m1[3].match(/\w+/);
m3 = m1[4].match(/[a-z-]*/);
if(m2 && m3){
switch(m3[0]){
case 'farthest-corner':
case 'cover': // is equivalent to farthest-corner
case '': // mozilla removes "cover" from definition :(
var tl = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.cy, 2));
var tr = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));
var br = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));
var bl = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.cy, 2));
gradient.rx = gradient.ry = Math.max(tl, tr, br, bl);
break;
case 'closest-corner':
var tl = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.cy, 2));
var tr = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));
var br = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));
var bl = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.cy, 2));
gradient.rx = gradient.ry = Math.min(tl, tr, br, bl);
break;
case 'farthest-side':
if(m2[0] === 'circle'){
gradient.rx = gradient.ry = Math.max(
gradient.cx,
gradient.cy,
gradient.x1 - gradient.cx,
gradient.y1 - gradient.cy
);
} else { // ellipse
gradient.type = m2[0];
gradient.rx = Math.max(
gradient.cx,
gradient.x1 - gradient.cx
);
gradient.ry = Math.max(
gradient.cy,
gradient.y1 - gradient.cy
);
}
break;
case 'closest-side':
case 'contain': // is equivalent to closest-side
if(m2[0] === 'circle'){
gradient.rx = gradient.ry = Math.min(
gradient.cx,
gradient.cy,
gradient.x1 - gradient.cx,
gradient.y1 - gradient.cy
);
} else { // ellipse
gradient.type = m2[0];
gradient.rx = Math.min(
gradient.cx,
gradient.x1 - gradient.cx
);
gradient.ry = Math.min(
gradient.cy,
gradient.y1 - gradient.cy
);
}
break;
// TODO: add support for "30px 40px" sizes (webkit only)
}
}
// color stops
m2 = m1[5].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)(?:\s\d{1,3}(?:%|px))?)+/g);
if(m2){
m2Len = m2.length;
step = 1 / Math.max(m2Len - 1, 1);
for(i = 0; i < m2Len; i+=1){
m3 = m2[i].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%|px)?/);
if(m3[2]){
stop = parseFloat(m3[2]);
if(m3[3] === '%'){
stop /= 100;
} else { // px - stupid opera
stop /= bounds.width;
}
} else {
stop = i * step;
}
gradient.colorStops.push({
color: m3[1],
stop: stop
});
}
}
break;
}
}
return gradient;
};
_html2canvas.Generate.Gradient = function(src, bounds) {
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d'),
gradient, grad, i, len, img;
canvas.width = bounds.width;
canvas.height = bounds.height;
// TODO: add support for multi defined background gradients (like radial gradient example in background.html)
gradient = _html2canvas.Generate.parseGradient(src, bounds);
img = new Image();
if(gradient){
if(gradient.type === 'linear'){
grad = ctx.createLinearGradient(gradient.x0, gradient.y0, gradient.x1, gradient.y1);
for (i = 0, len = gradient.colorStops.length; i < len; i+=1) {
try {
grad.addColorStop(gradient.colorStops[i].stop, gradient.colorStops[i].color);
}
catch(e) {
h2clog(['failed to add color stop: ', e, '; tried to add: ', gradient.colorStops[i], '; stop: ', i, '; in: ', src]);
}
}
ctx.fillStyle = grad;
ctx.fillRect(0, 0, bounds.width, bounds.height);
img.src = canvas.toDataURL();
} else if(gradient.type === 'circle'){
grad = ctx.createRadialGradient(gradient.cx, gradient.cy, 0, gradient.cx, gradient.cy, gradient.rx);
for (i = 0, len = gradient.colorStops.length; i < len; i+=1) {
try {
grad.addColorStop(gradient.colorStops[i].stop, gradient.colorStops[i].color);
}
catch(e) {
h2clog(['failed to add color stop: ', e, '; tried to add: ', gradient.colorStops[i], '; stop: ', i, '; in: ', src]);
}
}
ctx.fillStyle = grad;
ctx.fillRect(0, 0, bounds.width, bounds.height);
img.src = canvas.toDataURL();
} else if(gradient.type === 'ellipse'){
// draw circle
var canvasRadial = document.createElement('canvas'),
ctxRadial = canvasRadial.getContext('2d'),
ri = Math.max(gradient.rx, gradient.ry),
di = ri * 2, imgRadial;
canvasRadial.width = canvasRadial.height = di;
grad = ctxRadial.createRadialGradient(gradient.rx, gradient.ry, 0, gradient.rx, gradient.ry, ri);
for (i = 0, len = gradient.colorStops.length; i < len; i+=1) {
try {
grad.addColorStop(gradient.colorStops[i].stop, gradient.colorStops[i].color);
}
catch(e) {
h2clog(['failed to add color stop: ', e, '; tried to add: ', gradient.colorStops[i], '; stop: ', i, '; in: ', src]);
}
}
ctxRadial.fillStyle = grad;
ctxRadial.fillRect(0, 0, di, di);
ctx.fillStyle = gradient.colorStops[i - 1].color;
ctx.fillRect(0, 0, canvas.width, canvas.height);
imgRadial = new Image();
imgRadial.onload = function() { // wait until the image is filled
// transform circle to ellipse
ctx.drawImage(imgRadial, gradient.cx - gradient.rx, gradient.cy - gradient.ry, 2 * gradient.rx, 2 * gradient.ry);
img.src = canvas.toDataURL();
}
imgRadial.src = canvasRadial.toDataURL();
}
}
return img;
};
_html2canvas.Generate.ListAlpha = function(number) {
var tmp = "",
modulus;
do {
modulus = number % 26;
tmp = String.fromCharCode((modulus) + 64) + tmp;
number = number / 26;
}while((number*26) > 26);
return tmp;
};
_html2canvas.Generate.ListRoman = function(number) {
var romanArray = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"],
decimal = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1],
roman = "",
v,
len = romanArray.length;
if (number <= 0 || number >= 4000) {
return number;
}
for (v=0; v < len; v+=1) {
while (number >= decimal[v]) {
number -= decimal[v];
roman += romanArray[v];
}
}
return roman;
};
})();
/*
html2canvas v0.34 <http://html2canvas.hertzen.com>
Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
http://www.twitter.com/niklasvh
Released under MIT License
*/
/*
* New function for traversing elements
*/
_html2canvas.Parse = function ( images, options ) {
var support = {
rangeBounds: false,
svgRendering: options.svgRendering && (function( ){
var img = new Image(),
canvas = document.createElement("canvas"),
ctx = (canvas.getContext === undefined) ? false : canvas.getContext("2d");
if (ctx === false) {
// browser doesn't support canvas, good luck supporting SVG on canvas
return false;
}
canvas.width = canvas.height = 10;
img.src = [
"data:image/svg+xml,",
"<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'>",
"<foreignObject width='10' height='10'>",
"<div xmlns='http://www.w3.org/1999/xhtml' style='width:10;height:10;'>",
"sup",
"</div>",
"</foreignObject>",
"</svg>"
].join("");
try {
ctx.drawImage(img, 0, 0);
canvas.toDataURL();
} catch(e) {
return false;
}
h2clog('html2canvas: Parse: SVG powered rendering available');
return true;
})()
},
element = (( options.elements === undefined ) ? document.body : options.elements[0]), // select body by default
needReorder = false,
numDraws = 0,
fontData = {},
doc = element.ownerDocument,
ignoreElementsRegExp = new RegExp("(" + options.ignoreElements + ")"),
body = doc.body,
r,
testElement,
rangeBounds,
rangeHeight,
stack,
ctx,
docDim,
i,
children,
childrenLen;
function docSize(){
return {
width: Math.max(
Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth),
Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth),
Math.max(doc.body.clientWidth, doc.documentElement.clientWidth)
),
height: Math.max(
Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight),
Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight),
Math.max(doc.body.clientHeight, doc.documentElement.clientHeight)
)
};
}
images = images || {};
// Test whether we can use ranges to measure bounding boxes
// Opera doesn't provide valid bounds.height/bottom even though it supports the method.
if (doc.createRange) {
r = doc.createRange();
//this.support.rangeBounds = new Boolean(r.getBoundingClientRect);
if (r.getBoundingClientRect){
testElement = doc.createElement('boundtest');
testElement.style.height = "123px";
testElement.style.display = "block";
body.appendChild(testElement);
r.selectNode(testElement);
rangeBounds = r.getBoundingClientRect();
rangeHeight = rangeBounds.height;
if (rangeHeight === 123) {
support.rangeBounds = true;
}
body.removeChild(testElement);
}
}
/*
var rootStack = new this.storageContext($(document).width(),$(document).height());
rootStack.opacity = this.getCSS(this.element,"opacity");
var stack = this.newElement(this.element,rootStack);
this.parseElement(this.element,stack);
*/
var getCSS = _html2canvas.Util.getCSS;
function getCSSInt(element, attribute) {
var val = parseInt(getCSS(element, attribute), 10);
return (isNaN(val)) ? 0 : val; // borders in old IE are throwing 'medium' for demo.html
}
// Drawing a rectangle
function renderRect (ctx, x, y, w, h, bgcolor) {
if (bgcolor !=="transparent"){
ctx.setVariable("fillStyle", bgcolor);
ctx.fillRect (x, y, w, h);
numDraws+=1;
}
}
function textTransform (text, transform) {
switch(transform){
case "lowercase":
return text.toLowerCase();
case "capitalize":
return text.replace( /(^|\s|:|-|\(|\))([a-z])/g , function (m, p1, p2) {
if (m.length > 0) {
return p1 + p2.toUpperCase();
}
} );
case "uppercase":
return text.toUpperCase();
default:
return text;
}
}
function trimText (text) {
return text.replace(/^\s*/g, "").replace(/\s*$/g, "");
}
function fontMetrics (font, fontSize) {
if (fontData[font + "-" + fontSize] !== undefined) {
return fontData[font + "-" + fontSize];
}
var container = doc.createElement('div'),
img = doc.createElement('img'),
span = doc.createElement('span'),
baseline,
middle,
metricsObj;
container.style.visibility = "hidden";
container.style.fontFamily = font;
container.style.fontSize = fontSize;
container.style.margin = 0;
container.style.padding = 0;
body.appendChild(container);
// http://probablyprogramming.com/2009/03/15/the-tiniest-gif-ever (handtinywhite.gif)
img.src = "data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACwAAAAAAQABAAACAkQBADs=";
img.width = 1;
img.height = 1;
img.style.margin = 0;
img.style.padding = 0;
img.style.verticalAlign = "baseline";
span.style.fontFamily = font;
span.style.fontSize = fontSize;
span.style.margin = 0;
span.style.padding = 0;
span.appendChild(doc.createTextNode('Hidden Text'));
container.appendChild(span);
container.appendChild(img);
baseline = (img.offsetTop - span.offsetTop) + 1;
container.removeChild(span);
container.appendChild(doc.createTextNode('Hidden Text'));
container.style.lineHeight = "normal";
img.style.verticalAlign = "super";
middle = (img.offsetTop-container.offsetTop) + 1;
metricsObj = {
baseline: baseline,
lineWidth: 1,
middle: middle
};
fontData[font + "-" + fontSize] = metricsObj;
body.removeChild(container);
return metricsObj;
}
function drawText(currentText, x, y, ctx){
if (trimText(currentText).length>0) {
ctx.fillText(currentText,x,y);
numDraws+=1;
}
}
function renderText(el, textNode, stack) {
var ctx = stack.ctx,
family = getCSS(el, "fontFamily"),
size = getCSS(el, "fontSize"),
color = getCSS(el, "color"),
text_decoration = getCSS(el, "textDecoration"),
text_align = getCSS(el, "textAlign"),
letter_spacing = getCSS(el, "letterSpacing"),
bounds,
text,
metrics,
renderList,
listLen,
bold = getCSS(el, "fontWeight"),
font_style = getCSS(el, "fontStyle"),
font_variant = getCSS(el, "fontVariant"),
align = false,
newTextNode,
textValue,
textOffset = 0,
oldTextNode,
c,
range,
parent,
wrapElement,
backupText;
// apply text-transform:ation to the text
textNode.nodeValue = textTransform(textNode.nodeValue, getCSS(el, "textTransform"));
text = trimText(textNode.nodeValue);
if (text.length>0){
if (text_decoration !== "none"){
metrics = fontMetrics(family, size);
}
text_align = text_align.replace(["-webkit-auto"],["auto"]);
if (options.letterRendering === false && /^(left|right|justify|auto)$/.test(text_align) && /^(normal|none)$/.test(letter_spacing)){
// this.setContextVariable(ctx,"textAlign",text_align);
renderList = textNode.nodeValue.split(/(\b| )/);
}else{
// this.setContextVariable(ctx,"textAlign","left");
renderList = textNode.nodeValue.split("");
}
switch(parseInt(bold, 10)){
case 401:
bold = "bold";
break;
case 400:
bold = "normal";
break;
}
ctx.setVariable("fillStyle", color);
/*
need to be defined in the order as defined in http://www.w3.org/TR/CSS21/fonts.html#font-shorthand
to properly work in Firefox
*/
ctx.setVariable("font", font_style+ " " + font_variant + " " + bold + " " + size + " " + family);
if (align){
ctx.setVariable("textAlign", "right");
}else{
ctx.setVariable("textAlign", "left");
}
/*
if (stack.clip){
ctx.rect (stack.clip.left, stack.clip.top, stack.clip.width, stack.clip.height);
ctx.clip();
}
*/
oldTextNode = textNode;
for ( c=0, listLen = renderList.length; c < listLen; c+=1 ) {
textValue = null;
if (support.rangeBounds){
// getBoundingClientRect is supported for ranges
if (text_decoration !== "none" || trimText(renderList[c]).length !== 0) {
textValue = renderList[c];
if (doc.createRange){
range = doc.createRange();
range.setStart(textNode, textOffset);
range.setEnd(textNode, textOffset + textValue.length);
}else{
// TODO add IE support
range = body.createTextRange();
}
bounds = adjustBounds(textNode, range.getBoundingClientRect());
}
}else{
// it isn't supported, so let's wrap it inside an element instead and get the bounds there
// IE 9 bug
if (typeof oldTextNode.nodeValue !== "string" ){
continue;
}
newTextNode = oldTextNode.splitText(renderList[c].length);
parent = oldTextNode.parentNode;
wrapElement = doc.createElement('wrapper');
backupText = oldTextNode.cloneNode(true);
wrapElement.appendChild(oldTextNode.cloneNode(true));
parent.replaceChild(wrapElement, oldTextNode);
bounds = _html2canvas.Util.Bounds(wrapElement);
textValue = oldTextNode.nodeValue;
oldTextNode = newTextNode;
parent.replaceChild(backupText, wrapElement);
}
if (textValue !== null){
drawText(textValue, bounds.left, bounds.bottom, ctx);
}
switch(text_decoration) {
case "underline":
// Draws a line at the baseline of the font
// TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size
renderRect(ctx, bounds.left, Math.round(bounds.top + metrics.baseline + metrics.lineWidth), bounds.width, 1, color);
break;
case "overline":
renderRect(ctx, bounds.left, bounds.top, bounds.width, 1, color);
break;
case "line-through":
// TODO try and find exact position for line-through
renderRect(ctx, bounds.left, Math.ceil(bounds.top + metrics.middle + metrics.lineWidth), bounds.width, 1, color);
break;
}
textOffset += renderList[c].length;
}
}
}
function listPosition (element, val) {
var boundElement = doc.createElement( "boundelement" ),
type,
bounds;
boundElement.style.display = "inline";
//boundElement.style.width = "1px";
//boundElement.style.height = "1px";
type = element.style.listStyleType;
element.style.listStyleType = "none";
boundElement.appendChild( doc.createTextNode( val ) );
element.insertBefore(boundElement, element.firstChild);
bounds = _html2canvas.Util.Bounds( boundElement );
element.removeChild( boundElement );
element.style.listStyleType = type;
return bounds;
}
function elementIndex( el ) {
var i = -1,
count = 1,
childs = el.parentNode.childNodes;
if ( el.parentNode ) {
while( childs[ ++i ] !== el ) {
if ( childs[ i ].nodeType === 1 ) {
count++;
}
}
return count;
} else {
return -1;
}
}
function renderListItem(element, stack, elBounds) {
var position = getCSS(element, "listStylePosition"),
x,
y,
type = getCSS(element, "listStyleType"),
currentIndex,
text,
listBounds,
bold = getCSS(element, "fontWeight");
if (/^(decimal|decimal-leading-zero|upper-alpha|upper-latin|upper-roman|lower-alpha|lower-greek|lower-latin|lower-roman)$/i.test(type)) {
currentIndex = elementIndex( element );
switch(type){
case "decimal":
text = currentIndex;
break;
case "decimal-leading-zero":
if (currentIndex.toString().length === 1){
text = currentIndex = "0" + currentIndex.toString();
}else{
text = currentIndex.toString();
}
break;
case "upper-roman":
text = _html2canvas.Generate.ListRoman( currentIndex );
break;
case "lower-roman":
text = _html2canvas.Generate.ListRoman( currentIndex ).toLowerCase();
break;
case "lower-alpha":
text = _html2canvas.Generate.ListAlpha( currentIndex ).toLowerCase();
break;
case "upper-alpha":
text = _html2canvas.Generate.ListAlpha( currentIndex );
break;
}
text += ". ";
listBounds = listPosition(element, text);
switch(bold){
case 401:
bold = "bold";
break;
case 400:
bold = "normal";
break;
}
ctx.setVariable( "fillStyle", getCSS(element, "color") );
ctx.setVariable( "font", getCSS(element, "fontVariant") + " " + bold + " " + getCSS(element, "fontStyle") + " " + getCSS(element, "fontSize") + " " + getCSS(element, "fontFamily") );
if ( position === "inside" ) {
ctx.setVariable("textAlign", "left");
// this.setFont(stack.ctx, element, false);
x = elBounds.left;
}else{
return;
/*
TODO really need to figure out some more accurate way to try and find the position.
as defined in http://www.w3.org/TR/CSS21/generate.html#propdef-list-style-position, it does not even have a specified "correct" position, so each browser
may display it whatever way it feels like.
"The position of the list-item marker adjacent to floats is undefined in CSS 2.1. CSS 2.1 does not specify the precise location of the marker box or its position in the painting order"
ctx.setVariable("textAlign", "right");
// this.setFont(stack.ctx, element, true);
x = elBounds.left - 10;
*/
}
y = listBounds.bottom;
drawText(text, x, y, ctx);
}
}
function loadImage (src){
var img = images[src];
if (img && img.succeeded === true) {
return img.img;
} else {
return false;
}
}
function clipBounds(src, dst){
var x = Math.max(src.left, dst.left),
y = Math.max(src.top, dst.top),
x2 = Math.min((src.left + src.width), (dst.left + dst.width)),
y2 = Math.min((src.top + src.height), (dst.top + dst.height));
return {
left:x,
top:y,
width:x2-x,
height:y2-y
};
}
function setZ(zIndex, parentZ){
// TODO fix static elements overlapping relative/absolute elements under same stack, if they are defined after them
var newContext;
if (!parentZ){
newContext = h2czContext(0);
return newContext;
}
if (zIndex !== "auto"){
needReorder = true;
newContext = h2czContext(zIndex);
parentZ.children.push(newContext);
return newContext;
}
return parentZ;
}
function renderBorders(el, ctx, bounds, clip){
/*
* TODO add support for different border-style's than solid
*/
var x = bounds.left,
y = bounds.top,
w = bounds.width,
h = bounds.height,
borderSide,
borderData,
bx,
by,
bw,
bh,
borderBounds,
borders = (function(el){
var borders = [],
sides = ["Top","Right","Bottom","Left"],
s;
for (s = 0; s < 4; s+=1){
borders.push({
width: getCSSInt(el, 'border' + sides[s] + 'Width'),
color: getCSS(el, 'border' + sides[s] + 'Color')
});
}
return borders;
}(el));
for (borderSide = 0; borderSide < 4; borderSide+=1){
borderData = borders[borderSide];
if (borderData.width>0){
bx = x;
by = y;
bw = w;
bh = h - (borders[2].width);
switch(borderSide){
case 0:
// top border
bh = borders[0].width;
break;
case 1:
// right border
bx = x + w - (borders[1].width);
bw = borders[1].width;
break;
case 2:
// bottom border
by = (by + h) - (borders[2].width);
bh = borders[2].width;
break;
case 3:
// left border
bw = borders[3].width;
break;
}
borderBounds = {
left:bx,
top:by,
width: bw,
height:bh
};
if (clip){
borderBounds = clipBounds(borderBounds, clip);
}
if (borderBounds.width>0 && borderBounds.height>0){
renderRect(ctx, bx, by, borderBounds.width, borderBounds.height, borderData.color);
}
}
}
return borders;
}
function renderFormValue (el, bounds, stack){
var valueWrap = doc.createElement('valuewrap'),
cssArr = ['lineHeight','textAlign','fontFamily','color','fontSize','paddingLeft','paddingTop','width','height','border','borderLeftWidth','borderTopWidth'],
i,
textValue,
textNode,
arrLen,
style;
for (i = 0, arrLen = cssArr.length; i < arrLen; i+=1){
style = cssArr[i];
try {
valueWrap.style[style] = getCSS(el, style);
} catch( e ) {
// Older IE has issues with "border"
h2clog("html2canvas: Parse: Exception caught in renderFormValue: " + e.message);
}
}
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
textValue = el.options[el.selectedIndex].text;
} else{
textValue = el.value;
}
textNode = doc.createTextNode(textValue);
valueWrap.appendChild(textNode);
body.appendChild(valueWrap);
renderText(el, textNode, stack);
body.removeChild(valueWrap);
}
function renderImage (ctx, image, sx, sy, sw, sh, dx, dy, dw, dh) {
ctx.drawImage(
image,
sx, //sx
sy, //sy
sw, //sw
sh, //sh
dx, //dx
dy, // dy
dw, //dw
dh //dh
);
numDraws+=1;
}
function renderBackgroundRepeat (ctx, image, x, y, width, height, elx, ely){
var sourceX = 0,
sourceY=0;
if (elx-x>0){
sourceX = elx-x;
}
if (ely-y>0){
sourceY = ely-y;
}
renderImage(
ctx,
image,
sourceX, // source X
sourceY, // source Y
width-sourceX, // source Width
height-sourceY, // source Height
x+sourceX, // destination X
y+sourceY, // destination Y
width-sourceX, // destination width
height-sourceY // destination height
);
}
function renderBackgroundRepeatY (ctx, image, bgp, x, y, w, h){
var height,
width = Math.min(image.width,w),bgy;
bgp.top = bgp.top-Math.ceil(bgp.top/image.height)*image.height;
for(bgy=(y+bgp.top);bgy<h+y;){
if ( Math.floor(bgy+image.height)>h+y){
height = (h+y)-bgy;
}else{
height = image.height;
}
renderBackgroundRepeat(ctx,image,x+bgp.left,bgy,width,height,x,y);
bgy = Math.floor(bgy+image.height);
}
}
function renderBackgroundRepeatX(ctx, image, bgp, x, y, w, h){
var height = Math.min(image.height,h),
width,bgx;
bgp.left = bgp.left-Math.ceil(bgp.left/image.width)*image.width;
for (bgx=(x+bgp.left);bgx<w+x;) {
if (Math.floor(bgx+image.width)>w+x){
width = (w+x)-bgx;
}else{
width = image.width;
}
renderBackgroundRepeat(ctx,image,bgx,(y+bgp.top),width,height,x,y);
bgx = Math.floor(bgx+image.width);
}
}
function renderBackground(el,bounds,ctx){
// TODO add support for multi background-images
var background_image = getCSS(el, "backgroundImage"),
background_repeat = getCSS(el, "backgroundRepeat").split(",")[0],
image,
bgp,
bgy,
bgw,
bgsx,
bgsy,
bgdx,
bgdy,
bgh,
h,
height,
add;
// if (typeof background_image !== "undefined" && /^(1|none)$/.test(background_image) === false && /^(-webkit|-moz|linear-gradient|-o-)/.test(background_image)===false){
if ( !/data:image\/.*;base64,/i.test(background_image) && !/^(-webkit|-moz|linear-gradient|-o-)/.test(background_image) ) {
background_image = background_image.split(",")[0];
}
if ( typeof background_image !== "undefined" && /^(1|none)$/.test( background_image ) === false ) {
background_image = _html2canvas.Util.backgroundImage( background_image );
image = loadImage( background_image );
bgp = _html2canvas.Util.BackgroundPosition(el, bounds, image);
// TODO add support for background-origin
if ( image ){
switch ( background_repeat ) {
case "repeat-x":
renderBackgroundRepeatX( ctx, image, bgp, bounds.left, bounds.top, bounds.width, bounds.height );
break;
case "repeat-y":
renderBackgroundRepeatY( ctx, image, bgp, bounds.left, bounds.top, bounds.width, bounds.height );
break;
case "no-repeat":
/*
this.drawBackgroundRepeat(
ctx,
image,
bgp.left+bounds.left, // sx
bgp.top+bounds.top, // sy
Math.min(bounds.width,image.width),
Math.min(bounds.height,image.height),
bounds.left,
bounds.top
);*/
bgw = bounds.width - bgp.left;
bgh = bounds.height - bgp.top;
bgsx = bgp.left;
bgsy = bgp.top;
bgdx = bgp.left+bounds.left;
bgdy = bgp.top+bounds.top;
//
// bgw = Math.min(bgw,image.width);
// bgh = Math.min(bgh,image.height);
if (bgsx<0){
bgsx = Math.abs(bgsx);
bgdx += bgsx;
bgw = Math.min(bounds.width,image.width-bgsx);
}else{
bgw = Math.min(bgw,image.width);
bgsx = 0;
}
if (bgsy<0){
bgsy = Math.abs(bgsy);
bgdy += bgsy;
// bgh = bgh-bgsy;
bgh = Math.min(bounds.height,image.height-bgsy);
}else{
bgh = Math.min(bgh,image.height);
bgsy = 0;
}
if (bgh>0 && bgw > 0){
renderImage(
ctx,
image,
bgsx, // source X : 0
bgsy, // source Y : 1695
bgw, // source Width : 18
bgh, // source Height : 1677
bgdx, // destination X :906
bgdy, // destination Y : 1020
bgw, // destination width : 18
bgh // destination height : 1677
);
}
break;
default:
bgp.top = bgp.top-Math.ceil(bgp.top/image.height)*image.height;
for(bgy=(bounds.top+bgp.top);bgy<bounds.height+bounds.top;){
h = Math.min(image.height,(bounds.height+bounds.top)-bgy);
if ( Math.floor(bgy+image.height)>h+bgy){
height = (h+bgy)-bgy;
}else{
height = image.height;
}
// console.log(height);
if (bgy<bounds.top){
add = bounds.top-bgy;
bgy = bounds.top;
}else{
add = 0;
}
renderBackgroundRepeatX(ctx,image,bgp,bounds.left,bgy,bounds.width,height);
if (add>0){
bgp.top += add;
}
bgy = Math.floor(bgy+image.height)-add;
}
break;
}
}else{
h2clog("html2canvas: Error loading background:" + background_image);
//console.log(images);
}
}
}
function renderElement(el, parentStack){
var bounds = _html2canvas.Util.Bounds(el),
x = bounds.left,
y = bounds.top,
w = bounds.width,
h = bounds.height,
image,
bgcolor = getCSS(el, "backgroundColor"),
cssPosition = getCSS(el, "position"),
zindex,
opacity = getCSS(el, "opacity"),
stack,
stackLength,
borders,
ctx,
bgbounds,
imgSrc,
paddingLeft,
paddingTop,
paddingRight,
paddingBottom;
if (!parentStack){
docDim = docSize();
parentStack = {
opacity: 1
};
}else{
docDim = {};
}
//var zindex = this.formatZ(this.getCSS(el,"zIndex"),cssPosition,parentStack.zIndex,el.parentNode);
zindex = setZ( getCSS( el, "zIndex"), parentStack.zIndex );
stack = {
ctx: h2cRenderContext( docDim.width || w , docDim.height || h ),
zIndex: zindex,
opacity: opacity * parentStack.opacity,
cssPosition: cssPosition
};
// TODO correct overflow for absolute content residing under a static position
if (parentStack.clip){
stack.clip = _html2canvas.Util.Extend( {}, parentStack.clip );
//stack.clip = parentStack.clip;
// stack.clip.height = stack.clip.height - parentStack.borders[2].width;
}
if ( options.useOverflow === true && /(hidden|scroll|auto)/.test(getCSS(el, "overflow")) === true && /(BODY)/i.test(el.nodeName) === false ){
if (stack.clip){
stack.clip = clipBounds(stack.clip, bounds);
}else{
stack.clip = bounds;
}
}
stackLength = zindex.children.push(stack);
ctx = zindex.children[stackLength-1].ctx;
ctx.setVariable("globalAlpha", stack.opacity);
// draw element borders
borders = renderBorders(el, ctx, bounds, false);
stack.borders = borders;
// let's modify clip area for child elements, so borders dont get overwritten
/*
if (stack.clip){
stack.clip.width = stack.clip.width-(borders[1].width);
stack.clip.height = stack.clip.height-(borders[2].width);
}
*/
if (ignoreElementsRegExp.test(el.nodeName) && options.iframeDefault !== "transparent"){
if (options.iframeDefault === "default"){
bgcolor = "#efefef";
}else{
bgcolor = options.iframeDefault;
}
}
// draw base element bgcolor
bgbounds = {
left: x + borders[3].width,
top: y + borders[0].width,
width: w - (borders[1].width + borders[3].width),
height: h - (borders[0].width + borders[2].width)
};
//if (this.withinBounds(stack.clip,bgbounds)){
if (stack.clip){
bgbounds = clipBounds(bgbounds, stack.clip);
//}
}
if (bgbounds.height > 0 && bgbounds.width > 0){
renderRect(
ctx,
bgbounds.left,
bgbounds.top,
bgbounds.width,
bgbounds.height,
bgcolor
);
renderBackground(el, bgbounds, ctx);
}
switch(el.nodeName){
case "IMG":
imgSrc = el.getAttribute('src');
image = loadImage(imgSrc);
if (image){
paddingLeft = getCSSInt(el, 'paddingLeft');
paddingTop = getCSSInt(el, 'paddingTop');
paddingRight = getCSSInt(el, 'paddingRight');
paddingBottom = getCSSInt(el, 'paddingBottom');
renderImage(
ctx,
image,
0, //sx
0, //sy
image.width, //sw
image.height, //sh
x + paddingLeft + borders[3].width, //dx
y + paddingTop + borders[0].width, // dy
bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight), //dw
bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom) //dh
);
}else{
h2clog("html2canvas: Error loading <img>:" + imgSrc);
}
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){
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){
renderFormValue(el, bounds, stack);
}
break;
case "SELECT":
if (el.options.length > 0){
renderFormValue(el, bounds, stack);
}
break;
case "LI":
renderListItem(el, stack, bgbounds);
break;
case "CANVAS":
paddingLeft = getCSSInt(el, 'paddingLeft');
paddingTop = getCSSInt(el, 'paddingTop');
paddingRight = getCSSInt(el, 'paddingRight');
paddingBottom = getCSSInt(el, 'paddingBottom');
renderImage(
ctx,
el,
0, //sx
0, //sy
el.width, //sw
el.height, //sh
x + paddingLeft + borders[3].width, //dx
y + paddingTop + borders[0].width, // dy
bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight), //dw
bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom) //dh
);
break;
}
return zindex.children[stackLength - 1];
}
function parseElement (el, stack) {
// skip hidden elements and their children
if (getCSS(el, 'display') !== "none" && getCSS(el, 'visibility') !== "hidden") {
stack = renderElement(el, stack) || stack;
ctx = stack.ctx;
if ( !ignoreElementsRegExp.test( el.nodeName ) ) {
var elementChildren = _html2canvas.Util.Children( el ),
i,
node,
childrenLen;
for (i = 0, childrenLen = elementChildren.length; i < childrenLen; i+=1) {
node = elementChildren[i];
if ( node.nodeType === 1 ) {
parseElement(node, stack);
}else if ( node.nodeType === 3 ) {
renderText(el, node, stack);
}
}
}
}
}
stack = renderElement(element, null);
/*
SVG powered HTML rendering, non-tainted canvas available from FF 11+ onwards
*/
if ( support.svgRendering ) {
(function( body ){
var img = new Image(),
size = docSize(),
html = "";
function parseDOM( el ) {
var children = _html2canvas.Util.Children( el ),
len = children.length,
attr,
a,
alen,
elm,
i;
for ( i = 0; i < len; i+=1 ) {
elm = children[ i ];
if ( elm.nodeType === 3 ) {
// Text node
html += elm.nodeValue.replace(/\</g,"<").replace(/\>/g,">");
} else if ( elm.nodeType === 1 ) {
// Element
if ( !/^(script|meta|title)$/.test(elm.nodeName.toLowerCase()) ) {
html += "<" + elm.nodeName.toLowerCase();
// add attributes
if ( elm.hasAttributes() ) {
attr = elm.attributes;
alen = attr.length;
for ( a = 0; a < alen; a+=1 ) {
html += " " + attr[ a ].name + '="' + attr[ a ].value + '"';
}
}
html += '>';
parseDOM( elm );
html += "</" + elm.nodeName.toLowerCase() + ">";
}
}
}
}
parseDOM( body );
img.src = [
"data:image/svg+xml,",
"<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='" + size.width + "' height='" + size.height + "'>",
"<foreignObject width='" + size.width + "' height='" + size.height + "'>",
"<html xmlns='http://www.w3.org/1999/xhtml' style='margin:0;'>",
html.replace(/\#/g,"%23"),
"</html>",
"</foreignObject>",
"</svg>"
].join("");
img.onload = function() {
stack.svgRender = img;
};
})( document.documentElement );
}
// parse every child element
for (i = 0, children = element.children, childrenLen = children.length; i < childrenLen; i+=1){
parseElement(children[i], stack);
}
stack.backgroundColor = getCSS( document.documentElement, "backgroundColor" );
return stack;
};
function h2czContext(zindex) {
return {
zindex: zindex,
children: []
};
}
/*
html2canvas v0.34 <http://html2canvas.hertzen.com>
Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
http://www.twitter.com/niklasvh
Released under MIT License
*/
_html2canvas.Preload = function( options ) {
var images = {
numLoaded: 0, // also failed are counted here
numFailed: 0,
numTotal: 0,
cleanupDone: false
},
pageOrigin,
methods,
i,
count = 0,
element = options.elements[0] || document.body,
doc = element.ownerDocument,
domImages = doc.images, // TODO probably should limit it to images present in the element only
imgLen = domImages.length,
link = doc.createElement("a"),
supportCORS = (function( img ){
return (img.crossOrigin !== undefined);
})(new Image()),
timeoutTimer;
link.href = window.location.href;
pageOrigin = link.protocol + link.host;
function isSameOrigin(url){
link.href = url;
link.href = link.href; // YES, BELIEVE IT OR NOT, that is required for IE9 - http://jsfiddle.net/niklasvh/2e48b/
var origin = link.protocol + link.host;
return (origin === pageOrigin);
}
function start(){
h2clog("html2canvas: start: images: " + images.numLoaded + " / " + images.numTotal + " (failed: " + images.numFailed + ")");
if (!images.firstRun && images.numLoaded >= images.numTotal){
h2clog("Finished loading images: # " + images.numTotal + " (failed: " + images.numFailed + ")");
if (typeof options.complete === "function"){
options.complete(images);
}
}
}
// TODO modify proxy to serve images with CORS enabled, where available
function proxyGetImage(url, img, imageObj){
var callback_name,
scriptUrl = options.proxy,
script;
link.href = url;
url = link.href; // work around for pages with base href="" set - WARNING: this may change the url
callback_name = 'html2canvas_' + (count++);
imageObj.callbackname = callback_name;
if (scriptUrl.indexOf("?") > -1) {
scriptUrl += "&";
} else {
scriptUrl += "?";
}
scriptUrl += 'url=' + encodeURIComponent(url) + '&callback=' + callback_name;
script = doc.createElement("script");
window[callback_name] = function(a){
if (a.substring(0,6) === "error:"){
imageObj.succeeded = false;
images.numLoaded++;
images.numFailed++;
start();
} else {
setImageLoadHandlers(img, imageObj);
img.src = a;
}
window[callback_name] = undefined; // to work with IE<9 // NOTE: that the undefined callback property-name still exists on the window object (for IE<9)
try {
delete window[callback_name]; // for all browser that support this
} catch(ex) {}
script.parentNode.removeChild(script);
script = null;
delete imageObj.script;
delete imageObj.callbackname;
};
script.setAttribute("type", "text/javascript");
script.setAttribute("src", scriptUrl);
imageObj.script = script;
window.document.body.appendChild(script);
}
function getImages (el) {
// if (!this.ignoreRe.test(el.nodeName)){
//
var contents = _html2canvas.Util.Children(el),
i,
background_image,
src,
img,
elNodeType = false;
// Firefox fails with permission denied on pages with iframes
try {
var contentsLen = contents.length;
for (i = 0; i < contentsLen; i+=1 ){
// var ignRe = new RegExp("("+this.ignoreElements+")");
// if (!ignRe.test(element.nodeName)){
getImages(contents[i]);
// }
}
}
catch( e ) {}
// }
try {
elNodeType = el.nodeType;
} catch (ex) {
elNodeType = false;
h2clog("html2canvas: failed to access some element's nodeType - Exception: " + ex.message);
}
if (elNodeType === 1 || elNodeType === undefined){
// opera throws exception on external-content.html
try {
background_image = _html2canvas.Util.getCSS(el, 'backgroundImage');
}catch(e) {
h2clog("html2canvas: failed to get background-image - Exception: " + e.message);
}
if ( background_image && background_image !== "1" && background_image !== "none" ) {
// TODO add multi image background support
if (/^(-webkit|-o|-moz|-ms|linear)-/.test( background_image )) {
img = _html2canvas.Generate.Gradient( background_image, _html2canvas.Util.Bounds( el ) );
if ( img !== undefined ){
images[background_image] = {
img: img,
succeeded: true
};
images.numTotal++;
images.numLoaded++;
start();
}
} else {
src = _html2canvas.Util.backgroundImage(background_image.match(/data:image\/.*;base64,/i) ? background_image : background_image.split(",")[0]);
methods.loadImage(src);
}
/*
if (background_image && background_image !== "1" && background_image !== "none" && background_image.substring(0,7) !== "-webkit" && background_image.substring(0,3)!== "-o-" && background_image.substring(0,4) !== "-moz"){
// TODO add multi image background support
src = _html2canvas.Util.backgroundImage(background_image.split(",")[0]);
methods.loadImage(src); */
}
}
}
function setImageLoadHandlers(img, imageObj) {
img.onload = function() {
if ( imageObj.timer !== undefined ) {
// CORS succeeded
window.clearTimeout( imageObj.timer );
}
images.numLoaded++;
imageObj.succeeded = true;
img.onerror = img.onload = null;
start();
};
img.onerror = function() {
if (img.crossOrigin === "anonymous") {
// CORS failed
window.clearTimeout( imageObj.timer );
// let's try with proxy instead
if ( options.proxy ) {
var src = img.src;
img = new Image();
imageObj.img = img;
img.src = src;
proxyGetImage( img.src, img, imageObj );
return;
}
}
images.numLoaded++;
images.numFailed++;
imageObj.succeeded = false;
img.onerror = img.onload = null;
start();
};
// TODO Opera has no load/error event for SVG images
// Opera ninja onload's cached images
/*
window.setTimeout(function(){
if ( img.width !== 0 && imageObj.succeeded === undefined ) {
img.onload();
}
}, 100); // needs a reflow for base64 encoded images? interestingly timeout of 0 doesn't work but 1 does.
*/
}
methods = {
loadImage: function( src ) {
var img, imageObj;
if ( src && images[src] === undefined ) {
img = new Image();
if ( src.match(/data:image\/.*;base64,/i) ) {
img.src = src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, '');
imageObj = images[src] = {
img: img
};
images.numTotal++;
setImageLoadHandlers(img, imageObj);
} else if ( isSameOrigin( src ) || options.allowTaint === true ) {
imageObj = images[src] = {
img: img
};
images.numTotal++;
setImageLoadHandlers(img, imageObj);
img.src = src;
} else if ( supportCORS && !options.allowTaint && options.useCORS ) {
// attempt to load with CORS
img.crossOrigin = "anonymous";
imageObj = images[src] = {
img: img
};
images.numTotal++;
setImageLoadHandlers(img, imageObj);
img.src = src;
// work around for https://bugs.webkit.org/show_bug.cgi?id=80028
img.customComplete = function () {
if (!this.img.complete) {
this.timer = window.setTimeout(this.img.customComplete, 100);
} else {
this.img.onerror();
}
}.bind(imageObj);
img.customComplete();
} else if ( options.proxy ) {
imageObj = images[src] = {
img: img
};
images.numTotal++;
proxyGetImage( src, img, imageObj );
}
}
},
cleanupDOM: function(cause) {
var img, src;
if (!images.cleanupDone) {
if (cause && typeof cause === "string") {
h2clog("html2canvas: Cleanup because: " + cause);
} else {
h2clog("html2canvas: Cleanup after timeout: " + options.timeout + " ms.");
}
for (src in images) {
if (images.hasOwnProperty(src)) {
img = images[src];
if (typeof img === "object" && img.callbackname && img.succeeded === undefined) {
// cancel proxy image request
window[img.callbackname] = undefined; // to work with IE<9 // NOTE: that the undefined callback property-name still exists on the window object (for IE<9)
try {
delete window[img.callbackname]; // for all browser that support this
} catch(ex) {}
if (img.script && img.script.parentNode) {
img.script.setAttribute("src", "about:blank"); // try to cancel running request
img.script.parentNode.removeChild(img.script);
}
images.numLoaded++;
images.numFailed++;
h2clog("html2canvas: Cleaned up failed img: '" + src + "' Steps: " + images.numLoaded + " / " + images.numTotal);
}
}
}
// cancel any pending requests
if(window.stop !== undefined) {
window.stop();
} else if(document.execCommand !== undefined) {
document.execCommand("Stop", false);
}
if (document.close !== undefined) {
document.close();
}
images.cleanupDone = true;
if (!(cause && typeof cause === "string")) {
start();
}
}
},
renderingDone: function() {
if (timeoutTimer) {
window.clearTimeout(timeoutTimer);
}
}
};
if (options.timeout > 0) {
timeoutTimer = window.setTimeout(methods.cleanupDOM, options.timeout);
}
h2clog('html2canvas: Preload starts: finding background-images');
images.firstRun = true;
getImages( element );
h2clog('html2canvas: Preload: Finding images');
// load <img> images
for (i = 0; i < imgLen; i+=1){
methods.loadImage( domImages[i].getAttribute( "src" ) );
}
images.firstRun = false;
h2clog('html2canvas: Preload: Done.');
if ( images.numTotal === images.numLoaded ) {
start();
}
return methods;
};
/*
html2canvas v0.34 <http://html2canvas.hertzen.com>
Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
http://www.twitter.com/niklasvh
Released under MIT License
*/
function h2cRenderContext(width, height) {
var storage = [];
return {
storage: storage,
width: width,
height: height,
fillRect: function () {
storage.push({
type: "function",
name: "fillRect",
'arguments': arguments
});
},
drawImage: function () {
storage.push({
type: "function",
name: "drawImage",
'arguments': arguments
});
},
fillText: function () {
storage.push({
type: "function",
name: "fillText",
'arguments': arguments
});
},
setVariable: function (variable, value) {
storage.push({
type: "variable",
name: variable,
'arguments': value
});
}
};
}
/*
html2canvas v0.34 <http://html2canvas.hertzen.com>
Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
http://www.twitter.com/niklasvh
Released under MIT License
*/
_html2canvas.Renderer = function(parseQueue, options){
var queue = [];
function sortZ(zStack){
var subStacks = [],
stackValues = [],
zStackChildren = zStack.children,
s,
i,
stackLen,
zValue,
zLen,
stackChild,
b,
subStackLen;
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;
}
}
}
}
sortZ(parseQueue.zIndex);
if ( typeof options._renderer._create !== "function" ) {
throw new Error("Invalid renderer defined");
}
return options._renderer._create( parseQueue, options, document, queue, _html2canvas );
};
/*
html2canvas v0.34 <http://html2canvas.hertzen.com>
Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
http://www.twitter.com/niklasvh
Released under MIT License
*/
html2canvas = function( elements, opts ) {
var queue,
canvas,
options = {
// general
logging: false,
elements: elements,
// preload options
proxy: "http://html2canvas.appspot.com/",
timeout: 0, // no timeout
useCORS: false, // try to load images as CORS (where available), before falling back to proxy
allowTaint: false, // whether to allow images to taint the canvas, won't need proxy if set to true
// parse options
svgRendering: false, // use svg powered rendering where available (FF11+)
iframeDefault: "default",
ignoreElements: "IFRAME|OBJECT|PARAM",
useOverflow: true,
letterRendering: false,
// render options
flashcanvas: undefined, // path to flashcanvas
width: null,
height: null,
taintTest: true, // do a taint test with all images before applying to canvas
renderer: "Canvas"
}, renderer;
options = _html2canvas.Util.Extend(opts, options);
if (typeof options.renderer === "string" && _html2canvas.Renderer[options.renderer] !== undefined) {
options._renderer = _html2canvas.Renderer[options.renderer]( options );
} else if (typeof options.renderer === "function") {
options._renderer = options.renderer( options );
} else {
throw("Unknown renderer");
}
_html2canvas.logging = options.logging;
options.complete = function( images ) {
if (typeof options.onpreloaded === "function") {
if ( options.onpreloaded( images ) === false ) {
return;
}
}
queue = _html2canvas.Parse( images, options );
if (typeof options.onparsed === "function") {
if ( options.onparsed( queue ) === false ) {
return;
}
}
canvas = _html2canvas.Renderer( queue, options );
if (typeof options.onrendered === "function") {
options.onrendered( canvas );
}
};
// for pages without images, we still want this to be async, i.e. return methods before executing
window.setTimeout( function(){
_html2canvas.Preload( options );
}, 0 );
return {
render: function( queue, opts ) {
return _html2canvas.Renderer( queue, _html2canvas.Util.Extend(opts, options) );
},
parse: function( images, opts ) {
return _html2canvas.Parse( images, _html2canvas.Util.Extend(opts, options) );
},
preload: function( opts ) {
return _html2canvas.Preload( _html2canvas.Util.Extend(opts, options) );
},
log: h2clog
};
};
html2canvas.log = h2clog; // for renderers
html2canvas.Renderer = {
Canvas: undefined // We are assuming this will be used
};
/*
html2canvas v0.34 <http://html2canvas.hertzen.com>
Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
http://www.twitter.com/niklasvh
Released under MIT License
*/
_html2canvas.Renderer.Canvas = function( options ) {
options = options || {};
var doc = document,
canvas = options.canvas || doc.createElement('canvas'),
usingFlashcanvas = false,
_createCalled = false,
canvasReadyToDraw = false,
methods,
flashMaxSize = 2880; // flash bitmap limited to 2880x2880px // http://stackoverflow.com/questions/2033792/argumenterror-error-2015-invalid-bitmapdata
if (canvas.getContext){
h2clog("html2canvas: Renderer: using canvas renderer");
canvasReadyToDraw = true;
} else if ( options.flashcanvas !== undefined ){
usingFlashcanvas = true;
h2clog("html2canvas: Renderer: canvas not available, using flashcanvas");
var script = doc.createElement("script");
script.src = options.flashcanvas;
script.onload = (function(script, func){
var intervalFunc;
if (script.onload === undefined) {
// IE lack of support for script onload
if( script.onreadystatechange !== undefined ) {
intervalFunc = function() {
if (script.readyState !== "loaded" && script.readyState !== "complete") {
window.setTimeout( intervalFunc, 250 );
} else {
// it is loaded
func();
}
};
window.setTimeout( intervalFunc, 250 );
} else {
h2clog("html2canvas: Renderer: Can't track when flashcanvas is loaded");
}
} else {
return func;
}
})(script, function(){
if (typeof window.FlashCanvas !== "undefined") {
h2clog("html2canvas: Renderer: Flashcanvas initialized");
window.FlashCanvas.initElement( canvas );
canvasReadyToDraw = true;
if ( _createCalled !== false ) {
methods._create.apply( null, _createCalled );
}
}
});
doc.body.appendChild( script );
}
methods = {
_create: function( zStack, options, doc, queue, _html2canvas ) {
if ( !canvasReadyToDraw ) {
_createCalled = arguments;
return canvas;
}
var ctx = canvas.getContext("2d"),
storageContext,
i,
queueLen,
a,
newCanvas,
bounds,
testCanvas = document.createElement("canvas"),
hasCTX = ( testCanvas.getContext !== undefined ),
storageLen,
renderItem,
testctx = ( hasCTX ) ? testCanvas.getContext("2d") : {},
safeImages = [],
fstyle;
canvas.width = canvas.style.width = (!usingFlashcanvas) ? options.width || zStack.ctx.width : Math.min(flashMaxSize, (options.width || zStack.ctx.width) );
canvas.height = canvas.style.height = (!usingFlashcanvas) ? options.height || zStack.ctx.height : Math.min(flashMaxSize, (options.height || zStack.ctx.height) );
fstyle = ctx.fillStyle;
ctx.fillStyle = zStack.backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = fstyle;
if ( options.svgRendering && zStack.svgRender !== undefined ) {
// TODO: enable async rendering to support this
ctx.drawImage( zStack.svgRender, 0, 0 );
} else {
for ( i = 0, queueLen = queue.length; i < queueLen; i+=1 ) {
storageContext = queue.splice(0, 1)[0];
storageContext.canvasPosition = storageContext.canvasPosition || {};
//this.canvasRenderContext(storageContext,parentctx);
// set common settings for canvas
ctx.textBaseline = "bottom";
if (storageContext.clip){
ctx.save();
ctx.beginPath();
// console.log(storageContext);
ctx.rect(storageContext.clip.left, storageContext.clip.top, storageContext.clip.width, storageContext.clip.height);
ctx.clip();
}
if (storageContext.ctx.storage){
for (a = 0, storageLen = storageContext.ctx.storage.length; a < storageLen; a+=1){
renderItem = storageContext.ctx.storage[a];
switch(renderItem.type){
case "variable":
ctx[renderItem.name] = renderItem['arguments'];
break;
case "function":
if (renderItem.name === "fillRect") {
if (!usingFlashcanvas || renderItem['arguments'][0] + renderItem['arguments'][2] < flashMaxSize && renderItem['arguments'][1] + renderItem['arguments'][3] < flashMaxSize) {
ctx.fillRect.apply( ctx, renderItem['arguments'] );
}
}else if(renderItem.name === "fillText") {
if (!usingFlashcanvas || renderItem['arguments'][1] < flashMaxSize && renderItem['arguments'][2] < flashMaxSize) {
ctx.fillText.apply( ctx, renderItem['arguments'] );
}
}else if(renderItem.name === "drawImage") {
if (renderItem['arguments'][8] > 0 && renderItem['arguments'][7]){
if ( hasCTX && options.taintTest ) {
if ( safeImages.indexOf( renderItem['arguments'][ 0 ].src ) === -1 ) {
testctx.drawImage( renderItem['arguments'][ 0 ], 0, 0 );
try {
testctx.getImageData( 0, 0, 1, 1 );
} catch(e) {
testCanvas = doc.createElement("canvas");
testctx = testCanvas.getContext("2d");
continue;
}
safeImages.push( renderItem['arguments'][ 0 ].src );
}
}
ctx.drawImage.apply( ctx, renderItem['arguments'] );
}
}
break;
default:
}
}
}
if (storageContext.clip){
ctx.restore();
}
}
}
h2clog("html2canvas: Renderer: Canvas renderer done - returning canvas obj");
queueLen = options.elements.length;
if (queueLen === 1) {
if (typeof options.elements[ 0 ] === "object" && options.elements[ 0 ].nodeName !== "BODY" && usingFlashcanvas === false) {
// crop image to the bounds of selected (single) element
bounds = _html2canvas.Util.Bounds( options.elements[ 0 ] );
newCanvas = doc.createElement('canvas');
newCanvas.width = bounds.width;
newCanvas.height = bounds.height;
ctx = newCanvas.getContext("2d");
ctx.drawImage( canvas, bounds.left, bounds.top, bounds.width, bounds.height, 0, 0, bounds.width, bounds.height );
canvas = null;
return newCanvas;
}
} /*else {
// TODO clip and resize multiple elements
for ( i = 0; i < queueLen; i+=1 ) {
if (options.elements[ i ] instanceof Element) {
}
}
}
*/
return canvas;
}
};
return methods;
};
window.html2canvas = html2canvas;
}(window, document));
================================================
FILE: javascripts/main.js
================================================
/*global $,glitch,glitchReplace */
$(function(){
var headerContainer = $("#glitch-header").wrap("<div>").parent();
var glitchHeader = function(){
glitch.transition(headerContainer.children(), $("#glitch-header").clone(), {
effect:"slide",
delay: 1000,
complete: function() {
setTimeout(glitchHeader, 1000);
}
});
};
glitchHeader();
});
================================================
FILE: nojquery.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen" />
<link rel="stylesheet" type="text/css" href="stylesheets/pygment_trac.css" media="screen" />
<!-- <link rel="stylesheet" type="text/css" href="stylesheets/print.css" media="print" /> -->
<title>Glitch.js by sjhewitt</title>
<script src="https://raw.github.com/sjhewitt/glitch.js/master/glitch.js"></script>
<script src="javascripts/html2canvas.js"></script>
</head>
<body>
<div class="outer-container">
<header>
<div class="container">
<h1><a href="index.html">Glitch.js</a></h1>
<h2>Glitched DOM elements</h2>
</div>
</header>
<div class="container">
<div id="example1" class="example">
<h1>Glitch an image</h1>
<img class="source" src="images/Lenna.png" style="width: 100%;" />
<div class="middle"><button class="btn">Glitch</button></div>
<div class="target"></div>
</div>
<script>
(function(){
var example1 = document.getElementById('example1');
var btn = example1.getElementsByClassName('btn')[0];
btn.onclick = function(){
glitch(example1.getElementsByClassName('source'), {
complete: function(canvas){
var target = example1.getElementsByClassName('target')[0];
target.appendChild(canvas);
}
});
};
})();
</script>
<div id="example2" class="example">
<h1>Glitch some HTML elements</h1>
<div class="source">
<h2 style="background: #238aa1;">Header Element</h2>
<div>
<input type="text" value="input text" />
</div>
<ul>
<li>List Element 1</li>
<li>List Element 2</li>
<li>List Element 3</li>
<li>List Element 4</li>
</ul>
<button class="btn">Button with rounded corners</button>
</div>
<div class="middle"><button class="btn glitch">Glitch</button></div>
<div class="target"></div>
</div>
<script>
(function(){
var example2 = document.getElementById('example2');
var btn = example2.getElementsByClassName('glitch')[0];
btn.onclick = function(){
glitch.replace(example2.getElementsByClassName('source')[0]);
};
})();
</script>
</div>
</div>
</body>
</html>
================================================
FILE: params.json
================================================
{"body":"### Welcome to Glitch.js\r\nMore info coming soon","tagline":"Glitch transition effect","note":"Don't delete this file! It's used internally to help with page regeneration.","google":"","name":"Glitch.js"}
================================================
FILE: stylesheets/pygment_trac.css
================================================
.highlight .c { color: #999988; font-style: italic } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { font-weight: bold } /* Keyword */
.highlight .o { font-weight: bold } /* Operator */
.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #999999 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { font-weight: bold } /* Keyword.Constant */
.highlight .kd { font-weight: bold } /* Keyword.Declaration */
.highlight .kn { font-weight: bold } /* Keyword.Namespace */
.highlight .kp { font-weight: bold } /* Keyword.Pseudo */
.highlight .kr { font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #009999 } /* Literal.Number */
.highlight .s { color: #d14 } /* Literal.String */
.highlight .na { color: #008080 } /* Name.Attribute */
.highlight .nb { color: #0086B3 } /* Name.Builtin */
.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
.highlight .no { color: #008080 } /* Name.Constant */
.highlight .ni { color: #800080 } /* Name.Entity */
.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
.highlight .nn { color: #555555 } /* Name.Namespace */
.highlight .nt { color: #CBDFFF } /* Name.Tag */
.highlight .nv { color: #008080 } /* Name.Variable */
.highlight .ow { font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #009999 } /* Literal.Number.Float */
.highlight .mh { color: #009999 } /* Literal.Number.Hex */
.highlight .mi { color: #009999 } /* Literal.Number.Integer */
.highlight .mo { color: #009999 } /* Literal.Number.Oct */
.highlight .sb { color: #d14 } /* Literal.String.Backtick */
.highlight .sc { color: #d14 } /* Literal.String.Char */
.highlight .sd { color: #d14 } /* Literal.String.Doc */
.highlight .s2 { color: #d14 } /* Literal.String.Double */
.highlight .se { color: #d14 } /* Literal.String.Escape */
.highlight .sh { color: #d14 } /* Literal.String.Heredoc */
.highlight .si { color: #d14 } /* Literal.String.Interpol */
.highlight .sx { color: #d14 } /* Literal.String.Other */
.highlight .sr { color: #009926 } /* Literal.String.Regex */
.highlight .s1 { color: #d14 } /* Literal.String.Single */
.highlight .ss { color: #990073 } /* Literal.String.Symbol */
.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #008080 } /* Name.Variable.Class */
.highlight .vg { color: #008080 } /* Name.Variable.Global */
.highlight .vi { color: #008080 } /* Name.Variable.Instance */
.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */
.type-csharp .highlight .k { color: #0000FF }
.type-csharp .highlight .kt { color: #0000FF }
.type-csharp .highlight .nf { color: #000000; font-weight: normal }
.type-csharp .highlight .nc { color: #2B91AF }
.type-csharp .highlight .nn { color: #000000 }
.type-csharp .highlight .s { color: #A31515 }
.type-csharp .highlight .sc { color: #A31515 }
================================================
FILE: stylesheets/stylesheet.css
================================================
body {
margin: 0;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
color: #eaeaea;
font: 16px;
line-height: 1.5;
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
}
/* General & 'Reset' Stuff */
.container {
width: 90%;
max-width: 600px;
margin: 0 auto;
}
section {
display: block;
margin: 0 0 20px 0;
}
h1, h2, h3, h4, h5, h6 {
margin: 0 0 20px;
}
li {
line-height: 1.4 ;
}
/* Header, <header>
header - container
h1 - project name
h2 - project description
*/
#glitch-header {
background: #151515 url("../images/bkg.png") 0 0;
margin-bottom: 20px;
}
header {
background: rgba(0, 0, 0, 0.1);
width: 100%;
border-bottom: 1px dashed #b5e853;
padding: 20px 0;
margin: 0 0 40px 0;
}
header h1 {
font-size: 30px;
line-height: 1.5;
margin: 0;
font-weight: bold;
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
color: #b5e853;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1),
0 0 5px rgba(181, 232, 83, 0.1),
0 0 10px rgba(181, 232, 83, 0.1);
letter-spacing: -1px;
-webkit-font-smoothing: antialiased;
}
header h1 a {
color: #b5e853;
text-decoration: none;
}
header h1:before {
content: "./ ";
font-size: 24px;
}
header h2 {
font-size: 18px;
font-weight: 300;
color: #666;
}
#downloads .btn {
display: inline-block;
text-align: center;
margin: 0;
}
/* Main Content
*/
#main_content {
width: 100%;
-webkit-font-smoothing: antialiased;
}
section img {
max-width: 100%
}
h1, h2, h3, h4, h5, h6 {
font-weight: normal;
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
color: #b5e853;
letter-spacing: -0.03em;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1),
0 0 5px rgba(181, 232, 83, 0.1),
0 0 10px rgba(181, 232, 83, 0.1);
}
#main_content h1 {
font-size: 30px;
}
#main_content h2 {
font-size: 24px;
}
#main_content h3 {
font-size: 18px;
}
#main_content h4 {
font-size: 14px;
}
#main_content h5 {
font-size: 12px;
text-transform: uppercase;
margin: 0 0 5px 0;
}
#main_content h6 {
font-size: 12px;
text-transform: uppercase;
color: #999;
margin: 0 0 5px 0;
}
dt {
font-style: italic;
font-weight: bold;
}
ul li {
list-style: none;
}
ul li:before {
content: ">>";
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
font-size: 13px;
color: #b5e853;
margin-left: -37px;
margin-right: 21px;
line-height: 16px;
}
blockquote {
color: #aaa;
padding-left: 10px;
border-left: 1px dotted #666;
}
pre {
background: rgba(0, 0, 0, 0.9);
border: 1px solid rgba(255, 255, 255, 0.15);
padding: 10px;
font-size: 14px;
color: #b5e853;
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
text-wrap: normal;
overflow: auto;
overflow-y: hidden;
}
table {
width: 100%;
margin: 0 0 20px 0;
}
th {
text-align: left;
border-bottom: 1px dashed #b5e853;
padding: 5px 10px;
}
td {
padding: 5px 10px;
}
hr {
height: 0;
border: 0;
border-bottom: 1px dashed #b5e853;
color: #b5e853;
}
/* Buttons
*/
.btn {
display: inline-block;
background: -webkit-linear-gradient(top, rgba(40, 40, 40, 0.3), rgba(35, 35, 35, 0.3) 50%, rgba(10, 10, 10, 0.3) 50%, rgba(0, 0, 0, 0.3));
padding: 8px 18px;
border-radius: 50px;
border: 2px solid rgba(0, 0, 0, 0.7);
border-bottom: 2px solid rgba(0, 0, 0, 0.7);
border-top: 2px solid rgba(0, 0, 0, 1);
color: rgba(255, 255, 255, 0.8);
font-family: Helvetica, Arial, sans-serif;
font-weight: bold;
font-size: 13px;
text-decoration: none;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.75);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.btn:hover {
background: -webkit-linear-gradient(top, rgba(40, 40, 40, 0.6), rgba(35, 35, 35, 0.6) 50%, rgba(10, 10, 10, 0.8) 50%, rgba(0, 0, 0, 0.8));
}
.btn .icon {
display: inline-block;
width: 16px;
height: 16px;
margin: 1px 8px 0 0;
float: left;
}
.btn-github .icon {
opacity: 0.6;
background: url("../images/blacktocat.png") 0 0 no-repeat;
}
/* Links
a, a:hover, a:visited
*/
a {
color: #63c0f5;
text-shadow: 0 0 5px rgba(104, 182, 255, 0.5);
}
/* Clearfix */
.cf:before, .cf:after {
content:"";
display:table;
}
.cf:after {
clear:both;
}
.cf {
zoom:1;
}
.example {
border-bottom: 1px solid #B5E853;
padding-bottom: 10px;
margin-bottom: 10px;
}
.middle {
text-align: center;
}
.middle .btn {
cursor: pointer;
text-transform: uppercase;
font-size: 18px;
}
gitextract_z_57uipc/
├── examples.html
├── index.html
├── javascripts/
│ ├── html2canvas.js
│ └── main.js
├── nojquery.html
├── params.json
└── stylesheets/
├── pygment_trac.css
└── stylesheet.css
SYMBOL INDEX (35 symbols across 1 files)
FILE: javascripts/html2canvas.js
function h2clog (line 25) | function h2clog(a) {
function adjustBounds (line 50) | function adjustBounds(el, box) {
function toPX (line 85) | function toPX( attribute, val ) {
function docSize (line 808) | function docSize(){
function getCSSInt (line 868) | function getCSSInt(element, attribute) {
function renderRect (line 874) | function renderRect (ctx, x, y, w, h, bgcolor) {
function textTransform (line 883) | function textTransform (text, transform) {
function trimText (line 905) | function trimText (text) {
function fontMetrics (line 909) | function fontMetrics (font, fontSize) {
function drawText (line 979) | function drawText(currentText, x, y, ctx){
function renderText (line 987) | function renderText(el, textNode, stack) {
function listPosition (line 1156) | function listPosition (element, val) {
function elementIndex (line 1183) | function elementIndex( el ) {
function renderListItem (line 1201) | function renderListItem(element, stack, elBounds) {
function loadImage (line 1293) | function loadImage (src){
function clipBounds (line 1307) | function clipBounds(src, dst){
function setZ (line 1323) | function setZ(zIndex, parentZ){
function renderBorders (line 1343) | function renderBorders(el, ctx, bounds, clip){
function renderFormValue (line 1432) | function renderFormValue (el, bounds, stack){
function renderImage (line 1489) | function renderImage (ctx, image, sx, sy, sw, sh, dx, dy, dw, dh) {
function renderBackgroundRepeat (line 1506) | function renderBackgroundRepeat (ctx, image, x, y, width, height, elx, e...
function renderBackgroundRepeatY (line 1532) | function renderBackgroundRepeatY (ctx, image, bgp, x, y, w, h){
function renderBackgroundRepeatX (line 1555) | function renderBackgroundRepeatX(ctx, image, bgp, x, y, w, h){
function renderBackground (line 1580) | function renderBackground(el,bounds,ctx){
function renderElement (line 1734) | function renderElement(el, parentStack){
function parseElement (line 1947) | function parseElement (el, stack) {
function parseDOM (line 1988) | function parseDOM( el ) {
function h2czContext (line 2067) | function h2czContext(zindex) {
function isSameOrigin (line 2112) | function isSameOrigin(url){
function start (line 2119) | function start(){
function proxyGetImage (line 2132) | function proxyGetImage(url, img, imageObj){
function getImages (line 2178) | function getImages (el) {
function setImageLoadHandlers (line 2254) | function setImageLoadHandlers(img, imageObj) {
function h2cRenderContext (line 2442) | function h2cRenderContext(width, height) {
function sortZ (line 2491) | function sortZ(zStack){
Condensed preview — 8 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (124K chars).
[
{
"path": "examples.html",
"chars": 7197,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset='utf-8'>\n <meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\">\n\n "
},
{
"path": "index.html",
"chars": 1787,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset='utf-8'>\n <meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\">\n\n "
},
{
"path": "javascripts/html2canvas.js",
"chars": 94984,
"preview": "/**\r\n @license html2canvas v0.34 <http://html2canvas.hertzen.com>\r\n Copyright (c) 2011 Niklas von Hertzen. All rights "
},
{
"path": "javascripts/main.js",
"chars": 359,
"preview": "/*global $,glitch,glitchReplace */\n$(function(){\n\tvar headerContainer = $(\"#glitch-header\").wrap(\"<div>\").parent();\n\tvar"
},
{
"path": "nojquery.html",
"chars": 2261,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset='utf-8'>\n <meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\">\n\n "
},
{
"path": "params.json",
"chars": 214,
"preview": "{\"body\":\"### Welcome to Glitch.js\\r\\nMore info coming soon\",\"tagline\":\"Glitch transition effect\",\"note\":\"Don't delete th"
},
{
"path": "stylesheets/pygment_trac.css",
"chars": 4131,
"preview": ".highlight .c { color: #999988; font-style: italic } /* Comment */\n.highlight .err { color: #a61717; background-color: #"
},
{
"path": "stylesheets/stylesheet.css",
"chars": 4651,
"preview": "body {\n margin: 0;\n padding: 0;\n background: #151515 url(\"../images/bkg.png\") 0 0;\n color: #eaeaea;\n font: 16px;\n "
}
]
About this extraction
This page contains the full source code of the sjhewitt/glitch.js GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 8 files (112.9 KB), approximately 26.6k tokens, and a symbol index with 35 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.