├── .gitignore
├── .jshintrc
├── .ruby-version
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Dockerfile
├── Gruntfile.js
├── ISSUE_TEMPLATE.md
├── LICENSE
├── README.md
├── bower.json
├── component.json
├── composer.json
├── deploy.rb
├── dist
├── jquery.mask.js
└── jquery.mask.min.js
├── docker-compose.yml
├── package-lock.json
├── package.js
├── package.json
├── src
└── jquery.mask.js
└── test
├── jquery.mask.test.js
├── qunit.css
├── qunit.js
├── sinon-1.10.3.js
├── sinon-qunit-1.0.0.js
├── sinon-qunit.js
├── test-for-jquery-1.11.1.html
├── test-for-jquery-1.7.2.html
├── test-for-jquery-1.8.3.html
├── test-for-jquery-1.9.1.html
├── test-for-jquery-2.1.1.html
├── test-for-jquery-3.0.0.html
├── test-for-zepto.html
└── zepto
├── data.js
├── event.js
└── zepto.min.js
/.gitignore:
--------------------------------------------------------------------------------
1 | index.html
2 | css/*
3 | img/*
4 | js/*
5 | node_modules/
6 | bower_components/
7 | .sparkleshare
8 | libpeerconnection.log
9 | .versions
10 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "bitwise": true,
3 | "browser": true,
4 | "camelcase": true,
5 | "curly": true,
6 | "eqeqeq": true,
7 | "esnext": true,
8 | "expr": true,
9 | "globals": {
10 | "console": false,
11 | "define": false,
12 | "document": false,
13 | "expect": false,
14 | "module": false,
15 | "require": false,
16 | "window": false
17 | },
18 | "immed": true,
19 | "indent": 4,
20 | "latedef": false,
21 | "maxcomplexity": 15,
22 | "newcap": true,
23 | "noarg": true,
24 | "node": true,
25 | "noempty": true,
26 | "nonstandard": true,
27 | "quotmark": "single",
28 | "regexp": true,
29 | "smarttabs": true,
30 | "strict": false,
31 | "trailing": true,
32 | "undef": true,
33 | "unused": true
34 | }
35 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.0.0p598
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "8.9.3"
4 | before_script:
5 | - npm install -g grunt-cli
6 | - npm install
7 | script: grunt test
8 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | == v1.14.16 (Jul/31 2019 16:32 +0100 by Igor Escobar) ==
2 |
3 | Bugfixes:
4 |
5 | * Fixed oldVal being updated prior to caret position calculation
6 | * Solve loading JQuery as module on Meteor
7 |
8 | == v1.14.15 (Mar/08 2018 22:59 +0000 by Igor Escobar) ==
9 |
10 | Bugfixes:
11 |
12 | * rolling back change to fix caret positioning. it didn’t worked on some devices
13 |
14 | == v1.14.14 (Mar/02 2018 16:55 +0000 by Igor Escobar) ==
15 |
16 | Bugfixes:
17 |
18 | * fixing mask positioning delays
19 | * unmask: also removing place holder if added on the first place.
20 | * unmask: unsetting maxlength if we set it in the first place
21 |
22 | == v1.14.13 (Dec/11 2017 18:59 +0000 by Igor Escobar) ==
23 |
24 | Bugfixes:
25 |
26 | * fixes caret issue explained on #636
27 | * fixing use strict issue
28 |
29 | == v1.14.12 (Oct/04 2017 09:57 +0100 by Igor Escobar) ==
30 |
31 | Bugfixes:
32 |
33 | * bug fixing on caret positioning on some devices
34 |
35 | == v1.14.11 (May/30 2017 21:53 +0100 by Igor Escobar) ==
36 |
37 | Bugfixes:
38 |
39 | * fixing a lot of caret positioning issues. Thanks to @onuradsay
40 |
41 | == v1.14.10 (Feb/13 2017 14:18 +0000 by Igor Escobar) ==
42 |
43 | Bugfixes:
44 |
45 | * fixing exception when oValue in undefined
46 |
47 | == v1.14.9 (Jan/25 2017 11:17 +0000 by Igor Escobar) ==
48 |
49 | Bugfixes:
50 |
51 | * don’t use input event when using samsung browser or old chrome versions
52 |
53 | == v1.14.8 (Dec/26 2016 13:18 +0000 by Igor Escobar) ==
54 |
55 | Bugfixes:
56 |
57 | * fixing caret on android with chrome 28
58 |
59 | == v1.14.7 (Dec/25 2016 03:51 +0000 by Igor Escobar) ==
60 |
61 | Bugfixes:
62 |
63 | * improving caret positioning when cursor is on the middle
64 |
65 | == v1.14.6 (Dec/24 2016 17:14 +0000 by Igor Escobar) ==
66 |
67 | Bugfixes:
68 |
69 | * fix caret positioning with multiple mask chars
70 |
71 | == v1.14.5 (Dec/24 2016 14:42 +0000 by Igor Escobar) ==
72 |
73 | Changes:
74 |
75 | * fixing reserved word
76 |
77 | == v1.14.4 (Dec/24 2016 14:38 +0000 by Igor Escobar) ==
78 |
79 | Bugfixes:
80 |
81 | * fixing android cursor positioning (special thanks to @felipejunges and @fernandobandeira)
82 |
83 | == v1.14.3 (Nov/28 2016 11:53 +0000 by Igor Escobar) ==
84 |
85 | Bugfixes:
86 |
87 | * fixing caret positioning on safari
88 |
89 | == v1.14.2 (Nov/27 2016 20:04 +0000 by Igor Escobar) ==
90 |
91 | Bugfixes:
92 |
93 | * apply auto maxlength in case the mask doesn't have recursive pattern
94 |
95 | == v1.14.1 (Nov/27 2016 19:20 +0000 by Igor Escobar) ==
96 |
97 | Bugfixes:
98 |
99 | * Fix input value mangling when inserting before a static mask character
100 | * fixing caret position issue
101 |
102 | == v1.14.0 (Apr/03 2016 17:52 +0100 by Igor Escobar) ==
103 |
104 | Bugfixes:
105 |
106 | * Fix cursor jumping while editing in non-IE browsers. Thanks to @archwyrm
107 |
108 | Features:
109 |
110 | * adding masked function for better angular use
111 |
112 | == v1.13.9 (Mar/20 2016 16:17 +0000 by Igor Escobar) ==
113 |
114 | Changes:
115 |
116 | * giving the opportunity to pass watchInputs locally
117 |
118 | == v1.13.8 (Mar/06 2016 23:25 +0000 by Igor Escobar) ==
119 |
120 | Changes:
121 |
122 | * adding support for meteor
123 |
124 | == v1.13.7 (Mar/06 2016 22:46 +0000 by Igor Escobar) ==
125 |
126 | Bugfixes:
127 |
128 | * fixing onChange behaviour
129 |
130 | == v1.13.6 (Mar/06 2016 22:14 +0000 by Igor Escobar) ==
131 |
132 | Bugfixes:
133 |
134 | * fixing deploy procedure
135 |
136 | == v1.13.5 (Mar/06 2016 22:01 +0000 by Igor Escobar) ==
137 |
138 | Changes:
139 |
140 | * adding clearIfNotMatch to globalOptions
141 |
142 | Bugfixes:
143 |
144 | * fixing some bugs when using non-input elements
145 | * fixing mobile issues at #348.
146 | * using input event when supported
147 |
148 | == v1.13.4 (Aug/07 2015 14:21 +0100 by Igor Escobar) ==
149 |
150 | Bugfixes:
151 |
152 | * Add check to ensure that there are input elements before using them
153 |
154 | == v1.13.3 (Jul/16 2015 16:11 +0100 by Igor Escobar) ==
155 |
156 | Changes:
157 |
158 | * adding main property to package.json
159 |
160 | == v1.13.2 (Jul/16 2015 16:06 +0100 by Igor Escobar) ==
161 |
162 | Bugfixes:
163 |
164 | * change event wasnt being triggered in some cases
165 |
166 | == v1.13.1 (Jul/07 2015 15:38 +0100 by Igor Escobar) ==
167 |
168 | Bugfixes:
169 |
170 | * destroying input event too
171 |
172 | == v1.13.0 (Jul/07 2015 15:26 +0100 by Igor Escobar) ==
173 |
174 | Changes:
175 |
176 | * removing the autocomplete default.
177 |
178 | Bugfixes:
179 |
180 | * fixing bower file thanks to @lazyants
181 |
182 | Features:
183 |
184 | * prevent glitch when invalid chars.
185 | * turning off autocomplete when browsers doesn't support oninput event.
186 |
187 | == v1.12.0 (Jul/07 2015 11:37 +0100 by Igor Escobar) ==
188 |
189 | Features:
190 |
191 | * giving an alternative to the autocomplete/autofill problem.
192 |
193 | == v1.11.4 (Feb/26 2015 22:11 +0000 by Igor Escobar) ==
194 |
195 | Changes:
196 |
197 | * grunt, jshint and better applyDataMask. Thanks to @lagden
198 | * automated deploy to npm
199 |
200 | == v1.11.3 (Jan/28 2015 15:41 +0000 by Igor Escobar) ==
201 |
202 | Changes:
203 |
204 | * Added commonjs module definition
205 |
206 | == v1.11.2 (Dec/26 2014 15:36 +0000 by Igor Escobar) ==
207 |
208 | Bugfixes:
209 |
210 | * unreachable code
211 |
212 | == v1.11.1 (Dec/26 2014 15:34 +0000 by Igor Escobar) ==
213 |
214 | Bugfixes:
215 |
216 | * unreachable code
217 |
218 | == v1.11.0 (Dec/26 2014 15:33 +0000 by Igor Escobar) ==
219 |
220 | Features:
221 |
222 | * implementing selectOnFocus and data-mask-selectonfocus option
223 | * adding public method called: .applyDataMask in case you want to decide whether to apply masks in data-mask fields
224 |
225 | == v1.10.13 (Nov/19 2014 16:06 +0000 by Igor Escobar) ==
226 |
227 | Bugfixes:
228 |
229 | * fixing bug with watchInputs feature when mask is used as a function and not a string.
230 |
231 | == v1.10.12 (Nov/06 2014 13:08 +0000 by Igor Escobar) ==
232 |
233 | Changes:
234 |
235 | * making a few improvements to make selection, copy events easier
236 |
237 | == v1.10.11 (Nov/06 2014 11:26 +0000 by Igor Escobar) ==
238 |
239 | Bugfixes:
240 |
241 | * we need to revaluate dataMask flags everytime
242 |
243 | == v1.10.10 (Nov/06 2014 10:41 +0000 by Igor Escobar) ==
244 |
245 | Bugfixes:
246 |
247 | * fixing dynamically data-mask added elements
248 |
249 | == v1.10.9 (Nov/05 2014 10:52 +0000 by Igor Escobar) ==
250 |
251 | Bugfixes:
252 |
253 | * data-mask wasnt working
254 |
255 | == v1.10.8 (Nov/01 2014 13:49 +0000 by Igor Escobar) ==
256 |
257 | Changes:
258 |
259 | * we dont need to seek for data-mask every time
260 |
261 | == v1.10.7 (Nov/01 2014 13:18 +0000 by Igor Escobar) ==
262 |
263 | Changes:
264 |
265 | * little optimization
266 |
267 | == v1.10.6 (Oct/28 2014 13:59 +0000 by Igor Escobar) ==
268 |
269 | Bugfixes:
270 |
271 | * fixing weird cursor problems in weird cases.
272 | * dynamically added inputs wasnt working
273 |
274 | == v1.10.5 (Oct/23 2014 11:41 +0100 by Igor Escobar) ==
275 |
276 | Bugfixes:
277 |
278 | * fixing weird cursor problems in weird cases.
279 |
280 | == v1.10.4 (Oct/23 2014 11:02 +0100 by Igor Escobar) ==
281 |
282 | Bugfixes:
283 |
284 | * fixing on the fly mask change feature.
285 |
286 | == v1.10.3 (Oct/22 2014 09:50 +0100 by Igor Escobar) ==
287 |
288 | Bugfixes:
289 |
290 | * fixing unmask method.
291 |
292 | == v1.10.2 (Oct/20 2014 16:38 +0100 by Igor Escobar) ==
293 |
294 | Bugfixes:
295 |
296 | * onChange event fired at the wrong time when the field already has a value.
297 |
298 | == v1.10.1 (Oct/20 2014 16:08 +0100 by Igor Escobar) ==
299 |
300 | Bugfixes:
301 |
302 | * fixing onChange event behaviour
303 |
304 | == v1.10.0 (Oct/20 2014 10:56 +0100 by Igor Escobar) ==
305 |
306 | Features:
307 |
308 | * adding a way to change global settings like translation object and the byPassKeys object.
309 |
310 | == v1.9.2 (Oct/20 2014 10:08 +0100 by Igor Escobar) ==
311 |
312 | Bugfixes:
313 |
314 | * fixing fallback digits implementation. Thanks @A1rPun
315 |
316 | == v1.9.1 (Oct/18 2014 12:27 +0100 by Igor Escobar) ==
317 |
318 | Bugfixes:
319 |
320 | * cant convert circular json exception
321 |
322 | == v1.9.0 (Oct/18 2014 12:07 +0100 by Igor Escobar) ==
323 |
324 | Features:
325 |
326 | * adding onInvalid callback
327 |
328 | == v1.8.0 (Oct/17 2014 11:35 +0100 by Igor Escobar) ==
329 |
330 | Changes:
331 |
332 | * removing automatic maxlength support
333 | * making a few optimizations to make it faster and retro compatible with other libraries
334 | * creating globalOptions to make it more fast and flexible
335 |
336 | Bugfixes:
337 |
338 | * fixing issue #196
339 |
340 | Features:
341 |
342 | * adding the fallback translation option
343 |
344 | == v1.7.8 (Oct/15 2014 10:55 +0100 by Igor Escobar) ==
345 |
346 | Bugfixes:
347 |
348 | * change event may experience issues
349 | * avoid maximum call stack trace error
350 |
351 | == v1.7.7 (Sep/10 2014 22:31 +0100 by Igor Escobar) ==
352 |
353 | Bugfixes:
354 |
355 | * fixing clojure compile issue
356 |
357 | == v1.7.6 (Sep/10 2014 22:14 +0100 by Igor Escobar) ==
358 |
359 | Bugfixes:
360 |
361 | * fixing clearifnotmatch in masks with literal digits
362 |
363 | == v1.7.5 (Sep/09 2014 15:43 +0100 by Igor Escobar) ==
364 |
365 | Bugfixes:
366 |
367 | * fixing paste inside of empty fields.
368 |
369 | == v1.7.4 (Aug/11 2014 14:53 +0100 by Igor Escobar) ==
370 |
371 | Changes:
372 |
373 | * smaller and reliable code
374 |
375 | == v1.7.3 (Aug/11 2014 11:28 +0100 by Igor Escobar) ==
376 |
377 | Bugfixes:
378 |
379 | * fixing issue #185
380 |
381 | == v1.7.2 (Aug/08 2014 11:11 +0100 by Igor Escobar) ==
382 |
383 | Changes:
384 |
385 | * smaller code
386 |
387 | Bugfixes:
388 |
389 | * fixing remove bug
390 |
391 | == v1.7.1 (Aug/08 2014 00:55 +0100 by Igor Escobar) ==
392 |
393 | Changes:
394 |
395 | * upgrading zepto, smaller syntax and fixing build
396 |
397 | == v1.7.0 (Aug/07 2014 23:56 +0100 by Igor Escobar) ==
398 |
399 | Features:
400 |
401 | * applying masks to dynamically added elements. (html/javascript notation)
402 |
403 | == v1.6.5 (Jun/30 2014 10:24 +0100 by Igor Escobar) ==
404 |
405 | Bugfixes:
406 |
407 | * fixing clearIfNotMatch feature in cases of optional and recursive digits
408 |
409 | == v1.6.4 (May/08 2014 23:54 +0100 by Igor Escobar) ==
410 |
411 | Changes:
412 |
413 | * testing some deployment stunts
414 |
415 | == v1.6.3 (May/08 2014 23:51 +0100 by Igor Escobar) ==
416 |
417 | Changes:
418 |
419 | * testing some deployment stunts
420 |
421 | == v1.6.2 (May/08 2014 23:45 +0100 by Igor Escobar) ==
422 |
423 | Bugfixes:
424 |
425 | * fuckin typo
426 |
427 | == v1.6.1 (May/08 2014 23:39 +0100 by Igor Escobar) ==
428 |
429 | Bugfixes:
430 |
431 | * fixing autofocus bug
432 |
433 | == v1.6.0 (May/07 2014 21:13 +0100 by Igor Escobar) ==
434 |
435 | Bugfixes:
436 |
437 | * fixing autofocus bug
438 |
439 | Features:
440 |
441 | * adding support to the clearIfNotMatch option
442 | * HTML5 placeholder support
443 |
444 | == v1.5.7 (May/01 2014 18:37 +0100 by Igor Escobar) ==
445 |
446 | Changes:
447 |
448 | * some cleanup and stuff
449 |
450 | == v1.5.6 (May/01 2014 18:30 +0100 by Igor Escobar) ==
451 |
452 | Bugfixes:
453 |
454 | * Bug in calculating difference between mask characters between old and new field values
455 | * Fix stack limit exceeded
456 |
457 | == v1.5.5 (Apr/27 2014 13:47 +0100 by Igor Escobar) ==
458 |
459 | Changes:
460 |
461 | * UMD (Universal Module Definition) patterns for JavaScript modules
462 |
463 | Bugfixes:
464 |
465 | * caret position correction
466 | * 114 - Fix onChange Event error
467 |
468 | == v1.5.4 (Feb/09 2014 12:02 +0000 by Igor Escobar) ==
469 |
470 | Changes:
471 |
472 | * optmizing code
473 |
474 | == v1.5.3 (Feb/08 2014 14:59 +0000 by Igor Escobar) ==
475 |
476 | Bugfixes:
477 |
478 | * fixing ctrl a bug
479 |
480 | == v1.5.2 (Dec/20 2013 16:35 +0000 by Igor Escobar) ==
481 |
482 | Changes:
483 |
484 | * smaller source code
485 |
486 | == v1.5.1 (Dec/18 2013 22:34 +0000 by Igor Escobar) ==
487 |
488 | Changes:
489 |
490 | * fixing some code climate problems
491 |
492 | == v1.5.0 (Dec/18 2013 22:10 +0000 by Igor Escobar) ==
493 |
494 | Bugfixes:
495 |
496 | * fixing getCleanVal()
497 |
498 | Features:
499 |
500 | * new public method called cleanVal
501 |
502 | == v1.4.2 (Dec/16 2013 15:48 +0000 by Igor Escobar) ==
503 |
504 | Bugfixes:
505 |
506 | * Dirty fix for masks not completing with a literal
507 |
508 | == v1.4.1 (Dec/09 2013 21:23 +0000 by Igor Escobar) ==
509 |
510 | Changes:
511 |
512 | * revising ignored keys
513 |
514 | == v1.4.0 (Nov/28 2013 18:06 +0000 by Igor Escobar) ==
515 |
516 | Features:
517 |
518 | * caret positioning implementation
519 |
520 | == v1.3.1 (Oct/08 2013 20:38 +0100 by Igor Escobar) ==
521 |
522 | Changes:
523 |
524 | * adding more keys to ignore list to make the char navigation smoothly
525 |
526 | Bugfixes:
527 |
528 | * Sounds like 'options' has disappeared for some reason
529 |
530 | == v1.3.0 (Sep/13 2013 10:37 +0100 by Igor Escobar) ==
531 |
532 | Features:
533 |
534 | * creating the maxlength option
535 |
536 | == v1.2.0 (Sep/07 2013 12:07 +0100 by Igor Escobar) ==
537 |
538 | Features:
539 |
540 | * adding the possibility to put recursive digits inside masks
541 |
542 | == v1.1.3 (Sep/04 2013 21:21 +0100 by Igor Escobar) ==
543 |
544 | Bugfixes:
545 |
546 | * fixing late masking
547 |
548 | == v1.1.2 (Aug/26 2013 15:08 +0100 by Igor Escobar) ==
549 |
550 | Bugfixes:
551 |
552 | * fixing mask on div,span etc
553 |
554 | == v1.1.1 (Aug/26 2013 14:42 +0100 by Igor Escobar) ==
555 |
556 | Bugfixes:
557 |
558 | * better callback handling
559 |
560 | == v1.1.0 (Aug/24 2013 15:59 +0100 by Igor Escobar) ==
561 |
562 | Features:
563 |
564 | * adding onchange support
565 |
566 | == v1.0.3 (Aug/23 2013 23:10 +0100 by Igor Escobar) ==
567 |
568 | Changes:
569 |
570 | * optimizations to mask on non html fields
571 |
572 | == v1.0.2 (Aug/23 2013 22:46 +0100 by Igor Escobar) ==
573 |
574 | Bugfixes:
575 |
576 | * adding remask method do improve callback performance
577 |
578 | == v1.0.1 (Aug/23 2013 22:01 +0100 by Igor Escobar) ==
579 |
580 | Changes:
581 |
582 | * normal releases again
583 |
584 | == v1.0.0 (Aug/23 2013 21:59 +0100 by Igor Escobar) ==
585 |
586 | Features:
587 |
588 | * huge refactoring focusing no reduce source code weight and bugfixing
589 |
590 | == v0.11.5 (Aug/20 2013 17:11 +0100 by Igor Escobar) ==
591 |
592 | Bugfixes:
593 |
594 | * bug fixing when mask range is bigger than 2 digits.
595 |
596 | == v0.11.4 (Aug/19 2013 10:24 +0100 by Igor Escobar) ==
597 |
598 | Changes:
599 |
600 | * adding de delete key to byPassKeys
601 |
602 | == v0.11.3 (Aug/18 2013 00:48 +0100 by Igor Escobar) ==
603 |
604 | Bugfixes:
605 |
606 | * fixing zepto compatibily
607 |
608 | == v0.11.2 (Aug/17 2013 18:39 +0100 by Igor Escobar) ==
609 |
610 | Bugfixes:
611 |
612 | * jmask iterate all items
613 |
614 | == v0.11.1 (Aug/17 2013 18:32 +0100 by Igor Escobar) ==
615 |
616 | Changes:
617 |
618 | * a little bit smaller source code
619 |
620 | == v0.11.0 (Aug/16 2013 21:27 +0100 by Igor Escobar) ==
621 |
622 | Bugfixes:
623 |
624 | * Altered "ignored keys" hook to run events (i.e. onKeyPress) afterwards. Otherwise, we miss key triggered events when the user deletes the entire text box, etc.
625 |
626 | Features:
627 |
628 | * adding support to method getCleanVal
629 |
630 | == v0.10.1 (Jul/26 2013 09:35 +0100 by ) ==
631 |
632 |
633 |
634 | == v0.10.0 (Jul/19 2013 23:07 +0100 by Igor Escobar) ==
635 |
636 | Features:
637 |
638 | * adding data-mask support
639 |
640 | == v0.9.1 (Jul/19 2013 22:35 +0100 by Igor Escobar) ==
641 |
642 | Changes:
643 |
644 | * jQuery-Mask-Plugin is now available at bower.io
645 |
646 | Bugfixes:
647 |
648 | * fixing addEventListener on IE7
649 |
650 | == v0.9.0 (Apr/24 2013 07:44 +0100 by Igor Escobar) ==
651 |
652 | Features:
653 |
654 | * Adding compatibility with Zepto.js
655 |
656 | == v0.8.0 (Apr/07 2013 18:39 +0100 by Igor Escobar) ==
657 |
658 | Features:
659 |
660 | * applying masks anything != than input :)
661 | * implementing the possibility of range chars ex: A{1,3}
662 |
663 | == v0.7.11 (Apr/05 2013 22:12 +0100 by Igor Escobar) ==
664 |
665 | Changes:
666 |
667 | * now when you type a wrong char, the plugin will make your text fit inside of the mask instead of lose your data.
668 |
669 | == v0.7.10 (Apr/04 2013 22:14 +0100 by Igor Escobar) ==
670 |
671 | Changes:
672 |
673 | * changing yui-compressor to clojure-compiler
674 |
675 | == v0.7.9 (Apr/04 2013 22:04 +0100 by Igor Escobar) ==
676 |
677 | Changes:
678 |
679 | * refactoring and implementation of optional mask digits
680 |
681 | Bugfixes:
682 |
683 | * fixing maxlength and adding a smarter mask removal. issue #18
684 |
685 | == v0.7.8 (Mar/30 2013 00:48 +0000 by Igor Escobar) ==
686 |
687 | Changes:
688 |
689 | * a few changes to get the code smallest possible.
690 | * removing unnecessary methods and making code smaller.
691 |
692 | == v0.7.7 (Mar/29 2013 12:38 +0000 by Igor Escobar) ==
693 |
694 | Bugfixes:
695 |
696 | * fixing copy and paste problem related on issue #15
697 |
698 | == v0.7.6 (Mar/29 2013 00:28 +0000 by Igor Escobar) ==
699 |
700 | Bugfixes:
701 |
702 | * correcting mask formatationg problem related on issue #16
703 |
704 | == v0.7.5 (Mar/03 2013 20:56 +0000 by Igor Escobar) ==
705 |
706 | Changes:
707 |
708 | * generating .gz file on deploy
709 |
710 | == v0.7.4 (Mar/03 2013 20:38 +0000 by Igor Escobar) ==
711 |
712 | Changes:
713 |
714 | * changing minifier jsmin to yui compressor.
715 |
716 | == v0.7.3 (Mar/02 2013 01:12 +0000 by Igor Escobar) ==
717 |
718 | Bugfixes:
719 |
720 | * bug fixing when typed wrong data type on mixing masks.
721 |
722 | == v0.7.2 (Feb/24 2013 22:02 +0000 by Igor Escobar) ==
723 |
724 | Bugfixes:
725 |
726 | * fuckin stupid comma.
727 |
728 | == v0.7.1 (Feb/24 2013 21:57 +0000 by Igor Escobar) ==
729 |
730 | Changes:
731 |
732 | * testing the private method maskToRegex
733 | * a little bit of changes to make the code more testable
734 |
735 | == v0.7.0 (Feb/12 2013 00:30 +0000 by Igor Escobar) ==
736 |
737 | Features:
738 |
739 | * Now you can decide for jquery mask plugin how to interpret 0 to 9, A and S and even teach him how to reconize patterns.
740 |
741 | == v0.6.3 (Feb/11 2013 12:20 +0000 by Igor Escobar) ==
742 |
743 | Bugfixes:
744 |
745 | * When the user paste a text and the last char is valid sanitize may fail
746 |
747 | == v0.6.2 (Feb/11 2013 00:02 +0000 by Igor Escobar) ==
748 |
749 | Bugfixes:
750 |
751 | * allowing the user type the same character as the mask without erasing it.
752 |
753 | == v0.6.1 (Jan/20 2013 23:57 +0000 by Igor Escobar) ==
754 |
755 | Changes:
756 |
757 | * changing the way ta deployment occurs to correct jquery plugins deployments.
758 |
759 | == v0.6.0 (Jan/18 2013 17:19 +0000 by Igor Escobar) ==
760 |
761 | Changes:
762 |
763 | * Now pushing jQuery Mask Plugin to jQuery Plugins Repository
764 |
765 | == v0.5.4 (Jan/17 2013 23:06 +0000 by Igor Escobar) ==
766 |
767 | Changes:
768 |
769 | * upgrading jquery plugins manifest file
770 |
771 | == v0.5.3 (Jan/17 2013 22:48 +0000 by Igor Escobar) ==
772 |
773 | Bugfixes:
774 |
775 | * correctly generating jmask version inside of jquery mask source
776 |
777 | == v0.5.2 (Jan/17 2013 22:43 +0000 by Igor Escobar) ==
778 |
779 | Changes:
780 |
781 | * Now pushing to jQuery Plugin Repository
782 |
783 | == v0.5.1 (Jan/07 2013 23:33 +0000 by Igor Escobar) ==
784 |
785 | Changes:
786 |
787 | * improving the deploy process with the new stepup's upgrade.
788 |
789 | == v0.5.0 (Oct/27 2012 13:40 +0100 by Igor Escobar) ==
790 |
791 | Bugfixes:
792 |
793 | * Bug fixes on OnSupport method with Firefox.
794 |
795 | Features:
796 |
797 | * the first parameter of the .mask() function, now accepts a string or a anonymous function
798 |
799 | == v0.4.7 (Aug/06 2012 22:56 +0100 by Igor Escobar) ==
800 |
801 | Changes:
802 |
803 | * Nothing big, just class refactoring
804 |
805 | == v0.4.6 (Aug/06 2012 01:25 +0100 by Igor Escobar) ==
806 |
807 | Changes:
808 |
809 | - better OOP design
810 | - implementing the jquery data object on each mask field
811 | - implementing the public method .remove to disable and remove the mask
812 |
813 | == v0.4.5 (Aug/04 2012 01:31 +0100 by Igor Escobar) ==
814 |
815 | Changes:
816 |
817 | - improving support to complex jquery selectors
818 | - performance improvement.
819 | - callback handling improvement
820 |
821 | == v0.4.4 (Jun/03 2012 21:01 +0100 by Igor Escobar) ==
822 |
823 | Bugfixes:
824 |
825 | * Bug fixes on Internet Explorer 8.
826 |
827 | == v0.4.3 (Mar/19 2012 21:52 +0000 by Igor Escobar) ==
828 |
829 | Bugfixes:
830 |
831 | * Corrigindo bug para mascaras com +
832 |
833 | == v0.4.2 (Mar/18 2012 15:28 +0000 by Igor Escobar) ==
834 |
835 | Bugfixes:
836 |
837 | * Mascara não pararecia no firefox
838 |
839 | == v0.4.1 (Mar/18 2012 15:01 +0000 by Igor Escobar) ==
840 |
841 | Bugfixes:
842 |
843 | * Corrigindo tim das macaras.
844 |
845 | == v0.4.0 (Mar/18 2012 14:51 +0000 by Igor Escobar) ==
846 |
847 | Features:
848 |
849 | * Implementado mascara reversa para moeda/cpf/rg/etc.
850 | * Nova engine.
851 |
852 | == v0.3.0 (Mar/14 2012 10:14 +0000 by Igor Escobar) ==
853 |
854 | Changes:
855 |
856 | * License and comments up to date.
857 |
858 | Features:
859 |
860 | * On-the-fly mask change.
861 | * onComplete and onKeyPress new callbacks.
862 |
863 | == v0.2.5 (Mar/13 2012 22:55 +0000 by Igor Escobar) ==
864 |
865 | Bugfixes:
866 |
867 | - Corrigindo ctrl+v com mascara errada. - Cortando dados que exceder a mascara no ctrl+v ou se segurar alguma tecla. - Refatorando algumas partes do código.
868 |
869 | == v0.2.4 (Mar/13 2012 11:06 +0000 by Igor Escobar) ==
870 |
871 | Changes:
872 |
873 | * Codigo refatorado, otimizado, validação mais precisa e efetiva.
874 |
875 | == v0.2.3 (Mar/13 2012 01:01 +0000 by Igor Escobar) ==
876 |
877 | Changes:
878 |
879 | * Melhorando expressoes regulares.
880 |
881 | == v0.2.2 (Mar/13 2012 00:50 +0000 by Igor Escobar) ==
882 |
883 | Bugfixes:
884 |
885 | * Corrindo regex de validação
886 |
887 | == v0.2.1 (Mar/13 2012 00:41 +0000 by Igor Escobar) ==
888 |
889 | Bugfixes:
890 |
891 | * Corrigida validação alphanumerica.
892 |
893 | == v0.2.0 (Mar/13 2012 00:24 +0000 by Igor Escobar) ==
894 |
895 | Features:
896 |
897 | - Input Data Type Validation.
898 | - Automatic MaxLength (When are not defined).
899 | - Live Event Implemented for Ajax-based Apps.
900 | - Mixed mask with validation.
901 | * S for string digit
902 | * A for alphanumeric digit
903 | * 0 to 9 for numeric digit.
904 |
905 | == v0.1.1 (Mar/10 2012 14:05 +0000 by Igor Escobar) ==
906 |
907 | Bugfixes:
908 |
909 | * Implementando Crossbrowser event handling.
910 |
911 | == v0.1.0 (Mar/10 2012 13:10 +0000 by Igor Escobar) ==
912 |
913 | Features:
914 |
915 | * Implementando mascaras com espaço para data e hora
916 |
917 | == v0.0.1 (Mar/10 2012 04:42 +0000 by Igor Escobar) ==
918 |
919 | Changes:
920 |
921 | * Refatorando o codigo para suportar multiplas instancias
922 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ### Have you take a look into our docs?
2 | https://igorescobar.github.io/jQuery-Mask-Plugin/
3 |
4 | ### Want to contribute? Make sure you read this first
5 | https://github.com/igorescobar/jQuery-Mask-Plugin#contributing
6 |
7 | Is this plugin helping you out? Buy me a beer and cheers! :beer:
8 |
9 | :bowtie: https://www.paypal.me/igorcescobar
10 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM phusion/baseimage:0.9.17
2 |
3 | # Use baseimage-docker's init system.
4 | CMD ["/sbin/my_init"]
5 |
6 | # Java 8 for Google's clojure compiler
7 | RUN \
8 | echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \
9 | echo "deb http://dl.bintray.com/sbt/debian /" | tee -a /etc/apt/sources.list.d/sbt.list && \
10 | add-apt-repository -y ppa:webupd8team/java && \
11 | apt-get update && \
12 | apt-get install -y oracle-java8-installer git unzip ruby-full && \
13 | rm -rf /var/lib/apt/lists/* && \
14 | rm -rf /var/cache/oracle-jdk8-installer
15 |
16 | # Define commonly used JAVA_HOME variable
17 | ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
18 |
19 | RUN mkdir /app
20 | RUN mkdir /app/clojure-compiler
21 |
22 | # Clojure compiler
23 | RUN \
24 | curl -O http://dl.google.com/closure-compiler/compiler-latest.zip && \
25 | unzip compiler-latest.zip -d /app/clojure-compiler && \
26 | chmod a+x /app/clojure-compiler && \
27 | rm compiler-latest.zip
28 |
29 | RUN gem install bundler pry step-up --no-rdoc --no-ri
30 |
31 | # Install Node.js
32 | RUN curl --silent --location https://deb.nodesource.com/setup_0.12 | sudo bash -
33 | RUN apt-get install --yes nodejs
34 |
35 | RUN npm install -g grunt-cli
36 | WORKDIR /app/jquery-mask-plugin
37 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | require('load-grunt-tasks')(grunt);
3 | require('time-grunt')(grunt);
4 |
5 | grunt.initConfig({
6 | jshint: {
7 | options: {
8 | jshintrc: '.jshintrc',
9 | reporter: require('jshint-stylish')
10 | },
11 | all: ['src/{,*/}*.js']
12 | },
13 | connect: {
14 | server: {
15 | options: {
16 | port: 9001,
17 | base: './'
18 | }
19 | }
20 | },
21 | qunit: {
22 | all: {
23 | options: {
24 | urls: [
25 | 'http://localhost:9001/test/test-for-jquery-1.11.1.html',
26 | 'http://localhost:9001/test/test-for-jquery-1.7.2.html',
27 | 'http://localhost:9001/test/test-for-jquery-1.8.3.html',
28 | 'http://localhost:9001/test/test-for-jquery-1.9.1.html',
29 | 'http://localhost:9001/test/test-for-jquery-2.1.1.html',
30 | 'http://localhost:9001/test/test-for-jquery-3.0.0.html',
31 | 'http://localhost:9001/test/test-for-zepto.html'
32 | ]
33 | }
34 | }
35 | }
36 | });
37 |
38 | // A convenient task alias.
39 | grunt.registerTask('test', ['jshint', 'connect', 'qunit']);
40 | grunt.registerTask('default', ['test']);
41 |
42 | };
43 |
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Have you take a look into our docs?
2 | https://igorescobar.github.io/jQuery-Mask-Plugin/
3 |
4 | ### Make sure your read this before opening a new issue:
5 | https://github.com/igorescobar/jQuery-Mask-Plugin#problems-or-questions
6 |
7 | #### Device
8 | [...]
9 |
10 | #### Browser (and version)?
11 | [...]
12 |
13 | #### Functional `jsfiddle` exemplifying your problem:
14 | You can use this one as exemple: http://jsfiddle.net/igorescobar/6pco4om7/
15 |
16 | #### Describe de problem depth:
17 | [...]
18 |
19 |
20 | Is this plugin helping you out? Buy me a beer and cheers! :beer:
21 |
22 | :bowtie: https://www.paypal.me/igorcescobar
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Created by Igor Escobar on 2012-03-10. Please report any bug at http://blog.igorescobar.com
2 |
3 | Copyright (c) 2012 Igor Escobar http://blog.igorescobar.com
4 |
5 | The MIT License (http://www.opensource.org/licenses/mit-license.php)
6 |
7 | Permission is hereby granted, free of charge, to any person
8 | obtaining a copy of this software and associated documentation
9 | files (the "Software"), to deal in the Software without
10 | restriction, including without limitation the rights to use,
11 | copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the
13 | Software is furnished to do so, subject to the following
14 | conditions:
15 |
16 | The above copyright notice and this permission notice shall be
17 | included in all copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # jQuery Mask Plugin
2 | A jQuery Plugin to make masks on form fields and HTML elements.
3 |
4 | [](https://travis-ci.org/igorescobar/jQuery-Mask-Plugin)
5 | [](https://codeclimate.com/github/igorescobar/jQuery-Mask-Plugin)
6 | [](https://www.jsdelivr.com/package/npm/jquery-mask-plugin)
7 | [](https://cdnjs.com/libraries/jquery.mask)
8 |
9 | # Documentation, Demos & Usage Examples
10 | https://igorescobar.github.io/jQuery-Mask-Plugin/
11 |
12 | ## Features
13 |
14 | * Lightweight (~2kb minified, ~1kb gziped).
15 | * Built-in support for dynamically added elements.
16 | * Masks on any HTML element (no need to server-side mask anymore!)!
17 | * HTML notation support (data-mask, data-mask-recursive, data-mask-clearifnotmatch).
18 | * String/Numeric/Alpha/Mixed masks.
19 | * Reverse mask support for masks on numeric fields.
20 | * Sanitization.
21 | * Optional digits.
22 | * Recursive Digits.
23 | * Fallback Digits.
24 | * Advanced mask initialization.
25 | * Advanced Callbacks.
26 | * On-the-fly mask change.
27 | * Mask removal.
28 | * Full customization.
29 | * Compatibility with React/UMD/Zepto.js/Angular.JS.
30 | * HTML5 placeholder support.
31 | * Clear the field if it not matches support.
32 |
33 | ## Want to buy me a beer? :heart_eyes:
34 | http://paypal.me/igorcescobar
35 |
36 | ## Install it via Package Managers
37 | ### Bower
38 | `bower install jquery-mask-plugin`
39 | ### NPM
40 | `npm i jquery-mask-plugin`
41 | ### Meteor
42 | `meteor add igorescobar:jquery-mask-plugin`
43 | ### Packagist/Composer
44 | `composer require igorescobar/jquery-mask-plugin`
45 |
46 | ## CDNs
47 | ### CDNjs
48 | https://cdnjs.com/libraries/jquery.mask
49 | ### JSDelivr
50 | http://www.jsdelivr.com/projects/jquery.mask
51 |
52 | ## RubyGems
53 | ```ruby
54 | gem 'jquery_mask_rails' # more details at http://bit.ly/jquery-mask-gem
55 | ```
56 |
57 | ## Tutorials
58 | ### English
59 | * [Masks with jQuery Mask Plugin](http://bit.ly/masks-with-jquery-mask-plugin)
60 | * [Using jQuery Mask Plugin With Zepto.js](http://bit.ly/using-jquery-mask-plugin-with-zeptojs)
61 |
62 | ### Portuguese
63 | * [Mascaras com JQuery Mask Plugin](http://bit.ly/mascaras-com-jquery-mask-plugin)
64 | * [Mascara Javascript para os novos telefones de São Paulo](http://bit.ly/mascara-javascript-para-os-novos-telefones-de-sao-paulo)
65 |
66 | ### Fun (or not) facts
67 | * [I’ve had the chance to troll Donald Trump. But I didn’t.](http://www.igorescobar.com/blog/2016/08/21/ive-the-chance-to-troll-donald-trump-but-i-didnt/)
68 |
69 | ## Compatibility
70 | jQuery Mask Plugin has been tested with jQuery 1.7+ on all major browsers:
71 |
72 | * Firefox 2+ (Win, Mac, Linux);
73 | * IE7+ (Win);
74 | * Chrome 6+ (Win, Mac, Linux, Android, iPhone);
75 | * Safari 3.2+ (Win, Mac, iPhone);
76 | * Opera 8+ (Win, Mac, Linux, Android, iPhone).
77 | * Android Default Browser v4+
78 |
79 | ## Typescript support
80 | Definition can be found [here](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/jquery-mask-plugin).
81 |
82 | To install, open terminal and navigate to your working directory.
83 |
84 | ### Typescript 1.x users
85 | * Install [typings](https://github.com/typings/typings) by running `npm install typings --global`.
86 | * Then install the definition by running `typings install dt~jquery-mask-plugin --global --save`.
87 | ### Typescript 2.x users
88 | * Use npm `npm install --save-dev @types/jquery-mask-plugin`.
89 |
90 | For configuration options and troubleshooting refer to these repositories:
91 | * [Typings](https://github.com/typings/typings)
92 | * [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped)
93 | * [Typescript](https://github.com/Microsoft/TypeScript)
94 |
95 |
96 | ## Problems or Questions?
97 | Before opening a new [issue](https://github.com/igorescobar/jQuery-Mask-Plugin/issues) take a look on those frequently asked questions:
98 | #### [How to integrate with React.js?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/498)
99 | #### [How to integrate with Angular.js?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/499)
100 | #### [How to integrate with Vue.js?](https://github.com/ankurk91/vue-jquery-mask)
101 | #### [Problems with old versions of Android keyboard](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/135)
102 | #### [Negative numbers, or currency related problems](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/436#issuecomment-253176511)
103 | #### [Prefix or sufix on the Mask](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/166)
104 | #### [Add validation?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/387#issuecomment-192998092)
105 | #### [Field type number, email not working?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/450#issuecomment-253225719)
106 | #### [Want to keep the placeholder as the user types?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/633#issuecomment-350819224)
107 | #### [E-mail mask?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/582)
108 |
109 | ## Bugs?
110 | Did you read our [docs](https://igorescobar.github.io/jQuery-Mask-Plugin/docs.html)? Yes? Cool! So now... make sure that you have a *functional* [jsfiddle](http://jsfiddle.net/) exemplifying your problem and open an [issue](https://github.com/igorescobar/jQuery-Mask-Plugin/issues) for us. Don't know how to do it? Use this [fiddle example](http://jsfiddle.net/igorescobar/6pco4om7/).
111 |
112 | ## Contributing
113 | * **Bug Reporting**: Yes! You can contribute opening [issues](https://github.com/igorescobar/jQuery-Mask-Plugin/issues)!
114 | * **Documenting**: Do you think that something in our [docs](https://github.com/igorescobar/jQuery-Mask-Plugin/tree/gh-pages) should be better? Do you have a cool idea to increase the awesomeness? Summit your pull request with your idea!
115 | * **Bug Fixing**: No time to lose? Fix it and help others! Write some [tests](https://github.com/igorescobar/jQuery-Mask-Plugin/tree/master/test) to make sure that everything are working propertly.
116 | * **Improving**: Open an [issue](https://github.com/igorescobar/jQuery-Mask-Plugin/issues) and lets discuss it. Just to make sure that you're on the right track.
117 | * **Sharing**: Yes! Have we saved some of your time? Are you enjoying our mask plugin? Sharing is caring! Tweet it! Facebook it! Linkedin It(?!) :D
118 | * **Donating**: Hey, now that you don't need to worry about masks again... buy me a coffee, beer or a PlayStation 4 (Xbox One also accepted!) :o)
119 |
120 | ### Unit Tests
121 | We use [QUnit](http://qunitjs.com/) and [GruntJS](http://gruntjs.com/). To run our test suit is just run: ```grunt test``` in your console or you can open those ```test-for*.html``` files inside of our ```test/``` folder.
122 |
123 | In case you're familiar with [Docker](https://www.docker.com/) here is how you can use it:
124 | ```bash
125 | docker build -t jquery-mask .
126 | CONTAINER_ID=$(docker run -d -v $PWD:/app/jquery-mask-plugin jquery-mask)
127 | docker exec $CONTAINER_ID sh -c "npm install"
128 | docker exec -it $CONTAINER_ID /bin/bash
129 | grunt test
130 | ```
131 |
132 | ## Contributors
133 | * [Igor Lima](https://github.com/igorlima)
134 | * [Mark Simmons](https://github.com/Markipelago)
135 | * [Gabriel Schammah](https://github.com/gschammah)
136 | * [Marcelo Manzan](https://github.com/kawamanza)
137 | * [See the full list](https://github.com/igorescobar/jQuery-Mask-Plugin/graphs/contributors)
138 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-mask-plugin",
3 | "version": "1.14.16",
4 | "main": "dist/jquery.mask.js",
5 | "ignore": [
6 | "deploy.rb",
7 | "jquery.mask.json",
8 | "Gruntfile.js",
9 | "test/*",
10 | ".*"
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/component.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jQuery-Mask-Plugin",
3 | "description": "A jQuery Plugin to make masks on form fields and HTML elements.",
4 | "version": "1.14.16",
5 | "keywords": ["javascript", "mask", "form"],
6 | "scripts": [
7 | "dist/jquery.mask.js"
8 | ],
9 | "main": "dist/jquery.mask.js"
10 | }
11 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "igorescobar/jquery-mask-plugin",
3 | "type": "library",
4 | "description": "A jQuery Plugin to make masks on form fields and html elements.",
5 | "keywords": ["jquery", "mask", "plugin"],
6 | "homepage": "https://github.com/igorescobar/jQuery-Mask-Plugin",
7 | "license": "MIT",
8 | "authors": [
9 | {
10 | "name": "Igor Escobar",
11 | "email": "blog@igorescobar.com",
12 | "homepage": "https://about.me/igorescobar",
13 | "role": "Developer"
14 | }
15 | ],
16 | "support": {
17 | "issues": "https://github.com/igorescobar/jQuery-Mask-Plugin/issues"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/deploy.rb:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 | require 'zlib'
3 |
4 | JMASK_FILE = 'src/jquery.mask.js'
5 | JMASK_MIN_FILE = 'dist/jquery.mask.min.js'
6 | GHPAGES_JMASK_MIN_FILE = 'js/jquery.mask.min.js'
7 | JMASK_VERSION = `stepup version --next-release`.delete("\n")
8 | BOWER_MANIFEST_FILE = 'bower.json'
9 | NPM_MANIFEST_FILE = 'package.json'
10 | METEOR_MANIFEST_FILE = 'package.js'
11 | COMPONENT_MANIFEST_FILE = 'component.json'
12 |
13 | abort("No notes, do deal.") if JMASK_VERSION.empty?
14 |
15 | puts '# PUTTING NEW VERSION INSIDE OF JQUERY MASK FILE'
16 | unversioned_jmask_file = File.open(JMASK_FILE, 'rb') { |file| file.read }
17 | File.open(JMASK_FILE, 'w') do |file|
18 | file.write(unversioned_jmask_file.gsub(/\* @version: (v[0-9.+]+)/, "\* @version: #{JMASK_VERSION}"))
19 | end
20 |
21 | puts '# COPYING NEW JMASK FILE TO DIST/'
22 | `yes | cp #{JMASK_FILE} dist/`
23 |
24 | [BOWER_MANIFEST_FILE, NPM_MANIFEST_FILE, COMPONENT_MANIFEST_FILE, METEOR_MANIFEST_FILE].each { |manifest_name|
25 | puts "# UPGRADING #{manifest_name} "
26 | manifest_file = File.open(manifest_name, 'rb') { |file| file.read }
27 | File.open(manifest_name, 'w') do |file|
28 | file.write(manifest_file.gsub(/"version": "([0-9.+]+)"/, "\"version\": \"#{JMASK_VERSION.gsub("v", "")}\""))
29 | end
30 | }
31 |
32 | puts '# GENERATING MIN FILE'
33 | jquery_mask_min_file = nil
34 | File.open(JMASK_FILE, 'r') do |file|
35 | minFile = File.open(JMASK_MIN_FILE, 'w')
36 | minFile.puts("// jQuery Mask Plugin #{JMASK_VERSION}")
37 | minFile.puts("// github.com/igorescobar/jQuery-Mask-Plugin")
38 | jquery_mask_min_file = `java -jar ../clojure-compiler/compiler.jar --js src/jquery.mask.js --charset UTF-8`
39 | minFile.puts(jquery_mask_min_file)
40 | minFile.close
41 | end
42 |
43 | puts '# GENERATING A NEW COMMIT WITH VERSIONED FILEs'
44 | `git commit -am 'generating jquery mask files #{JMASK_VERSION}'`
45 |
46 | puts '# PUSHING CHANGES TO REMOTE'
47 | `git pull --rebase && git push`
48 |
49 | puts '# CREATING NEW VERSION'
50 | `stepup version create --no-editor`
51 |
52 | puts '# UPGRATING CHANGELOG'
53 | `stepup changelog --format=wiki > CHANGELOG.md`
54 | `git commit -am "upgrading changelog"`
55 | `git push`
56 |
57 | puts '# UPGRADING gh-pages'
58 | `git checkout gh-pages`
59 | `git pull origin gh-pages`
60 |
61 | minFile = File.open(GHPAGES_JMASK_MIN_FILE, 'w')
62 | minFile.puts("// jQuery Mask Plugin #{JMASK_VERSION}")
63 | minFile.puts("// github.com/igorescobar/jQuery-Mask-Plugin")
64 | minFile.puts(jquery_mask_min_file)
65 | minFile.close
66 |
67 | `git commit -am "upgrading plugin file"`
68 | `git push`
69 | `git checkout master`
70 |
71 | puts '# PUBLISHING NPM PACKAGE'
72 | `npm publish`
73 |
74 | puts '# PUBLISHING METEOR PACKAGE'
75 | `meteor publish`
76 |
77 | puts '# DONE!'
78 |
--------------------------------------------------------------------------------
/dist/jquery.mask.js:
--------------------------------------------------------------------------------
1 | /**
2 | * jquery.mask.js
3 | * @version: v1.14.16
4 | * @author: Igor Escobar
5 | *
6 | * Created by Igor Escobar on 2012-03-10. Please report any bug at github.com/igorescobar/jQuery-Mask-Plugin
7 | *
8 | * Copyright (c) 2012 Igor Escobar http://igorescobar.com
9 | *
10 | * The MIT License (http://www.opensource.org/licenses/mit-license.php)
11 | *
12 | * Permission is hereby granted, free of charge, to any person
13 | * obtaining a copy of this software and associated documentation
14 | * files (the "Software"), to deal in the Software without
15 | * restriction, including without limitation the rights to use,
16 | * copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | * copies of the Software, and to permit persons to whom the
18 | * Software is furnished to do so, subject to the following
19 | * conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
26 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
28 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
29 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
31 | * OTHER DEALINGS IN THE SOFTWARE.
32 | */
33 |
34 | /* jshint laxbreak: true */
35 | /* jshint maxcomplexity:17 */
36 | /* global define */
37 |
38 | // UMD (Universal Module Definition) patterns for JavaScript modules that work everywhere.
39 | // https://github.com/umdjs/umd/blob/master/templates/jqueryPlugin.js
40 | (function (factory, jQuery, Zepto) {
41 |
42 | if (typeof define === 'function' && define.amd) {
43 | define(['jquery'], factory);
44 | } else if (typeof exports === 'object' && typeof Meteor === 'undefined') {
45 | module.exports = factory(require('jquery'));
46 | } else {
47 | factory(jQuery || Zepto);
48 | }
49 |
50 | }(function ($) {
51 | 'use strict';
52 |
53 | var Mask = function (el, mask, options) {
54 |
55 | var p = {
56 | invalid: [],
57 | getCaret: function () {
58 | try {
59 | var sel,
60 | pos = 0,
61 | ctrl = el.get(0),
62 | dSel = document.selection,
63 | cSelStart = ctrl.selectionStart;
64 |
65 | // IE Support
66 | if (dSel && navigator.appVersion.indexOf('MSIE 10') === -1) {
67 | sel = dSel.createRange();
68 | sel.moveStart('character', -p.val().length);
69 | pos = sel.text.length;
70 | }
71 | // Firefox support
72 | else if (cSelStart || cSelStart === '0') {
73 | pos = cSelStart;
74 | }
75 |
76 | return pos;
77 | } catch (e) {}
78 | },
79 | setCaret: function(pos) {
80 | try {
81 | if (el.is(':focus')) {
82 | var range, ctrl = el.get(0);
83 |
84 | // Firefox, WebKit, etc..
85 | if (ctrl.setSelectionRange) {
86 | ctrl.setSelectionRange(pos, pos);
87 | } else { // IE
88 | range = ctrl.createTextRange();
89 | range.collapse(true);
90 | range.moveEnd('character', pos);
91 | range.moveStart('character', pos);
92 | range.select();
93 | }
94 | }
95 | } catch (e) {}
96 | },
97 | events: function() {
98 | el
99 | .on('keydown.mask', function(e) {
100 | el.data('mask-keycode', e.keyCode || e.which);
101 | el.data('mask-previus-value', el.val());
102 | el.data('mask-previus-caret-pos', p.getCaret());
103 | p.maskDigitPosMapOld = p.maskDigitPosMap;
104 | })
105 | .on($.jMaskGlobals.useInput ? 'input.mask' : 'keyup.mask', p.behaviour)
106 | .on('paste.mask drop.mask', function() {
107 | setTimeout(function() {
108 | el.keydown().keyup();
109 | }, 100);
110 | })
111 | .on('change.mask', function(){
112 | el.data('changed', true);
113 | })
114 | .on('blur.mask', function(){
115 | if (oldValue !== p.val() && !el.data('changed')) {
116 | el.trigger('change');
117 | }
118 | el.data('changed', false);
119 | })
120 | // it's very important that this callback remains in this position
121 | // otherwhise oldValue it's going to work buggy
122 | .on('blur.mask', function() {
123 | oldValue = p.val();
124 | })
125 | // select all text on focus
126 | .on('focus.mask', function (e) {
127 | if (options.selectOnFocus === true) {
128 | $(e.target).select();
129 | }
130 | })
131 | // clear the value if it not complete the mask
132 | .on('focusout.mask', function() {
133 | if (options.clearIfNotMatch && !regexMask.test(p.val())) {
134 | p.val('');
135 | }
136 | });
137 | },
138 | getRegexMask: function() {
139 | var maskChunks = [], translation, pattern, optional, recursive, oRecursive, r;
140 |
141 | for (var i = 0; i < mask.length; i++) {
142 | translation = jMask.translation[mask.charAt(i)];
143 |
144 | if (translation) {
145 |
146 | pattern = translation.pattern.toString().replace(/.{1}$|^.{1}/g, '');
147 | optional = translation.optional;
148 | recursive = translation.recursive;
149 |
150 | if (recursive) {
151 | maskChunks.push(mask.charAt(i));
152 | oRecursive = {digit: mask.charAt(i), pattern: pattern};
153 | } else {
154 | maskChunks.push(!optional && !recursive ? pattern : (pattern + '?'));
155 | }
156 |
157 | } else {
158 | maskChunks.push(mask.charAt(i).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'));
159 | }
160 | }
161 |
162 | r = maskChunks.join('');
163 |
164 | if (oRecursive) {
165 | r = r.replace(new RegExp('(' + oRecursive.digit + '(.*' + oRecursive.digit + ')?)'), '($1)?')
166 | .replace(new RegExp(oRecursive.digit, 'g'), oRecursive.pattern);
167 | }
168 |
169 | return new RegExp(r);
170 | },
171 | destroyEvents: function() {
172 | el.off(['input', 'keydown', 'keyup', 'paste', 'drop', 'blur', 'focusout', ''].join('.mask '));
173 | },
174 | val: function(v) {
175 | var isInput = el.is('input'),
176 | method = isInput ? 'val' : 'text',
177 | r;
178 |
179 | if (arguments.length > 0) {
180 | if (el[method]() !== v) {
181 | el[method](v);
182 | }
183 | r = el;
184 | } else {
185 | r = el[method]();
186 | }
187 |
188 | return r;
189 | },
190 | calculateCaretPosition: function(oldVal) {
191 | var newVal = p.getMasked(),
192 | caretPosNew = p.getCaret();
193 | if (oldVal !== newVal) {
194 | var caretPosOld = el.data('mask-previus-caret-pos') || 0,
195 | newValL = newVal.length,
196 | oldValL = oldVal.length,
197 | maskDigitsBeforeCaret = 0,
198 | maskDigitsAfterCaret = 0,
199 | maskDigitsBeforeCaretAll = 0,
200 | maskDigitsBeforeCaretAllOld = 0,
201 | i = 0;
202 |
203 | for (i = caretPosNew; i < newValL; i++) {
204 | if (!p.maskDigitPosMap[i]) {
205 | break;
206 | }
207 | maskDigitsAfterCaret++;
208 | }
209 |
210 | for (i = caretPosNew - 1; i >= 0; i--) {
211 | if (!p.maskDigitPosMap[i]) {
212 | break;
213 | }
214 | maskDigitsBeforeCaret++;
215 | }
216 |
217 | for (i = caretPosNew - 1; i >= 0; i--) {
218 | if (p.maskDigitPosMap[i]) {
219 | maskDigitsBeforeCaretAll++;
220 | }
221 | }
222 |
223 | for (i = caretPosOld - 1; i >= 0; i--) {
224 | if (p.maskDigitPosMapOld[i]) {
225 | maskDigitsBeforeCaretAllOld++;
226 | }
227 | }
228 |
229 | // if the cursor is at the end keep it there
230 | if (caretPosNew > oldValL) {
231 | caretPosNew = newValL * 10;
232 | } else if (caretPosOld >= caretPosNew && caretPosOld !== oldValL) {
233 | if (!p.maskDigitPosMapOld[caretPosNew]) {
234 | var caretPos = caretPosNew;
235 | caretPosNew -= maskDigitsBeforeCaretAllOld - maskDigitsBeforeCaretAll;
236 | caretPosNew -= maskDigitsBeforeCaret;
237 | if (p.maskDigitPosMap[caretPosNew]) {
238 | caretPosNew = caretPos;
239 | }
240 | }
241 | }
242 | else if (caretPosNew > caretPosOld) {
243 | caretPosNew += maskDigitsBeforeCaretAll - maskDigitsBeforeCaretAllOld;
244 | caretPosNew += maskDigitsAfterCaret;
245 | }
246 | }
247 | return caretPosNew;
248 | },
249 | behaviour: function(e) {
250 | e = e || window.event;
251 | p.invalid = [];
252 |
253 | var keyCode = el.data('mask-keycode');
254 |
255 | if ($.inArray(keyCode, jMask.byPassKeys) === -1) {
256 | var newVal = p.getMasked(),
257 | caretPos = p.getCaret(),
258 | oldVal = el.data('mask-previus-value') || '';
259 |
260 | // this is a compensation to devices/browsers that don't compensate
261 | // caret positioning the right way
262 | setTimeout(function() {
263 | p.setCaret(p.calculateCaretPosition(oldVal));
264 | }, $.jMaskGlobals.keyStrokeCompensation);
265 |
266 | p.val(newVal);
267 | p.setCaret(caretPos);
268 | return p.callbacks(e);
269 | }
270 | },
271 | getMasked: function(skipMaskChars, val) {
272 | var buf = [],
273 | value = val === undefined ? p.val() : val + '',
274 | m = 0, maskLen = mask.length,
275 | v = 0, valLen = value.length,
276 | offset = 1, addMethod = 'push',
277 | resetPos = -1,
278 | maskDigitCount = 0,
279 | maskDigitPosArr = [],
280 | lastMaskChar,
281 | check;
282 |
283 | if (options.reverse) {
284 | addMethod = 'unshift';
285 | offset = -1;
286 | lastMaskChar = 0;
287 | m = maskLen - 1;
288 | v = valLen - 1;
289 | check = function () {
290 | return m > -1 && v > -1;
291 | };
292 | } else {
293 | lastMaskChar = maskLen - 1;
294 | check = function () {
295 | return m < maskLen && v < valLen;
296 | };
297 | }
298 |
299 | var lastUntranslatedMaskChar;
300 | while (check()) {
301 | var maskDigit = mask.charAt(m),
302 | valDigit = value.charAt(v),
303 | translation = jMask.translation[maskDigit];
304 |
305 | if (translation) {
306 | if (valDigit.match(translation.pattern)) {
307 | buf[addMethod](valDigit);
308 | if (translation.recursive) {
309 | if (resetPos === -1) {
310 | resetPos = m;
311 | } else if (m === lastMaskChar && m !== resetPos) {
312 | m = resetPos - offset;
313 | }
314 |
315 | if (lastMaskChar === resetPos) {
316 | m -= offset;
317 | }
318 | }
319 | m += offset;
320 | } else if (valDigit === lastUntranslatedMaskChar) {
321 | // matched the last untranslated (raw) mask character that we encountered
322 | // likely an insert offset the mask character from the last entry; fall
323 | // through and only increment v
324 | maskDigitCount--;
325 | lastUntranslatedMaskChar = undefined;
326 | } else if (translation.optional) {
327 | m += offset;
328 | v -= offset;
329 | } else if (translation.fallback) {
330 | buf[addMethod](translation.fallback);
331 | m += offset;
332 | v -= offset;
333 | } else {
334 | p.invalid.push({p: v, v: valDigit, e: translation.pattern});
335 | }
336 | v += offset;
337 | } else {
338 | if (!skipMaskChars) {
339 | buf[addMethod](maskDigit);
340 | }
341 |
342 | if (valDigit === maskDigit) {
343 | maskDigitPosArr.push(v);
344 | v += offset;
345 | } else {
346 | lastUntranslatedMaskChar = maskDigit;
347 | maskDigitPosArr.push(v + maskDigitCount);
348 | maskDigitCount++;
349 | }
350 |
351 | m += offset;
352 | }
353 | }
354 |
355 | var lastMaskCharDigit = mask.charAt(lastMaskChar);
356 | if (maskLen === valLen + 1 && !jMask.translation[lastMaskCharDigit]) {
357 | buf.push(lastMaskCharDigit);
358 | }
359 |
360 | var newVal = buf.join('');
361 | p.mapMaskdigitPositions(newVal, maskDigitPosArr, valLen);
362 | return newVal;
363 | },
364 | mapMaskdigitPositions: function(newVal, maskDigitPosArr, valLen) {
365 | var maskDiff = options.reverse ? newVal.length - valLen : 0;
366 | p.maskDigitPosMap = {};
367 | for (var i = 0; i < maskDigitPosArr.length; i++) {
368 | p.maskDigitPosMap[maskDigitPosArr[i] + maskDiff] = 1;
369 | }
370 | },
371 | callbacks: function (e) {
372 | var val = p.val(),
373 | changed = val !== oldValue,
374 | defaultArgs = [val, e, el, options],
375 | callback = function(name, criteria, args) {
376 | if (typeof options[name] === 'function' && criteria) {
377 | options[name].apply(this, args);
378 | }
379 | };
380 |
381 | callback('onChange', changed === true, defaultArgs);
382 | callback('onKeyPress', changed === true, defaultArgs);
383 | callback('onComplete', val.length === mask.length, defaultArgs);
384 | callback('onInvalid', p.invalid.length > 0, [val, e, el, p.invalid, options]);
385 | }
386 | };
387 |
388 | el = $(el);
389 | var jMask = this, oldValue = p.val(), regexMask;
390 |
391 | mask = typeof mask === 'function' ? mask(p.val(), undefined, el, options) : mask;
392 |
393 | // public methods
394 | jMask.mask = mask;
395 | jMask.options = options;
396 | jMask.remove = function() {
397 | var caret = p.getCaret();
398 | if (jMask.options.placeholder) {
399 | el.removeAttr('placeholder');
400 | }
401 | if (el.data('mask-maxlength')) {
402 | el.removeAttr('maxlength');
403 | }
404 | p.destroyEvents();
405 | p.val(jMask.getCleanVal());
406 | p.setCaret(caret);
407 | return el;
408 | };
409 |
410 | // get value without mask
411 | jMask.getCleanVal = function() {
412 | return p.getMasked(true);
413 | };
414 |
415 | // get masked value without the value being in the input or element
416 | jMask.getMaskedVal = function(val) {
417 | return p.getMasked(false, val);
418 | };
419 |
420 | jMask.init = function(onlyMask) {
421 | onlyMask = onlyMask || false;
422 | options = options || {};
423 |
424 | jMask.clearIfNotMatch = $.jMaskGlobals.clearIfNotMatch;
425 | jMask.byPassKeys = $.jMaskGlobals.byPassKeys;
426 | jMask.translation = $.extend({}, $.jMaskGlobals.translation, options.translation);
427 |
428 | jMask = $.extend(true, {}, jMask, options);
429 |
430 | regexMask = p.getRegexMask();
431 |
432 | if (onlyMask) {
433 | p.events();
434 | p.val(p.getMasked());
435 | } else {
436 | if (options.placeholder) {
437 | el.attr('placeholder' , options.placeholder);
438 | }
439 |
440 | // this is necessary, otherwise if the user submit the form
441 | // and then press the "back" button, the autocomplete will erase
442 | // the data. Works fine on IE9+, FF, Opera, Safari.
443 | if (el.data('mask')) {
444 | el.attr('autocomplete', 'off');
445 | }
446 |
447 | // detect if is necessary let the user type freely.
448 | // for is a lot faster than forEach.
449 | for (var i = 0, maxlength = true; i < mask.length; i++) {
450 | var translation = jMask.translation[mask.charAt(i)];
451 | if (translation && translation.recursive) {
452 | maxlength = false;
453 | break;
454 | }
455 | }
456 |
457 | if (maxlength) {
458 | el.attr('maxlength', mask.length).data('mask-maxlength', true);
459 | }
460 |
461 | p.destroyEvents();
462 | p.events();
463 |
464 | var caret = p.getCaret();
465 | p.val(p.getMasked());
466 | p.setCaret(caret);
467 | }
468 | };
469 |
470 | jMask.init(!el.is('input'));
471 | };
472 |
473 | $.maskWatchers = {};
474 | var HTMLAttributes = function () {
475 | var input = $(this),
476 | options = {},
477 | prefix = 'data-mask-',
478 | mask = input.attr('data-mask');
479 |
480 | if (input.attr(prefix + 'reverse')) {
481 | options.reverse = true;
482 | }
483 |
484 | if (input.attr(prefix + 'clearifnotmatch')) {
485 | options.clearIfNotMatch = true;
486 | }
487 |
488 | if (input.attr(prefix + 'selectonfocus') === 'true') {
489 | options.selectOnFocus = true;
490 | }
491 |
492 | if (notSameMaskObject(input, mask, options)) {
493 | return input.data('mask', new Mask(this, mask, options));
494 | }
495 | },
496 | notSameMaskObject = function(field, mask, options) {
497 | options = options || {};
498 | var maskObject = $(field).data('mask'),
499 | stringify = JSON.stringify,
500 | value = $(field).val() || $(field).text();
501 | try {
502 | if (typeof mask === 'function') {
503 | mask = mask(value);
504 | }
505 | return typeof maskObject !== 'object' || stringify(maskObject.options) !== stringify(options) || maskObject.mask !== mask;
506 | } catch (e) {}
507 | },
508 | eventSupported = function(eventName) {
509 | var el = document.createElement('div'), isSupported;
510 |
511 | eventName = 'on' + eventName;
512 | isSupported = (eventName in el);
513 |
514 | if ( !isSupported ) {
515 | el.setAttribute(eventName, 'return;');
516 | isSupported = typeof el[eventName] === 'function';
517 | }
518 | el = null;
519 |
520 | return isSupported;
521 | };
522 |
523 | $.fn.mask = function(mask, options) {
524 | options = options || {};
525 | var selector = this.selector,
526 | globals = $.jMaskGlobals,
527 | interval = globals.watchInterval,
528 | watchInputs = options.watchInputs || globals.watchInputs,
529 | maskFunction = function() {
530 | if (notSameMaskObject(this, mask, options)) {
531 | return $(this).data('mask', new Mask(this, mask, options));
532 | }
533 | };
534 |
535 | $(this).each(maskFunction);
536 |
537 | if (selector && selector !== '' && watchInputs) {
538 | clearInterval($.maskWatchers[selector]);
539 | $.maskWatchers[selector] = setInterval(function(){
540 | $(document).find(selector).each(maskFunction);
541 | }, interval);
542 | }
543 | return this;
544 | };
545 |
546 | $.fn.masked = function(val) {
547 | return this.data('mask').getMaskedVal(val);
548 | };
549 |
550 | $.fn.unmask = function() {
551 | clearInterval($.maskWatchers[this.selector]);
552 | delete $.maskWatchers[this.selector];
553 | return this.each(function() {
554 | var dataMask = $(this).data('mask');
555 | if (dataMask) {
556 | dataMask.remove().removeData('mask');
557 | }
558 | });
559 | };
560 |
561 | $.fn.cleanVal = function() {
562 | return this.data('mask').getCleanVal();
563 | };
564 |
565 | $.applyDataMask = function(selector) {
566 | selector = selector || $.jMaskGlobals.maskElements;
567 | var $selector = (selector instanceof $) ? selector : $(selector);
568 | $selector.filter($.jMaskGlobals.dataMaskAttr).each(HTMLAttributes);
569 | };
570 |
571 | var globals = {
572 | maskElements: 'input,td,span,div',
573 | dataMaskAttr: '*[data-mask]',
574 | dataMask: true,
575 | watchInterval: 300,
576 | watchInputs: true,
577 | keyStrokeCompensation: 10,
578 | // old versions of chrome dont work great with input event
579 | useInput: !/Chrome\/[2-4][0-9]|SamsungBrowser/.test(window.navigator.userAgent) && eventSupported('input'),
580 | watchDataMask: false,
581 | byPassKeys: [9, 16, 17, 18, 36, 37, 38, 39, 40, 91],
582 | translation: {
583 | '0': {pattern: /\d/},
584 | '9': {pattern: /\d/, optional: true},
585 | '#': {pattern: /\d/, recursive: true},
586 | 'A': {pattern: /[a-zA-Z0-9]/},
587 | 'S': {pattern: /[a-zA-Z]/}
588 | }
589 | };
590 |
591 | $.jMaskGlobals = $.jMaskGlobals || {};
592 | globals = $.jMaskGlobals = $.extend(true, {}, globals, $.jMaskGlobals);
593 |
594 | // looking for inputs with data-mask attribute
595 | if (globals.dataMask) {
596 | $.applyDataMask();
597 | }
598 |
599 | setInterval(function() {
600 | if ($.jMaskGlobals.watchDataMask) {
601 | $.applyDataMask();
602 | }
603 | }, globals.watchInterval);
604 | }, window.jQuery, window.Zepto));
605 |
--------------------------------------------------------------------------------
/dist/jquery.mask.min.js:
--------------------------------------------------------------------------------
1 | // jQuery Mask Plugin v1.14.16
2 | // github.com/igorescobar/jQuery-Mask-Plugin
3 | var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(a,n,f){a instanceof String&&(a=String(a));for(var p=a.length,k=0;k
g?h=10*d:e>=h&&e!==g?c.maskDigitPosMapOld[h]||(e=h,h=h-(k-l)-a,c.maskDigitPosMap[h]&&(h=e)):h>e&&(h=h+(l-k)+f)}return h},behaviour:function(d){d=
11 | d||window.event;c.invalid=[];var e=b.data("mask-keycode");if(-1===a.inArray(e,l.byPassKeys)){e=c.getMasked();var h=c.getCaret(),g=b.data("mask-previus-value")||"";setTimeout(function(){c.setCaret(c.calculateCaretPosition(g))},a.jMaskGlobals.keyStrokeCompensation);c.val(e);c.setCaret(h);return c.callbacks(d)}},getMasked:function(a,b){var h=[],f=void 0===b?c.val():b+"",g=0,k=d.length,n=0,p=f.length,m=1,r="push",u=-1,w=0;b=[];if(e.reverse){r="unshift";m=-1;var x=0;g=k-1;n=p-1;var A=function(){return-1<
12 | g&&-1",
6 | "homepage": "http://igorescobar.github.io/jQuery-Mask-Plugin/",
7 | "main": "./dist/jquery.mask.js",
8 | "repository": {
9 | "type": "git",
10 | "url": "https://github.com/igorescobar/jQuery-Mask-Plugin"
11 | },
12 | "bugs": {
13 | "url": "https://github.com/igorescobar/jQuery-Mask-Plugin/issues"
14 | },
15 | "keywords": [
16 | "mask",
17 | "masks",
18 | "form",
19 | "input",
20 | "jquery-plugin"
21 | ],
22 | "license": "MIT",
23 | "devDependencies": {
24 | "grunt": "^1.0.4",
25 | "grunt-contrib-connect": "*",
26 | "grunt-contrib-jshint": "^2.1.0",
27 | "grunt-contrib-qunit": "^3.1.0",
28 | "grunt-contrib-uglify": "*",
29 | "jshint-stylish": "^1.0.0",
30 | "load-grunt-tasks": "^3.1.0",
31 | "request": "2.88.0",
32 | "time-grunt": "^1.0.0"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/jquery.mask.js:
--------------------------------------------------------------------------------
1 | /**
2 | * jquery.mask.js
3 | * @version: v1.14.16
4 | * @author: Igor Escobar
5 | *
6 | * Created by Igor Escobar on 2012-03-10. Please report any bug at github.com/igorescobar/jQuery-Mask-Plugin
7 | *
8 | * Copyright (c) 2012 Igor Escobar http://igorescobar.com
9 | *
10 | * The MIT License (http://www.opensource.org/licenses/mit-license.php)
11 | *
12 | * Permission is hereby granted, free of charge, to any person
13 | * obtaining a copy of this software and associated documentation
14 | * files (the "Software"), to deal in the Software without
15 | * restriction, including without limitation the rights to use,
16 | * copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | * copies of the Software, and to permit persons to whom the
18 | * Software is furnished to do so, subject to the following
19 | * conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
26 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
28 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
29 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
31 | * OTHER DEALINGS IN THE SOFTWARE.
32 | */
33 |
34 | /* jshint laxbreak: true */
35 | /* jshint maxcomplexity:17 */
36 | /* global define */
37 |
38 | // UMD (Universal Module Definition) patterns for JavaScript modules that work everywhere.
39 | // https://github.com/umdjs/umd/blob/master/templates/jqueryPlugin.js
40 | (function (factory, jQuery, Zepto) {
41 |
42 | if (typeof define === 'function' && define.amd) {
43 | define(['jquery'], factory);
44 | } else if (typeof exports === 'object' && typeof Meteor === 'undefined') {
45 | module.exports = factory(require('jquery'));
46 | } else {
47 | factory(jQuery || Zepto);
48 | }
49 |
50 | }(function ($) {
51 | 'use strict';
52 |
53 | var Mask = function (el, mask, options) {
54 |
55 | var p = {
56 | invalid: [],
57 | getCaret: function () {
58 | try {
59 | var sel,
60 | pos = 0,
61 | ctrl = el.get(0),
62 | dSel = document.selection,
63 | cSelStart = ctrl.selectionStart;
64 |
65 | // IE Support
66 | if (dSel && navigator.appVersion.indexOf('MSIE 10') === -1) {
67 | sel = dSel.createRange();
68 | sel.moveStart('character', -p.val().length);
69 | pos = sel.text.length;
70 | }
71 | // Firefox support
72 | else if (cSelStart || cSelStart === '0') {
73 | pos = cSelStart;
74 | }
75 |
76 | return pos;
77 | } catch (e) {}
78 | },
79 | setCaret: function(pos) {
80 | try {
81 | if (el.is(':focus')) {
82 | var range, ctrl = el.get(0);
83 |
84 | // Firefox, WebKit, etc..
85 | if (ctrl.setSelectionRange) {
86 | ctrl.setSelectionRange(pos, pos);
87 | } else { // IE
88 | range = ctrl.createTextRange();
89 | range.collapse(true);
90 | range.moveEnd('character', pos);
91 | range.moveStart('character', pos);
92 | range.select();
93 | }
94 | }
95 | } catch (e) {}
96 | },
97 | events: function() {
98 | el
99 | .on('keydown.mask', function(e) {
100 | el.data('mask-keycode', e.keyCode || e.which);
101 | el.data('mask-previus-value', el.val());
102 | el.data('mask-previus-caret-pos', p.getCaret());
103 | p.maskDigitPosMapOld = p.maskDigitPosMap;
104 | })
105 | .on($.jMaskGlobals.useInput ? 'input.mask' : 'keyup.mask', p.behaviour)
106 | .on('paste.mask drop.mask', function() {
107 | setTimeout(function() {
108 | el.keydown().keyup();
109 | }, 100);
110 | })
111 | .on('change.mask', function(){
112 | el.data('changed', true);
113 | })
114 | .on('blur.mask', function(){
115 | if (oldValue !== p.val() && !el.data('changed')) {
116 | el.trigger('change');
117 | }
118 | el.data('changed', false);
119 | })
120 | // it's very important that this callback remains in this position
121 | // otherwhise oldValue it's going to work buggy
122 | .on('blur.mask', function() {
123 | oldValue = p.val();
124 | })
125 | // select all text on focus
126 | .on('focus.mask', function (e) {
127 | if (options.selectOnFocus === true) {
128 | $(e.target).select();
129 | }
130 | })
131 | // clear the value if it not complete the mask
132 | .on('focusout.mask', function() {
133 | if (options.clearIfNotMatch && !regexMask.test(p.val())) {
134 | p.val('');
135 | }
136 | });
137 | },
138 | getRegexMask: function() {
139 | var maskChunks = [], translation, pattern, optional, recursive, oRecursive, r;
140 |
141 | for (var i = 0; i < mask.length; i++) {
142 | translation = jMask.translation[mask.charAt(i)];
143 |
144 | if (translation) {
145 |
146 | pattern = translation.pattern.toString().replace(/.{1}$|^.{1}/g, '');
147 | optional = translation.optional;
148 | recursive = translation.recursive;
149 |
150 | if (recursive) {
151 | maskChunks.push(mask.charAt(i));
152 | oRecursive = {digit: mask.charAt(i), pattern: pattern};
153 | } else {
154 | maskChunks.push(!optional && !recursive ? pattern : (pattern + '?'));
155 | }
156 |
157 | } else {
158 | maskChunks.push(mask.charAt(i).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'));
159 | }
160 | }
161 |
162 | r = maskChunks.join('');
163 |
164 | if (oRecursive) {
165 | r = r.replace(new RegExp('(' + oRecursive.digit + '(.*' + oRecursive.digit + ')?)'), '($1)?')
166 | .replace(new RegExp(oRecursive.digit, 'g'), oRecursive.pattern);
167 | }
168 |
169 | return new RegExp(r);
170 | },
171 | destroyEvents: function() {
172 | el.off(['input', 'keydown', 'keyup', 'paste', 'drop', 'blur', 'focusout', ''].join('.mask '));
173 | },
174 | val: function(v) {
175 | var isInput = el.is('input'),
176 | method = isInput ? 'val' : 'text',
177 | r;
178 |
179 | if (arguments.length > 0) {
180 | if (el[method]() !== v) {
181 | el[method](v);
182 | }
183 | r = el;
184 | } else {
185 | r = el[method]();
186 | }
187 |
188 | return r;
189 | },
190 | calculateCaretPosition: function(oldVal) {
191 | var newVal = p.getMasked(),
192 | caretPosNew = p.getCaret();
193 | if (oldVal !== newVal) {
194 | var caretPosOld = el.data('mask-previus-caret-pos') || 0,
195 | newValL = newVal.length,
196 | oldValL = oldVal.length,
197 | maskDigitsBeforeCaret = 0,
198 | maskDigitsAfterCaret = 0,
199 | maskDigitsBeforeCaretAll = 0,
200 | maskDigitsBeforeCaretAllOld = 0,
201 | i = 0;
202 |
203 | for (i = caretPosNew; i < newValL; i++) {
204 | if (!p.maskDigitPosMap[i]) {
205 | break;
206 | }
207 | maskDigitsAfterCaret++;
208 | }
209 |
210 | for (i = caretPosNew - 1; i >= 0; i--) {
211 | if (!p.maskDigitPosMap[i]) {
212 | break;
213 | }
214 | maskDigitsBeforeCaret++;
215 | }
216 |
217 | for (i = caretPosNew - 1; i >= 0; i--) {
218 | if (p.maskDigitPosMap[i]) {
219 | maskDigitsBeforeCaretAll++;
220 | }
221 | }
222 |
223 | for (i = caretPosOld - 1; i >= 0; i--) {
224 | if (p.maskDigitPosMapOld[i]) {
225 | maskDigitsBeforeCaretAllOld++;
226 | }
227 | }
228 |
229 | // if the cursor is at the end keep it there
230 | if (caretPosNew > oldValL) {
231 | caretPosNew = newValL * 10;
232 | } else if (caretPosOld >= caretPosNew && caretPosOld !== oldValL) {
233 | if (!p.maskDigitPosMapOld[caretPosNew]) {
234 | var caretPos = caretPosNew;
235 | caretPosNew -= maskDigitsBeforeCaretAllOld - maskDigitsBeforeCaretAll;
236 | caretPosNew -= maskDigitsBeforeCaret;
237 | if (p.maskDigitPosMap[caretPosNew]) {
238 | caretPosNew = caretPos;
239 | }
240 | }
241 | }
242 | else if (caretPosNew > caretPosOld) {
243 | caretPosNew += maskDigitsBeforeCaretAll - maskDigitsBeforeCaretAllOld;
244 | caretPosNew += maskDigitsAfterCaret;
245 | }
246 | }
247 | return caretPosNew;
248 | },
249 | behaviour: function(e) {
250 | e = e || window.event;
251 | p.invalid = [];
252 |
253 | var keyCode = el.data('mask-keycode');
254 |
255 | if ($.inArray(keyCode, jMask.byPassKeys) === -1) {
256 | var newVal = p.getMasked(),
257 | caretPos = p.getCaret(),
258 | oldVal = el.data('mask-previus-value') || '';
259 |
260 | // this is a compensation to devices/browsers that don't compensate
261 | // caret positioning the right way
262 | setTimeout(function() {
263 | p.setCaret(p.calculateCaretPosition(oldVal));
264 | }, $.jMaskGlobals.keyStrokeCompensation);
265 |
266 | p.val(newVal);
267 | p.setCaret(caretPos);
268 | return p.callbacks(e);
269 | }
270 | },
271 | getMasked: function(skipMaskChars, val) {
272 | var buf = [],
273 | value = val === undefined ? p.val() : val + '',
274 | m = 0, maskLen = mask.length,
275 | v = 0, valLen = value.length,
276 | offset = 1, addMethod = 'push',
277 | resetPos = -1,
278 | maskDigitCount = 0,
279 | maskDigitPosArr = [],
280 | lastMaskChar,
281 | check;
282 |
283 | if (options.reverse) {
284 | addMethod = 'unshift';
285 | offset = -1;
286 | lastMaskChar = 0;
287 | m = maskLen - 1;
288 | v = valLen - 1;
289 | check = function () {
290 | return m > -1 && v > -1;
291 | };
292 | } else {
293 | lastMaskChar = maskLen - 1;
294 | check = function () {
295 | return m < maskLen && v < valLen;
296 | };
297 | }
298 |
299 | var lastUntranslatedMaskChar;
300 | while (check()) {
301 | var maskDigit = mask.charAt(m),
302 | valDigit = value.charAt(v),
303 | translation = jMask.translation[maskDigit];
304 |
305 | if (translation) {
306 | if (valDigit.match(translation.pattern)) {
307 | buf[addMethod](valDigit);
308 | if (translation.recursive) {
309 | if (resetPos === -1) {
310 | resetPos = m;
311 | } else if (m === lastMaskChar && m !== resetPos) {
312 | m = resetPos - offset;
313 | }
314 |
315 | if (lastMaskChar === resetPos) {
316 | m -= offset;
317 | }
318 | }
319 | m += offset;
320 | } else if (valDigit === lastUntranslatedMaskChar) {
321 | // matched the last untranslated (raw) mask character that we encountered
322 | // likely an insert offset the mask character from the last entry; fall
323 | // through and only increment v
324 | maskDigitCount--;
325 | lastUntranslatedMaskChar = undefined;
326 | } else if (translation.optional) {
327 | m += offset;
328 | v -= offset;
329 | } else if (translation.fallback) {
330 | buf[addMethod](translation.fallback);
331 | m += offset;
332 | v -= offset;
333 | } else {
334 | p.invalid.push({p: v, v: valDigit, e: translation.pattern});
335 | }
336 | v += offset;
337 | } else {
338 | if (!skipMaskChars) {
339 | buf[addMethod](maskDigit);
340 | }
341 |
342 | if (valDigit === maskDigit) {
343 | maskDigitPosArr.push(v);
344 | v += offset;
345 | } else {
346 | lastUntranslatedMaskChar = maskDigit;
347 | maskDigitPosArr.push(v + maskDigitCount);
348 | maskDigitCount++;
349 | }
350 |
351 | m += offset;
352 | }
353 | }
354 |
355 | var lastMaskCharDigit = mask.charAt(lastMaskChar);
356 | if (maskLen === valLen + 1 && !jMask.translation[lastMaskCharDigit]) {
357 | buf.push(lastMaskCharDigit);
358 | }
359 |
360 | var newVal = buf.join('');
361 | p.mapMaskdigitPositions(newVal, maskDigitPosArr, valLen);
362 | return newVal;
363 | },
364 | mapMaskdigitPositions: function(newVal, maskDigitPosArr, valLen) {
365 | var maskDiff = options.reverse ? newVal.length - valLen : 0;
366 | p.maskDigitPosMap = {};
367 | for (var i = 0; i < maskDigitPosArr.length; i++) {
368 | p.maskDigitPosMap[maskDigitPosArr[i] + maskDiff] = 1;
369 | }
370 | },
371 | callbacks: function (e) {
372 | var val = p.val(),
373 | changed = val !== oldValue,
374 | defaultArgs = [val, e, el, options],
375 | callback = function(name, criteria, args) {
376 | if (typeof options[name] === 'function' && criteria) {
377 | options[name].apply(this, args);
378 | }
379 | };
380 |
381 | callback('onChange', changed === true, defaultArgs);
382 | callback('onKeyPress', changed === true, defaultArgs);
383 | callback('onComplete', val.length === mask.length, defaultArgs);
384 | callback('onInvalid', p.invalid.length > 0, [val, e, el, p.invalid, options]);
385 | }
386 | };
387 |
388 | el = $(el);
389 | var jMask = this, oldValue = p.val(), regexMask;
390 |
391 | mask = typeof mask === 'function' ? mask(p.val(), undefined, el, options) : mask;
392 |
393 | // public methods
394 | jMask.mask = mask;
395 | jMask.options = options;
396 | jMask.remove = function() {
397 | var caret = p.getCaret();
398 | if (jMask.options.placeholder) {
399 | el.removeAttr('placeholder');
400 | }
401 | if (el.data('mask-maxlength')) {
402 | el.removeAttr('maxlength');
403 | }
404 | p.destroyEvents();
405 | p.val(jMask.getCleanVal());
406 | p.setCaret(caret);
407 | return el;
408 | };
409 |
410 | // get value without mask
411 | jMask.getCleanVal = function() {
412 | return p.getMasked(true);
413 | };
414 |
415 | // get masked value without the value being in the input or element
416 | jMask.getMaskedVal = function(val) {
417 | return p.getMasked(false, val);
418 | };
419 |
420 | jMask.init = function(onlyMask) {
421 | onlyMask = onlyMask || false;
422 | options = options || {};
423 |
424 | jMask.clearIfNotMatch = $.jMaskGlobals.clearIfNotMatch;
425 | jMask.byPassKeys = $.jMaskGlobals.byPassKeys;
426 | jMask.translation = $.extend({}, $.jMaskGlobals.translation, options.translation);
427 |
428 | jMask = $.extend(true, {}, jMask, options);
429 |
430 | regexMask = p.getRegexMask();
431 |
432 | if (onlyMask) {
433 | p.events();
434 | p.val(p.getMasked());
435 | } else {
436 | if (options.placeholder) {
437 | el.attr('placeholder' , options.placeholder);
438 | }
439 |
440 | // this is necessary, otherwise if the user submit the form
441 | // and then press the "back" button, the autocomplete will erase
442 | // the data. Works fine on IE9+, FF, Opera, Safari.
443 | if (el.data('mask')) {
444 | el.attr('autocomplete', 'off');
445 | }
446 |
447 | // detect if is necessary let the user type freely.
448 | // for is a lot faster than forEach.
449 | for (var i = 0, maxlength = true; i < mask.length; i++) {
450 | var translation = jMask.translation[mask.charAt(i)];
451 | if (translation && translation.recursive) {
452 | maxlength = false;
453 | break;
454 | }
455 | }
456 |
457 | if (maxlength) {
458 | el.attr('maxlength', mask.length).data('mask-maxlength', true);
459 | }
460 |
461 | p.destroyEvents();
462 | p.events();
463 |
464 | var caret = p.getCaret();
465 | p.val(p.getMasked());
466 | p.setCaret(caret);
467 | }
468 | };
469 |
470 | jMask.init(!el.is('input'));
471 | };
472 |
473 | $.maskWatchers = {};
474 | var HTMLAttributes = function () {
475 | var input = $(this),
476 | options = {},
477 | prefix = 'data-mask-',
478 | mask = input.attr('data-mask');
479 |
480 | if (input.attr(prefix + 'reverse')) {
481 | options.reverse = true;
482 | }
483 |
484 | if (input.attr(prefix + 'clearifnotmatch')) {
485 | options.clearIfNotMatch = true;
486 | }
487 |
488 | if (input.attr(prefix + 'selectonfocus') === 'true') {
489 | options.selectOnFocus = true;
490 | }
491 |
492 | if (notSameMaskObject(input, mask, options)) {
493 | return input.data('mask', new Mask(this, mask, options));
494 | }
495 | },
496 | notSameMaskObject = function(field, mask, options) {
497 | options = options || {};
498 | var maskObject = $(field).data('mask'),
499 | stringify = JSON.stringify,
500 | value = $(field).val() || $(field).text();
501 | try {
502 | if (typeof mask === 'function') {
503 | mask = mask(value);
504 | }
505 | return typeof maskObject !== 'object' || stringify(maskObject.options) !== stringify(options) || maskObject.mask !== mask;
506 | } catch (e) {}
507 | },
508 | eventSupported = function(eventName) {
509 | var el = document.createElement('div'), isSupported;
510 |
511 | eventName = 'on' + eventName;
512 | isSupported = (eventName in el);
513 |
514 | if ( !isSupported ) {
515 | el.setAttribute(eventName, 'return;');
516 | isSupported = typeof el[eventName] === 'function';
517 | }
518 | el = null;
519 |
520 | return isSupported;
521 | };
522 |
523 | $.fn.mask = function(mask, options) {
524 | options = options || {};
525 | var selector = this.selector,
526 | globals = $.jMaskGlobals,
527 | interval = globals.watchInterval,
528 | watchInputs = options.watchInputs || globals.watchInputs,
529 | maskFunction = function() {
530 | if (notSameMaskObject(this, mask, options)) {
531 | return $(this).data('mask', new Mask(this, mask, options));
532 | }
533 | };
534 |
535 | $(this).each(maskFunction);
536 |
537 | if (selector && selector !== '' && watchInputs) {
538 | clearInterval($.maskWatchers[selector]);
539 | $.maskWatchers[selector] = setInterval(function(){
540 | $(document).find(selector).each(maskFunction);
541 | }, interval);
542 | }
543 | return this;
544 | };
545 |
546 | $.fn.masked = function(val) {
547 | return this.data('mask').getMaskedVal(val);
548 | };
549 |
550 | $.fn.unmask = function() {
551 | clearInterval($.maskWatchers[this.selector]);
552 | delete $.maskWatchers[this.selector];
553 | return this.each(function() {
554 | var dataMask = $(this).data('mask');
555 | if (dataMask) {
556 | dataMask.remove().removeData('mask');
557 | }
558 | });
559 | };
560 |
561 | $.fn.cleanVal = function() {
562 | return this.data('mask').getCleanVal();
563 | };
564 |
565 | $.applyDataMask = function(selector) {
566 | selector = selector || $.jMaskGlobals.maskElements;
567 | var $selector = (selector instanceof $) ? selector : $(selector);
568 | $selector.filter($.jMaskGlobals.dataMaskAttr).each(HTMLAttributes);
569 | };
570 |
571 | var globals = {
572 | maskElements: 'input,td,span,div',
573 | dataMaskAttr: '[data-mask]',
574 | dataMask: true,
575 | watchInterval: 300,
576 | watchInputs: true,
577 | keyStrokeCompensation: 10,
578 | // old versions of chrome dont work great with input event
579 | useInput: !/Chrome\/[2-4][0-9]|SamsungBrowser/.test(window.navigator.userAgent) && eventSupported('input'),
580 | watchDataMask: false,
581 | byPassKeys: [9, 16, 17, 18, 36, 37, 38, 39, 40, 91],
582 | translation: {
583 | '0': {pattern: /\d/},
584 | '9': {pattern: /\d/, optional: true},
585 | '#': {pattern: /\d/, recursive: true},
586 | 'A': {pattern: /[a-zA-Z0-9]/},
587 | 'S': {pattern: /[a-zA-Z]/}
588 | }
589 | };
590 |
591 | $.jMaskGlobals = $.jMaskGlobals || {};
592 | globals = $.jMaskGlobals = $.extend(true, {}, globals, $.jMaskGlobals);
593 |
594 | // looking for inputs with data-mask attribute
595 | if (globals.dataMask) {
596 | $.applyDataMask();
597 | }
598 |
599 | setInterval(function() {
600 | if ($.jMaskGlobals.watchDataMask) {
601 | $.applyDataMask();
602 | }
603 | }, globals.watchInterval);
604 | }, window.jQuery, window.Zepto));
605 |
--------------------------------------------------------------------------------
/test/jquery.mask.test.js:
--------------------------------------------------------------------------------
1 | var QUNIT = true;
2 | $(document).ready(function(){
3 |
4 | var testfield = $('.simple-field'),
5 | testfieldDataMask = $('.simple-field-data-mask'),
6 | testfieldDataMaskWithReverse = $('.simple-field-data-mask-reverse'),
7 | testfieldDataMaskWithClearIfNotMatch = $('.simple-field-data-mask-clearifnotmatch'),
8 | testfieldDataMaskWithClearIfNotMatchAndOptionalMask = $('.simple-field-data-mask-clearifnotmatch-and-optional-mask'),
9 | testdiv = $('.simple-div'),
10 | typeTest = function (typedValue, obj) {
11 | obj = typeof obj === "undefined" ? testfield : obj;
12 |
13 | return obj.keydown().val(typedValue).trigger('input').val();
14 | },
15 | typeDivTest = function(typedValue){
16 | return testdiv.keydown().text(typedValue).trigger('input').text();
17 | };
18 |
19 | module('Setting Up');
20 | test("test if the mask method exists after plugin insertion", function() {
21 | equal( typeof testfield.mask , "function" , "mask function should exists" );
22 | });
23 |
24 | module('Simple Masks');
25 | test("Masks with only numbers.", function(){
26 | testfield.mask('000000');
27 |
28 | equal( typeTest("1."), "1");
29 | equal( typeTest('1éáa2aaaaqwo'), "12");
30 | equal( typeTest('1234567'), "123456");
31 |
32 | });
33 |
34 | test("When I change the mask on-the-fly things should work normally", function(){
35 | testfield.mask('0000.0000');
36 |
37 | equal( typeTest("1."), "1");
38 | equal( typeTest('1éáa2aaaaqwo'), "12");
39 | equal( typeTest('1234567'), "1234.567");
40 |
41 | // changing on-the-fly
42 | testfield.mask('0.000.000');
43 |
44 | equal( typeTest("1."), "1.");
45 | equal( typeTest('1éáa2aaaaqwo'), "1.2");
46 | equal( typeTest('1234567'), "1.234.567");
47 |
48 | });
49 |
50 | test("When I change the mask on-the-fly with onChange callback things should work normally", function(){
51 |
52 | var masks = ['0000.00009', '0.0000.0000'];
53 | var SPphoneMask = function(phone){
54 | return phone.length <= 9 ? masks[0] : masks[1];
55 | };
56 |
57 | testfield.mask(SPphoneMask, {onChange: function(phone, e, currentField, options){
58 | $(currentField).mask(SPphoneMask(phone), options);
59 | }});
60 |
61 | equal( typeTest("1"), "1");
62 | equal( typeTest("12"), "12");
63 | equal( typeTest("123"), "123");
64 | equal( typeTest("1234"), "1234");
65 | equal( typeTest("12345"), "1234.5");
66 | equal( typeTest("123456"), "1234.56");
67 | equal( typeTest("1234567"), "1234.567");
68 | equal( typeTest("12345678"), "1234.5678");
69 | equal( typeTest("123456789"), "1.2345.6789");
70 |
71 | });
72 |
73 | test("When I change the mask on-the-fly with onKeyPress callback things should work normally", function(){
74 |
75 | var masks = ['0000.00009', '0.0000.0000'];
76 | var SPphoneMask = function(phone){
77 | return phone.length <= 9 ? masks[0] : masks[1];
78 | };
79 |
80 | testfield.mask(SPphoneMask, {onKeyPress: function(phone, e, currentField, options){
81 | $(currentField).mask(SPphoneMask(phone), options);
82 | }});
83 |
84 | equal( typeTest("1"), "1");
85 | equal( typeTest("12"), "12");
86 | equal( typeTest("123"), "123");
87 | equal( typeTest("1234"), "1234");
88 | equal( typeTest("12345"), "1234.5");
89 | equal( typeTest("123456"), "1234.56");
90 | equal( typeTest("1234567"), "1234.567");
91 | equal( typeTest("12345678"), "1234.5678");
92 | equal( typeTest("123456789"), "1.2345.6789");
93 |
94 | });
95 |
96 | test("#onInvalid callback. should call when invalid", function(){
97 | testfield.mask('00/00/0000', {onInvalid: function(val, e, el, invalid, options){
98 | equal(val, "1")
99 | equal(typeof e, "object")
100 | equal(typeof el, "object")
101 | equal(invalid.length, 1);
102 | equal(invalid[0]["e"], "/\\d/");
103 | equal(invalid[0]["p"], 1);
104 | equal(invalid[0]["v"], "a");
105 | equal(typeof options.onInvalid, "function");
106 | }});
107 |
108 | equal( typeTest("1a") , "1");
109 | });
110 |
111 | test("#onInvalid callback. should not call when valid", function(){
112 | var callback = sinon.spy();
113 | testfield.mask('00/00/0000', {onInvalid: callback});
114 |
115 | equal( typeTest("11") , "11");
116 | equal(callback.called, false)
117 | });
118 |
119 | test('When I typed a char thats the same as the mask char', function(){
120 | testfield.unmask();
121 | testfield.mask('00/00/0000');
122 |
123 | equal( typeTest("00/"), "00/");
124 | equal( typeTest("00a"), "00/");
125 | equal( typeTest("00a00/00"), "00/00/00");
126 | equal( typeTest("0a/00/00"), "00/00/0");
127 | equal( typeTest("0a/0a/00"), "00/00");
128 |
129 | });
130 |
131 | test('When I typed exactly the same as the mask', function(){
132 | testfield.mask('00/00/0000');
133 | equal( typeTest("00"), "00");
134 | equal( typeTest("00/"), "00/");
135 | equal( typeTest("aa/"), "");
136 | equal( typeTest("00/0"), "00/0");
137 | equal( typeTest("00/00"), "00/00");
138 | equal( typeTest("00/00/0"), "00/00/0");
139 | equal( typeTest("00/00/00"), "00/00/00");
140 | });
141 |
142 | test("Testing masks with a literal on the last char", function () {
143 | testfield.mask("(99)");
144 |
145 | equal( typeTest("(99"), "(99)");
146 | });
147 |
148 |
149 | module('Masks with numbers and especial characters');
150 |
151 | test("Masks with numbers and special characters.", function(){
152 | testfield.mask('(000) 000-0000');
153 |
154 | equal( typeTest("1"), "(1");
155 | equal( typeTest('12'), "(12");
156 | equal( typeTest('123'), "(123");
157 | equal( typeTest('1234'), "(123) 4");
158 | equal( typeTest('12345'), "(123) 45");
159 | equal( typeTest('(123) 456'), "(123) 456");
160 | equal( typeTest('(123) 4567'), "(123) 456-7");
161 |
162 | });
163 |
164 | test("Testing masks with a annonymous function", function(){
165 | testfield.mask(function(){
166 | return "(123) 456-7899"
167 | });
168 |
169 | equal( typeTest("1"), "(1");
170 | equal( typeTest('12'), "(12");
171 | equal( typeTest('123'), "(123");
172 | equal( typeTest('1234'), "(123) 4");
173 | equal( typeTest('12345'), "(123) 45");
174 | equal( typeTest('123456'), "(123) 456");
175 | equal( typeTest('1234567'), "(123) 456-7");
176 |
177 | });
178 |
179 | test("Masks with numbers, strings e special characters", function(){
180 | testfield.mask('(999) A99-SSSS');
181 |
182 | equal( typeTest("(1"), "(1");
183 | equal( typeTest('(12'), "(12");
184 | equal( typeTest('(123'), "(123");
185 | equal( typeTest('(123) 4'), "(123) 4");
186 | equal( typeTest('(123) A'), "(123) A");
187 | equal( typeTest('123.'), "(123) ");
188 | equal( typeTest('(123) 45'), "(123) 45");
189 | equal( typeTest('(123) 456'), "(123) 456");
190 | equal( typeTest('(123) 456-A'), "(123) 456-A");
191 | equal( typeTest('(123) 456-AB'), "(123) 456-AB");
192 | equal( typeTest('(123) 456-ABC'), "(123) 456-ABC");
193 | equal( typeTest('(123) 456-ABCD'), "(123) 456-ABCD");
194 | equal( typeTest('(123) 456-ABCDE'), "(123) 456-ABCD");
195 | equal( typeTest('(123) 456-ABCD1'), "(123) 456-ABCD");
196 |
197 | });
198 |
199 | test("Masks with numbers, strings e special characters #2 ", function(){
200 | testfield.mask('AAA 000-S0S');
201 |
202 | equal( typeTest("1"), "1");
203 | equal( typeTest('12'), "12");
204 | equal( typeTest('123'), "123");
205 | equal( typeTest('123 4'), "123 4");
206 | equal( typeTest('123 45'), "123 45");
207 | equal( typeTest('123 456'), "123 456");
208 | equal( typeTest('123 456-7'), "123 456-");
209 |
210 | });
211 |
212 | module("Testing Reversible Masks");
213 |
214 | test("Testing a CPF Mask", function(){
215 | testfield.mask('000.000.000-00', {reverse: true});
216 |
217 | equal( typeTest("1"), "1");
218 | equal( typeTest("12"), "12");
219 | equal( typeTest("123"), "1-23");
220 | equal( typeTest("12-34"), "12-34");
221 | equal( typeTest("123-45"), "123-45");
222 | equal( typeTest("1.234-56"), "1.234-56");
223 | equal( typeTest("12.345-67"), "12.345-67");
224 | equal( typeTest("123.456-78"), "123.456-78");
225 | equal( typeTest("1.234.567-89"), "1.234.567-89");
226 | equal( typeTest("12.345.678-90"), "12.345.678-90");
227 | equal( typeTest("123.456.789-00"), "123.456.789-00");
228 | equal( typeTest("123.456.789-00"), "123.456.789-00");
229 |
230 | equal( typeTest("123.456.789a00"), "123.456.789-00");
231 | equal( typeTest("123-a5"), "12-35");
232 |
233 | equal( typeTest("1"), "1");
234 | equal( typeTest("12"), "12");
235 | equal( typeTest("1-23"), "1-23");
236 | equal( typeTest("12-34"), "12-34");
237 | equal( typeTest("12-345"), "123-45");
238 | equal( typeTest("1.234-56"), "1.234-56");
239 | equal( typeTest("12.345-67"), "12.345-67");
240 | equal( typeTest("123.456-78"), "123.456-78");
241 | equal( typeTest("1.234.567-89"), "1.234.567-89");
242 | equal( typeTest("12.345.678-90"), "12.345.678-90");
243 | equal( typeTest("123.456.789-00"), "123.456.789-00");
244 | equal( typeTest("123.456.789-00"), "123.456.789-00");
245 | equal( typeTest("123.456.789a00"), "123.456.789-00");
246 | });
247 |
248 | test("Testing Reverse numbers with recursive mask", function(){
249 | testfield.mask("#.##0,00", {reverse: true});
250 |
251 | equal(typeTest(""), "");
252 | equal(typeTest("1"), "1");
253 | equal(typeTest("12"), "12");
254 | equal(typeTest("123"), "1,23");
255 | equal(typeTest("1,234"), "12,34");
256 | equal(typeTest("12,345"), "123,45");
257 | equal(typeTest("123,456"), "1.234,56");
258 | equal(typeTest("1.234,567"), "12.345,67");
259 | equal(typeTest("12.345,678"), "123.456,78");
260 | equal(typeTest("123.456,789"), "1.234.567,89");
261 | equal(typeTest("1.234.567,890"), "12.345.678,90");
262 | equal(typeTest("12.345.678,901"), "123.456.789,01");
263 | equal(typeTest("123.456.789,012"), "1.234.567.890,12");
264 | equal(typeTest("1.234.567.890,1"), "123.456.789,01");
265 | equal(typeTest("123.456.789,0"), "12.345.678,90");
266 | equal(typeTest("12.345.678,9"), "1.234.567,89");
267 | equal(typeTest("1.234.567,8"), "123.456,78");
268 | });
269 |
270 | test("Testing numbers with recursive mask", function(){
271 | testfield.mask("0#.#");
272 |
273 | equal(typeTest(""), "");
274 | equal(typeTest("1"), "1");
275 | equal(typeTest("12"), "12");
276 | equal(typeTest("12."), "12.");
277 | equal(typeTest("12.3"), "12.3");
278 | equal(typeTest("12.34"), "12.34");
279 | equal(typeTest("12.345"), "12.34.5");
280 | equal(typeTest("12.34.5."), "12.34.5");
281 | equal(typeTest("12.34.56"), "12.34.56");
282 | equal(typeTest("12.34.567"), "12.34.56.7");
283 | equal(typeTest("12.34.56."), "12.34.56.");
284 | equal(typeTest("12.34.56"), "12.34.56");
285 | equal(typeTest("12.34.5"), "12.34.5");
286 | });
287 |
288 | test("Testing numbers with recursive mask with one #", function(){
289 | testfield.mask("0#", {});
290 |
291 | equal(typeTest(""), "");
292 | equal(typeTest("1"), "1");
293 | equal(typeTest("12"), "12");
294 | equal(typeTest("123"), "123");
295 | equal(typeTest("1234"), "1234");
296 | equal(typeTest("12345"), "12345");
297 | equal(typeTest("12345"), "12345");
298 | equal(typeTest("123456"), "123456");
299 | equal(typeTest("1234567"), "1234567");
300 | equal(typeTest("123456."), "123456");
301 | equal(typeTest("123456"), "123456");
302 | equal(typeTest("12345"), "12345");
303 | });
304 | test("Testing numbers with recursive mask with one # and reverse", function(){
305 | testfield.mask("#0", {reverse: true});
306 |
307 | equal(typeTest(""), "");
308 | equal(typeTest("1"), "1");
309 | equal(typeTest("12"), "12");
310 | equal(typeTest("123"), "123");
311 | equal(typeTest("1234"), "1234");
312 | equal(typeTest("12345"), "12345");
313 | equal(typeTest("12345"), "12345");
314 | equal(typeTest("123456"), "123456");
315 | equal(typeTest("1234567"), "1234567");
316 | equal(typeTest("123456."), "123456");
317 | equal(typeTest("123456"), "123456");
318 | equal(typeTest("12345"), "12345");
319 | });
320 | test("Testing reversible masks with a literal on the last char", function () {
321 | testfield.mask("(99)");
322 |
323 | equal( typeTest("(99"), "(99)");
324 | });
325 |
326 | module('Removing mask');
327 |
328 | test("when I get the unmasked value", function(){
329 | testfield.mask('(00) 0000-0000', { placeholder: '(__) ____-____' });
330 |
331 | equal(typeTest("1299999999"), "(12) 9999-9999");
332 | testfield.unmask()
333 | equal(testfield.val(), "1299999999");
334 |
335 | if (window.Zepto) {
336 | equal(testfield.attr('placeholder'), '');
337 | equal(testfield.attr('maxlength'), null);
338 | } else {
339 | equal(testfield.attr('placeholder'), undefined);
340 | equal(testfield.attr('maxlength'), undefined);
341 | }
342 | });
343 |
344 | module('Getting Unmasked Value');
345 |
346 | test("when I get the unmasked value", function(){
347 | testfield.mask('(00) 0000-0000');
348 |
349 | equal( typeTest("1299999999"), "(12) 9999-9999");
350 | equal( testfield.cleanVal(), "1299999999");
351 | });
352 |
353 | test("when I get the unmasked value with recursive mask", function(){
354 | testfield.mask('#.##0,00', {reverse:true});
355 |
356 | equal( typeTest("123123123123123123", testfield), "1.231.231.231.231.231,23");
357 | equal( testfield.cleanVal(), "123123123123123123");
358 | });
359 |
360 | module('Masking a value programmatically');
361 |
362 | test("when I get the masked value programmatically", function(){
363 | testfield.mask('(00) 0000-0000');
364 | typeTest("1299999999", testfield);
365 | equal( testfield.masked("3488888888"), "(34) 8888-8888");
366 | });
367 |
368 | module('personalized settings')
369 |
370 | test("when adding more itens to the table translation",function(){
371 | testfield.mask('00/00/0000', {'translation': {0: {pattern: /[0-9*]/}}});
372 |
373 | equal( typeTest('12/34/5678'), '12/34/5678');
374 | equal( typeTest('**/34/5678'), '**/34/5678');
375 | });
376 |
377 | test("when adding more itens to the table translation #2",function(){
378 | testfield.mask('00/YY/0000', {'translation': {'Y': {pattern: /[0-9*]/}}});
379 |
380 | equal( typeTest('12/34/5678'), '12/34/5678');
381 | equal( typeTest('12/**/5678'), '12/**/5678');
382 | });
383 |
384 | test("when adding more itens to the table translation #3",function(){
385 | var old_translation = $.jMaskGlobals.translation
386 | $.jMaskGlobals.translation = {
387 | '1': {pattern: /\d/},
388 | '9': {pattern: /\d/, optional: true},
389 | '#': {pattern: /\d/, recursive: true},
390 | 'A': {pattern: /[a-zA-Z0-9]/},
391 | 'S': {pattern: /[a-zA-Z]/}
392 | };
393 |
394 | testfield.mask('00/11/1111');
395 |
396 | equal( typeTest('12/12/5678'), '00/12/1256');
397 |
398 | testfield.mask('11/00/1111');
399 | equal( typeTest('12/12/5678'), '12/00/1256');
400 |
401 | $.jMaskGlobals.translation = old_translation;
402 | });
403 |
404 | test("when adding more itens to the table translation #fallback",function(){
405 | testfield.mask('zz/z0/0000', {'translation': {'z': {pattern: /[0-9*]/, fallback: '*'}}});
406 |
407 | equal( typeTest('12/:4/5678'), '12/*4/5678');
408 | equal( typeTest('::/:4/5678'), '**/*4/5678');
409 | });
410 |
411 | test("test the translation #fallback #1" , function(){
412 | testfield.mask('00t00', {'translation': {'t': {pattern: /[:,.]/, fallback: ':'}}});
413 |
414 | equal( typeTest('1'), '1');
415 | equal( typeTest('13'), '13');
416 | equal( typeTest('137'), '13:7');
417 | equal( typeTest('1337'), '13:37');
418 | equal( typeTest('13z00'), '13:00');
419 | });
420 |
421 | test("test the translation #fallback #2" , function(){
422 | testfield.mask('00/t0/t0', {'translation': {'t': {pattern: /[:,.*]/, fallback: '*'}}});
423 |
424 | equal( typeTest('1'), '1');
425 | equal( typeTest('13'), '13');
426 | equal( typeTest('13/'), '13/');
427 | equal( typeTest('13/a'), '13/*');
428 | equal( typeTest('13/a1z1'), '13/*1/*1');
429 | });
430 |
431 | test("test the translation #fallback #3" , function(){
432 | testfield.mask('tt/00/00', {'translation': {'t': {pattern: /[:,.*]/, fallback: '*'}}});
433 |
434 | equal( typeTest('*'), '*');
435 | equal( typeTest('13'), '**/13');
436 | equal( typeTest('13/'), '**/13/');
437 | equal( typeTest('13/a'), '**/13/');
438 | equal( typeTest('13/a1z1'), '**/13/11');
439 | });
440 |
441 | test("when adding opcional chars",function(){
442 | testfield.mask('099.099.099.099');
443 |
444 | equal( typeTest('0.0.0.0'), '0.0.0.0');
445 | equal( typeTest('00.00.00.00'), '00.00.00.00');
446 | equal( typeTest('00.000.00.000'), '00.000.00.000');
447 | equal( typeTest('000.00.000.00'), '000.00.000.00');
448 | equal( typeTest('000.000.000.000'), '000.000.000.000');
449 | equal( typeTest('000000000000'), '000.000.000.000');
450 | equal( typeTest('0'), '0');
451 | equal( typeTest('00'), '00');
452 | equal( typeTest('00.'), '00.');
453 | equal( typeTest('00.0'), '00.0');
454 | equal( typeTest('00.00'), '00.00');
455 | equal( typeTest('00.00.'), '00.00.');
456 | equal( typeTest('00.00.000'), '00.00.000');
457 | equal( typeTest('00.00.000.'), '00.00.000.');
458 | equal( typeTest('00.00.000.0'), '00.00.000.0');
459 | equal( typeTest('00..'), '00.');
460 | });
461 |
462 | test("when aplying mask on a element different than a form field",function(){
463 | testdiv.mask('000.000.000-00', {reverse: true});
464 |
465 | equal( typeDivTest('12312312312'), '123.123.123-12');
466 | equal( typeDivTest('123.123.123-12'), '123.123.123-12');
467 | equal( typeDivTest('123.123a123-12'), '123.123.123-12');
468 | equal( typeDivTest('191'), '1-91');
469 |
470 | testdiv.mask('00/00/0000');
471 | equal( typeDivTest('000000'), '00/00/00');
472 | equal( typeDivTest('00000000'), '00/00/0000');
473 | equal( typeDivTest('00/00/0000'), '00/00/0000');
474 | equal( typeDivTest('0a/00/0000'), '00/00/000');
475 |
476 | });
477 |
478 | module('Testing data-mask attribute support');
479 |
480 | test("Testing data-mask attribute", function(){
481 | equal( typeTest("00/", testfieldDataMask), "00/");
482 | equal( typeTest("00a", testfieldDataMask), "00/");
483 | equal( typeTest("00a00/00", testfieldDataMask), "00/00/00");
484 | equal( typeTest("0a/00/00", testfieldDataMask), "00/00/0");
485 | equal( typeTest("0a/0a/00", testfieldDataMask), "00/00");
486 | equal( typeTest("00000000", testfieldDataMask), "00/00/0000");
487 | });
488 |
489 | test("Testing data-mask-reverse attribute", function(){
490 | equal( typeTest("0000", testfieldDataMaskWithReverse), "00,00");
491 | equal( typeTest("000000", testfieldDataMaskWithReverse), "0.000,00");
492 | equal( typeTest("0000000000", testfieldDataMaskWithReverse), "00.000.000,00");
493 | });
494 |
495 | module('Event fire test');
496 |
497 | // TODO: need to understand why zepto.js isnt calling change event!
498 | if(!window.Zepto) {
499 | test('onChange Test', 2, function(){
500 | testfield.unmask();
501 |
502 | var callback = sinon.spy();
503 | var mock = sinon.mock()
504 | var typeAndBlur = function(typedValue){
505 | testfield.trigger('keydown');
506 | testfield.val(typedValue);
507 | testfield.trigger('input');
508 | testfield.trigger("blur");
509 | };
510 |
511 | testfield.mask('000.(000).000/0-0');
512 |
513 | testfield.on("change", callback);
514 |
515 | typeAndBlur("");
516 | typeAndBlur("1");
517 | typeAndBlur("12");
518 | typeAndBlur("123");
519 | typeAndBlur("1234");
520 | typeAndBlur("12345");
521 | typeAndBlur("123456");
522 | typeAndBlur("1234567");
523 | typeAndBlur("12345678");
524 | typeAndBlur("123456789");
525 | typeAndBlur("123456789");
526 | typeAndBlur("1234567891");
527 | typeAndBlur("12345678912");
528 |
529 | equal(testfield.val(), "123.(456).789/1-2" );
530 | equal(true, sinon.match(11).or(12).test(callback.callCount))
531 |
532 | testfield.off("change");
533 | testfield.unmask();
534 |
535 | });
536 | }
537 |
538 |
539 | test('onDrop Test', function(){
540 | ok(true, "todo");
541 | });
542 |
543 | module('testing Remove If Not Match Feature');
544 |
545 | test('test when clearifnotmatch javascript notation', 4, function(){
546 | var typeAndFocusOut = function(typedValue){
547 | testfield.keydown().val(typedValue).trigger('input');
548 | testfield.trigger("focusout");
549 | };
550 |
551 | testfield.mask('000');
552 |
553 | typeAndFocusOut("1");
554 | equal( testfield.val(), "1" );
555 |
556 | testfield.mask('000', {clearIfNotMatch: true});
557 |
558 | typeAndFocusOut("1");
559 | equal( testfield.val(), "" );
560 |
561 | typeAndFocusOut("12");
562 | equal( testfield.val(), "" );
563 |
564 | typeAndFocusOut("123");
565 | equal( testfield.val(), "123" );
566 | });
567 |
568 | test('test when clearifnotmatch javascript notation #2', 4, function(){
569 | var typeAndFocusOut = function(typedValue){
570 | testfield.keydown().val(typedValue).trigger('input');
571 | testfield.trigger("focusout");
572 | };
573 |
574 | testfield.mask('7 (000) 000-0000');
575 |
576 | typeAndFocusOut("1");
577 | equal( testfield.val(), "7 (1" );
578 |
579 | testfield.mask('7 (000) 000-0000', {clearIfNotMatch: true});
580 |
581 | typeAndFocusOut("1");
582 | equal( testfield.val(), "" );
583 |
584 | typeAndFocusOut("12");
585 | equal( testfield.val(), "" );
586 |
587 | typeAndFocusOut("7 (123) 123-1234");
588 | equal( testfield.val(), "7 (123) 123-1234" );
589 | });
590 |
591 | test('test when clearifnotmatch is HTML notation', 3, function(){
592 | var typeAndFocusOut = function(typedValue){
593 | testfieldDataMaskWithClearIfNotMatch.keydown().val(typedValue).trigger('input');
594 | testfieldDataMaskWithClearIfNotMatch.trigger("focusout");
595 | };
596 |
597 | typeAndFocusOut("1");
598 | equal( testfieldDataMaskWithClearIfNotMatch.val(), "" );
599 |
600 | typeAndFocusOut("12");
601 | equal( testfieldDataMaskWithClearIfNotMatch.val(), "" );
602 |
603 | typeAndFocusOut("123");
604 | equal( testfieldDataMaskWithClearIfNotMatch.val(), "123" );
605 | });
606 |
607 | module('testing Remove If Not Match Feature');
608 |
609 | test('test when clearifnotmatch javascript notation', 1, function(){
610 |
611 | testfield.mask('000', {placeholder: '___'});
612 | equal( testfield.attr('placeholder'), "___" );
613 |
614 | });
615 |
616 | test('test when clearifnotmatch with optional mask', 9, function(){
617 | // html notation
618 | var typeAndBlur = function(field, typedValue){
619 | field.keydown().val(typedValue).trigger('input');
620 | field.trigger("focusout");
621 | };
622 |
623 | typeAndBlur(testfieldDataMaskWithClearIfNotMatchAndOptionalMask, "1");
624 | equal( testfieldDataMaskWithClearIfNotMatchAndOptionalMask.val(), "" );
625 |
626 | typeAndBlur(testfieldDataMaskWithClearIfNotMatchAndOptionalMask, "12");
627 | equal( testfieldDataMaskWithClearIfNotMatchAndOptionalMask.val(), "12" );
628 |
629 | typeAndBlur(testfieldDataMaskWithClearIfNotMatchAndOptionalMask, "123");
630 | equal( testfieldDataMaskWithClearIfNotMatchAndOptionalMask.val(), "123" );
631 |
632 | // javascript notation
633 | testfield.mask('099.099.099.099', {clearIfNotMatch: true});
634 |
635 | typeAndBlur(testfield, "1");
636 | equal( testfield.val(), "" );
637 |
638 | typeAndBlur(testfield, "123.");
639 | equal( testfield.val(), "" );
640 |
641 | typeAndBlur(testfield, "123.0");
642 | equal( testfield.val(), "" );
643 |
644 | typeAndBlur(testfield, "123.01.000.");
645 | equal( testfield.val(), "" );
646 |
647 | typeAndBlur(testfield, "123.01.000.123");
648 | equal( testfield.val(), "123.01.000.123" );
649 |
650 | typeAndBlur(testfield, "0.0.0.0");
651 | equal( testfield.val(), "0.0.0.0" );
652 | });
653 |
654 | test('test when clearifnotmatch with recursive mask', 4, function(){
655 | // html notation
656 | var typeAndBlur = function(field, typedValue){
657 | field.keydown().val(typedValue).trigger('input');
658 | field.trigger("focusout");
659 | };
660 |
661 | // javascript notation
662 | testfield.mask('#.##0,00', {clearIfNotMatch: true, reverse: true});
663 |
664 | typeAndBlur(testfield, "0");
665 | equal( testfield.val(), "" );
666 |
667 | typeAndBlur(testfield, "00");
668 | equal( testfield.val(), "" );
669 |
670 | typeAndBlur(testfield, "0,00");
671 | equal( testfield.val(), "0,00" );
672 |
673 | typeAndBlur(testfield, "1.000,00");
674 | equal( testfield.val(), "1.000,00" );
675 |
676 | });
677 |
678 | module('dynamically loaded elements')
679 | test('#non-inputs', function(){
680 | expect(5);
681 |
682 | var $container = $('#container-dy-non-inputs');
683 | var clock = this.clock;
684 | var ticker;
685 | var tester;
686 | var c = 0;
687 |
688 | function write() {
689 |
690 | if (c >= 5) {
691 | clearInterval(ticker);
692 | clearInterval(tester);
693 | return;
694 | }
695 |
696 | c++;
697 |
698 | $container.append('' + c + c + c + c + '
');
699 | clock.tick(1000);
700 | };
701 |
702 | function testIt() {
703 |
704 | var cs = $container.find('.c');
705 | $.each(cs, function(k, field){
706 | var t = k + 1;
707 | equal($(field).text(), '' + t + t + ':' + t + t);
708 | t++;
709 | });
710 | };
711 |
712 | ticker = setInterval(write, 1000);
713 |
714 | write();
715 | $('.c', $container).mask('00:00');
716 | testIt()
717 | });
718 | });
719 |
--------------------------------------------------------------------------------
/test/qunit.css:
--------------------------------------------------------------------------------
1 | /**
2 | * QUnit v1.11.0 - A JavaScript Unit Testing Framework
3 | *
4 | * http://qunitjs.com
5 | *
6 | * Copyright 2012 jQuery Foundation and other contributors
7 | * Released under the MIT license.
8 | * http://jquery.org/license
9 | */
10 |
11 | /** Font Family and Sizes */
12 |
13 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
14 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
15 | }
16 |
17 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
18 | #qunit-tests { font-size: smaller; }
19 |
20 |
21 | /** Resets */
22 |
23 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
24 | margin: 0;
25 | padding: 0;
26 | }
27 |
28 |
29 | /** Header */
30 |
31 | #qunit-header {
32 | padding: 0.5em 0 0.5em 1em;
33 |
34 | color: #8699a4;
35 | background-color: #0d3349;
36 |
37 | font-size: 1.5em;
38 | line-height: 1em;
39 | font-weight: normal;
40 |
41 | border-radius: 5px 5px 0 0;
42 | -moz-border-radius: 5px 5px 0 0;
43 | -webkit-border-top-right-radius: 5px;
44 | -webkit-border-top-left-radius: 5px;
45 | }
46 |
47 | #qunit-header a {
48 | text-decoration: none;
49 | color: #c2ccd1;
50 | }
51 |
52 | #qunit-header a:hover,
53 | #qunit-header a:focus {
54 | color: #fff;
55 | }
56 |
57 | #qunit-testrunner-toolbar label {
58 | display: inline-block;
59 | padding: 0 .5em 0 .1em;
60 | }
61 |
62 | #qunit-banner {
63 | height: 5px;
64 | }
65 |
66 | #qunit-testrunner-toolbar {
67 | padding: 0.5em 0 0.5em 2em;
68 | color: #5E740B;
69 | background-color: #eee;
70 | overflow: hidden;
71 | }
72 |
73 | #qunit-userAgent {
74 | padding: 0.5em 0 0.5em 2.5em;
75 | background-color: #2b81af;
76 | color: #fff;
77 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
78 | }
79 |
80 | #qunit-modulefilter-container {
81 | float: right;
82 | }
83 |
84 | /** Tests: Pass/Fail */
85 |
86 | #qunit-tests {
87 | list-style-position: inside;
88 | }
89 |
90 | #qunit-tests li {
91 | padding: 0.4em 0.5em 0.4em 2.5em;
92 | border-bottom: 1px solid #fff;
93 | list-style-position: inside;
94 | }
95 |
96 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
97 | display: none;
98 | }
99 |
100 | #qunit-tests li strong {
101 | cursor: pointer;
102 | }
103 |
104 | #qunit-tests li a {
105 | padding: 0.5em;
106 | color: #c2ccd1;
107 | text-decoration: none;
108 | }
109 | #qunit-tests li a:hover,
110 | #qunit-tests li a:focus {
111 | color: #000;
112 | }
113 |
114 | #qunit-tests li .runtime {
115 | float: right;
116 | font-size: smaller;
117 | }
118 |
119 | .qunit-assert-list {
120 | margin-top: 0.5em;
121 | padding: 0.5em;
122 |
123 | background-color: #fff;
124 |
125 | border-radius: 5px;
126 | -moz-border-radius: 5px;
127 | -webkit-border-radius: 5px;
128 | }
129 |
130 | .qunit-collapsed {
131 | display: none;
132 | }
133 |
134 | #qunit-tests table {
135 | border-collapse: collapse;
136 | margin-top: .2em;
137 | }
138 |
139 | #qunit-tests th {
140 | text-align: right;
141 | vertical-align: top;
142 | padding: 0 .5em 0 0;
143 | }
144 |
145 | #qunit-tests td {
146 | vertical-align: top;
147 | }
148 |
149 | #qunit-tests pre {
150 | margin: 0;
151 | white-space: pre-wrap;
152 | word-wrap: break-word;
153 | }
154 |
155 | #qunit-tests del {
156 | background-color: #e0f2be;
157 | color: #374e0c;
158 | text-decoration: none;
159 | }
160 |
161 | #qunit-tests ins {
162 | background-color: #ffcaca;
163 | color: #500;
164 | text-decoration: none;
165 | }
166 |
167 | /*** Test Counts */
168 |
169 | #qunit-tests b.counts { color: black; }
170 | #qunit-tests b.passed { color: #5E740B; }
171 | #qunit-tests b.failed { color: #710909; }
172 |
173 | #qunit-tests li li {
174 | padding: 5px;
175 | background-color: #fff;
176 | border-bottom: none;
177 | list-style-position: inside;
178 | }
179 |
180 | /*** Passing Styles */
181 |
182 | #qunit-tests li li.pass {
183 | color: #3c510c;
184 | background-color: #fff;
185 | border-left: 10px solid #C6E746;
186 | }
187 |
188 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
189 | #qunit-tests .pass .test-name { color: #366097; }
190 |
191 | #qunit-tests .pass .test-actual,
192 | #qunit-tests .pass .test-expected { color: #999999; }
193 |
194 | #qunit-banner.qunit-pass { background-color: #C6E746; }
195 |
196 | /*** Failing Styles */
197 |
198 | #qunit-tests li li.fail {
199 | color: #710909;
200 | background-color: #fff;
201 | border-left: 10px solid #EE5757;
202 | white-space: pre;
203 | }
204 |
205 | #qunit-tests > li:last-child {
206 | border-radius: 0 0 5px 5px;
207 | -moz-border-radius: 0 0 5px 5px;
208 | -webkit-border-bottom-right-radius: 5px;
209 | -webkit-border-bottom-left-radius: 5px;
210 | }
211 |
212 | #qunit-tests .fail { color: #000000; background-color: #EE5757; }
213 | #qunit-tests .fail .test-name,
214 | #qunit-tests .fail .module-name { color: #000000; }
215 |
216 | #qunit-tests .fail .test-actual { color: #EE5757; }
217 | #qunit-tests .fail .test-expected { color: green; }
218 |
219 | #qunit-banner.qunit-fail { background-color: #EE5757; }
220 |
221 |
222 | /** Result */
223 |
224 | #qunit-testresult {
225 | padding: 0.5em 0.5em 0.5em 2.5em;
226 |
227 | color: #2b81af;
228 | background-color: #D2E0E6;
229 |
230 | border-bottom: 1px solid white;
231 | }
232 | #qunit-testresult .module-name {
233 | font-weight: bold;
234 | }
235 |
236 | /** Fixture */
237 |
238 | #qunit-fixture {
239 | position: absolute;
240 | top: -10000px;
241 | left: -10000px;
242 | width: 1000px;
243 | height: 1000px;
244 | }
--------------------------------------------------------------------------------
/test/sinon-qunit-1.0.0.js:
--------------------------------------------------------------------------------
1 | /**
2 | * sinon-qunit 1.0.0, 2010/12/09
3 | *
4 | * @author Christian Johansen (christian@cjohansen.no)
5 | *
6 | * (The BSD License)
7 | *
8 | * Copyright (c) 2010-2011, Christian Johansen, christian@cjohansen.no
9 | * All rights reserved.
10 | *
11 | * Redistribution and use in source and binary forms, with or without modification,
12 | * are permitted provided that the following conditions are met:
13 | *
14 | * * Redistributions of source code must retain the above copyright notice,
15 | * this list of conditions and the following disclaimer.
16 | * * Redistributions in binary form must reproduce the above copyright notice,
17 | * this list of conditions and the following disclaimer in the documentation
18 | * and/or other materials provided with the distribution.
19 | * * Neither the name of Christian Johansen nor the names of his contributors
20 | * may be used to endorse or promote products derived from this software
21 | * without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 | */
34 | /*global sinon, QUnit, test*/
35 | sinon.assert.fail = function (msg) {
36 | QUnit.ok(false, msg);
37 | };
38 |
39 | sinon.assert.pass = function (assertion) {
40 | QUnit.ok(true, assertion);
41 | };
42 |
43 | sinon.config = {
44 | injectIntoThis: true,
45 | injectInto: null,
46 | properties: ["spy", "stub", "mock", "clock", "sandbox"],
47 | useFakeTimers: true,
48 | useFakeServer: false
49 | };
50 |
51 | (function (global) {
52 | var qTest = QUnit.test;
53 |
54 | QUnit.test = global.test = function (testName, expected, callback, async) {
55 | if (arguments.length === 2) {
56 | callback = expected;
57 | expected = null;
58 | }
59 |
60 | return qTest(testName, expected, sinon.test(callback), async);
61 | };
62 | }(this));
63 |
--------------------------------------------------------------------------------
/test/sinon-qunit.js:
--------------------------------------------------------------------------------
1 | /**
2 | * sinon-qunit 1.0.0, 2010/12/09
3 | *
4 | * @author Christian Johansen (christian@cjohansen.no)
5 | *
6 | * (The BSD License)
7 | *
8 | * Copyright (c) 2010-2011, Christian Johansen, christian@cjohansen.no
9 | * All rights reserved.
10 | *
11 | * Redistribution and use in source and binary forms, with or without modification,
12 | * are permitted provided that the following conditions are met:
13 | *
14 | * * Redistributions of source code must retain the above copyright notice,
15 | * this list of conditions and the following disclaimer.
16 | * * Redistributions in binary form must reproduce the above copyright notice,
17 | * this list of conditions and the following disclaimer in the documentation
18 | * and/or other materials provided with the distribution.
19 | * * Neither the name of Christian Johansen nor the names of his contributors
20 | * may be used to endorse or promote products derived from this software
21 | * without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 | */
34 | /*global sinon, QUnit, test*/
35 | sinon.assert.fail = function (msg) {
36 | QUnit.ok(false, msg);
37 | };
38 |
39 | sinon.assert.pass = function (assertion) {
40 | QUnit.ok(true, assertion);
41 | };
42 |
43 | sinon.config = {
44 | injectIntoThis: true,
45 | injectInto: null,
46 | properties: ["spy", "stub", "mock", "clock", "sandbox"],
47 | useFakeTimers: true,
48 | useFakeServer: false
49 | };
50 |
51 | (function (global) {
52 | var qTest = QUnit.test;
53 |
54 | QUnit.test = global.test = function (testName, expected, callback, async) {
55 | if (arguments.length === 2) {
56 | callback = expected;
57 | expected = null;
58 | }
59 |
60 | return qTest(testName, expected, sinon.test(callback), async);
61 | };
62 | }(this));
63 |
--------------------------------------------------------------------------------
/test/test-for-jquery-1.11.1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | jQuery-Mask-Plugin UnitTesting
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | test markup, will be hidden
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/test/test-for-jquery-1.7.2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | jQuery-Mask-Plugin UnitTesting
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | test markup, will be hidden
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/test/test-for-jquery-1.8.3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | jQuery-Mask-Plugin UnitTesting
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | test markup, will be hidden
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/test/test-for-jquery-1.9.1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | jQuery-Mask-Plugin UnitTesting
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | test markup, will be hidden
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/test/test-for-jquery-2.1.1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | jQuery-Mask-Plugin UnitTesting
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | test markup, will be hidden
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/test/test-for-jquery-3.0.0.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | jQuery-Mask-Plugin UnitTesting
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | test markup, will be hidden
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/test/test-for-zepto.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Zepto-Mask-Plugin UnitTesting
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | test markup, will be hidden
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/test/zepto/data.js:
--------------------------------------------------------------------------------
1 | // Zepto.js
2 | // (c) 2010-2014 Thomas Fuchs
3 | // Zepto.js may be freely distributed under the MIT license.
4 |
5 | // The following code is heavily inspired by jQuery's $.fn.data()
6 |
7 | ;(function($){
8 | var data = {}, dataAttr = $.fn.data, camelize = $.camelCase,
9 | exp = $.expando = 'Zepto' + (+new Date()), emptyArray = []
10 |
11 | // Get value from node:
12 | // 1. first try key as given,
13 | // 2. then try camelized key,
14 | // 3. fall back to reading "data-*" attribute.
15 | function getData(node, name) {
16 | var id = node[exp], store = id && data[id]
17 | if (name === undefined) return store || setData(node)
18 | else {
19 | if (store) {
20 | if (name in store) return store[name]
21 | var camelName = camelize(name)
22 | if (camelName in store) return store[camelName]
23 | }
24 | return dataAttr.call($(node), name)
25 | }
26 | }
27 |
28 | // Store value under camelized key on node
29 | function setData(node, name, value) {
30 | var id = node[exp] || (node[exp] = ++$.uuid),
31 | store = data[id] || (data[id] = attributeData(node))
32 | if (name !== undefined) store[camelize(name)] = value
33 | return store
34 | }
35 |
36 | // Read all "data-*" attributes from a node
37 | function attributeData(node) {
38 | var store = {}
39 | $.each(node.attributes || emptyArray, function(i, attr){
40 | if (attr.name.indexOf('data-') == 0)
41 | store[camelize(attr.name.replace('data-', ''))] =
42 | $.zepto.deserializeValue(attr.value)
43 | })
44 | return store
45 | }
46 |
47 | $.fn.data = function(name, value) {
48 | return value === undefined ?
49 | // set multiple values via object
50 | $.isPlainObject(name) ?
51 | this.each(function(i, node){
52 | $.each(name, function(key, value){ setData(node, key, value) })
53 | }) :
54 | // get value from first element
55 | (0 in this ? getData(this[0], name) : undefined) :
56 | // set value on all elements
57 | this.each(function(){ setData(this, name, value) })
58 | }
59 |
60 | $.fn.removeData = function(names) {
61 | if (typeof names == 'string') names = names.split(/\s+/)
62 | return this.each(function(){
63 | var id = this[exp], store = id && data[id]
64 | if (store) $.each(names || store, function(key){
65 | delete store[names ? camelize(this) : key]
66 | })
67 | })
68 | }
69 |
70 | // Generate extended `remove` and `empty` functions
71 | ;['remove', 'empty'].forEach(function(methodName){
72 | var origFn = $.fn[methodName]
73 | $.fn[methodName] = function() {
74 | var elements = this.find('*')
75 | if (methodName === 'remove') elements = elements.add(this)
76 | elements.removeData()
77 | return origFn.call(this)
78 | }
79 | })
80 | })(Zepto)
81 |
--------------------------------------------------------------------------------
/test/zepto/event.js:
--------------------------------------------------------------------------------
1 | // Zepto.js
2 | // (c) 2010-2014 Thomas Fuchs
3 | // Zepto.js may be freely distributed under the MIT license.
4 |
5 | ;(function($){
6 | var _zid = 1, undefined,
7 | slice = Array.prototype.slice,
8 | isFunction = $.isFunction,
9 | isString = function(obj){ return typeof obj == 'string' },
10 | handlers = {},
11 | specialEvents={},
12 | focusinSupported = 'onfocusin' in window,
13 | focus = { focus: 'focusin', blur: 'focusout' },
14 | hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' }
15 |
16 | specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents'
17 |
18 | function zid(element) {
19 | return element._zid || (element._zid = _zid++)
20 | }
21 | function findHandlers(element, event, fn, selector) {
22 | event = parse(event)
23 | if (event.ns) var matcher = matcherFor(event.ns)
24 | return (handlers[zid(element)] || []).filter(function(handler) {
25 | return handler
26 | && (!event.e || handler.e == event.e)
27 | && (!event.ns || matcher.test(handler.ns))
28 | && (!fn || zid(handler.fn) === zid(fn))
29 | && (!selector || handler.sel == selector)
30 | })
31 | }
32 | function parse(event) {
33 | var parts = ('' + event).split('.')
34 | return {e: parts[0], ns: parts.slice(1).sort().join(' ')}
35 | }
36 | function matcherFor(ns) {
37 | return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)')
38 | }
39 |
40 | function eventCapture(handler, captureSetting) {
41 | return handler.del &&
42 | (!focusinSupported && (handler.e in focus)) ||
43 | !!captureSetting
44 | }
45 |
46 | function realEvent(type) {
47 | return hover[type] || (focusinSupported && focus[type]) || type
48 | }
49 |
50 | function add(element, events, fn, data, selector, delegator, capture){
51 | var id = zid(element), set = (handlers[id] || (handlers[id] = []))
52 | events.split(/\s/).forEach(function(event){
53 | if (event == 'ready') return $(document).ready(fn)
54 | var handler = parse(event)
55 | handler.fn = fn
56 | handler.sel = selector
57 | // emulate mouseenter, mouseleave
58 | if (handler.e in hover) fn = function(e){
59 | var related = e.relatedTarget
60 | if (!related || (related !== this && !$.contains(this, related)))
61 | return handler.fn.apply(this, arguments)
62 | }
63 | handler.del = delegator
64 | var callback = delegator || fn
65 | handler.proxy = function(e){
66 | e = compatible(e)
67 | if (e.isImmediatePropagationStopped()) return
68 | e.data = data
69 | var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args))
70 | if (result === false) e.preventDefault(), e.stopPropagation()
71 | return result
72 | }
73 | handler.i = set.length
74 | set.push(handler)
75 | if ('addEventListener' in element)
76 | element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
77 | })
78 | }
79 | function remove(element, events, fn, selector, capture){
80 | var id = zid(element)
81 | ;(events || '').split(/\s/).forEach(function(event){
82 | findHandlers(element, event, fn, selector).forEach(function(handler){
83 | delete handlers[id][handler.i]
84 | if ('removeEventListener' in element)
85 | element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
86 | })
87 | })
88 | }
89 |
90 | $.event = { add: add, remove: remove }
91 |
92 | $.proxy = function(fn, context) {
93 | var args = (2 in arguments) && slice.call(arguments, 2)
94 | if (isFunction(fn)) {
95 | var proxyFn = function(){ return fn.apply(context, args ? args.concat(slice.call(arguments)) : arguments) }
96 | proxyFn._zid = zid(fn)
97 | return proxyFn
98 | } else if (isString(context)) {
99 | if (args) {
100 | args.unshift(fn[context], fn)
101 | return $.proxy.apply(null, args)
102 | } else {
103 | return $.proxy(fn[context], fn)
104 | }
105 | } else {
106 | throw new TypeError("expected function")
107 | }
108 | }
109 |
110 | $.fn.bind = function(event, data, callback){
111 | return this.on(event, data, callback)
112 | }
113 | $.fn.unbind = function(event, callback){
114 | return this.off(event, callback)
115 | }
116 | $.fn.one = function(event, selector, data, callback){
117 | return this.on(event, selector, data, callback, 1)
118 | }
119 |
120 | var returnTrue = function(){return true},
121 | returnFalse = function(){return false},
122 | ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$)/,
123 | eventMethods = {
124 | preventDefault: 'isDefaultPrevented',
125 | stopImmediatePropagation: 'isImmediatePropagationStopped',
126 | stopPropagation: 'isPropagationStopped'
127 | }
128 |
129 | function compatible(event, source) {
130 | if (source || !event.isDefaultPrevented) {
131 | source || (source = event)
132 |
133 | $.each(eventMethods, function(name, predicate) {
134 | var sourceMethod = source[name]
135 | event[name] = function(){
136 | this[predicate] = returnTrue
137 | return sourceMethod && sourceMethod.apply(source, arguments)
138 | }
139 | event[predicate] = returnFalse
140 | })
141 |
142 | if (source.defaultPrevented !== undefined ? source.defaultPrevented :
143 | 'returnValue' in source ? source.returnValue === false :
144 | source.getPreventDefault && source.getPreventDefault())
145 | event.isDefaultPrevented = returnTrue
146 | }
147 | return event
148 | }
149 |
150 | function createProxy(event) {
151 | var key, proxy = { originalEvent: event }
152 | for (key in event)
153 | if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key]
154 |
155 | return compatible(proxy, event)
156 | }
157 |
158 | $.fn.delegate = function(selector, event, callback){
159 | return this.on(event, selector, callback)
160 | }
161 | $.fn.undelegate = function(selector, event, callback){
162 | return this.off(event, selector, callback)
163 | }
164 |
165 | $.fn.live = function(event, callback){
166 | $(document.body).delegate(this.selector, event, callback)
167 | return this
168 | }
169 | $.fn.die = function(event, callback){
170 | $(document.body).undelegate(this.selector, event, callback)
171 | return this
172 | }
173 |
174 | $.fn.on = function(event, selector, data, callback, one){
175 | var autoRemove, delegator, $this = this
176 | if (event && !isString(event)) {
177 | $.each(event, function(type, fn){
178 | $this.on(type, selector, data, fn, one)
179 | })
180 | return $this
181 | }
182 |
183 | if (!isString(selector) && !isFunction(callback) && callback !== false)
184 | callback = data, data = selector, selector = undefined
185 | if (isFunction(data) || data === false)
186 | callback = data, data = undefined
187 |
188 | if (callback === false) callback = returnFalse
189 |
190 | return $this.each(function(_, element){
191 | if (one) autoRemove = function(e){
192 | remove(element, e.type, callback)
193 | return callback.apply(this, arguments)
194 | }
195 |
196 | if (selector) delegator = function(e){
197 | var evt, match = $(e.target).closest(selector, element).get(0)
198 | if (match && match !== element) {
199 | evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element})
200 | return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1)))
201 | }
202 | }
203 |
204 | add(element, event, callback, data, selector, delegator || autoRemove)
205 | })
206 | }
207 | $.fn.off = function(event, selector, callback){
208 | var $this = this
209 | if (event && !isString(event)) {
210 | $.each(event, function(type, fn){
211 | $this.off(type, selector, fn)
212 | })
213 | return $this
214 | }
215 |
216 | if (!isString(selector) && !isFunction(callback) && callback !== false)
217 | callback = selector, selector = undefined
218 |
219 | if (callback === false) callback = returnFalse
220 |
221 | return $this.each(function(){
222 | remove(this, event, callback, selector)
223 | })
224 | }
225 |
226 | $.fn.trigger = function(event, args){
227 | event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event)
228 | event._args = args
229 | return this.each(function(){
230 | // items in the collection might not be DOM elements
231 | if('dispatchEvent' in this) this.dispatchEvent(event)
232 | else $(this).triggerHandler(event, args)
233 | })
234 | }
235 |
236 | // triggers event handlers on current element just as if an event occurred,
237 | // doesn't trigger an actual event, doesn't bubble
238 | $.fn.triggerHandler = function(event, args){
239 | var e, result
240 | this.each(function(i, element){
241 | e = createProxy(isString(event) ? $.Event(event) : event)
242 | e._args = args
243 | e.target = element
244 | $.each(findHandlers(element, event.type || event), function(i, handler){
245 | result = handler.proxy(e)
246 | if (e.isImmediatePropagationStopped()) return false
247 | })
248 | })
249 | return result
250 | }
251 |
252 | // shortcut methods for `.bind(event, fn)` for each event type
253 | ;('focusin focusout load resize scroll unload click dblclick '+
254 | 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+
255 | 'change select keydown keypress keyup error').split(' ').forEach(function(event) {
256 | $.fn[event] = function(callback) {
257 | return callback ?
258 | this.bind(event, callback) :
259 | this.trigger(event)
260 | }
261 | })
262 |
263 | ;['focus', 'blur'].forEach(function(name) {
264 | $.fn[name] = function(callback) {
265 | if (callback) this.bind(name, callback)
266 | else this.each(function(){
267 | try { this[name]() }
268 | catch(e) {}
269 | })
270 | return this
271 | }
272 | })
273 |
274 | $.Event = function(type, props) {
275 | if (!isString(type)) props = type, type = props.type
276 | var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true
277 | if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name])
278 | event.initEvent(type, bubbles, true)
279 | return compatible(event)
280 | }
281 |
282 | })(Zepto)
283 |
--------------------------------------------------------------------------------
/test/zepto/zepto.min.js:
--------------------------------------------------------------------------------
1 | /* Zepto v1.1.4 - zepto event ajax form ie - zeptojs.com/license */
2 |
3 | var Zepto = (function() {
4 | var undefined, key, $, classList, emptyArray = [], slice = emptyArray.slice, filter = emptyArray.filter,
5 | document = window.document,
6 | elementDisplay = {}, classCache = {},
7 | cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 },
8 | fragmentRE = /^\s*<(\w+|!)[^>]*>/,
9 | singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
10 | tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
11 | rootNodeRE = /^(?:body|html)$/i,
12 | capitalRE = /([A-Z])/g,
13 |
14 | // special attributes that should be get/set via method calls
15 | methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'],
16 |
17 | adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ],
18 | table = document.createElement('table'),
19 | tableRow = document.createElement('tr'),
20 | containers = {
21 | 'tr': document.createElement('tbody'),
22 | 'tbody': table, 'thead': table, 'tfoot': table,
23 | 'td': tableRow, 'th': tableRow,
24 | '*': document.createElement('div')
25 | },
26 | readyRE = /complete|loaded|interactive/,
27 | simpleSelectorRE = /^[\w-]*$/,
28 | class2type = {},
29 | toString = class2type.toString,
30 | zepto = {},
31 | camelize, uniq,
32 | tempParent = document.createElement('div'),
33 | propMap = {
34 | 'tabindex': 'tabIndex',
35 | 'readonly': 'readOnly',
36 | 'for': 'htmlFor',
37 | 'class': 'className',
38 | 'maxlength': 'maxLength',
39 | 'cellspacing': 'cellSpacing',
40 | 'cellpadding': 'cellPadding',
41 | 'rowspan': 'rowSpan',
42 | 'colspan': 'colSpan',
43 | 'usemap': 'useMap',
44 | 'frameborder': 'frameBorder',
45 | 'contenteditable': 'contentEditable'
46 | },
47 | isArray = Array.isArray ||
48 | function(object){ return object instanceof Array }
49 |
50 | zepto.matches = function(element, selector) {
51 | if (!selector || !element || element.nodeType !== 1) return false
52 | var matchesSelector = element.webkitMatchesSelector || element.mozMatchesSelector ||
53 | element.oMatchesSelector || element.matchesSelector
54 | if (matchesSelector) return matchesSelector.call(element, selector)
55 | // fall back to performing a selector:
56 | var match, parent = element.parentNode, temp = !parent
57 | if (temp) (parent = tempParent).appendChild(element)
58 | match = ~zepto.qsa(parent, selector).indexOf(element)
59 | temp && tempParent.removeChild(element)
60 | return match
61 | }
62 |
63 | function type(obj) {
64 | return obj == null ? String(obj) :
65 | class2type[toString.call(obj)] || "object"
66 | }
67 |
68 | function isFunction(value) { return type(value) == "function" }
69 | function isWindow(obj) { return obj != null && obj == obj.window }
70 | function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE }
71 | function isObject(obj) { return type(obj) == "object" }
72 | function isPlainObject(obj) {
73 | return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype
74 | }
75 | function likeArray(obj) { return typeof obj.length == 'number' }
76 |
77 | function compact(array) { return filter.call(array, function(item){ return item != null }) }
78 | function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array }
79 | camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) }
80 | function dasherize(str) {
81 | return str.replace(/::/g, '/')
82 | .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
83 | .replace(/([a-z\d])([A-Z])/g, '$1_$2')
84 | .replace(/_/g, '-')
85 | .toLowerCase()
86 | }
87 | uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) }
88 |
89 | function classRE(name) {
90 | return name in classCache ?
91 | classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)'))
92 | }
93 |
94 | function maybeAddPx(name, value) {
95 | return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value
96 | }
97 |
98 | function defaultDisplay(nodeName) {
99 | var element, display
100 | if (!elementDisplay[nodeName]) {
101 | element = document.createElement(nodeName)
102 | document.body.appendChild(element)
103 | display = getComputedStyle(element, '').getPropertyValue("display")
104 | element.parentNode.removeChild(element)
105 | display == "none" && (display = "block")
106 | elementDisplay[nodeName] = display
107 | }
108 | return elementDisplay[nodeName]
109 | }
110 |
111 | function children(element) {
112 | return 'children' in element ?
113 | slice.call(element.children) :
114 | $.map(element.childNodes, function(node){ if (node.nodeType == 1) return node })
115 | }
116 |
117 | // `$.zepto.fragment` takes a html string and an optional tag name
118 | // to generate DOM nodes nodes from the given html string.
119 | // The generated DOM nodes are returned as an array.
120 | // This function can be overriden in plugins for example to make
121 | // it compatible with browsers that don't support the DOM fully.
122 | zepto.fragment = function(html, name, properties) {
123 | var dom, nodes, container
124 |
125 | // A special case optimization for a single tag
126 | if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1))
127 |
128 | if (!dom) {
129 | if (html.replace) html = html.replace(tagExpanderRE, "<$1>$2>")
130 | if (name === undefined) name = fragmentRE.test(html) && RegExp.$1
131 | if (!(name in containers)) name = '*'
132 |
133 | container = containers[name]
134 | container.innerHTML = '' + html
135 | dom = $.each(slice.call(container.childNodes), function(){
136 | container.removeChild(this)
137 | })
138 | }
139 |
140 | if (isPlainObject(properties)) {
141 | nodes = $(dom)
142 | $.each(properties, function(key, value) {
143 | if (methodAttributes.indexOf(key) > -1) nodes[key](value)
144 | else nodes.attr(key, value)
145 | })
146 | }
147 |
148 | return dom
149 | }
150 |
151 | // `$.zepto.Z` swaps out the prototype of the given `dom` array
152 | // of nodes with `$.fn` and thus supplying all the Zepto functions
153 | // to the array. Note that `__proto__` is not supported on Internet
154 | // Explorer. This method can be overriden in plugins.
155 | zepto.Z = function(dom, selector) {
156 | dom = dom || []
157 | dom.__proto__ = $.fn
158 | dom.selector = selector || ''
159 | return dom
160 | }
161 |
162 | // `$.zepto.isZ` should return `true` if the given object is a Zepto
163 | // collection. This method can be overriden in plugins.
164 | zepto.isZ = function(object) {
165 | return object instanceof zepto.Z
166 | }
167 |
168 | // `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and
169 | // takes a CSS selector and an optional context (and handles various
170 | // special cases).
171 | // This method can be overriden in plugins.
172 | zepto.init = function(selector, context) {
173 | var dom
174 | // If nothing given, return an empty Zepto collection
175 | if (!selector) return zepto.Z()
176 | // Optimize for string selectors
177 | else if (typeof selector == 'string') {
178 | selector = selector.trim()
179 | // If it's a html fragment, create nodes from it
180 | // Note: In both Chrome 21 and Firefox 15, DOM error 12
181 | // is thrown if the fragment doesn't begin with <
182 | if (selector[0] == '<' && fragmentRE.test(selector))
183 | dom = zepto.fragment(selector, RegExp.$1, context), selector = null
184 | // If there's a context, create a collection on that context first, and select
185 | // nodes from there
186 | else if (context !== undefined) return $(context).find(selector)
187 | // If it's a CSS selector, use it to select nodes.
188 | else dom = zepto.qsa(document, selector)
189 | }
190 | // If a function is given, call it when the DOM is ready
191 | else if (isFunction(selector)) return $(document).ready(selector)
192 | // If a Zepto collection is given, just return it
193 | else if (zepto.isZ(selector)) return selector
194 | else {
195 | // normalize array if an array of nodes is given
196 | if (isArray(selector)) dom = compact(selector)
197 | // Wrap DOM nodes.
198 | else if (isObject(selector))
199 | dom = [selector], selector = null
200 | // If it's a html fragment, create nodes from it
201 | else if (fragmentRE.test(selector))
202 | dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
203 | // If there's a context, create a collection on that context first, and select
204 | // nodes from there
205 | else if (context !== undefined) return $(context).find(selector)
206 | // And last but no least, if it's a CSS selector, use it to select nodes.
207 | else dom = zepto.qsa(document, selector)
208 | }
209 | // create a new Zepto collection from the nodes found
210 | return zepto.Z(dom, selector)
211 | }
212 |
213 | // `$` will be the base `Zepto` object. When calling this
214 | // function just call `$.zepto.init, which makes the implementation
215 | // details of selecting nodes and creating Zepto collections
216 | // patchable in plugins.
217 | $ = function(selector, context){
218 | return zepto.init(selector, context)
219 | }
220 |
221 | function extend(target, source, deep) {
222 | for (key in source)
223 | if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
224 | if (isPlainObject(source[key]) && !isPlainObject(target[key]))
225 | target[key] = {}
226 | if (isArray(source[key]) && !isArray(target[key]))
227 | target[key] = []
228 | extend(target[key], source[key], deep)
229 | }
230 | else if (source[key] !== undefined) target[key] = source[key]
231 | }
232 |
233 | // Copy all but undefined properties from one or more
234 | // objects to the `target` object.
235 | $.extend = function(target){
236 | var deep, args = slice.call(arguments, 1)
237 | if (typeof target == 'boolean') {
238 | deep = target
239 | target = args.shift()
240 | }
241 | args.forEach(function(arg){ extend(target, arg, deep) })
242 | return target
243 | }
244 |
245 | // `$.zepto.qsa` is Zepto's CSS selector implementation which
246 | // uses `document.querySelectorAll` and optimizes for some special cases, like `#id`.
247 | // This method can be overriden in plugins.
248 | zepto.qsa = function(element, selector){
249 | var found,
250 | maybeID = selector[0] == '#',
251 | maybeClass = !maybeID && selector[0] == '.',
252 | nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked
253 | isSimple = simpleSelectorRE.test(nameOnly)
254 | return (isDocument(element) && isSimple && maybeID) ?
255 | ( (found = element.getElementById(nameOnly)) ? [found] : [] ) :
256 | (element.nodeType !== 1 && element.nodeType !== 9) ? [] :
257 | slice.call(
258 | isSimple && !maybeID ?
259 | maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class
260 | element.getElementsByTagName(selector) : // Or a tag
261 | element.querySelectorAll(selector) // Or it's not simple, and we need to query all
262 | )
263 | }
264 |
265 | function filtered(nodes, selector) {
266 | return selector == null ? $(nodes) : $(nodes).filter(selector)
267 | }
268 |
269 | $.contains = document.documentElement.contains ?
270 | function(parent, node) {
271 | return parent !== node && parent.contains(node)
272 | } :
273 | function(parent, node) {
274 | while (node && (node = node.parentNode))
275 | if (node === parent) return true
276 | return false
277 | }
278 |
279 | function funcArg(context, arg, idx, payload) {
280 | return isFunction(arg) ? arg.call(context, idx, payload) : arg
281 | }
282 |
283 | function setAttribute(node, name, value) {
284 | value == null ? node.removeAttribute(name) : node.setAttribute(name, value)
285 | }
286 |
287 | // access className property while respecting SVGAnimatedString
288 | function className(node, value){
289 | var klass = node.className,
290 | svg = klass && klass.baseVal !== undefined
291 |
292 | if (value === undefined) return svg ? klass.baseVal : klass
293 | svg ? (klass.baseVal = value) : (node.className = value)
294 | }
295 |
296 | // "true" => true
297 | // "false" => false
298 | // "null" => null
299 | // "42" => 42
300 | // "42.5" => 42.5
301 | // "08" => "08"
302 | // JSON => parse if valid
303 | // String => self
304 | function deserializeValue(value) {
305 | var num
306 | try {
307 | return value ?
308 | value == "true" ||
309 | ( value == "false" ? false :
310 | value == "null" ? null :
311 | !/^0/.test(value) && !isNaN(num = Number(value)) ? num :
312 | /^[\[\{]/.test(value) ? $.parseJSON(value) :
313 | value )
314 | : value
315 | } catch(e) {
316 | return value
317 | }
318 | }
319 |
320 | $.type = type
321 | $.isFunction = isFunction
322 | $.isWindow = isWindow
323 | $.isArray = isArray
324 | $.isPlainObject = isPlainObject
325 |
326 | $.isEmptyObject = function(obj) {
327 | var name
328 | for (name in obj) return false
329 | return true
330 | }
331 |
332 | $.inArray = function(elem, array, i){
333 | return emptyArray.indexOf.call(array, elem, i)
334 | }
335 |
336 | $.camelCase = camelize
337 | $.trim = function(str) {
338 | return str == null ? "" : String.prototype.trim.call(str)
339 | }
340 |
341 | // plugin compatibility
342 | $.uuid = 0
343 | $.support = { }
344 | $.expr = { }
345 |
346 | $.map = function(elements, callback){
347 | var value, values = [], i, key
348 | if (likeArray(elements))
349 | for (i = 0; i < elements.length; i++) {
350 | value = callback(elements[i], i)
351 | if (value != null) values.push(value)
352 | }
353 | else
354 | for (key in elements) {
355 | value = callback(elements[key], key)
356 | if (value != null) values.push(value)
357 | }
358 | return flatten(values)
359 | }
360 |
361 | $.each = function(elements, callback){
362 | var i, key
363 | if (likeArray(elements)) {
364 | for (i = 0; i < elements.length; i++)
365 | if (callback.call(elements[i], i, elements[i]) === false) return elements
366 | } else {
367 | for (key in elements)
368 | if (callback.call(elements[key], key, elements[key]) === false) return elements
369 | }
370 |
371 | return elements
372 | }
373 |
374 | $.grep = function(elements, callback){
375 | return filter.call(elements, callback)
376 | }
377 |
378 | if (window.JSON) $.parseJSON = JSON.parse
379 |
380 | // Populate the class2type map
381 | $.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
382 | class2type[ "[object " + name + "]" ] = name.toLowerCase()
383 | })
384 |
385 | // Define methods that will be available on all
386 | // Zepto collections
387 | $.fn = {
388 | // Because a collection acts like an array
389 | // copy over these useful array functions.
390 | forEach: emptyArray.forEach,
391 | reduce: emptyArray.reduce,
392 | push: emptyArray.push,
393 | sort: emptyArray.sort,
394 | indexOf: emptyArray.indexOf,
395 | concat: emptyArray.concat,
396 |
397 | // `map` and `slice` in the jQuery API work differently
398 | // from their array counterparts
399 | map: function(fn){
400 | return $($.map(this, function(el, i){ return fn.call(el, i, el) }))
401 | },
402 | slice: function(){
403 | return $(slice.apply(this, arguments))
404 | },
405 |
406 | ready: function(callback){
407 | // need to check if document.body exists for IE as that browser reports
408 | // document ready when it hasn't yet created the body element
409 | if (readyRE.test(document.readyState) && document.body) callback($)
410 | else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false)
411 | return this
412 | },
413 | get: function(idx){
414 | return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length]
415 | },
416 | toArray: function(){ return this.get() },
417 | size: function(){
418 | return this.length
419 | },
420 | remove: function(){
421 | return this.each(function(){
422 | if (this.parentNode != null)
423 | this.parentNode.removeChild(this)
424 | })
425 | },
426 | each: function(callback){
427 | emptyArray.every.call(this, function(el, idx){
428 | return callback.call(el, idx, el) !== false
429 | })
430 | return this
431 | },
432 | filter: function(selector){
433 | if (isFunction(selector)) return this.not(this.not(selector))
434 | return $(filter.call(this, function(element){
435 | return zepto.matches(element, selector)
436 | }))
437 | },
438 | add: function(selector,context){
439 | return $(uniq(this.concat($(selector,context))))
440 | },
441 | is: function(selector){
442 | return this.length > 0 && zepto.matches(this[0], selector)
443 | },
444 | not: function(selector){
445 | var nodes=[]
446 | if (isFunction(selector) && selector.call !== undefined)
447 | this.each(function(idx){
448 | if (!selector.call(this,idx)) nodes.push(this)
449 | })
450 | else {
451 | var excludes = typeof selector == 'string' ? this.filter(selector) :
452 | (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector)
453 | this.forEach(function(el){
454 | if (excludes.indexOf(el) < 0) nodes.push(el)
455 | })
456 | }
457 | return $(nodes)
458 | },
459 | has: function(selector){
460 | return this.filter(function(){
461 | return isObject(selector) ?
462 | $.contains(this, selector) :
463 | $(this).find(selector).size()
464 | })
465 | },
466 | eq: function(idx){
467 | return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1)
468 | },
469 | first: function(){
470 | var el = this[0]
471 | return el && !isObject(el) ? el : $(el)
472 | },
473 | last: function(){
474 | var el = this[this.length - 1]
475 | return el && !isObject(el) ? el : $(el)
476 | },
477 | find: function(selector){
478 | var result, $this = this
479 | if (!selector) result = []
480 | else if (typeof selector == 'object')
481 | result = $(selector).filter(function(){
482 | var node = this
483 | return emptyArray.some.call($this, function(parent){
484 | return $.contains(parent, node)
485 | })
486 | })
487 | else if (this.length == 1) result = $(zepto.qsa(this[0], selector))
488 | else result = this.map(function(){ return zepto.qsa(this, selector) })
489 | return result
490 | },
491 | closest: function(selector, context){
492 | var node = this[0], collection = false
493 | if (typeof selector == 'object') collection = $(selector)
494 | while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector)))
495 | node = node !== context && !isDocument(node) && node.parentNode
496 | return $(node)
497 | },
498 | parents: function(selector){
499 | var ancestors = [], nodes = this
500 | while (nodes.length > 0)
501 | nodes = $.map(nodes, function(node){
502 | if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) {
503 | ancestors.push(node)
504 | return node
505 | }
506 | })
507 | return filtered(ancestors, selector)
508 | },
509 | parent: function(selector){
510 | return filtered(uniq(this.pluck('parentNode')), selector)
511 | },
512 | children: function(selector){
513 | return filtered(this.map(function(){ return children(this) }), selector)
514 | },
515 | contents: function() {
516 | return this.map(function() { return slice.call(this.childNodes) })
517 | },
518 | siblings: function(selector){
519 | return filtered(this.map(function(i, el){
520 | return filter.call(children(el.parentNode), function(child){ return child!==el })
521 | }), selector)
522 | },
523 | empty: function(){
524 | return this.each(function(){ this.innerHTML = '' })
525 | },
526 | // `pluck` is borrowed from Prototype.js
527 | pluck: function(property){
528 | return $.map(this, function(el){ return el[property] })
529 | },
530 | show: function(){
531 | return this.each(function(){
532 | this.style.display == "none" && (this.style.display = '')
533 | if (getComputedStyle(this, '').getPropertyValue("display") == "none")
534 | this.style.display = defaultDisplay(this.nodeName)
535 | })
536 | },
537 | replaceWith: function(newContent){
538 | return this.before(newContent).remove()
539 | },
540 | wrap: function(structure){
541 | var func = isFunction(structure)
542 | if (this[0] && !func)
543 | var dom = $(structure).get(0),
544 | clone = dom.parentNode || this.length > 1
545 |
546 | return this.each(function(index){
547 | $(this).wrapAll(
548 | func ? structure.call(this, index) :
549 | clone ? dom.cloneNode(true) : dom
550 | )
551 | })
552 | },
553 | wrapAll: function(structure){
554 | if (this[0]) {
555 | $(this[0]).before(structure = $(structure))
556 | var children
557 | // drill down to the inmost element
558 | while ((children = structure.children()).length) structure = children.first()
559 | $(structure).append(this)
560 | }
561 | return this
562 | },
563 | wrapInner: function(structure){
564 | var func = isFunction(structure)
565 | return this.each(function(index){
566 | var self = $(this), contents = self.contents(),
567 | dom = func ? structure.call(this, index) : structure
568 | contents.length ? contents.wrapAll(dom) : self.append(dom)
569 | })
570 | },
571 | unwrap: function(){
572 | this.parent().each(function(){
573 | $(this).replaceWith($(this).children())
574 | })
575 | return this
576 | },
577 | clone: function(){
578 | return this.map(function(){ return this.cloneNode(true) })
579 | },
580 | hide: function(){
581 | return this.css("display", "none")
582 | },
583 | toggle: function(setting){
584 | return this.each(function(){
585 | var el = $(this)
586 | ;(setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide()
587 | })
588 | },
589 | prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') },
590 | next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') },
591 | html: function(html){
592 | return 0 in arguments ?
593 | this.each(function(idx){
594 | var originHtml = this.innerHTML
595 | $(this).empty().append( funcArg(this, html, idx, originHtml) )
596 | }) :
597 | (0 in this ? this[0].innerHTML : null)
598 | },
599 | text: function(text){
600 | return 0 in arguments ?
601 | this.each(function(idx){
602 | var newText = funcArg(this, text, idx, this.textContent)
603 | this.textContent = newText == null ? '' : ''+newText
604 | }) :
605 | (0 in this ? this[0].textContent : null)
606 | },
607 | attr: function(name, value){
608 | var result
609 | return (typeof name == 'string' && !(1 in arguments)) ?
610 | (!this.length || this[0].nodeType !== 1 ? undefined :
611 | (!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result
612 | ) :
613 | this.each(function(idx){
614 | if (this.nodeType !== 1) return
615 | if (isObject(name)) for (key in name) setAttribute(this, key, name[key])
616 | else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)))
617 | })
618 | },
619 | removeAttr: function(name){
620 | return this.each(function(){ this.nodeType === 1 && setAttribute(this, name) })
621 | },
622 | prop: function(name, value){
623 | name = propMap[name] || name
624 | return (1 in arguments) ?
625 | this.each(function(idx){
626 | this[name] = funcArg(this, value, idx, this[name])
627 | }) :
628 | (this[0] && this[0][name])
629 | },
630 | data: function(name, value){
631 | var attrName = 'data-' + name.replace(capitalRE, '-$1').toLowerCase()
632 |
633 | var data = (1 in arguments) ?
634 | this.attr(attrName, value) :
635 | this.attr(attrName)
636 |
637 | return data !== null ? deserializeValue(data) : undefined
638 | },
639 | val: function(value){
640 | return 0 in arguments ?
641 | this.each(function(idx){
642 | this.value = funcArg(this, value, idx, this.value)
643 | }) :
644 | (this[0] && (this[0].multiple ?
645 | $(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') :
646 | this[0].value)
647 | )
648 | },
649 | offset: function(coordinates){
650 | if (coordinates) return this.each(function(index){
651 | var $this = $(this),
652 | coords = funcArg(this, coordinates, index, $this.offset()),
653 | parentOffset = $this.offsetParent().offset(),
654 | props = {
655 | top: coords.top - parentOffset.top,
656 | left: coords.left - parentOffset.left
657 | }
658 |
659 | if ($this.css('position') == 'static') props['position'] = 'relative'
660 | $this.css(props)
661 | })
662 | if (!this.length) return null
663 | var obj = this[0].getBoundingClientRect()
664 | return {
665 | left: obj.left + window.pageXOffset,
666 | top: obj.top + window.pageYOffset,
667 | width: Math.round(obj.width),
668 | height: Math.round(obj.height)
669 | }
670 | },
671 | css: function(property, value){
672 | if (arguments.length < 2) {
673 | var element = this[0], computedStyle = getComputedStyle(element, '')
674 | if(!element) return
675 | if (typeof property == 'string')
676 | return element.style[camelize(property)] || computedStyle.getPropertyValue(property)
677 | else if (isArray(property)) {
678 | var props = {}
679 | $.each(isArray(property) ? property: [property], function(_, prop){
680 | props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop))
681 | })
682 | return props
683 | }
684 | }
685 |
686 | var css = ''
687 | if (type(property) == 'string') {
688 | if (!value && value !== 0)
689 | this.each(function(){ this.style.removeProperty(dasherize(property)) })
690 | else
691 | css = dasherize(property) + ":" + maybeAddPx(property, value)
692 | } else {
693 | for (key in property)
694 | if (!property[key] && property[key] !== 0)
695 | this.each(function(){ this.style.removeProperty(dasherize(key)) })
696 | else
697 | css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';'
698 | }
699 |
700 | return this.each(function(){ this.style.cssText += ';' + css })
701 | },
702 | index: function(element){
703 | return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0])
704 | },
705 | hasClass: function(name){
706 | if (!name) return false
707 | return emptyArray.some.call(this, function(el){
708 | return this.test(className(el))
709 | }, classRE(name))
710 | },
711 | addClass: function(name){
712 | if (!name) return this
713 | return this.each(function(idx){
714 | classList = []
715 | var cls = className(this), newName = funcArg(this, name, idx, cls)
716 | newName.split(/\s+/g).forEach(function(klass){
717 | if (!$(this).hasClass(klass)) classList.push(klass)
718 | }, this)
719 | classList.length && className(this, cls + (cls ? " " : "") + classList.join(" "))
720 | })
721 | },
722 | removeClass: function(name){
723 | return this.each(function(idx){
724 | if (name === undefined) return className(this, '')
725 | classList = className(this)
726 | funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){
727 | classList = classList.replace(classRE(klass), " ")
728 | })
729 | className(this, classList.trim())
730 | })
731 | },
732 | toggleClass: function(name, when){
733 | if (!name) return this
734 | return this.each(function(idx){
735 | var $this = $(this), names = funcArg(this, name, idx, className(this))
736 | names.split(/\s+/g).forEach(function(klass){
737 | (when === undefined ? !$this.hasClass(klass) : when) ?
738 | $this.addClass(klass) : $this.removeClass(klass)
739 | })
740 | })
741 | },
742 | scrollTop: function(value){
743 | if (!this.length) return
744 | var hasScrollTop = 'scrollTop' in this[0]
745 | if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset
746 | return this.each(hasScrollTop ?
747 | function(){ this.scrollTop = value } :
748 | function(){ this.scrollTo(this.scrollX, value) })
749 | },
750 | scrollLeft: function(value){
751 | if (!this.length) return
752 | var hasScrollLeft = 'scrollLeft' in this[0]
753 | if (value === undefined) return hasScrollLeft ? this[0].scrollLeft : this[0].pageXOffset
754 | return this.each(hasScrollLeft ?
755 | function(){ this.scrollLeft = value } :
756 | function(){ this.scrollTo(value, this.scrollY) })
757 | },
758 | position: function() {
759 | if (!this.length) return
760 |
761 | var elem = this[0],
762 | // Get *real* offsetParent
763 | offsetParent = this.offsetParent(),
764 | // Get correct offsets
765 | offset = this.offset(),
766 | parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset()
767 |
768 | // Subtract element margins
769 | // note: when an element has margin: auto the offsetLeft and marginLeft
770 | // are the same in Safari causing offset.left to incorrectly be 0
771 | offset.top -= parseFloat( $(elem).css('margin-top') ) || 0
772 | offset.left -= parseFloat( $(elem).css('margin-left') ) || 0
773 |
774 | // Add offsetParent borders
775 | parentOffset.top += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0
776 | parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0
777 |
778 | // Subtract the two offsets
779 | return {
780 | top: offset.top - parentOffset.top,
781 | left: offset.left - parentOffset.left
782 | }
783 | },
784 | offsetParent: function() {
785 | return this.map(function(){
786 | var parent = this.offsetParent || document.body
787 | while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static")
788 | parent = parent.offsetParent
789 | return parent
790 | })
791 | }
792 | }
793 |
794 | // for now
795 | $.fn.detach = $.fn.remove
796 |
797 | // Generate the `width` and `height` functions
798 | ;['width', 'height'].forEach(function(dimension){
799 | var dimensionProperty =
800 | dimension.replace(/./, function(m){ return m[0].toUpperCase() })
801 |
802 | $.fn[dimension] = function(value){
803 | var offset, el = this[0]
804 | if (value === undefined) return isWindow(el) ? el['inner' + dimensionProperty] :
805 | isDocument(el) ? el.documentElement['scroll' + dimensionProperty] :
806 | (offset = this.offset()) && offset[dimension]
807 | else return this.each(function(idx){
808 | el = $(this)
809 | el.css(dimension, funcArg(this, value, idx, el[dimension]()))
810 | })
811 | }
812 | })
813 |
814 | function traverseNode(node, fun) {
815 | fun(node)
816 | for (var i = 0, len = node.childNodes.length; i < len; i++)
817 | traverseNode(node.childNodes[i], fun)
818 | }
819 |
820 | // Generate the `after`, `prepend`, `before`, `append`,
821 | // `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods.
822 | adjacencyOperators.forEach(function(operator, operatorIndex) {
823 | var inside = operatorIndex % 2 //=> prepend, append
824 |
825 | $.fn[operator] = function(){
826 | // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings
827 | var argType, nodes = $.map(arguments, function(arg) {
828 | argType = type(arg)
829 | return argType == "object" || argType == "array" || arg == null ?
830 | arg : zepto.fragment(arg)
831 | }),
832 | parent, copyByClone = this.length > 1
833 | if (nodes.length < 1) return this
834 |
835 | return this.each(function(_, target){
836 | parent = inside ? target : target.parentNode
837 |
838 | // convert all methods to a "before" operation
839 | target = operatorIndex == 0 ? target.nextSibling :
840 | operatorIndex == 1 ? target.firstChild :
841 | operatorIndex == 2 ? target :
842 | null
843 |
844 | var parentInDocument = $.contains(document.documentElement, parent)
845 |
846 | nodes.forEach(function(node){
847 | if (copyByClone) node = node.cloneNode(true)
848 | else if (!parent) return $(node).remove()
849 |
850 | parent.insertBefore(node, target)
851 | if (parentInDocument) traverseNode(node, function(el){
852 | if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' &&
853 | (!el.type || el.type === 'text/javascript') && !el.src)
854 | window['eval'].call(window, el.innerHTML)
855 | })
856 | })
857 | })
858 | }
859 |
860 | // after => insertAfter
861 | // prepend => prependTo
862 | // before => insertBefore
863 | // append => appendTo
864 | $.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){
865 | $(html)[operator](this)
866 | return this
867 | }
868 | })
869 |
870 | zepto.Z.prototype = $.fn
871 |
872 | // Export internal API functions in the `$.zepto` namespace
873 | zepto.uniq = uniq
874 | zepto.deserializeValue = deserializeValue
875 | $.zepto = zepto
876 |
877 | return $
878 | })()
879 |
880 | window.Zepto = Zepto
881 | window.$ === undefined && (window.$ = Zepto)
882 |
883 | ;(function($){
884 | var _zid = 1, undefined,
885 | slice = Array.prototype.slice,
886 | isFunction = $.isFunction,
887 | isString = function(obj){ return typeof obj == 'string' },
888 | handlers = {},
889 | specialEvents={},
890 | focusinSupported = 'onfocusin' in window,
891 | focus = { focus: 'focusin', blur: 'focusout' },
892 | hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' }
893 |
894 | specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents'
895 |
896 | function zid(element) {
897 | return element._zid || (element._zid = _zid++)
898 | }
899 | function findHandlers(element, event, fn, selector) {
900 | event = parse(event)
901 | if (event.ns) var matcher = matcherFor(event.ns)
902 | return (handlers[zid(element)] || []).filter(function(handler) {
903 | return handler
904 | && (!event.e || handler.e == event.e)
905 | && (!event.ns || matcher.test(handler.ns))
906 | && (!fn || zid(handler.fn) === zid(fn))
907 | && (!selector || handler.sel == selector)
908 | })
909 | }
910 | function parse(event) {
911 | var parts = ('' + event).split('.')
912 | return {e: parts[0], ns: parts.slice(1).sort().join(' ')}
913 | }
914 | function matcherFor(ns) {
915 | return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)')
916 | }
917 |
918 | function eventCapture(handler, captureSetting) {
919 | return handler.del &&
920 | (!focusinSupported && (handler.e in focus)) ||
921 | !!captureSetting
922 | }
923 |
924 | function realEvent(type) {
925 | return hover[type] || (focusinSupported && focus[type]) || type
926 | }
927 |
928 | function add(element, events, fn, data, selector, delegator, capture){
929 | var id = zid(element), set = (handlers[id] || (handlers[id] = []))
930 | events.split(/\s/).forEach(function(event){
931 | if (event == 'ready') return $(document).ready(fn)
932 | var handler = parse(event)
933 | handler.fn = fn
934 | handler.sel = selector
935 | // emulate mouseenter, mouseleave
936 | if (handler.e in hover) fn = function(e){
937 | var related = e.relatedTarget
938 | if (!related || (related !== this && !$.contains(this, related)))
939 | return handler.fn.apply(this, arguments)
940 | }
941 | handler.del = delegator
942 | var callback = delegator || fn
943 | handler.proxy = function(e){
944 | e = compatible(e)
945 | if (e.isImmediatePropagationStopped()) return
946 | e.data = data
947 | var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args))
948 | if (result === false) e.preventDefault(), e.stopPropagation()
949 | return result
950 | }
951 | handler.i = set.length
952 | set.push(handler)
953 | if ('addEventListener' in element)
954 | element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
955 | })
956 | }
957 | function remove(element, events, fn, selector, capture){
958 | var id = zid(element)
959 | ;(events || '').split(/\s/).forEach(function(event){
960 | findHandlers(element, event, fn, selector).forEach(function(handler){
961 | delete handlers[id][handler.i]
962 | if ('removeEventListener' in element)
963 | element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
964 | })
965 | })
966 | }
967 |
968 | $.event = { add: add, remove: remove }
969 |
970 | $.proxy = function(fn, context) {
971 | var args = (2 in arguments) && slice.call(arguments, 2)
972 | if (isFunction(fn)) {
973 | var proxyFn = function(){ return fn.apply(context, args ? args.concat(slice.call(arguments)) : arguments) }
974 | proxyFn._zid = zid(fn)
975 | return proxyFn
976 | } else if (isString(context)) {
977 | if (args) {
978 | args.unshift(fn[context], fn)
979 | return $.proxy.apply(null, args)
980 | } else {
981 | return $.proxy(fn[context], fn)
982 | }
983 | } else {
984 | throw new TypeError("expected function")
985 | }
986 | }
987 |
988 | $.fn.bind = function(event, data, callback){
989 | return this.on(event, data, callback)
990 | }
991 | $.fn.unbind = function(event, callback){
992 | return this.off(event, callback)
993 | }
994 | $.fn.one = function(event, selector, data, callback){
995 | return this.on(event, selector, data, callback, 1)
996 | }
997 |
998 | var returnTrue = function(){return true},
999 | returnFalse = function(){return false},
1000 | ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$)/,
1001 | eventMethods = {
1002 | preventDefault: 'isDefaultPrevented',
1003 | stopImmediatePropagation: 'isImmediatePropagationStopped',
1004 | stopPropagation: 'isPropagationStopped'
1005 | }
1006 |
1007 | function compatible(event, source) {
1008 | if (source || !event.isDefaultPrevented) {
1009 | source || (source = event)
1010 |
1011 | $.each(eventMethods, function(name, predicate) {
1012 | var sourceMethod = source[name]
1013 | event[name] = function(){
1014 | this[predicate] = returnTrue
1015 | return sourceMethod && sourceMethod.apply(source, arguments)
1016 | }
1017 | event[predicate] = returnFalse
1018 | })
1019 |
1020 | if (source.defaultPrevented !== undefined ? source.defaultPrevented :
1021 | 'returnValue' in source ? source.returnValue === false :
1022 | source.getPreventDefault && source.getPreventDefault())
1023 | event.isDefaultPrevented = returnTrue
1024 | }
1025 | return event
1026 | }
1027 |
1028 | function createProxy(event) {
1029 | var key, proxy = { originalEvent: event }
1030 | for (key in event)
1031 | if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key]
1032 |
1033 | return compatible(proxy, event)
1034 | }
1035 |
1036 | $.fn.delegate = function(selector, event, callback){
1037 | return this.on(event, selector, callback)
1038 | }
1039 | $.fn.undelegate = function(selector, event, callback){
1040 | return this.off(event, selector, callback)
1041 | }
1042 |
1043 | $.fn.live = function(event, callback){
1044 | $(document.body).delegate(this.selector, event, callback)
1045 | return this
1046 | }
1047 | $.fn.die = function(event, callback){
1048 | $(document.body).undelegate(this.selector, event, callback)
1049 | return this
1050 | }
1051 |
1052 | $.fn.on = function(event, selector, data, callback, one){
1053 | var autoRemove, delegator, $this = this
1054 | if (event && !isString(event)) {
1055 | $.each(event, function(type, fn){
1056 | $this.on(type, selector, data, fn, one)
1057 | })
1058 | return $this
1059 | }
1060 |
1061 | if (!isString(selector) && !isFunction(callback) && callback !== false)
1062 | callback = data, data = selector, selector = undefined
1063 | if (isFunction(data) || data === false)
1064 | callback = data, data = undefined
1065 |
1066 | if (callback === false) callback = returnFalse
1067 |
1068 | return $this.each(function(_, element){
1069 | if (one) autoRemove = function(e){
1070 | remove(element, e.type, callback)
1071 | return callback.apply(this, arguments)
1072 | }
1073 |
1074 | if (selector) delegator = function(e){
1075 | var evt, match = $(e.target).closest(selector, element).get(0)
1076 | if (match && match !== element) {
1077 | evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element})
1078 | return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1)))
1079 | }
1080 | }
1081 |
1082 | add(element, event, callback, data, selector, delegator || autoRemove)
1083 | })
1084 | }
1085 | $.fn.off = function(event, selector, callback){
1086 | var $this = this
1087 | if (event && !isString(event)) {
1088 | $.each(event, function(type, fn){
1089 | $this.off(type, selector, fn)
1090 | })
1091 | return $this
1092 | }
1093 |
1094 | if (!isString(selector) && !isFunction(callback) && callback !== false)
1095 | callback = selector, selector = undefined
1096 |
1097 | if (callback === false) callback = returnFalse
1098 |
1099 | return $this.each(function(){
1100 | remove(this, event, callback, selector)
1101 | })
1102 | }
1103 |
1104 | $.fn.trigger = function(event, args){
1105 | event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event)
1106 | event._args = args
1107 | return this.each(function(){
1108 | // items in the collection might not be DOM elements
1109 | if('dispatchEvent' in this) this.dispatchEvent(event)
1110 | else $(this).triggerHandler(event, args)
1111 | })
1112 | }
1113 |
1114 | // triggers event handlers on current element just as if an event occurred,
1115 | // doesn't trigger an actual event, doesn't bubble
1116 | $.fn.triggerHandler = function(event, args){
1117 | var e, result
1118 | this.each(function(i, element){
1119 | e = createProxy(isString(event) ? $.Event(event) : event)
1120 | e._args = args
1121 | e.target = element
1122 | $.each(findHandlers(element, event.type || event), function(i, handler){
1123 | result = handler.proxy(e)
1124 | if (e.isImmediatePropagationStopped()) return false
1125 | })
1126 | })
1127 | return result
1128 | }
1129 |
1130 | // shortcut methods for `.bind(event, fn)` for each event type
1131 | ;('focusin focusout load resize scroll unload click dblclick '+
1132 | 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+
1133 | 'change select keydown keypress keyup error').split(' ').forEach(function(event) {
1134 | $.fn[event] = function(callback) {
1135 | return callback ?
1136 | this.bind(event, callback) :
1137 | this.trigger(event)
1138 | }
1139 | })
1140 |
1141 | ;['focus', 'blur'].forEach(function(name) {
1142 | $.fn[name] = function(callback) {
1143 | if (callback) this.bind(name, callback)
1144 | else this.each(function(){
1145 | try { this[name]() }
1146 | catch(e) {}
1147 | })
1148 | return this
1149 | }
1150 | })
1151 |
1152 | $.Event = function(type, props) {
1153 | if (!isString(type)) props = type, type = props.type
1154 | var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true
1155 | if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name])
1156 | event.initEvent(type, bubbles, true)
1157 | return compatible(event)
1158 | }
1159 |
1160 | })(Zepto)
1161 |
1162 | ;(function($){
1163 | var jsonpID = 0,
1164 | document = window.document,
1165 | key,
1166 | name,
1167 | rscript = /