├── .editorconfig
├── .gitattributes
├── .gitignore
├── 404.php
├── LICENSE.md
├── composer.json
├── contact.php
├── docs.php
├── download.php
├── favicon.ico
├── humans.txt
├── index.php
├── public
├── css
│ └── app.css
└── js
│ ├── app.js
│ └── html2canvas.js
├── readme.md
├── robots.txt
├── src
└── helpers.php
└── views
├── analytics.php
├── fonts.php
├── footer.php
├── header.php
└── icons.php
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | indent_size = 4
8 | indent_style = space
9 | insert_final_newline = true
10 | trim_trailing_whitespace = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | .htaccess
--------------------------------------------------------------------------------
/404.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
404
9 | The page requested does not exist!
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 Dammyammy [dami@ogunmoye.com] & RasBan [rasban037@gmail.com]
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dammyammy/logo-generator",
3 | "description": "The Logo Generator.",
4 | "keywords": ["Logo Generator"],
5 | "license": "MIT",
6 | "type": "project",
7 | "author": "",
8 | "autoload": {
9 | "files": [
10 | "src/helpers.php"
11 | ]
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/contact.php:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
14 |
15 |
16 |
17 |
23 |
24 |
--------------------------------------------------------------------------------
/docs.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
15 |
16 |
17 |
22 |
23 |
--------------------------------------------------------------------------------
/download.php:
--------------------------------------------------------------------------------
1 |
11 |
12 | Here is your awesome logo ready for download.
13 |
14 |
15 |
16 |
17 |
22 |
23 |
49 |
50 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dammyammy/logo-generator/8fa592eeff8e8c36958f8676aadde57517f1d735/favicon.ico
--------------------------------------------------------------------------------
/humans.txt:
--------------------------------------------------------------------------------
1 | humans.txt
2 |
3 | # humanstxt.org/
4 | # The humans responsible & technology colophon
5 |
6 | # TEAM
7 |
8 | -- -- <@DOsAHandle>
9 | -- -- <@RasBanXclusive>
10 |
11 | # TECHNOLOGY COLOPHON
12 |
13 | HTML5, CSS3
14 | jQuery, PHP
15 | HTML2Canvas, AlertifyJS
16 | Bootstrap 3, FontAwesome
17 | Google Web Fonts
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
Generate your awesome logo.
12 |
13 |
14 |
Simply edit text, add your own colours, fonts & Instantly download it all for free.
15 |
16 |
62 |
63 |
70 |
71 |
72 |
73 | Preview Logo
74 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/public/css/app.css:
--------------------------------------------------------------------------------
1 | /* MailChimp Form Embed Code - Classic - 08/17/2011 */
2 | #mc_embed_signup form {display:block; position:relative; text-align:left; padding:10px 0 10px 3%}
3 | #mc_embed_signup h2 {font-weight:bold; padding:0; margin:15px 0; font-size:1.4em;}
4 | #mc_embed_signup input {border:1px solid #999; -webkit-appearance:none;}
5 | #mc_embed_signup input[type=checkbox]{-webkit-appearance:checkbox;}
6 | #mc_embed_signup input[type=radio]{-webkit-appearance:radio;}
7 | #mc_embed_signup input:focus {border-color:#333;}
8 | #mc_embed_signup .button {clear:both; background-color: #aaa; border: 0 none; border-radius:4px; color: #FFFFFF; cursor: pointer; display: inline-block; font-size:15px; font-weight: bold; height: 32px; line-height: 32px; margin: 0 5px 10px 0; padding: 0 22px; text-align: center; text-decoration: none; vertical-align: top; white-space: nowrap; width: auto;}
9 | #mc_embed_signup .button:hover {background-color:#777;}
10 | #mc_embed_signup .small-meta {font-size: 11px;}
11 | #mc_embed_signup .nowrap {white-space:nowrap;}
12 |
13 | #mc_embed_signup .mc-field-group {clear:left; position:relative; width:96%; padding-bottom:3%; min-height:50px;}
14 | #mc_embed_signup .size1of2 {clear:none; float:left; display:inline-block; width:46%; margin-right:4%;}
15 | * html #mc_embed_signup .size1of2 {margin-right:2%; /* Fix for IE6 double margins. */}
16 | #mc_embed_signup .mc-field-group label {display:block; margin-bottom:3px;}
17 | #mc_embed_signup .mc-field-group input {display:block; width:100%; padding:8px 0; text-indent:2%;}
18 | #mc_embed_signup .mc-field-group select {display:inline-block; width:99%; padding:5px 0; margin-bottom:2px;}
19 |
20 | #mc_embed_signup .indicates-required {text-align:right; font-size:11px; margin-right:4%;}
21 | #mc_embed_signup .asterisk {color:#c60; font-size:200%;}
22 | #mc_embed_signup .mc-field-group .asterisk {position:absolute; top:25px; right:10px;}
23 | #mc_embed_signup .clear {clear:both;}
24 |
25 | #mc_embed_signup .mc-field-group.input-group ul {margin:0; padding:5px 0; list-style:none;}
26 | #mc_embed_signup .mc-field-group.input-group ul li {display:block; padding:3px 0; margin:0;}
27 | #mc_embed_signup .mc-field-group.input-group label {display:inline;}
28 | #mc_embed_signup .mc-field-group.input-group input {display:inline; width:auto; border:none;}
29 |
30 | #mc_embed_signup div#mce-responses {float:left; top:-1.4em; padding:0em .5em 0em .5em; overflow:hidden; width:90%;margin: 0 5%; clear: both;}
31 | #mc_embed_signup div.response {margin:1em 0; padding:1em .5em .5em 0; font-weight:bold; float:left; top:-1.5em; z-index:1; width:80%;}
32 | #mc_embed_signup #mce-error-response {display:none;}
33 | #mc_embed_signup #mce-success-response {color:#529214; display:none;}
34 | #mc_embed_signup label.error {display:block; float:none; width:auto; margin-left:1.05em; text-align:left; padding:.5em 0;}
35 |
36 | #mc-embedded-subscribe {clear:both; width:auto; display:block; margin:1em 0 1em 5%;}
37 | #mc_embed_signup #num-subscribers {font-size:1.1em;}
38 | #mc_embed_signup #num-subscribers span {padding:.5em; border:1px solid #ccc; margin-right:.5em; font-weight:bold;}
39 |
40 | #mc_embed_signup{background:#fff; clear:left; font:16px 'Archivo Narrow', sans-serif; }
41 | /*
42 | * Globals
43 | */
44 |
45 | /* Links */
46 | a,
47 | a:focus,
48 | a:hover {
49 | color: #333;
50 | }
51 |
52 | /* Custom default button */
53 | .btn-default,
54 | .btn-default:hover,
55 | .btn-default:focus {
56 | color: #fff;
57 | text-shadow: none; /* Prevent inheritence from `body` */
58 | background-color: #333;
59 | border: 1px solid #333;
60 | }
61 |
62 |
63 | /*
64 | * Base structure
65 | */
66 |
67 | html,
68 | body {
69 | height: 100%;
70 | background-color: #fff;
71 | }
72 | body {
73 | color: #333;
74 | text-align: center;
75 | /*text-shadow: 0 1px 3px rgba(0,0,0,.5);*/
76 | font-family: 'Archivo Narrow', sans-serif;
77 | }
78 |
79 | /* Extra markup and styles for table-esque vertical and horizontal centering */
80 | .site-wrapper {
81 | display: table;
82 | width: 100%;
83 | height: 100%; /* For at least Firefox */
84 | min-height: 100%;
85 | }
86 | .site-wrapper-inner {
87 | display: table-cell;
88 | vertical-align: top;
89 | }
90 | .cover-container {
91 | margin-right: auto;
92 | margin-left: auto;
93 | }
94 |
95 | /* Padding for spacing */
96 | .inner {
97 | padding: 30px;
98 | }
99 |
100 |
101 | /*
102 | * Header
103 | */
104 | .masthead-brand {
105 | margin-top: 10px;
106 | margin-bottom: 10px;
107 | }
108 |
109 | .masthead-nav > li {
110 | display: inline-block;
111 | }
112 | .masthead-nav > li + li {
113 | margin-left: 20px;
114 | }
115 | .masthead-nav > li > a {
116 | padding-right: 0;
117 | padding-left: 0;
118 | font-size: 16px;
119 | font-weight: bold;
120 | color: #333; /* IE8 proofing */
121 | /*color: rgba(255,255,255,.75);*/
122 | border-bottom: 2px solid transparent;
123 | }
124 | .masthead-nav > li > a:hover,
125 | .masthead-nav > li > a:focus {
126 | background-color: transparent;
127 | border-bottom-color: #a9a9a9;
128 | border-bottom-color: rgba(255,255,255,.25);
129 | }
130 | .masthead-nav > .active > a,
131 | .masthead-nav > .active > a:hover,
132 | .masthead-nav > .active > a:focus {
133 | color: #333;
134 | border-bottom-color: #333;
135 | }
136 |
137 | @media (min-width: 768px) {
138 | .masthead-brand {
139 | float: left;
140 | }
141 | .masthead-nav {
142 | float: right;
143 | }
144 | }
145 |
146 | /*
147 | * Cover
148 | */
149 |
150 | .cover {
151 | padding: 0 20px;
152 | }
153 | .cover .btn-lg {
154 | padding: 10px 20px;
155 | font-weight: bold;
156 | }
157 |
158 | /*
159 | * Footer
160 | */
161 |
162 | .mastfoot {
163 | bottom: 0;
164 | color: #999; /* IE8 proofing */
165 | color: rgba(255,255,255,.5);
166 | }
167 |
168 |
169 | /*
170 | * Affix and center
171 | */
172 |
173 | @media (min-width: 768px) {
174 | /* Pull out the header and footer */
175 | .masthead {
176 | position: fixed;
177 | top: 0;
178 | }
179 | .mastfoot {
180 | position: relative;
181 | bottom: 0;
182 | }
183 | /* Start the vertical centering */
184 | .site-wrapper-inner {
185 | vertical-align: middle;
186 | }
187 | /* Handle the widths */
188 | .masthead,
189 | .mastfoot,
190 | .cover-container {
191 | width: 100%; /* Must be percentage or pixels for horizontal alignment */
192 | }
193 | }
194 |
195 | @media (min-width: 992px) {
196 | .masthead,
197 | .mastfoot,
198 | .cover-container {
199 | width: 100%;
200 | }
201 | }
202 |
203 | .pt30 { padding-top: 30px;}
204 | .pb30 { padding-bottom: 30px;}
205 |
206 | #logo-output {
207 | color: #000 !important;
208 | padding-left: 1rem;
209 | padding-right: 1rem;
210 | font-size: 46px;
211 | font-weight: bold;
212 | letter-spacing: -0.035em;
213 | text-transform: none;
214 | font-family: 'Advent Pro', sans-serif;
215 | color: #6d6e70;
216 | background: transparent !important;
217 | padding-top: 3rem;
218 | margin-bottom: 20px;
219 | width: 400px;
220 | top: 0;
221 | left: 0;
222 | vertical-align: middle;
223 | }
224 |
225 | .icon {
226 | vertical-align: top;
227 | height: 25px !important;
228 | width: 25px !important;
229 | font-size: 25px !important;
230 | margin: 5px 0 0 0px;
231 | }
232 |
233 | .btn-max {
234 | background-color: transparent !important;
235 | text-transform: uppercase;
236 | border-radius: 0 !important;
237 | border: 3px #333 solid !important;
238 | vertical-align: middle;
239 | }
240 |
241 | .btn-max:hover {
242 | color: #f9f9f9;
243 | background: #333 !important;
244 | border: 3px #fff solid !important;
245 | }
246 |
247 | .btn-max:visited, .btn-max:active, .btn-max:focus { color: #333 !important;}
248 |
249 | input, select {
250 | width: auto;
251 | height: 42px !important;
252 | font-size: 32px;
253 | }
254 |
255 | input[type="text"] {
256 | width: auto;
257 | height: 50px !important;
258 | border: 2px #000 solid;
259 | font-size: 32px;
260 | }
261 |
262 | #credits {
263 | color: #333 !important;
264 | }
265 |
266 | #credits a {
267 | color: #333 !important;
268 | font-weight: bold;
269 | }
270 |
271 | #credits a:hover {
272 | color: blue !important;
273 | font-weight: bold;
274 | }
275 | .error404 { font-size: 14rem !important; font-weight: bold; color: #fd5c63 !important;}
276 |
277 | small { font-size: 2rem;}
--------------------------------------------------------------------------------
/public/js/app.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var icon = $('#icon');
3 | var name = $('input[name=logo-name]');
4 | var iconColor = $('input[name=icon-color]');
5 | var secondaryColor = $('input[name=secondary-color]');
6 | var baseColor = $('input[name=base-color]');
7 | var font = $('select[name=font]');
8 |
9 | icon.bind('change keyup', function (e) {
10 | $('#icon-output').html(' ' );
11 | $('#icon-output > i.icon').css('color', iconColor.val());
12 | });
13 |
14 | iconColor.on('change', function (event) {
15 | $('#icon-output > i.icon').css('color', iconColor.val());
16 | alertify.success('Icon Color Successfully Changed to ' + iconColor.val());
17 | });
18 |
19 | baseColor.on('change', function () {
20 | $('#logo-output > p').css('color', baseColor.val());
21 | alertify.success('Base Color Successfully Changed to ' + baseColor.val());
22 | });
23 |
24 | secondaryColor.bind('change', function () {
25 | var color = secondaryColor.val();
26 | var oldname = $('#logo-output > p');
27 | var oldlogo = $('#icon-output').html();
28 |
29 | alertify.prompt('Type the letter(s) you wish to apply the secondary color to e.g. Rite in HireRite!')
30 | .set('labels', {ok:'Change Color!', cancel:'Naa!'})
31 | .set('title', 'Apply Secondary Color to Logo!')
32 | .set('onok', function(closeEvent) {
33 | var input = $('.ajs-input').val();
34 | oldlogo = '' + oldlogo + ' ';
35 |
36 | oldname.html(function () {
37 | var withSpan = '' + input + ' ';
38 | return $(this).html().replace(input, withSpan);
39 | });
40 | alertify.success('Secondary Color changed to ' + color + ' for text ' + input);
41 | } );
42 | });
43 |
44 | name.on('keyup', function () {
45 | var newname = name.val() + '' + ' ';
46 | $('#logo-output > p').html( newname );
47 | });
48 |
49 | $('button#preview').on('click', function () {
50 | html2canvas(document.getElementById('logo-output'), {
51 | letterRendering: true,
52 | background: undefined,
53 | onrendered: function(canvas) {
54 | document.getElementById('img_val').value = canvas.toDataURL("image/png");
55 | document.getElementById("downloader").submit();
56 | }
57 | });
58 | alertify.success(' Please Wait... ');
59 | });
60 |
61 | font.bind('change keyup', function () {
62 | $('#logo-output > p').css('font-family', font.val());
63 | alertify.success('Font Successfully Changed!');
64 | });
65 | })(jQuery);
--------------------------------------------------------------------------------
/public/js/html2canvas.js:
--------------------------------------------------------------------------------
1 | /*
2 | html2canvas 0.5.0-alpha1
3 | Copyright (c) 2015 Niklas von Hertzen
4 |
5 | Released under MIT License
6 | */
7 |
8 | (function(window, document, exports, global, define, undefined){
9 |
10 | /*!
11 | * @overview es6-promise - a tiny implementation of Promises/A+.
12 | * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
13 | * @license Licensed under MIT license
14 | * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE
15 | * @version 2.0.1
16 | */
17 |
18 | (function(){function r(a,b){n[l]=a;n[l+1]=b;l+=2;2===l&&A()}function s(a){return"function"===typeof a}function F(){return function(){process.nextTick(t)}}function G(){var a=0,b=new B(t),c=document.createTextNode("");b.observe(c,{characterData:!0});return function(){c.data=a=++a%2}}function H(){var a=new MessageChannel;a.port1.onmessage=t;return function(){a.port2.postMessage(0)}}function I(){return function(){setTimeout(t,1)}}function t(){for(var a=0;a= 0x80 (not a basic code point)',
86 | 'invalid-input': 'Invalid input'
87 | },
88 |
89 | /** Convenience shortcuts */
90 | baseMinusTMin = base - tMin,
91 | floor = Math.floor,
92 | stringFromCharCode = String.fromCharCode,
93 |
94 | /** Temporary variable */
95 | key;
96 |
97 | /*--------------------------------------------------------------------------*/
98 |
99 | /**
100 | * A generic error utility function.
101 | * @private
102 | * @param {String} type The error type.
103 | * @returns {Error} Throws a `RangeError` with the applicable error message.
104 | */
105 | function error(type) {
106 | throw RangeError(errors[type]);
107 | }
108 |
109 | /**
110 | * A generic `Array#map` utility function.
111 | * @private
112 | * @param {Array} array The array to iterate over.
113 | * @param {Function} callback The function that gets called for every array
114 | * item.
115 | * @returns {Array} A new array of values returned by the callback function.
116 | */
117 | function map(array, fn) {
118 | var length = array.length;
119 | var result = [];
120 | while (length--) {
121 | result[length] = fn(array[length]);
122 | }
123 | return result;
124 | }
125 |
126 | /**
127 | * A simple `Array#map`-like wrapper to work with domain name strings or email
128 | * addresses.
129 | * @private
130 | * @param {String} domain The domain name or email address.
131 | * @param {Function} callback The function that gets called for every
132 | * character.
133 | * @returns {Array} A new string of characters returned by the callback
134 | * function.
135 | */
136 | function mapDomain(string, fn) {
137 | var parts = string.split('@');
138 | var result = '';
139 | if (parts.length > 1) {
140 | // In email addresses, only the domain name should be punycoded. Leave
141 | // the local part (i.e. everything up to `@`) intact.
142 | result = parts[0] + '@';
143 | string = parts[1];
144 | }
145 | var labels = string.split(regexSeparators);
146 | var encoded = map(labels, fn).join('.');
147 | return result + encoded;
148 | }
149 |
150 | /**
151 | * Creates an array containing the numeric code points of each Unicode
152 | * character in the string. While JavaScript uses UCS-2 internally,
153 | * this function will convert a pair of surrogate halves (each of which
154 | * UCS-2 exposes as separate characters) into a single code point,
155 | * matching UTF-16.
156 | * @see `punycode.ucs2.encode`
157 | * @see
158 | * @memberOf punycode.ucs2
159 | * @name decode
160 | * @param {String} string The Unicode input string (UCS-2).
161 | * @returns {Array} The new array of code points.
162 | */
163 | function ucs2decode(string) {
164 | var output = [],
165 | counter = 0,
166 | length = string.length,
167 | value,
168 | extra;
169 | while (counter < length) {
170 | value = string.charCodeAt(counter++);
171 | if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
172 | // high surrogate, and there is a next character
173 | extra = string.charCodeAt(counter++);
174 | if ((extra & 0xFC00) == 0xDC00) { // low surrogate
175 | output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
176 | } else {
177 | // unmatched surrogate; only append this code unit, in case the next
178 | // code unit is the high surrogate of a surrogate pair
179 | output.push(value);
180 | counter--;
181 | }
182 | } else {
183 | output.push(value);
184 | }
185 | }
186 | return output;
187 | }
188 |
189 | /**
190 | * Creates a string based on an array of numeric code points.
191 | * @see `punycode.ucs2.decode`
192 | * @memberOf punycode.ucs2
193 | * @name encode
194 | * @param {Array} codePoints The array of numeric code points.
195 | * @returns {String} The new Unicode string (UCS-2).
196 | */
197 | function ucs2encode(array) {
198 | return map(array, function(value) {
199 | var output = '';
200 | if (value > 0xFFFF) {
201 | value -= 0x10000;
202 | output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
203 | value = 0xDC00 | value & 0x3FF;
204 | }
205 | output += stringFromCharCode(value);
206 | return output;
207 | }).join('');
208 | }
209 |
210 | /**
211 | * Converts a basic code point into a digit/integer.
212 | * @see `digitToBasic()`
213 | * @private
214 | * @param {Number} codePoint The basic numeric code point value.
215 | * @returns {Number} The numeric value of a basic code point (for use in
216 | * representing integers) in the range `0` to `base - 1`, or `base` if
217 | * the code point does not represent a value.
218 | */
219 | function basicToDigit(codePoint) {
220 | if (codePoint - 48 < 10) {
221 | return codePoint - 22;
222 | }
223 | if (codePoint - 65 < 26) {
224 | return codePoint - 65;
225 | }
226 | if (codePoint - 97 < 26) {
227 | return codePoint - 97;
228 | }
229 | return base;
230 | }
231 |
232 | /**
233 | * Converts a digit/integer into a basic code point.
234 | * @see `basicToDigit()`
235 | * @private
236 | * @param {Number} digit The numeric value of a basic code point.
237 | * @returns {Number} The basic code point whose value (when used for
238 | * representing integers) is `digit`, which needs to be in the range
239 | * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
240 | * used; else, the lowercase form is used. The behavior is undefined
241 | * if `flag` is non-zero and `digit` has no uppercase form.
242 | */
243 | function digitToBasic(digit, flag) {
244 | // 0..25 map to ASCII a..z or A..Z
245 | // 26..35 map to ASCII 0..9
246 | return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
247 | }
248 |
249 | /**
250 | * Bias adaptation function as per section 3.4 of RFC 3492.
251 | * http://tools.ietf.org/html/rfc3492#section-3.4
252 | * @private
253 | */
254 | function adapt(delta, numPoints, firstTime) {
255 | var k = 0;
256 | delta = firstTime ? floor(delta / damp) : delta >> 1;
257 | delta += floor(delta / numPoints);
258 | for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
259 | delta = floor(delta / baseMinusTMin);
260 | }
261 | return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
262 | }
263 |
264 | /**
265 | * Converts a Punycode string of ASCII-only symbols to a string of Unicode
266 | * symbols.
267 | * @memberOf punycode
268 | * @param {String} input The Punycode string of ASCII-only symbols.
269 | * @returns {String} The resulting string of Unicode symbols.
270 | */
271 | function decode(input) {
272 | // Don't use UCS-2
273 | var output = [],
274 | inputLength = input.length,
275 | out,
276 | i = 0,
277 | n = initialN,
278 | bias = initialBias,
279 | basic,
280 | j,
281 | index,
282 | oldi,
283 | w,
284 | k,
285 | digit,
286 | t,
287 | /** Cached calculation results */
288 | baseMinusT;
289 |
290 | // Handle the basic code points: let `basic` be the number of input code
291 | // points before the last delimiter, or `0` if there is none, then copy
292 | // the first basic code points to the output.
293 |
294 | basic = input.lastIndexOf(delimiter);
295 | if (basic < 0) {
296 | basic = 0;
297 | }
298 |
299 | for (j = 0; j < basic; ++j) {
300 | // if it's not a basic code point
301 | if (input.charCodeAt(j) >= 0x80) {
302 | error('not-basic');
303 | }
304 | output.push(input.charCodeAt(j));
305 | }
306 |
307 | // Main decoding loop: start just after the last delimiter if any basic code
308 | // points were copied; start at the beginning otherwise.
309 |
310 | for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
311 |
312 | // `index` is the index of the next character to be consumed.
313 | // Decode a generalized variable-length integer into `delta`,
314 | // which gets added to `i`. The overflow checking is easier
315 | // if we increase `i` as we go, then subtract off its starting
316 | // value at the end to obtain `delta`.
317 | for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
318 |
319 | if (index >= inputLength) {
320 | error('invalid-input');
321 | }
322 |
323 | digit = basicToDigit(input.charCodeAt(index++));
324 |
325 | if (digit >= base || digit > floor((maxInt - i) / w)) {
326 | error('overflow');
327 | }
328 |
329 | i += digit * w;
330 | t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
331 |
332 | if (digit < t) {
333 | break;
334 | }
335 |
336 | baseMinusT = base - t;
337 | if (w > floor(maxInt / baseMinusT)) {
338 | error('overflow');
339 | }
340 |
341 | w *= baseMinusT;
342 |
343 | }
344 |
345 | out = output.length + 1;
346 | bias = adapt(i - oldi, out, oldi == 0);
347 |
348 | // `i` was supposed to wrap around from `out` to `0`,
349 | // incrementing `n` each time, so we'll fix that now:
350 | if (floor(i / out) > maxInt - n) {
351 | error('overflow');
352 | }
353 |
354 | n += floor(i / out);
355 | i %= out;
356 |
357 | // Insert `n` at position `i` of the output
358 | output.splice(i++, 0, n);
359 |
360 | }
361 |
362 | return ucs2encode(output);
363 | }
364 |
365 | /**
366 | * Converts a string of Unicode symbols (e.g. a domain name label) to a
367 | * Punycode string of ASCII-only symbols.
368 | * @memberOf punycode
369 | * @param {String} input The string of Unicode symbols.
370 | * @returns {String} The resulting Punycode string of ASCII-only symbols.
371 | */
372 | function encode(input) {
373 | var n,
374 | delta,
375 | handledCPCount,
376 | basicLength,
377 | bias,
378 | j,
379 | m,
380 | q,
381 | k,
382 | t,
383 | currentValue,
384 | output = [],
385 | /** `inputLength` will hold the number of code points in `input`. */
386 | inputLength,
387 | /** Cached calculation results */
388 | handledCPCountPlusOne,
389 | baseMinusT,
390 | qMinusT;
391 |
392 | // Convert the input in UCS-2 to Unicode
393 | input = ucs2decode(input);
394 |
395 | // Cache the length
396 | inputLength = input.length;
397 |
398 | // Initialize the state
399 | n = initialN;
400 | delta = 0;
401 | bias = initialBias;
402 |
403 | // Handle the basic code points
404 | for (j = 0; j < inputLength; ++j) {
405 | currentValue = input[j];
406 | if (currentValue < 0x80) {
407 | output.push(stringFromCharCode(currentValue));
408 | }
409 | }
410 |
411 | handledCPCount = basicLength = output.length;
412 |
413 | // `handledCPCount` is the number of code points that have been handled;
414 | // `basicLength` is the number of basic code points.
415 |
416 | // Finish the basic string - if it is not empty - with a delimiter
417 | if (basicLength) {
418 | output.push(delimiter);
419 | }
420 |
421 | // Main encoding loop:
422 | while (handledCPCount < inputLength) {
423 |
424 | // All non-basic code points < n have been handled already. Find the next
425 | // larger one:
426 | for (m = maxInt, j = 0; j < inputLength; ++j) {
427 | currentValue = input[j];
428 | if (currentValue >= n && currentValue < m) {
429 | m = currentValue;
430 | }
431 | }
432 |
433 | // Increase `delta` enough to advance the decoder's state to ,
434 | // but guard against overflow
435 | handledCPCountPlusOne = handledCPCount + 1;
436 | if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
437 | error('overflow');
438 | }
439 |
440 | delta += (m - n) * handledCPCountPlusOne;
441 | n = m;
442 |
443 | for (j = 0; j < inputLength; ++j) {
444 | currentValue = input[j];
445 |
446 | if (currentValue < n && ++delta > maxInt) {
447 | error('overflow');
448 | }
449 |
450 | if (currentValue == n) {
451 | // Represent delta as a generalized variable-length integer
452 | for (q = delta, k = base; /* no condition */; k += base) {
453 | t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
454 | if (q < t) {
455 | break;
456 | }
457 | qMinusT = q - t;
458 | baseMinusT = base - t;
459 | output.push(
460 | stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
461 | );
462 | q = floor(qMinusT / baseMinusT);
463 | }
464 |
465 | output.push(stringFromCharCode(digitToBasic(q, 0)));
466 | bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
467 | delta = 0;
468 | ++handledCPCount;
469 | }
470 | }
471 |
472 | ++delta;
473 | ++n;
474 |
475 | }
476 | return output.join('');
477 | }
478 |
479 | /**
480 | * Converts a Punycode string representing a domain name or an email address
481 | * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
482 | * it doesn't matter if you call it on a string that has already been
483 | * converted to Unicode.
484 | * @memberOf punycode
485 | * @param {String} input The Punycoded domain name or email address to
486 | * convert to Unicode.
487 | * @returns {String} The Unicode representation of the given Punycode
488 | * string.
489 | */
490 | function toUnicode(input) {
491 | return mapDomain(input, function(string) {
492 | return regexPunycode.test(string)
493 | ? decode(string.slice(4).toLowerCase())
494 | : string;
495 | });
496 | }
497 |
498 | /**
499 | * Converts a Unicode string representing a domain name or an email address to
500 | * Punycode. Only the non-ASCII parts of the domain name will be converted,
501 | * i.e. it doesn't matter if you call it with a domain that's already in
502 | * ASCII.
503 | * @memberOf punycode
504 | * @param {String} input The domain name or email address to convert, as a
505 | * Unicode string.
506 | * @returns {String} The Punycode representation of the given domain name or
507 | * email address.
508 | */
509 | function toASCII(input) {
510 | return mapDomain(input, function(string) {
511 | return regexNonASCII.test(string)
512 | ? 'xn--' + encode(string)
513 | : string;
514 | });
515 | }
516 |
517 | /*--------------------------------------------------------------------------*/
518 |
519 | /** Define the public API */
520 | punycode = {
521 | /**
522 | * A string representing the current Punycode.js version number.
523 | * @memberOf punycode
524 | * @type String
525 | */
526 | 'version': '1.3.1',
527 | /**
528 | * An object of methods to convert from JavaScript's internal character
529 | * representation (UCS-2) to Unicode code points, and back.
530 | * @see
531 | * @memberOf punycode
532 | * @type Object
533 | */
534 | 'ucs2': {
535 | 'decode': ucs2decode,
536 | 'encode': ucs2encode
537 | },
538 | 'decode': decode,
539 | 'encode': encode,
540 | 'toASCII': toASCII,
541 | 'toUnicode': toUnicode
542 | };
543 |
544 | /** Expose `punycode` */
545 | // Some AMD build optimizers, like r.js, check for specific condition patterns
546 | // like the following:
547 | if (
548 | typeof define == 'function' &&
549 | typeof define.amd == 'object' &&
550 | define.amd
551 | ) {
552 | define('punycode', function() {
553 | return punycode;
554 | });
555 | } else if (freeExports && freeModule) {
556 | if (module.exports == freeExports) { // in Node.js or RingoJS v0.8.0+
557 | freeModule.exports = punycode;
558 | } else { // in Narwhal or RingoJS v0.7.0-
559 | for (key in punycode) {
560 | punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
561 | }
562 | }
563 | } else { // in Rhino or a web browser
564 | root.punycode = punycode;
565 | }
566 |
567 | }(this));
568 |
569 | var html2canvasNodeAttribute = "data-html2canvas-node";
570 | var html2canvasCanvasCloneAttribute = "data-html2canvas-canvas-clone";
571 | var html2canvasCanvasCloneIndex = 0;
572 | var html2canvasCloneIndex = 0;
573 |
574 | window.html2canvas = function(nodeList, options) {
575 | var index = html2canvasCloneIndex++;
576 | options = options || {};
577 | if (options.logging) {
578 | window.html2canvas.logging = true;
579 | window.html2canvas.start = Date.now();
580 | }
581 |
582 | options.async = typeof(options.async) === "undefined" ? true : options.async;
583 | options.allowTaint = typeof(options.allowTaint) === "undefined" ? false : options.allowTaint;
584 | options.removeContainer = typeof(options.removeContainer) === "undefined" ? true : options.removeContainer;
585 | options.javascriptEnabled = typeof(options.javascriptEnabled) === "undefined" ? false : options.javascriptEnabled;
586 | options.imageTimeout = typeof(options.imageTimeout) === "undefined" ? 10000 : options.imageTimeout;
587 | options.renderer = typeof(options.renderer) === "function" ? options.renderer : CanvasRenderer;
588 | options.strict = !!options.strict;
589 |
590 | if (typeof(nodeList) === "string") {
591 | if (typeof(options.proxy) !== "string") {
592 | return Promise.reject("Proxy must be used when rendering url");
593 | }
594 | var width = options.width != null ? options.width : window.innerWidth;
595 | var height = options.height != null ? options.height : window.innerHeight;
596 | return loadUrlDocument(absoluteUrl(nodeList), options.proxy, document, width, height, options).then(function(container) {
597 | return renderWindow(container.contentWindow.document.documentElement, container, options, width, height);
598 | });
599 | }
600 |
601 | var node = ((nodeList === undefined) ? [document.documentElement] : ((nodeList.length) ? nodeList : [nodeList]))[0];
602 | node.setAttribute(html2canvasNodeAttribute + index, index);
603 | return renderDocument(node.ownerDocument, options, node.ownerDocument.defaultView.innerWidth, node.ownerDocument.defaultView.innerHeight, index).then(function(canvas) {
604 | if (typeof(options.onrendered) === "function") {
605 | log("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas");
606 | options.onrendered(canvas);
607 | }
608 | return canvas;
609 | });
610 | };
611 |
612 | window.html2canvas.punycode = this.punycode;
613 | window.html2canvas.proxy = {};
614 |
615 | function renderDocument(document, options, windowWidth, windowHeight, html2canvasIndex) {
616 | return createWindowClone(document, document, windowWidth, windowHeight, options, document.defaultView.pageXOffset, document.defaultView.pageYOffset).then(function(container) {
617 | log("Document cloned");
618 | var attributeName = html2canvasNodeAttribute + html2canvasIndex;
619 | var selector = "[" + attributeName + "='" + html2canvasIndex + "']";
620 | document.querySelector(selector).removeAttribute(attributeName);
621 | var clonedWindow = container.contentWindow;
622 | var node = clonedWindow.document.querySelector(selector);
623 | var oncloneHandler = (typeof(options.onclone) === "function") ? Promise.resolve(options.onclone(clonedWindow.document)) : Promise.resolve(true);
624 | return oncloneHandler.then(function() {
625 | return renderWindow(node, container, options, windowWidth, windowHeight);
626 | });
627 | });
628 | }
629 |
630 | function renderWindow(node, container, options, windowWidth, windowHeight) {
631 | var clonedWindow = container.contentWindow;
632 | var support = new Support(clonedWindow.document);
633 | var imageLoader = new ImageLoader(options, support);
634 | var bounds = getBounds(node);
635 | var width = options.type === "view" ? windowWidth : documentWidth(clonedWindow.document);
636 | var height = options.type === "view" ? windowHeight : documentHeight(clonedWindow.document);
637 | var renderer = new options.renderer(width, height, imageLoader, options, document);
638 | var parser = new NodeParser(node, renderer, support, imageLoader, options);
639 | return parser.ready.then(function() {
640 | log("Finished rendering");
641 | var canvas;
642 |
643 | if (options.type === "view") {
644 | canvas = crop(renderer.canvas, {width: renderer.canvas.width, height: renderer.canvas.height, top: 0, left: 0, x: 0, y: 0});
645 | } else if (node === clonedWindow.document.body || node === clonedWindow.document.documentElement || options.canvas != null) {
646 | canvas = renderer.canvas;
647 | } else {
648 | canvas = crop(renderer.canvas, {width: options.width != null ? options.width : bounds.width, height: options.height != null ? options.height : bounds.height, top: bounds.top, left: bounds.left, x: clonedWindow.pageXOffset, y: clonedWindow.pageYOffset});
649 | }
650 |
651 | cleanupContainer(container, options);
652 | return canvas;
653 | });
654 | }
655 |
656 | function cleanupContainer(container, options) {
657 | if (options.removeContainer) {
658 | container.parentNode.removeChild(container);
659 | log("Cleaned up container");
660 | }
661 | }
662 |
663 | function crop(canvas, bounds) {
664 | var croppedCanvas = document.createElement("canvas");
665 | var x1 = Math.min(canvas.width - 1, Math.max(0, bounds.left));
666 | var x2 = Math.min(canvas.width, Math.max(1, bounds.left + bounds.width));
667 | var y1 = Math.min(canvas.height - 1, Math.max(0, bounds.top));
668 | var y2 = Math.min(canvas.height, Math.max(1, bounds.top + bounds.height));
669 | croppedCanvas.width = bounds.width;
670 | croppedCanvas.height = bounds.height;
671 | log("Cropping canvas at:", "left:", bounds.left, "top:", bounds.top, "width:", (x2-x1), "height:", (y2-y1));
672 | log("Resulting crop with width", bounds.width, "and height", bounds.height, " with x", x1, "and y", y1);
673 | croppedCanvas.getContext("2d").drawImage(canvas, x1, y1, x2-x1, y2-y1, bounds.x, bounds.y, x2-x1, y2-y1);
674 | return croppedCanvas;
675 | }
676 |
677 | function documentWidth (doc) {
678 | return Math.max(
679 | Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth),
680 | Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth),
681 | Math.max(doc.body.clientWidth, doc.documentElement.clientWidth)
682 | );
683 | }
684 |
685 | function documentHeight (doc) {
686 | return Math.max(
687 | Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight),
688 | Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight),
689 | Math.max(doc.body.clientHeight, doc.documentElement.clientHeight)
690 | );
691 | }
692 |
693 | function smallImage() {
694 | return "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
695 | }
696 |
697 | function isIE9() {
698 | return document.documentMode && document.documentMode <= 9;
699 | }
700 |
701 | // https://github.com/niklasvh/html2canvas/issues/503
702 | function cloneNodeIE9(node, javascriptEnabled) {
703 | var clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false);
704 |
705 | var child = node.firstChild;
706 | while(child) {
707 | if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') {
708 | clone.appendChild(cloneNodeIE9(child, javascriptEnabled));
709 | }
710 | child = child.nextSibling;
711 | }
712 |
713 | return clone;
714 | }
715 |
716 | function createWindowClone(ownerDocument, containerDocument, width, height, options, x ,y) {
717 | labelCanvasElements(ownerDocument);
718 | var documentElement = isIE9() ? cloneNodeIE9(ownerDocument.documentElement, options.javascriptEnabled) : ownerDocument.documentElement.cloneNode(true);
719 | var container = containerDocument.createElement("iframe");
720 |
721 | container.className = "html2canvas-container";
722 | container.style.visibility = "hidden";
723 | container.style.position = "fixed";
724 | container.style.left = "-10000px";
725 | container.style.top = "0px";
726 | container.style.border = "0";
727 | container.width = width;
728 | container.height = height;
729 | container.scrolling = "no"; // ios won't scroll without it
730 | containerDocument.body.appendChild(container);
731 |
732 | return new Promise(function(resolve) {
733 | var documentClone = container.contentWindow.document;
734 |
735 | cloneNodeValues(ownerDocument.documentElement, documentElement, "textarea");
736 | cloneNodeValues(ownerDocument.documentElement, documentElement, "select");
737 |
738 | /* Chrome doesn't detect relative background-images assigned in inline