├── test ├── overlay │ ├── lazyload.htm │ ├── img │ │ ├── close.gif │ │ ├── close.png │ │ ├── next.gif │ │ ├── image-1.jpg │ │ ├── image-2.jpg │ │ ├── image-3.jpg │ │ ├── image-4.jpg │ │ ├── overlay.png │ │ └── overlay-white.png │ ├── style.css │ ├── 2overlays.html │ ├── modal.html │ ├── lightbox.html │ ├── index.htm │ └── test.js ├── tabs │ ├── lazyload │ │ ├── 3.htm │ │ ├── 2.htm │ │ ├── load1.htm │ │ ├── 1.htm │ │ ├── index.html │ │ └── slideshow.html │ ├── slideshow │ │ └── slideshow.css │ ├── horizontal.css │ ├── horizontal.html │ ├── tabs.css │ ├── ajax.html │ ├── history.html │ └── index.html ├── dateinput │ ├── next.gif │ ├── prev.gif │ ├── minimal.htm │ ├── customized.htm │ └── skin1.css ├── form │ ├── img │ │ ├── radio.png │ │ ├── button.png │ │ ├── checkbox.png │ │ └── select.png │ ├── dateinput.htm │ ├── dateinput.css │ ├── draggable.htm │ ├── styleable.htm │ └── dateinput-layout.htm ├── img │ ├── arrow_next.gif │ ├── arrow_prev.gif │ ├── blue_next.gif │ ├── blue_prev.gif │ ├── 6481762_3d2c7e79f7.jpg │ ├── 375832178_02b1b0e4b1.jpg │ ├── 543642045_9aa7beb2c0.jpg │ ├── 2132556613_ab0a4b8d2f_o.jpg │ ├── 2220611397_73b6486fe9.jpg │ ├── 3720930469_66ffe057f8.jpg │ └── 3942153630_38e1a62b2d.jpg ├── tooltip │ ├── click.html │ ├── dynamic.html │ ├── style.css │ ├── scrollable.html │ └── index.html ├── toolbox │ └── mask │ │ └── mask.htm ├── rangeinput │ ├── img │ │ ├── h30.png │ │ ├── h300.png │ │ ├── h80.png │ │ ├── pattern.png │ │ ├── apple │ │ │ ├── bg.png │ │ │ ├── iphone.png │ │ │ ├── dragger.png │ │ │ └── gradient.jpg │ │ ├── small-vertical.png │ │ ├── small-horizontal.png │ │ └── IDEAS │ ├── css │ │ ├── multiple.css │ │ ├── skin1.css │ │ └── small.css │ ├── vertical.htm │ ├── multiple.htm │ └── scrollbar.htm ├── validator │ ├── validator.htm │ ├── no-form.htm │ └── minimal.htm └── scrollable │ ├── single.html │ ├── size2.html │ ├── style.css │ ├── lazyload.htm │ └── index.html ├── lib ├── rhino.jar └── compiler.jar ├── .gitignore ├── README.md └── src ├── toolbox ├── toolbox.mousewheel.js ├── toolbox.history.js ├── toolbox.expose.js └── toolbox.flashembed.js ├── tooltip ├── tooltip.slide.js ├── tooltip.dynamic.js └── tooltip.js ├── scrollable ├── scrollable.autoscroll.js ├── scrollable.navigator.js └── scrollable.js ├── overlay ├── overlay.apple.js └── overlay.js ├── tabs ├── tabs.slideshow.js └── tabs.js ├── rangeinput └── rangeinput.js ├── validator └── validator.js └── dateinput └── dateinput.js /test/overlay/lazyload.htm: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/tabs/lazyload/3.htm: -------------------------------------------------------------------------------- 1 | third 2 | -------------------------------------------------------------------------------- /test/tabs/lazyload/2.htm: -------------------------------------------------------------------------------- 1 | second page 2 | -------------------------------------------------------------------------------- /lib/rhino.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/lib/rhino.jar -------------------------------------------------------------------------------- /lib/compiler.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/lib/compiler.jar -------------------------------------------------------------------------------- /test/dateinput/next.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/dateinput/next.gif -------------------------------------------------------------------------------- /test/dateinput/prev.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/dateinput/prev.gif -------------------------------------------------------------------------------- /test/form/img/radio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/form/img/radio.png -------------------------------------------------------------------------------- /test/img/arrow_next.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/img/arrow_next.gif -------------------------------------------------------------------------------- /test/img/arrow_prev.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/img/arrow_prev.gif -------------------------------------------------------------------------------- /test/img/blue_next.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/img/blue_next.gif -------------------------------------------------------------------------------- /test/img/blue_prev.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/img/blue_prev.gif -------------------------------------------------------------------------------- /test/tooltip/click.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/tooltip/click.html -------------------------------------------------------------------------------- /test/form/img/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/form/img/button.png -------------------------------------------------------------------------------- /test/form/img/checkbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/form/img/checkbox.png -------------------------------------------------------------------------------- /test/form/img/select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/form/img/select.png -------------------------------------------------------------------------------- /test/overlay/img/close.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/overlay/img/close.gif -------------------------------------------------------------------------------- /test/overlay/img/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/overlay/img/close.png -------------------------------------------------------------------------------- /test/overlay/img/next.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/overlay/img/next.gif -------------------------------------------------------------------------------- /test/toolbox/mask/mask.htm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/toolbox/mask/mask.htm -------------------------------------------------------------------------------- /test/tooltip/dynamic.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/tooltip/dynamic.html -------------------------------------------------------------------------------- /test/overlay/img/image-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/overlay/img/image-1.jpg -------------------------------------------------------------------------------- /test/overlay/img/image-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/overlay/img/image-2.jpg -------------------------------------------------------------------------------- /test/overlay/img/image-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/overlay/img/image-3.jpg -------------------------------------------------------------------------------- /test/overlay/img/image-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/overlay/img/image-4.jpg -------------------------------------------------------------------------------- /test/overlay/img/overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/overlay/img/overlay.png -------------------------------------------------------------------------------- /test/rangeinput/img/h30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/rangeinput/img/h30.png -------------------------------------------------------------------------------- /test/rangeinput/img/h300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/rangeinput/img/h300.png -------------------------------------------------------------------------------- /test/rangeinput/img/h80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/rangeinput/img/h80.png -------------------------------------------------------------------------------- /test/validator/validator.htm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/validator/validator.htm -------------------------------------------------------------------------------- /test/img/6481762_3d2c7e79f7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/img/6481762_3d2c7e79f7.jpg -------------------------------------------------------------------------------- /test/rangeinput/img/pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/rangeinput/img/pattern.png -------------------------------------------------------------------------------- /test/img/375832178_02b1b0e4b1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/img/375832178_02b1b0e4b1.jpg -------------------------------------------------------------------------------- /test/img/543642045_9aa7beb2c0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/img/543642045_9aa7beb2c0.jpg -------------------------------------------------------------------------------- /test/rangeinput/img/apple/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/rangeinput/img/apple/bg.png -------------------------------------------------------------------------------- /test/img/2132556613_ab0a4b8d2f_o.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/img/2132556613_ab0a4b8d2f_o.jpg -------------------------------------------------------------------------------- /test/img/2220611397_73b6486fe9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/img/2220611397_73b6486fe9.jpg -------------------------------------------------------------------------------- /test/img/3720930469_66ffe057f8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/img/3720930469_66ffe057f8.jpg -------------------------------------------------------------------------------- /test/img/3942153630_38e1a62b2d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/img/3942153630_38e1a62b2d.jpg -------------------------------------------------------------------------------- /test/overlay/img/overlay-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/overlay/img/overlay-white.png -------------------------------------------------------------------------------- /test/rangeinput/img/apple/iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/rangeinput/img/apple/iphone.png -------------------------------------------------------------------------------- /test/rangeinput/img/apple/dragger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/rangeinput/img/apple/dragger.png -------------------------------------------------------------------------------- /test/rangeinput/img/apple/gradient.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/rangeinput/img/apple/gradient.jpg -------------------------------------------------------------------------------- /test/rangeinput/img/small-vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/rangeinput/img/small-vertical.png -------------------------------------------------------------------------------- /test/rangeinput/img/small-horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codegram/jquerytools/HEAD/test/rangeinput/img/small-horizontal.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | 3 | # patch 4 | *.rej 5 | *.orig 6 | 7 | # vim 8 | *~ 9 | 10 | # emacs 11 | \#*\# 12 | \.\#* 13 | 14 | # MacOS directory store 15 | .DS_Store 16 | -------------------------------------------------------------------------------- /test/tabs/lazyload/load1.htm: -------------------------------------------------------------------------------- 1 | 2 |
7 | lskdjf alskdfj asldfkj aslkf jasdlfk j 8 |
9 | 10 |
11 |
12 | 5 | ut enim diam, at iaculis purus. Nunc porta imperdiet iaculis. Phasellus purus dui, aliquam nec iaculis ut, dignissim et velit. Sed viverra vulputate purus ut vestibulum. Cras nec purus ac lectus varius suscipit in et orci. Vestibulum ac erat felis, sodales laoreet lectus. Ut consectetur iaculis elit, in varius diam feugiat non. 6 |
7 | 8 |9 | Donec turpis urna, elementum eget ultricies sed, semper a massa. Vivamus euismod lacus nec arcu aliquam sollicitudin. Donec nec ante eu tortor ullamcorper molestie. Donec tempus dictum neque, pellentesque semper lorem elementum quis. Maecenas aliquet magna in purus elementum a vestibulum massa gravida. Duis sit amet tortor porttitor nulla interdum sagittis ac eget quam. Suspe 10 |
11 | -------------------------------------------------------------------------------- /test/rangeinput/vertical.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | -------------------------------------------------------------------------------- /test/scrollable/size2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 22 | 23 | 24 |38 | Scrollable error when size = 2 39 |
40 | 41 |42 | 43 |
44 | -------------------------------------------------------------------------------- /test/scrollable/style.css: -------------------------------------------------------------------------------- 1 | 2 | /* minimal settings */ 3 | .scrollable { 4 | 5 | /* required settings for the root element */ 6 | position:relative; 7 | overflow:hidden; 8 | width: 660px; 9 | 10 | /* configurable styling */ 11 | border:1px solid #ccc; 12 | padding:20px 0; 13 | height:130px; 14 | } 15 | 16 | .scrollable .items { 17 | margin-left:10px; 18 | position:relative; 19 | width:20000em; 20 | } 21 | 22 | .scrollable .items div { 23 | text-align:center; 24 | width:110px; 25 | padding:25px 0px; 26 | font-size:30px; 27 | font-family: 'bitstream vera sans'; 28 | border:1px outset #ccc; 29 | background-color: #efefef; 30 | margin-right: 20px; 31 | float:left; 32 | -moz-border-radius:5px; 33 | } 34 | 35 | .navi { 36 | height:30px; 37 | margin-bottom:20px; 38 | } 39 | 40 | .navi a { 41 | width:20px; 42 | height: 20px; 43 | background-color:blue; 44 | display:block; 45 | float:left; 46 | margin-right:10px; 47 | } 48 | 49 | .navi a.active { 50 | background-color:yellow; 51 | } 52 | 53 | /* custom style */ 54 | body { 55 | padding:50px 100px; 56 | } 57 | -------------------------------------------------------------------------------- /test/overlay/style.css: -------------------------------------------------------------------------------- 1 | /* automatically absolutely positioned */ 2 | div.overlay { 3 | width:400px; 4 | display:none; 5 | color:#fff; 6 | padding:10px; 7 | } 8 | 9 | div.overlay a.close { 10 | background-image:url(img/close.png); 11 | position:absolute; 12 | right:5px; 13 | top:7px; 14 | cursor:pointer; 15 | height:27px; 16 | width:27px; 17 | } 18 | 19 | #overlay { 20 | height:200px; 21 | background-color:#666; 22 | -moz-border-radius:15px; 23 | } 24 | 25 | #overlay2 { 26 | background-image:url(img/overlay.png) 27 | } 28 | 29 | #img { 30 | position:absolute; 31 | } 32 | 33 | .next, .prev { 34 | position:absolute; 35 | cursor:pointer; 36 | display:block; 37 | width:100px; 38 | height:200px; 39 | background:url(img/next.gif) no-repeat; 40 | } 41 | 42 | .prev { 43 | left:10px; 44 | } 45 | 46 | .next { 47 | right:10px; 48 | } 49 | 50 | .info { 51 | position:absolute; 52 | bottom:10px; 53 | background-color:#333; 54 | opacity:0.7; 55 | padding:4px 15px; 56 | } 57 | 58 | .info strong { 59 | display:block; 60 | } 61 | 62 | .disabled { 63 | visibility:hidden; 64 | } 65 | -------------------------------------------------------------------------------- /test/rangeinput/css/skin1.css: -------------------------------------------------------------------------------- 1 | 2 | #wrapper { 3 | background:#666 url(../img/h300.png) repeat-x; 4 | padding:10px 20px; 5 | width:510px; 6 | height:130px; 7 | } 8 | 9 | .slider { 10 | background:#333 url(../img/h30.png) repeat-x 0 0; 11 | height:30px; 12 | position:relative; 13 | cursor:pointer; 14 | margin:15px 0; 15 | -moz-border-radius:5px; 16 | border:1px inset #333; 17 | width:400px; 18 | float:left; 19 | clear:right; 20 | } 21 | 22 | .progress { 23 | height:30px; 24 | background-color:#34405F; 25 | display:none; 26 | opacity:0.5; 27 | } 28 | 29 | .handle { 30 | background:#3CB2FB url(../img/h30.png) repeat-x 0 0; 31 | height:28px; 32 | width:28px; 33 | top:0; 34 | position:absolute; 35 | display:block; 36 | margin-top:1px; 37 | -moz-border-radius:14px; 38 | } 39 | 40 | .range { 41 | float:left; 42 | margin-left:15px; 43 | border:0; 44 | background:transparent; 45 | font-size:30px; 46 | color:#fff; 47 | width:90px; 48 | margin:12px 0 0 15px; 49 | } 50 | 51 | .handle:hover { 52 | background-color:#72B0D6; 53 | } 54 | 55 | .handle:focus { 56 | background-color:#4E75FF; 57 | } 58 | -------------------------------------------------------------------------------- /test/overlay/2overlays.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 23 | 24 |25 | show 26 |
27 | 28 |29 | show b 30 |
31 | 32 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /test/tabs/horizontal.css: -------------------------------------------------------------------------------- 1 | 2 | /* root element for accordion. decorated with rounded borders and gradient background image */ 3 | #accordion { 4 | background:#FFFFFF url(/img/global/gradient/h150.png) repeat scroll 0; 5 | height:80px; 6 | padding:10px 0 10px 20px; 7 | width:560px; 8 | border:1px solid #ddd; 9 | } 10 | 11 | /* accordion header */ 12 | #accordion img { 13 | float:left; 14 | margin-right:10px; 15 | cursor:pointer; 16 | opacity:0.5; 17 | filter: alpha(opacity=50); 18 | } 19 | 20 | /* currently active header */ 21 | #accordion img.current { 22 | cursor:default; 23 | opacity:1; 24 | filter: alpha(opacity=100); 25 | } 26 | 27 | /* 28 | accordion pane. should initially have zero width and display:none. 29 | the first pane should override these with inline style 30 | */ 31 | #accordion div { 32 | width:0px; 33 | float:left; 34 | display:none; 35 | margin-right:10px; 36 | } 37 | 38 | /* content inside a pane should have fixed width */ 39 | #accordion div h3 { 40 | color:#444; 41 | margin:0 0 -10px 0; 42 | width:190px; 43 | font-size:15px; 44 | } 45 | 46 | #accordion div p { 47 | font-size:11px; 48 | width:190px; 49 | } 50 | -------------------------------------------------------------------------------- /test/validator/no-form.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 27 | 28 |
24 |
25 | 28 | Consectetur adipiscing elit. Praesent bibendum eros ac nulla. Integer vel lacus ac neque viverra. 29 |
30 |
33 |
34 | 37 | Cras diam. Donec dolor lacus, vestibulum at, varius in, mollis id, dolor. Aliquam erat volutpat. 38 |
39 |
42 |
43 | 46 | Non lectus lacinia egestas. Nulla hendrerit, felis quis elementum viverra, purus felis egestas magna. 47 |
48 |36 | You can only interact with elements that are inside this dialog. To close press the OK button or ESC key. 37 |
38 | 39 |40 | 41 |
42 |
32 |
38 |
56 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | 61 |64 | 65 | 66 |
67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/tooltip/tooltip.slide.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * jQuery Tools @VERSION / Tooltip Slide Effect 4 | * 5 | * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE. 6 | * 7 | * http://flowplayer.org/tools/tooltip/slide.html 8 | * 9 | * Since: September 2009 10 | * Date: @DATE 11 | */ 12 | (function($) { 13 | 14 | // version number 15 | var t = $.tools.tooltip; 16 | 17 | // extend global configuragion with effect specific defaults 18 | $.extend(t.conf, { 19 | direction: 'up', // down, left, right 20 | bounce: false, 21 | slideOffset: 10, 22 | slideInSpeed: 200, 23 | slideOutSpeed: 200, 24 | slideFade: !$.browser.msie 25 | }); 26 | 27 | // directions for slide effect 28 | var dirs = { 29 | up: ['-', 'top'], 30 | down: ['+', 'top'], 31 | left: ['-', 'left'], 32 | right: ['+', 'left'] 33 | }; 34 | 35 | /* default effect: "slide" */ 36 | t.addEffect("slide", 37 | 38 | // show effect 39 | function(done) { 40 | 41 | // variables 42 | var conf = this.getConf(), 43 | tip = this.getTip(), 44 | params = conf.slideFade ? {opacity: conf.opacity} : {}, 45 | dir = dirs[conf.direction] || dirs.up; 46 | 47 | // direction 48 | params[dir[1]] = dir[0] +'='+ conf.slideOffset; 49 | 50 | // perform animation 51 | if (conf.slideFade) { tip.css({opacity:0}); } 52 | tip.show().animate(params, conf.slideInSpeed, done); 53 | }, 54 | 55 | // hide effect 56 | function(done) { 57 | 58 | // variables 59 | var conf = this.getConf(), 60 | offset = conf.slideOffset, 61 | params = conf.slideFade ? {opacity: 0} : {}, 62 | dir = dirs[conf.direction] || dirs.up; 63 | 64 | // direction 65 | var sign = "" + dir[0]; 66 | if (conf.bounce) { sign = sign == '+' ? '-' : '+'; } 67 | params[dir[1]] = sign +'='+ offset; 68 | 69 | // perform animation 70 | this.getTip().animate(params, conf.slideOutSpeed, function() { 71 | $(this).hide(); 72 | done.call(); 73 | }); 74 | } 75 | ); 76 | 77 | })(jQuery); 78 | 79 | -------------------------------------------------------------------------------- /src/scrollable/scrollable.autoscroll.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * jQuery Tools @VERSION / Scrollable Autoscroll 4 | * 5 | * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE. 6 | * 7 | * http://flowplayer.org/tools/scrollable/autoscroll.html 8 | * 9 | * Since: September 2009 10 | * Date: @DATE 11 | */ 12 | (function($) { 13 | 14 | var t = $.tools.scrollable; 15 | 16 | t.autoscroll = { 17 | 18 | conf: { 19 | autoplay: true, 20 | interval: 3000, 21 | autopause: true 22 | } 23 | }; 24 | 25 | // jQuery plugin implementation 26 | $.fn.autoscroll = function(conf) { 27 | 28 | if (typeof conf == 'number') { 29 | conf = {interval: conf}; 30 | } 31 | 32 | var opts = $.extend({}, t.autoscroll.conf, conf), ret; 33 | 34 | this.each(function() { 35 | 36 | var api = $(this).data("scrollable"); 37 | if (api) { ret = api; } 38 | 39 | // interval stuff 40 | var timer, hoverTimer, stopped = true; 41 | 42 | api.play = function() { 43 | 44 | // do not start additional timer if already exists 45 | if (timer) { return; } 46 | 47 | stopped = false; 48 | 49 | // construct new timer 50 | timer = setInterval(function() { 51 | api.next(); 52 | }, opts.interval); 53 | 54 | api.next(); 55 | }; 56 | 57 | api.pause = function() { 58 | timer = clearInterval(timer); 59 | }; 60 | 61 | // when stopped - mouseover won't restart 62 | api.stop = function() { 63 | api.pause(); 64 | stopped = true; 65 | }; 66 | 67 | /* when mouse enters, autoscroll stops */ 68 | if (opts.autopause) { 69 | api.getRoot().add(api.getNaviButtons()).hover(function() { 70 | api.pause(); 71 | clearInterval(hoverTimer); 72 | 73 | }, function() { 74 | if (!stopped) { 75 | hoverTimer = setTimeout(api.play, opts.interval); 76 | } 77 | }); 78 | } 79 | 80 | if (opts.autoplay) { 81 | setTimeout(api.play, opts.interval); 82 | } 83 | 84 | }); 85 | 86 | return opts.api ? ret : this; 87 | 88 | }; 89 | 90 | })(jQuery); 91 | -------------------------------------------------------------------------------- /test/form/dateinput.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 20 | 21 | 22 | 23 | 24 |19 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis viverra, leo sit amet auctor fermentum, risus lorem posuere tortor, in accumsan purus magna imperdiet sem. 20 |
21 | 22 |23 | Suspendisse enim. Pellentesque facilisis aliquam enim. Maecenas facilisis molestie lectus. Sed ornare ultricies tortor. Vivamus nibh metus, faucibus quis, semper ut, dignissim id, diam. 24 |
25 |29 | Mauris ultricies. Nam feugiat egestas nulla. Donec augue dui, molestie sed, tristique sit amet, blandit eu, turpis. Mauris hendrerit, nisi et sodales tempor, orci tellus laoreet elit, sed molestie dui quam vitae dui. 30 |
31 |32 | Pellentesque nisl. Ut adipiscing vehicula risus. Nam eget tortor. Maecenas id augue. Vivamus interdum nulla ac dolor. Fusce metus. Suspendisse eu purus. Maecenas quis lacus eget dui volutpat molestie. 33 |
34 |38 | Maecenas at odio. Nunc laoreet lectus vel ante. Nullam imperdiet. Sed justo dolor, mattis eu, euismod sed, tempus a, nisl. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. 39 |
40 | 41 |42 | In sed dolor. Etiam eget quam ac nibh pharetra adipiscing. Nullam vitae ligula. Sed sit amet leo sit amet arcu mollis ultrices. Vivamus rhoncus sapien nec lorem. In mattis nisi. Vivamus at enim. Integer semper imperdiet massa. Vestibulum nulla massa, pretium quis, porta id, vestibulum vitae, velit. 43 |
44 |18 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis viverra, leo sit amet auctor fermentum, risus lorem posuere tortor, in accumsan purus magna imperdiet sem. 19 |
20 | 21 |22 | Suspendisse enim. Pellentesque facilisis aliquam enim. Maecenas facilisis molestie lectus. Sed ornare ultricies tortor. Vivamus nibh metus, faucibus quis, semper ut, dignissim id, diam. 23 |
24 |28 | Mauris ultricies. Nam feugiat egestas nulla. Donec augue dui, molestie sed, tristique sit amet, blandit eu, turpis. Mauris hendrerit, nisi et sodales tempor, orci tellus laoreet elit, sed molestie dui quam vitae dui. 29 |
30 |31 | Pellentesque nisl. Ut adipiscing vehicula risus. Nam eget tortor. Maecenas id augue. Vivamus interdum nulla ac dolor. Fusce metus. Suspendisse eu purus. Maecenas quis lacus eget dui volutpat molestie. 32 |
33 |37 | Maecenas at odio. Nunc laoreet lectus vel ante. Nullam imperdiet. Sed justo dolor, mattis eu, euismod sed, tempus a, nisl. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. 38 |
39 | 40 |41 | In sed dolor. Etiam eget quam ac nibh pharetra adipiscing. Nullam vitae ligula. Sed sit amet leo sit amet arcu mollis ultrices. Vivamus rhoncus sapien nec lorem. In mattis nisi. Vivamus at enim. Integer semper imperdiet massa. Vestibulum nulla massa, pretium quis, porta id, vestibulum vitae, velit. 42 |
43 |71 | show 72 | show b 73 | 74 | show 2 75 | show 2b 76 |
77 | 78 |119 | 120 | 121 | 122 |
123 | 124 | -------------------------------------------------------------------------------- /test/tooltip/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 42 | 43 | 44 | 45 | 46 | 63 | 64 |
123 | 133 | 134 | 135 | 136 |
137 | 138 | -------------------------------------------------------------------------------- /src/scrollable/scrollable.navigator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * jQuery Tools @VERSION / Scrollable Navigator 4 | * 5 | * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE. 6 | * 7 | * http://flowplayer.org/tools/scrollable/navigator.html 8 | * 9 | * Since: September 2009 10 | * Date: @DATE 11 | */ 12 | (function($) { 13 | 14 | var t = $.tools.scrollable; 15 | 16 | t.navigator = { 17 | 18 | conf: { 19 | navi: '.navi', 20 | naviItem: null, 21 | activeClass: 'active', 22 | indexed: false, 23 | idPrefix: null, 24 | 25 | // 1.2 26 | history: false 27 | } 28 | }; 29 | 30 | function find(root, query) { 31 | var el = $(query); 32 | return el.length < 2 ? el : root.parent().find(query); 33 | } 34 | 35 | // jQuery plugin implementation 36 | $.fn.navigator = function(conf) { 37 | 38 | // configuration 39 | if (typeof conf == 'string') { conf = {navi: conf}; } 40 | conf = $.extend({}, t.navigator.conf, conf); 41 | 42 | var ret; 43 | 44 | this.each(function() { 45 | 46 | var api = $(this).data("scrollable"), 47 | navi = find(api.getRoot(), conf.navi), 48 | buttons = api.getNaviButtons(), 49 | cls = conf.activeClass, 50 | history = conf.history && $.fn.history; 51 | 52 | // @deprecated stuff 53 | if (api) { ret = api; } 54 | 55 | api.getNaviButtons = function() { 56 | return buttons.add(navi); 57 | }; 58 | 59 | 60 | function doClick(el, i, e) { 61 | api.seekTo(i); 62 | if (history) { 63 | if (location.hash) { 64 | location.hash = el.attr("href").replace("#", ""); 65 | } 66 | } else { 67 | return e.preventDefault(); 68 | } 69 | } 70 | 71 | function els() { 72 | return navi.find(conf.naviItem || '> *'); 73 | } 74 | 75 | function addItem(i) { 76 | 77 | var item = $("<" + (conf.naviItem || 'a') + "/>").click(function(e) { 78 | doClick($(this), i, e); 79 | 80 | }).attr("href", "#" + i); 81 | 82 | // index number / id attribute 83 | if (i === 0) { item.addClass(cls); } 84 | if (conf.indexed) { item.text(i + 1); } 85 | if (conf.idPrefix) { item.attr("id", conf.idPrefix + i); } 86 | 87 | return item.appendTo(navi); 88 | } 89 | 90 | 91 | // generate navigator 92 | if (els().length) { 93 | els().each(function(i) { 94 | $(this).click(function(e) { 95 | doClick($(this), i, e); 96 | }); 97 | }); 98 | 99 | } else { 100 | $.each(api.getItems(), function(i) { 101 | addItem(i); 102 | }); 103 | } 104 | 105 | // activate correct entry 106 | api.onBeforeSeek(function(e, index) { 107 | setTimeout(function() { 108 | if (!e.isDefaultPrevented()) { 109 | var el = els().eq(index); 110 | if (!e.isDefaultPrevented() && el.length) { 111 | els().removeClass(cls).eq(index).addClass(cls); 112 | } 113 | } 114 | }, 1); 115 | }); 116 | 117 | function doHistory(evt, hash) { 118 | var el = els().eq(hash.replace("#", "")); 119 | if (!el.length) { 120 | el = els().filter("[href=" + hash + "]"); 121 | } 122 | el.click(); 123 | } 124 | 125 | // new item being added 126 | api.onAddItem(function(e, item) { 127 | item = addItem(api.getItems().index(item)); 128 | if (history) { item.history(doHistory); } 129 | }); 130 | 131 | if (history) { els().history(doHistory); } 132 | 133 | }); 134 | 135 | return conf.api ? ret : this; 136 | 137 | }; 138 | 139 | })(jQuery); 140 | -------------------------------------------------------------------------------- /src/overlay/overlay.apple.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * jQuery Tools @VERSION / Overlay Apple effect. 4 | * 5 | * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE. 6 | * 7 | * http://flowplayer.org/tools/overlay/apple.html 8 | * 9 | * Since: July 2009 10 | * Date: @DATE 11 | */ 12 | (function($) { 13 | 14 | // version number 15 | var t = $.tools.overlay, 16 | w = $(window); 17 | 18 | // extend global configuragion with effect specific defaults 19 | $.extend(t.conf, { 20 | start: { 21 | top: null, 22 | left: null 23 | }, 24 | 25 | fadeInSpeed: 'fast', 26 | zIndex: 9999 27 | }); 28 | 29 | // utility function 30 | function getPosition(el) { 31 | var p = el.offset(); 32 | return { 33 | top: p.top + el.height() / 2, 34 | left: p.left + el.width() / 2 35 | }; 36 | } 37 | 38 | //{{{ load 39 | 40 | var loadEffect = function(pos, onLoad) { 41 | 42 | var overlay = this.getOverlay(), 43 | conf = this.getConf(), 44 | trigger = this.getTrigger(), 45 | self = this, 46 | oWidth = overlay.outerWidth({margin:true}), 47 | img = overlay.data("img"); 48 | 49 | 50 | // growing image is required. 51 | if (!img) { 52 | var bg = overlay.css("backgroundImage"); 53 | 54 | if (!bg) { 55 | throw "background-image CSS property not set for overlay"; 56 | } 57 | 58 | // url("bg.jpg") --> bg.jpg 59 | bg = bg.slice(bg.indexOf("(") + 1, bg.indexOf(")")).replace(/\"/g, ""); 60 | overlay.css("backgroundImage", "none"); 61 | 62 | img = $('Click here to download latest version
" : 235 | "Download latest version from here
"); 236 | 237 | if (root.tagName == 'A') { 238 | root.onclick = function() { 239 | location.href = URL; 240 | }; 241 | } 242 | } 243 | 244 | // onFail 245 | if (opts.onFail) { 246 | var ret = opts.onFail.call(this); 247 | if (typeof ret == 'string') { root.innerHTML = ret; } 248 | } 249 | } 250 | 251 | // http://flowplayer.org/forum/8/18186#post-18593 252 | if (IE) { 253 | window[opts.id] = document.getElementById(opts.id); 254 | } 255 | 256 | // API methods for callback 257 | extend(this, { 258 | 259 | getRoot: function() { 260 | return root; 261 | }, 262 | 263 | getOptions: function() { 264 | return opts; 265 | }, 266 | 267 | 268 | getConf: function() { 269 | return conf; 270 | }, 271 | 272 | getApi: function() { 273 | return root.firstChild; 274 | } 275 | 276 | }); 277 | } 278 | 279 | // setup jquery support 280 | if (JQUERY) { 281 | 282 | // tools version number 283 | jQuery.tools = jQuery.tools || {version: '@VERSION'}; 284 | 285 | jQuery.tools.flashembed = { 286 | conf: GLOBAL_OPTS 287 | }; 288 | 289 | jQuery.fn.flashembed = function(opts, conf) { 290 | return this.each(function() { 291 | $(this).data("flashembed", flashembed(this, opts, conf)); 292 | }); 293 | }; 294 | } 295 | 296 | })(); 297 | 298 | -------------------------------------------------------------------------------- /src/tooltip/tooltip.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * jQuery Tools @VERSION Tooltip - UI essentials 4 | * 5 | * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE. 6 | * 7 | * http://flowplayer.org/tools/tooltip/ 8 | * 9 | * Since: November 2008 10 | * Date: @DATE 11 | */ 12 | (function($) { 13 | 14 | /* 15 | removed: oneInstance, lazy, 16 | tip must next to the trigger 17 | isShown(fully), layout, tipClass, layout 18 | */ 19 | 20 | // static constructs 21 | $.tools = $.tools || {version: '@VERSION'}; 22 | 23 | $.tools.tooltip = { 24 | 25 | conf: { 26 | 27 | // default effect variables 28 | effect: 'toggle', 29 | fadeOutSpeed: "fast", 30 | predelay: 0, 31 | delay: 30, 32 | opacity: 1, 33 | tip: 0, 34 | 35 | // 'top', 'bottom', 'right', 'left', 'center' 36 | position: ['top', 'center'], 37 | offset: [0, 0], 38 | relative: false, 39 | cancelDefault: true, 40 | 41 | // type to event mapping 42 | events: { 43 | def: "mouseenter,mouseleave", 44 | input: "focus,blur", 45 | widget: "focus mouseenter,blur mouseleave", 46 | tooltip: "mouseenter,mouseleave" 47 | }, 48 | 49 | // 1.2 50 | layout: '', 51 | tipClass: 'tooltip' 52 | }, 53 | 54 | addEffect: function(name, loadFn, hideFn) { 55 | effects[name] = [loadFn, hideFn]; 56 | } 57 | }; 58 | 59 | 60 | var effects = { 61 | toggle: [ 62 | function(done) { 63 | var conf = this.getConf(), tip = this.getTip(), o = conf.opacity; 64 | if (o < 1) { tip.css({opacity: o}); } 65 | tip.show(); 66 | done.call(); 67 | }, 68 | 69 | function(done) { 70 | this.getTip().hide(); 71 | done.call(); 72 | } 73 | ], 74 | 75 | fade: [ 76 | function(done) { 77 | var conf = this.getConf(); 78 | this.getTip().fadeTo(conf.fadeInSpeed, conf.opacity, done); 79 | }, 80 | function(done) { 81 | this.getTip().fadeOut(this.getConf().fadeOutSpeed, done); 82 | } 83 | ] 84 | }; 85 | 86 | 87 | /* calculate tip position relative to the trigger */ 88 | function getPosition(trigger, tip, conf) { 89 | 90 | 91 | // get origin top/left position 92 | var top = conf.relative ? trigger.position().top : trigger.offset().top, 93 | left = conf.relative ? trigger.position().left : trigger.offset().left, 94 | pos = conf.position[0]; 95 | 96 | top -= tip.outerHeight() - conf.offset[0]; 97 | left += trigger.outerWidth() + conf.offset[1]; 98 | 99 | // adjust Y 100 | var height = tip.outerHeight() + trigger.outerHeight(); 101 | if (pos == 'center') { top += height / 2; } 102 | if (pos == 'bottom') { top += height; } 103 | 104 | // adjust X 105 | pos = conf.position[1]; 106 | var width = tip.outerWidth() + trigger.outerWidth(); 107 | if (pos == 'center') { left -= width / 2; } 108 | if (pos == 'left') { left -= width; } 109 | 110 | return {top: top, left: left}; 111 | } 112 | 113 | 114 | 115 | function Tooltip(trigger, conf) { 116 | 117 | var self = this, 118 | fire = trigger.add(self), 119 | tip, 120 | timer = 0, 121 | pretimer = 0, 122 | title = trigger.attr("title"), 123 | effect = effects[conf.effect], 124 | shown, 125 | 126 | // get show/hide configuration 127 | isInput = trigger.is(":input"), 128 | isWidget = isInput && trigger.is(":checkbox, :radio, select, :button, :submit"), 129 | type = trigger.attr("type"), 130 | evt = conf.events[type] || conf.events[isInput ? (isWidget ? 'widget' : 'input') : 'def']; 131 | 132 | 133 | // check that configuration is sane 134 | if (!effect) { throw "Nonexistent effect \"" + conf.effect + "\""; } 135 | 136 | evt = evt.split(/,\s*/); 137 | if (evt.length != 2) { throw "Tooltip: bad events configuration for " + type; } 138 | 139 | 140 | // trigger --> show 141 | trigger.bind(evt[0], function(e) { 142 | clearTimeout(timer); 143 | if (conf.predelay) { 144 | pretimer = setTimeout(function() { self.show(e); }, conf.predelay); 145 | 146 | } else { 147 | self.show(e); 148 | } 149 | 150 | // trigger --> hide 151 | }).bind(evt[1], function(e) { 152 | clearTimeout(pretimer); 153 | if (conf.delay) { 154 | timer = setTimeout(function() { self.hide(e); }, conf.delay); 155 | 156 | } else { 157 | self.hide(e); 158 | } 159 | 160 | }); 161 | 162 | 163 | // remove default title 164 | if (title && conf.cancelDefault) { 165 | trigger.removeAttr("title"); 166 | trigger.data("title", title); 167 | } 168 | 169 | $.extend(self, { 170 | 171 | show: function(e) { 172 | 173 | // tip not initialized yet 174 | if (!tip) { 175 | 176 | // autogenerated tooltip 177 | if (title) { 178 | tip = $(conf.layout).addClass(conf.tipClass).appendTo(document.body) 179 | .hide().append(title); 180 | 181 | // single tip element for all 182 | } else if (conf.tip) { 183 | tip = $(conf.tip).eq(0); 184 | 185 | // manual tooltip 186 | } else { 187 | tip = trigger.next(); 188 | if (!tip.length) { tip = trigger.parent().next(); } 189 | } 190 | 191 | if (!tip.length) { throw "Cannot find tooltip for " + trigger; } 192 | } 193 | 194 | if (self.isShown()) { return self; } 195 | 196 | // stop previous animation 197 | tip.stop(true, true); 198 | 199 | // get position 200 | var pos = getPosition(trigger, tip, conf); 201 | 202 | 203 | // onBeforeShow 204 | e = e || $.Event(); 205 | e.type = "onBeforeShow"; 206 | fire.trigger(e, [pos]); 207 | if (e.isDefaultPrevented()) { return self; } 208 | 209 | 210 | // onBeforeShow may have altered the configuration 211 | pos = getPosition(trigger, tip, conf); 212 | 213 | // set position 214 | tip.css({position:'absolute', top: pos.top, left: pos.left}); 215 | 216 | shown = true; 217 | 218 | // invoke effect 219 | effect[0].call(self, function() { 220 | e.type = "onShow"; 221 | shown = 'full'; 222 | fire.trigger(e); 223 | }); 224 | 225 | 226 | // tooltip events 227 | var event = conf.events.tooltip.split(/,\s*/); 228 | 229 | tip.bind(event[0], function() { 230 | clearTimeout(timer); 231 | clearTimeout(pretimer); 232 | }); 233 | 234 | if (event[1] && !trigger.is("input:not(:checkbox, :radio), textarea")) { 235 | tip.bind(event[1], function(e) { 236 | 237 | // being moved to the trigger element 238 | if (e.relatedTarget != trigger[0]) { 239 | trigger.trigger(evt[1].split(" ")[0]); 240 | } 241 | }); 242 | } 243 | 244 | return self; 245 | }, 246 | 247 | hide: function(e) { 248 | 249 | if (!tip || !self.isShown()) { return self; } 250 | 251 | // onBeforeHide 252 | e = e || $.Event(); 253 | e.type = "onBeforeHide"; 254 | fire.trigger(e); 255 | if (e.isDefaultPrevented()) { return; } 256 | 257 | shown = false; 258 | 259 | effects[conf.effect][1].call(self, function() { 260 | e.type = "onHide"; 261 | shown = false; 262 | fire.trigger(e); 263 | }); 264 | 265 | return self; 266 | }, 267 | 268 | isShown: function(fully) { 269 | return fully ? shown == 'full' : shown; 270 | }, 271 | 272 | getConf: function() { 273 | return conf; 274 | }, 275 | 276 | getTip: function() { 277 | return tip; 278 | }, 279 | 280 | getTrigger: function() { 281 | return trigger; 282 | } 283 | 284 | }); 285 | 286 | // callbacks 287 | $.each("onHide,onBeforeShow,onShow,onBeforeHide".split(","), function(i, name) { 288 | 289 | // configuration 290 | if ($.isFunction(conf[name])) { 291 | $(self).bind(name, conf[name]); 292 | } 293 | 294 | // API 295 | self[name] = function(fn) { 296 | $(self).bind(name, fn); 297 | return self; 298 | }; 299 | }); 300 | 301 | } 302 | 303 | 304 | // jQuery plugin implementation 305 | $.fn.tooltip = function(conf) { 306 | 307 | // return existing instance 308 | var api = this.data("tooltip"); 309 | if (api) { return api; } 310 | 311 | conf = $.extend(true, {}, $.tools.tooltip.conf, conf); 312 | 313 | // position can also be given as string 314 | if (typeof conf.position == 'string') { 315 | conf.position = conf.position.split(/,?\s/); 316 | } 317 | 318 | // install tooltip for each entry in jQuery object 319 | this.each(function() { 320 | api = new Tooltip($(this), conf); 321 | $(this).data("tooltip", api); 322 | }); 323 | 324 | return conf.api ? api: this; 325 | }; 326 | 327 | }) (jQuery); 328 | 329 | 330 | 331 | -------------------------------------------------------------------------------- /src/rangeinput/rangeinput.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * jQuery Tools @VERSION Rangeinput - HTML5 for humans 4 | * 5 | * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE. 6 | * 7 | * http://flowplayer.org/tools/rangeinput/ 8 | * 9 | * Since: Mar 2010 10 | * Date: @DATE 11 | */ 12 | (function($) { 13 | 14 | $.tools = $.tools || {version: '@VERSION'}; 15 | 16 | var tool; 17 | 18 | tool = $.tools.rangeinput = { 19 | 20 | conf: { 21 | min: 0, 22 | max: 100, // as defined in the standard 23 | step: 'any', // granularity of the value. a non-zero float or int (or "any") 24 | steps: 0, 25 | value: 0, 26 | precision: undefined, 27 | vertical: 0, 28 | keyboard: true, 29 | progress: false, 30 | speed: 100, 31 | 32 | // set to null if not needed 33 | css: { 34 | input: 'range', 35 | slider: 'slider', 36 | progress: 'progress', 37 | handle: 'handle' 38 | } 39 | 40 | } 41 | }; 42 | 43 | //{{{ fn.drag 44 | 45 | /* 46 | FULL featured drag and drop. 0.7 kb minified, 0.3 gzipped. done. 47 | Who told d'n'd is rocket science? Usage: 48 | 49 | $(".myelement").drag({y: false}).bind("drag", function(event, x, y) { 50 | // do your custom thing 51 | }); 52 | 53 | Configuration: 54 | x: true, // enable horizontal drag 55 | y: true, // enable vertical drag 56 | drag: true // true = perform drag, false = only fire events 57 | 58 | Events: dragStart, drag, dragEnd. 59 | */ 60 | var doc, draggable; 61 | 62 | $.fn.drag = function(conf) { 63 | 64 | // disable IE specialities 65 | document.ondragstart = function () { return false; }; 66 | 67 | conf = $.extend({x: true, y: true, drag: true}, conf); 68 | 69 | doc = doc || $(document).bind("mousedown mouseup", function(e) { 70 | 71 | var el = $(e.target); 72 | 73 | // start 74 | if (e.type == "mousedown" && el.data("drag")) { 75 | 76 | var offset = el.position(), 77 | x0 = e.pageX - offset.left, 78 | y0 = e.pageY - offset.top, 79 | start = true; 80 | 81 | doc.bind("mousemove.drag", function(e) { 82 | var x = e.pageX -x0, 83 | y = e.pageY -y0, 84 | props = {}; 85 | 86 | if (conf.x) { props.left = x; } 87 | if (conf.y) { props.top = y; } 88 | 89 | if (start) { 90 | el.trigger("dragStart"); 91 | start = false; 92 | } 93 | if (conf.drag) { el.css(props); } 94 | el.trigger("drag", [y, x]); 95 | draggable = el; 96 | }); 97 | 98 | e.preventDefault(); 99 | 100 | } else { 101 | 102 | try { 103 | if (draggable) { 104 | draggable.trigger("dragEnd"); 105 | } 106 | } finally { 107 | doc.unbind("mousemove.drag"); 108 | draggable = null; 109 | } 110 | } 111 | 112 | }); 113 | 114 | return this.data("drag", true); 115 | }; 116 | 117 | //}}} 118 | 119 | 120 | 121 | function round(value, precision) { 122 | var n = Math.pow(10, precision); 123 | return Math.round(value * n) / n; 124 | } 125 | 126 | // get hidden element's width or height even though it's hidden 127 | function dim(el, key) { 128 | var v = parseInt(el.css(key), 10); 129 | if (v) { return v; } 130 | var s = el[0].currentStyle; 131 | return s && s.width && parseInt(s.width, 10); 132 | } 133 | 134 | function hasEvent(el) { 135 | var e = el.data("events"); 136 | return e && e.onSlide; 137 | } 138 | 139 | function RangeInput(input, conf) { 140 | 141 | // private variables 142 | var self = this, 143 | css = conf.css, 144 | root = $("").data("rangeinput", self), 145 | vertical, 146 | value, // current value 147 | origo, // handle's start point 148 | len, // length of the range 149 | pos; // current position of the handle 150 | 151 | // create range 152 | input.before(root); 153 | 154 | var handle = root.addClass(css.slider).find("a").addClass(css.handle), 155 | progress = root.find("div").addClass(css.progress); 156 | 157 | // get (HTML5) attributes into configuration 158 | $.each("min,max,step,value".split(","), function(i, key) { 159 | var val = input.attr(key); 160 | if (parseFloat(val)) { 161 | conf[key] = parseFloat(val, 10); 162 | } 163 | }); 164 | 165 | var range = conf.max - conf.min, 166 | step = conf.step == 'any' ? 0 : conf.step, 167 | precision = conf.precision; 168 | 169 | if (precision === undefined) { 170 | try { 171 | precision = step.toString().split(".")[1].length; 172 | } catch (err) { 173 | precision = 0; 174 | } 175 | } 176 | 177 | // Replace built-in range input (type attribute cannot be changed) 178 | if (input.attr("type") == 'range') { 179 | var tmp = $(""); 180 | $.each("name,readonly,disabled,required".split(","), function(i, attr) { 181 | tmp.attr(attr, input.attr(attr)); 182 | }); 183 | tmp.val(conf.value); 184 | input.replaceWith(tmp); 185 | input = tmp; 186 | } 187 | 188 | input.addClass(css.input); 189 | 190 | var fire = $(self).add(input), fireOnSlide = true; 191 | 192 | 193 | /** 194 | The flesh and bone of this tool. All sliding is routed trough this. 195 | 196 | @param evt types include: click, keydown, blur and api (setValue call) 197 | @param isSetValue when called trough setValue() call (keydown, blur, api) 198 | 199 | vertical configuration gives additional complexity. 200 | */ 201 | function slide(evt, x, val, isSetValue) { 202 | 203 | // calculate value based on slide position 204 | if (val === undefined) { 205 | val = x / len * range; 206 | 207 | // x is calculated based on val. we need to strip off min during calculation 208 | } else if (isSetValue) { 209 | val -= conf.min; 210 | } 211 | 212 | // increment in steps 213 | if (step) { 214 | val = Math.round(val / step) * step; 215 | } 216 | 217 | // count x based on value or tweak x if stepping is done 218 | if (x === undefined || step) { 219 | x = val * len / range; 220 | } 221 | 222 | // crazy value? 223 | if (isNaN(val)) { return self; } 224 | 225 | // stay within range 226 | x = Math.max(0, Math.min(x, len)); 227 | val = x / len * range; 228 | 229 | if (isSetValue || !vertical) { 230 | val += conf.min; 231 | } 232 | 233 | // in vertical ranges value rises upwards 234 | if (vertical) { 235 | if (isSetValue) { 236 | x = len -x; 237 | } else { 238 | val = conf.max - val; 239 | } 240 | } 241 | 242 | // precision 243 | val = round(val, precision); 244 | 245 | // onSlide 246 | var isClick = evt.type == "click"; 247 | if (fireOnSlide && value !== undefined && !isClick) { 248 | evt.type = "onSlide"; 249 | fire.trigger(evt, [val, x]); 250 | if (evt.isDefaultPrevented()) { return self; } 251 | } 252 | 253 | // speed & callback 254 | var speed = isClick ? conf.speed : 0, 255 | callback = isClick ? function() { 256 | evt.type = "change"; 257 | fire.trigger(evt, [val]); 258 | } : null; 259 | 260 | if (vertical) { 261 | handle.animate({top: x}, speed, callback); 262 | if (conf.progress) { 263 | progress.animate({height: len - x + handle.width() / 2}, speed); 264 | } 265 | 266 | } else { 267 | handle.animate({left: x}, speed, callback); 268 | if (conf.progress) { 269 | progress.animate({width: x + handle.width() / 2}, speed); 270 | } 271 | } 272 | 273 | // store current value 274 | value = val; 275 | pos = x; 276 | 277 | // se input field's value 278 | input.val(val); 279 | 280 | return self; 281 | } 282 | 283 | 284 | $.extend(self, { 285 | 286 | getValue: function() { 287 | return value; 288 | }, 289 | 290 | setValue: function(val, e) { 291 | return slide(e || $.Event("api"), undefined, val, true); 292 | }, 293 | 294 | getConf: function() { 295 | return conf; 296 | }, 297 | 298 | getProgress: function() { 299 | return progress; 300 | }, 301 | 302 | getHandle: function() { 303 | return handle; 304 | }, 305 | 306 | getInput: function() { 307 | return input; 308 | }, 309 | 310 | step: function(am, e) { 311 | e = e || $.Event(); 312 | var step = conf.step == 'any' ? 1 : conf.step; 313 | self.setValue(value + step * (am || 1), e); 314 | }, 315 | 316 | // HTML5 compatible name 317 | stepUp: function(am) { 318 | return self.step(am || 1); 319 | }, 320 | 321 | // HTML5 compatible name 322 | stepDown: function(am) { 323 | return self.step(-am || -1); 324 | } 325 | 326 | }); 327 | 328 | // callbacks 329 | $.each("onSlide,change".split(","), function(i, name) { 330 | 331 | // from configuration 332 | if ($.isFunction(conf[name])) { 333 | $(self).bind(name, conf[name]); 334 | } 335 | 336 | // API methods 337 | self[name] = function(fn) { 338 | $(self).bind(name, fn); 339 | return self; 340 | }; 341 | }); 342 | 343 | 344 | // dragging 345 | handle.drag({drag: false}).bind("dragStart", function() { 346 | 347 | /* do some pre- calculations for seek() function. improves performance */ 348 | 349 | // avoid redundant event triggering (= heavy stuff) 350 | fireOnSlide = hasEvent($(self)) || hasEvent(input); 351 | 352 | 353 | }).bind("drag", function(e, y, x) { 354 | 355 | if (input.is(":disabled")) { return false; } 356 | slide(e, vertical ? y : x); 357 | 358 | }).bind("dragEnd", function(e) { 359 | if (!e.isDefaultPrevented()) { 360 | e.type = "change"; 361 | fire.trigger(e, [value]); 362 | } 363 | 364 | }).click(function(e) { 365 | return e.preventDefault(); 366 | }); 367 | 368 | // clicking 369 | root.click(function(e) { 370 | if (input.is(":disabled") || e.target == handle[0]) { 371 | return e.preventDefault(); 372 | } 373 | 374 | init(); 375 | var fix = handle.width() / 2; 376 | slide(e, vertical ? len-origo-fix + e.pageY : e.pageX -origo -fix); 377 | }); 378 | 379 | if (conf.keyboard) { 380 | 381 | input.keydown(function(e) { 382 | 383 | if (input.attr("readonly")) { return; } 384 | 385 | var key = e.keyCode, 386 | up = $([75, 76, 38, 33, 39]).index(key) != -1, 387 | down = $([74, 72, 40, 34, 37]).index(key) != -1; 388 | 389 | if ((up || down) && !(e.shiftKey || e.altKey || e.ctrlKey)) { 390 | 391 | // UP: k=75, l=76, up=38, pageup=33, right=39 392 | if (up) { 393 | self.step(key == 33 ? 10 : 1, e); 394 | 395 | // DOWN: j=74, h=72, down=40, pagedown=34, left=37 396 | } else if (down) { 397 | self.step(key == 34 ? -10 : -1, e); 398 | } 399 | return e.preventDefault(); 400 | } 401 | }); 402 | } 403 | 404 | 405 | input.blur(function(e) { 406 | var val = $(this).val(); 407 | if (val !== value) { 408 | self.setValue(val, e); 409 | } 410 | }); 411 | 412 | 413 | // HTML5 DOM methods 414 | $.extend(input[0], { stepUp: self.stepUp, stepDown: self.stepDown}); 415 | 416 | 417 | // calculate all dimension related stuff 418 | function init() { 419 | vertical = conf.vertical || dim(root, "height") > dim(root, "width"); 420 | 421 | if (vertical) { 422 | len = dim(root, "height") - dim(handle, "height"); 423 | origo = root.offset().top + len; 424 | 425 | } else { 426 | len = dim(root, "width") - dim(handle, "width"); 427 | origo = root.offset().left; 428 | } 429 | } 430 | 431 | function begin() { 432 | init(); 433 | self.setValue(conf.value || conf.min); 434 | } 435 | begin(); 436 | 437 | // some browsers cannot get dimensions upon initialization 438 | if (!len) { 439 | $(window).load(begin); 440 | } 441 | } 442 | 443 | $.expr[':'].range = function(el) { 444 | var type = el.getAttribute("type"); 445 | return type && type == 'range' || !!$(el).filter("input").data("rangeinput"); 446 | }; 447 | 448 | 449 | // jQuery plugin implementation 450 | $.fn.rangeinput = function(conf) { 451 | 452 | // already installed 453 | if (this.data("rangeinput")) { return this; } 454 | 455 | // extend configuration with globals 456 | conf = $.extend(true, {}, tool.conf, conf); 457 | 458 | var els; 459 | 460 | this.each(function() { 461 | var el = new RangeInput($(this), $.extend(true, {}, conf)); 462 | var input = el.getInput().data("rangeinput", el); 463 | els = els ? els.add(input) : input; 464 | }); 465 | 466 | return els ? els : this; 467 | }; 468 | 469 | 470 | }) (jQuery); 471 | 472 | -------------------------------------------------------------------------------- /src/validator/validator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * jQuery Tools Validator @VERSION - HTML5 is here. Now use it. 4 | * 5 | * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE. 6 | * 7 | * http://flowplayer.org/tools/form/validator/ 8 | * 9 | * Since: Mar 2010 10 | * Date: @DATE 11 | */ 12 | /*jslint evil: true */ 13 | (function($) { 14 | 15 | $.tools = $.tools || {version: '@VERSION'}; 16 | 17 | // globals 18 | var typeRe = /\[type=([a-z]+)\]/, 19 | numRe = /^-?[0-9]*(\.[0-9]+)?$/, 20 | 21 | // http://net.tutsplus.com/tutorials/other/8-regular-expressions-you-should-know/ 22 | emailRe = /^([a-z0-9_\.\-\+]+)@([\da-z\.\-]+)\.([a-z\.]{2,6})$/i, 23 | urlRe = /^(https?:\/\/)?([\da-z\.\-]+)\.([a-z\.]{2,6})([\/\w \.\-]*)*\/?$/i, 24 | v; 25 | 26 | v = $.tools.validator = { 27 | 28 | conf: { 29 | grouped: false, // show all error messages at once inside the container 30 | effect: 'default', // show/hide effect for error message. only 'default' is built-in 31 | errorClass: 'invalid', // input field class name in case of validation error 32 | 33 | // when to check for validity? 34 | inputEvent: null, // change, blur, keyup, null 35 | errorInputEvent: 'keyup', // change, blur, keyup, null 36 | formEvent: 'submit', // submit, null 37 | 38 | lang: 'en', // default language for error messages 39 | message: '', 40 | messageAttr: 'data-message', // name of the attribute for overridden error message 41 | messageClass: 'error', // error message element's class name 42 | offset: [0, 0], 43 | position: 'center right', 44 | singleError: false, // validate all inputs at once 45 | speed: 'normal' // message's fade-in speed 46 | }, 47 | 48 | 49 | /* The Error Messages */ 50 | messages: { 51 | "*": { en: "Please correct this value" } 52 | }, 53 | 54 | localize: function(lang, messages) { 55 | $.each(messages, function(key, msg) { 56 | v.messages[key] = v.messages[key] || {}; 57 | v.messages[key][lang] = msg; 58 | }); 59 | }, 60 | 61 | localizeFn: function(key, messages) { 62 | v.messages[key] = v.messages[key] || {}; 63 | $.extend(v.messages[key], messages); 64 | }, 65 | 66 | /** 67 | * Adds a new validator 68 | */ 69 | fn: function(matcher, msg, fn) { 70 | 71 | // no message supplied 72 | if ($.isFunction(msg)) { 73 | fn = msg; 74 | 75 | // message(s) on second argument 76 | } else { 77 | if (typeof msg == 'string') { msg = {en: msg}; } 78 | this.messages[matcher.key || matcher] = msg; 79 | } 80 | 81 | // check for "[type=xxx]" (not supported by jQuery) 82 | var test = typeRe.exec(matcher); 83 | if (test) { matcher = isType(test[1]); } 84 | 85 | // add validator to the arsenal 86 | fns.push([matcher, fn]); 87 | }, 88 | 89 | /* Add new show/hide effect */ 90 | addEffect: function(name, showFn, closeFn) { 91 | effects[name] = [showFn, closeFn]; 92 | } 93 | 94 | }; 95 | 96 | /* calculate error message position relative to the input */ 97 | function getPosition(trigger, el, conf) { 98 | 99 | // get origin top/left position 100 | var top = trigger.offset().top, 101 | left = trigger.offset().left, 102 | pos = conf.position.split(/,?\s+/), 103 | y = pos[0], 104 | x = pos[1]; 105 | 106 | top -= el.outerHeight() - conf.offset[0]; 107 | left += trigger.outerWidth() + conf.offset[1]; 108 | 109 | // adjust Y 110 | var height = el.outerHeight() + trigger.outerHeight(); 111 | if (y == 'center') { top += height / 2; } 112 | if (y == 'bottom') { top += height; } 113 | 114 | // adjust X 115 | var width = trigger.outerWidth(); 116 | if (x == 'center') { left -= (width + el.outerWidth()) / 2; } 117 | if (x == 'left') { left -= width; } 118 | 119 | return {top: top, left: left}; 120 | } 121 | 122 | 123 | 124 | // $.is("[type=xxx]") or $.filter("[type=xxx]") not working in jQuery 1.3.2 or 1.4.2 125 | function isType(type) { 126 | function fn() { 127 | return this.getAttribute("type") == type; 128 | } 129 | fn.key = "[type=" + type + "]"; 130 | return fn; 131 | } 132 | 133 | 134 | var fns = [], effects = { 135 | 136 | 'default' : [ 137 | 138 | // show errors function 139 | function(errs) { 140 | 141 | var conf = this.getConf(); 142 | 143 | // loop errors 144 | $.each(errs, function(i, err) { 145 | 146 | // add error class 147 | var input = err.input; 148 | input.addClass(conf.errorClass); 149 | 150 | // get handle to the error container 151 | var msg = input.data("msg.el"); 152 | 153 | // create it if not present 154 | if (!msg) { 155 | msg = $(conf.message).addClass(conf.messageClass).appendTo(document.body); 156 | input.data("msg.el", msg); 157 | } 158 | 159 | // clear the container 160 | msg.css({visibility: 'hidden'}).find("span").remove(); 161 | 162 | // populate messages 163 | $.each(err.messages, function(i, m) { 164 | $("").html(m).appendTo(msg); 165 | }); 166 | 167 | // make sure the width is sane (not the body's width) 168 | if (msg.outerWidth() == msg.parent().width()) { 169 | msg.add(msg.find("p")).css({display: 'inline'}); 170 | } 171 | 172 | // insert into correct position (relative to the field) 173 | var pos = getPosition(input, msg, conf); 174 | 175 | msg.css({ visibility: 'visible', position: 'absolute', top: pos.top, left: pos.left }) 176 | .fadeIn(conf.speed); 177 | }); 178 | 179 | 180 | // hide errors function 181 | }, function(inputs) { 182 | 183 | var conf = this.getConf(); 184 | inputs.removeClass(conf.errorClass).each(function() { 185 | var msg = $(this).data("msg.el"); 186 | if (msg) { msg.css({visibility: 'hidden'}); } 187 | }); 188 | } 189 | ] 190 | }; 191 | 192 | 193 | /* sperial selectors */ 194 | $.each("email,url,number".split(","), function(i, key) { 195 | $.expr[':'][key] = function(el) { 196 | return el.getAttribute("type") === key; 197 | }; 198 | }); 199 | 200 | 201 | /* 202 | oninvalid() jQuery plugin. 203 | Usage: $("input:eq(2)").oninvalid(function() { ... }); 204 | */ 205 | $.fn.oninvalid = function( fn ){ 206 | return this[fn ? "bind" : "trigger"]("OI", fn); 207 | }; 208 | 209 | 210 | /******* built-in HTML5 standard validators *********/ 211 | 212 | v.fn(":email", "Please enter a valid email address", function(el, v) { 213 | return !v || emailRe.test(v); 214 | }); 215 | 216 | v.fn(":url", "Please enter a valid URL", function(el, v) { 217 | return !v || urlRe.test(v); 218 | }); 219 | 220 | v.fn(":number", "Please enter a numeric value.", function(el, v) { 221 | return numRe.test(v); 222 | }); 223 | 224 | v.fn("[max]", "Please enter a value smaller than $1", function(el, v) { 225 | 226 | // skip dateinputs 227 | if ($.tools.dateinput && el.is(":date")) { return true; } 228 | 229 | var max = el.attr("max"); 230 | return parseFloat(v) <= parseFloat(max) ? true : [max]; 231 | }); 232 | 233 | v.fn("[min]", "Please enter a value larger than $1", function(el, v) { 234 | 235 | // skip dateinputs 236 | if ($.tools.dateinput && el.is(":date")) { return true; } 237 | 238 | var min = el.attr("min"); 239 | return parseFloat(v) >= parseFloat(min) ? true : [min]; 240 | }); 241 | 242 | v.fn("[required]", "Please complete this mandatory field.", function(el, v) { 243 | if (el.is(":checkbox")) { return el.is(":checked"); } 244 | return !!v; 245 | }); 246 | 247 | v.fn("[pattern]", function(el) { 248 | var p = new RegExp("^" + el.attr("pattern") + "$"); 249 | return p.test(el.val()); 250 | }); 251 | 252 | 253 | function Validator(inputs, form, conf) { 254 | 255 | // private variables 256 | var self = this, 257 | fire = form.add(self); 258 | 259 | // make sure there are input fields available 260 | inputs = inputs.not(":button, :image, :reset, :submit"); 261 | 262 | // utility function 263 | function pushMessage(to, matcher, returnValue) { 264 | 265 | // only one message allowed 266 | if (!conf.grouped && to.length) { return; } 267 | 268 | // the error message 269 | var msg; 270 | 271 | // substitutions are returned 272 | if (returnValue === false || $.isArray(returnValue)) { 273 | msg = v.messages[matcher.key || matcher] || v.messages["*"]; 274 | msg = msg[conf.lang] || v.messages["*"].en; 275 | 276 | // substitution 277 | var matches = msg.match(/\$\d/g); 278 | 279 | if (matches && $.isArray(returnValue)) { 280 | $.each(matches, function(i) { 281 | msg = msg.replace(this, returnValue[i]); 282 | }); 283 | } 284 | 285 | // error message is returned directly 286 | } else { 287 | msg = returnValue[conf.lang] || returnValue; 288 | } 289 | 290 | to.push(msg); 291 | } 292 | 293 | 294 | // API methods 295 | $.extend(self, { 296 | 297 | getConf: function() { 298 | return conf; 299 | }, 300 | 301 | getForm: function() { 302 | return form; 303 | }, 304 | 305 | getInputs: function() { 306 | return inputs; 307 | }, 308 | 309 | /* @param e - for internal use only */ 310 | invalidate: function(errs, e) { 311 | 312 | // errors are given manually: { fieldName1: 'message1', fieldName2: 'message2' } 313 | if (!e) { 314 | var errors = []; 315 | $.each(errs, function(key, val) { 316 | var input = inputs.filter("[name=" + key + "]"); 317 | if (input.length) { 318 | 319 | // trigger HTML5 ininvalid event 320 | input.trigger("OI", [val]); 321 | 322 | errors.push({ input: input, messages: [val]}); 323 | } 324 | }); 325 | 326 | errs = errors; 327 | e = $.Event(); 328 | } 329 | 330 | // onFail callback 331 | e.type = "onFail"; 332 | fire.trigger(e, [errs]); 333 | 334 | // call the effect 335 | if (!e.isDefaultPrevented()) { 336 | effects[conf.effect][0].call(self, errs, e); 337 | } 338 | 339 | return self; 340 | }, 341 | 342 | reset: function(els) { 343 | els = els || inputs; 344 | els.removeClass(conf.errorClass).each(function() { 345 | var msg = $(this).data("msg.el"); 346 | if (msg) { 347 | msg.remove(); 348 | $(this).data("msg.el", null); 349 | } 350 | }).unbind(conf.errorInputEvent || ''); 351 | return self; 352 | }, 353 | 354 | destroy: function() { 355 | form.unbind(conf.formEvent).unbind("reset.V"); 356 | inputs.unbind(conf.inputEvent || '').unbind("change.V"); 357 | return self.reset(); 358 | }, 359 | 360 | 361 | //{{{ checkValidity() - flesh and bone of this tool 362 | 363 | /* @returns boolean */ 364 | checkValidity: function(els, e) { 365 | 366 | els = els || inputs; 367 | els = els.not(":disabled"); 368 | if (!els.length) { return true; } 369 | 370 | e = e || $.Event(); 371 | 372 | // onBeforeValidate 373 | e.type = "onBeforeValidate"; 374 | fire.trigger(e, [els]); 375 | if (e.isDefaultPrevented()) { return e.result; } 376 | 377 | var errs = [], 378 | event = conf.errorInputEvent + ".v"; 379 | 380 | // loop trough the inputs 381 | els.each(function() { 382 | 383 | // field and it's error message container 384 | var msgs = [], 385 | el = $(this).unbind(event).data("messages", msgs); 386 | 387 | // loop all validator functions 388 | $.each(fns, function() { 389 | var fn = this, match = fn[0]; 390 | 391 | // match found 392 | if (el.filter(match).length) { 393 | 394 | // execute a validator function 395 | var returnValue = fn[1].call(self, el, el.val()); 396 | 397 | 398 | // validation failed. multiple substitutions can be returned with an array 399 | if (returnValue !== true) { 400 | 401 | // onBeforeFail 402 | e.type = "onBeforeFail"; 403 | fire.trigger(e, [el, match]); 404 | if (e.isDefaultPrevented()) { return false; } 405 | 406 | // overridden custom message 407 | var msg = el.attr(conf.messageAttr); 408 | if (msg) { 409 | msgs = [msg]; 410 | return false; 411 | } else { 412 | pushMessage(msgs, match, returnValue); 413 | } 414 | } 415 | } 416 | }); 417 | 418 | if (msgs.length) { 419 | 420 | errs.push({input: el, messages: msgs}); 421 | 422 | // trigger HTML5 ininvalid event 423 | el.trigger("OI", [msgs]); 424 | 425 | // begin validating upon error event type (such as keyup) 426 | if (conf.errorInputEvent) { 427 | el.bind(event, function(e) { 428 | self.checkValidity(el, e); 429 | }); 430 | } 431 | } 432 | 433 | if (conf.singleError && errs.length) { return false; } 434 | 435 | }); 436 | 437 | 438 | // validation done. now check that we have a proper effect at hand 439 | var eff = effects[conf.effect]; 440 | if (!eff) { throw "Validator: cannot find effect \"" + conf.effect + "\""; } 441 | 442 | // errors found 443 | if (errs.length) { 444 | self.invalidate(errs, e); 445 | return false; 446 | 447 | // no errors 448 | } else { 449 | 450 | // call the effect 451 | eff[1].call(self, els, e); 452 | 453 | // onSuccess callback 454 | e.type = "onSuccess"; 455 | fire.trigger(e, [els]); 456 | 457 | els.unbind(event); 458 | } 459 | 460 | return true; 461 | } 462 | //}}} 463 | 464 | }); 465 | 466 | // callbacks 467 | $.each("onBeforeValidate,onBeforeFail,onFail,onSuccess".split(","), function(i, name) { 468 | 469 | // configuration 470 | if ($.isFunction(conf[name])) { 471 | $(self).bind(name, conf[name]); 472 | } 473 | 474 | // API methods 475 | self[name] = function(fn) { 476 | $(self).bind(name, fn); 477 | return self; 478 | }; 479 | }); 480 | 481 | 482 | // form validation 483 | if (conf.formEvent) { 484 | form.bind(conf.formEvent, function(e) { 485 | if (!self.checkValidity(null, e)) { 486 | return e.preventDefault(); 487 | } 488 | }); 489 | } 490 | 491 | // form reset 492 | form.bind("reset.V", function() { 493 | self.reset(); 494 | }); 495 | 496 | // disable browser's default validation mechanism 497 | if (inputs[0] && inputs[0].validity) { 498 | inputs.each(function() { 499 | this.oninvalid = function() { 500 | return false; 501 | }; 502 | }); 503 | } 504 | 505 | // Web Forms 2.0 compatibility 506 | if (form[0]) { 507 | form[0].checkValidity = self.checkValidity; 508 | } 509 | 510 | // input validation 511 | if (conf.inputEvent) { 512 | inputs.bind(conf.inputEvent, function(e) { 513 | self.checkValidity($(this), e); 514 | }); 515 | } 516 | 517 | inputs.filter(":checkbox, select").filter("[required]").bind("change.V", function(e) { 518 | var el = $(this); 519 | if (this.checked || (el.is("select") && $(this).val())) { 520 | effects[conf.effect][1].call(self, el, e); 521 | } 522 | }); 523 | 524 | } 525 | 526 | 527 | // jQuery plugin initialization 528 | $.fn.validator = function(conf) { 529 | 530 | var instance = this.data("validator"); 531 | 532 | // destroy existing instance 533 | if (instance) { 534 | instance.destroy(); 535 | this.removeData("validator"); 536 | } 537 | 538 | // configuration 539 | conf = $.extend(true, {}, v.conf, conf); 540 | 541 | // selector is a form 542 | if (this.is("form")) { 543 | return this.each(function() { 544 | var form = $(this); 545 | instance = new Validator(form.find(":input"), form, conf); 546 | form.data("validator", instance); 547 | }); 548 | 549 | } else { 550 | instance = new Validator(this, this.eq(0).closest("form"), conf); 551 | return this.data("validator", instance); 552 | } 553 | 554 | }; 555 | 556 | })(jQuery); 557 | 558 | 559 | -------------------------------------------------------------------------------- /src/dateinput/dateinput.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * jQuery Tools @VERSION Dateinput - for humans 4 | * 5 | * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE. 6 | * 7 | * http://flowplayer.org/tools/form/dateinput/ 8 | * 9 | * Since: Mar 2010 10 | * Date: @DATE 11 | */ 12 | (function($) { 13 | 14 | /* TODO: 15 | preserve today highlighted 16 | */ 17 | 18 | $.tools = $.tools || {version: '@VERSION'}; 19 | 20 | var instances = [], 21 | tool, 22 | 23 | // h=72, j=74, k=75, l=76, down=40, left=37, up=38, right=39 24 | KEYS = [75, 76, 38, 39, 74, 72, 40, 37], 25 | LABELS = {}; 26 | 27 | tool = $.tools.dateinput = { 28 | 29 | conf: { 30 | format: 'mm/dd/yy', 31 | selectors: false, 32 | yearRange: [-5, 5], 33 | lang: 'en', 34 | offset: [0, 0], 35 | speed: 0, 36 | firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... 37 | min: 0, 38 | max: 0, 39 | trigger: false, 40 | 41 | css: { 42 | 43 | prefix: 'cal', 44 | input: 'date', 45 | 46 | // ids 47 | root: 0, 48 | head: 0, 49 | title: 0, 50 | prev: 0, 51 | next: 0, 52 | month: 0, 53 | year: 0, 54 | days: 0, 55 | 56 | body: 0, 57 | weeks: 0, 58 | today: 0, 59 | current: 0, 60 | 61 | // classnames 62 | week: 0, 63 | off: 0, 64 | sunday: 0, 65 | focus: 0, 66 | disabled: 0, 67 | trigger: 0 68 | } 69 | }, 70 | 71 | localize: function(language, labels) { 72 | $.each(labels, function(key, val) { 73 | labels[key] = val.split(","); 74 | }); 75 | LABELS[language] = labels; 76 | } 77 | 78 | }; 79 | 80 | tool.localize("en", { 81 | months: 'January,February,March,April,May,June,July,August,September,October,November,December', 82 | shortMonths: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec', 83 | days: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday', 84 | shortDays: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat' 85 | }); 86 | 87 | 88 | //{{{ private functions 89 | 90 | 91 | // @return amount of days in certain month 92 | function dayAm(year, month) { 93 | return 32 - new Date(year, month, 32).getDate(); 94 | } 95 | 96 | function zeropad(val, len) { 97 | val = '' + val; 98 | len = len || 2; 99 | while (val.length < len) { val = "0" + val; } 100 | return val; 101 | } 102 | 103 | // thanks: http://stevenlevithan.com/assets/misc/date.format.js 104 | var Re = /d{1,4}|m{1,4}|yy(?:yy)?|"[^"]*"|'[^']*'/g, tmpTag = $(""); 105 | 106 | function format(date, fmt, lang) { 107 | 108 | var d = date.getDate(), 109 | D = date.getDay(), 110 | m = date.getMonth(), 111 | y = date.getFullYear(), 112 | 113 | flags = { 114 | d: d, 115 | dd: zeropad(d), 116 | ddd: LABELS[lang].shortDays[D], 117 | dddd: LABELS[lang].days[D], 118 | m: m + 1, 119 | mm: zeropad(m + 1), 120 | mmm: LABELS[lang].shortMonths[m], 121 | mmmm: LABELS[lang].months[m], 122 | yy: String(y).slice(2), 123 | yyyy: y 124 | }; 125 | 126 | var ret = fmt.replace(Re, function ($0) { 127 | return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1); 128 | }); 129 | 130 | // a small trick to handle special characters 131 | return tmpTag.html(ret).html(); 132 | 133 | } 134 | 135 | function integer(val) { 136 | return parseInt(val, 10); 137 | } 138 | 139 | function isSameDay(d1, d2) { 140 | return d1.getFullYear() === d2.getFullYear() && 141 | d1.getMonth() == d2.getMonth() && 142 | d1.getDate() == d2.getDate(); 143 | } 144 | 145 | function parseDate(val) { 146 | 147 | if (!val) { return; } 148 | if (val.constructor == Date) { return val; } 149 | 150 | if (typeof val == 'string') { 151 | 152 | // rfc3339? 153 | var els = val.split("-"); 154 | if (els.length == 3) { 155 | return new Date(integer(els[0]), integer(els[1]) -1, integer(els[2])); 156 | } 157 | 158 | // invalid offset 159 | if (!/^-?\d+$/.test(val)) { return; } 160 | 161 | // convert to integer 162 | val = integer(val); 163 | } 164 | 165 | var date = new Date(); 166 | date.setDate(date.getDate() + val); 167 | return date; 168 | } 169 | 170 | //}}} 171 | 172 | 173 | function Dateinput(input, conf) { 174 | 175 | // variables 176 | var self = this, 177 | now = new Date(), 178 | css = conf.css, 179 | labels = LABELS[conf.lang], 180 | root = $("#" + css.root), 181 | title = root.find("#" + css.title), 182 | trigger, 183 | pm, nm, 184 | currYear, currMonth, currDay, 185 | value = input.attr("data-value") || conf.value || input.val(), 186 | min = input.attr("min") || conf.min, 187 | max = input.attr("max") || conf.max, 188 | opened; 189 | 190 | // make sure value, min & max has values 191 | value = parseDate(value) || now; 192 | min = parseDate(min || conf.yearRange[0] * 365); 193 | max = parseDate(max || conf.yearRange[1] * 365); 194 | 195 | 196 | // check that language exists 197 | if (!labels) { throw "Dateinput: invalid language: " + conf.lang; } 198 | 199 | // Replace built-in date input: NOTE: input.attr("type", "text") throws exception by the browser 200 | if (input.attr("type") == 'date') { 201 | var tmp = $(""); 202 | $.each("name,readonly,disabled,value,required".split(","), function(i, attr) { 203 | tmp.attr(attr, input.attr(attr)); 204 | }); 205 | input.replaceWith(tmp); 206 | input = tmp; 207 | } 208 | input.addClass(css.input); 209 | 210 | var fire = input.add(self); 211 | 212 | // construct layout 213 | if (!root.length) { 214 | 215 | // root 216 | root = $('') 217 | .hide().css({position: 'absolute'}).attr("id", css.root); 218 | 219 | // elements 220 | root.children() 221 | .eq(0).attr("id", css.head).end() 222 | .eq(1).attr("id", css.body).children() 223 | .eq(0).attr("id", css.days).end() 224 | .eq(1).attr("id", css.weeks).end().end().end() 225 | .find("a").eq(0).attr("id", css.prev).end().eq(1).attr("id", css.next); 226 | 227 | // title 228 | title = root.find("#" + css.head).find("div").attr("id", css.title); 229 | 230 | // year & month selectors 231 | if (conf.selectors) { 232 | var monthSelector = $("").attr("id", css.month), 233 | yearSelector = $("").attr("id", css.year); 234 | title.append(monthSelector.add(yearSelector)); 235 | } 236 | 237 | // day titles 238 | var days = root.find("#" + css.days); 239 | 240 | // days of the week 241 | for (var d = 0; d < 7; d++) { 242 | days.append($("").text(labels.shortDays[(d + conf.firstDay) % 7])); 243 | } 244 | 245 | input.after(root); 246 | } 247 | 248 | 249 | // trigger icon 250 | if (conf.trigger) { 251 | trigger = $("").attr("href", "#").addClass(css.trigger).click(function(e) { 252 | self.show(); 253 | return e.preventDefault(); 254 | }).insertAfter(input); 255 | } 256 | 257 | 258 | // layout elements 259 | var weeks = root.find("#" + css.weeks); 260 | yearSelector = root.find("#" + css.year); 261 | monthSelector = root.find("#" + css.month); 262 | 263 | 264 | //{{{ pick 265 | 266 | function select(date, conf, e) { 267 | 268 | // current value 269 | value = date; 270 | currYear = date.getFullYear(); 271 | currMonth = date.getMonth(); 272 | currDay = date.getDate(); 273 | 274 | 275 | // change 276 | e = e || $.Event("api"); 277 | e.type = "change"; 278 | 279 | fire.trigger(e, [date]); 280 | if (e.isDefaultPrevented()) { return; } 281 | 282 | // formatting 283 | input.val(format(date, conf.format, conf.lang)); 284 | 285 | // store value into input 286 | input.data("date", date); 287 | 288 | self.hide(e); 289 | } 290 | //}}} 291 | 292 | 293 | //{{{ onShow 294 | 295 | function onShow(ev) { 296 | 297 | ev.type = "onShow"; 298 | fire.trigger(ev); 299 | 300 | $(document).bind("keydown.d", function(e) { 301 | 302 | var key = e.keyCode; 303 | 304 | // backspace clears the value 305 | if (key == 8) { 306 | input.val(""); 307 | return self.hide(e); 308 | } 309 | 310 | // esc key 311 | if (key == 27) { return self.hide(e); } 312 | 313 | if ($(KEYS).index(key) >= 0) { 314 | 315 | if (!opened) { 316 | self.show(e); 317 | return e.preventDefault(); 318 | } 319 | 320 | var days = $("#" + css.weeks + " a"), 321 | el = $("." + css.focus), 322 | index = days.index(el); 323 | 324 | el.removeClass(css.focus); 325 | 326 | if (key == 74 || key == 40) { index += 7; } 327 | else if (key == 75 || key == 38) { index -= 7; } 328 | else if (key == 76 || key == 39) { index += 1; } 329 | else if (key == 72 || key == 37) { index -= 1; } 330 | 331 | 332 | if (index == -1) { 333 | self.addMonth(-1); 334 | el = $("#" + css.weeks + " a:last"); 335 | 336 | } else if (index == 35) { 337 | self.addMonth(); 338 | el = $("#" + css.weeks + " a:first"); 339 | } else { 340 | el = days.eq(index); 341 | } 342 | 343 | el.addClass(css.focus); 344 | return e.preventDefault(); 345 | 346 | } 347 | 348 | // pageUp / pageDown 349 | if (key == 34) { return self.addMonth(); } 350 | if (key == 33) { return self.addMonth(-1); } 351 | 352 | // home 353 | if (key == 36) { return self.today(); } 354 | 355 | // enter 356 | if (key == 13) { 357 | if (!$(e.target).is("select")) { 358 | $("." + css.focus).click(); 359 | } 360 | } 361 | 362 | return $([16, 17, 18, 9]).index(key) >= 0; 363 | }); 364 | 365 | 366 | // click outside dateinput 367 | $(document).bind("click.d", function(e) { 368 | var el = e.target; 369 | if (!$(el).parents("#" + css.root).length && el != input[0] && (!trigger || el != trigger[0])) { 370 | self.hide(e); 371 | } 372 | }); 373 | } 374 | //}}} 375 | 376 | 377 | $.extend(self, { 378 | 379 | //{{{ show 380 | 381 | show: function(e) { 382 | 383 | if (input.is("[readonly]") || opened) { return; } 384 | 385 | // onBeforeShow 386 | e = e || $.Event(); 387 | e.type = "onBeforeShow"; 388 | fire.trigger(e); 389 | if (e.isDefaultPrevented()) { return; } 390 | 391 | $.each(instances, function() { 392 | this.hide(); 393 | }); 394 | 395 | opened = true; 396 | 397 | // month selector 398 | monthSelector.unbind("change").change(function() { 399 | self.setValue(yearSelector.val(), $(this).val()); 400 | }); 401 | 402 | // year selector 403 | yearSelector.unbind("change").change(function() { 404 | self.setValue($(this).val(), monthSelector.val()); 405 | }); 406 | 407 | // prev / next month 408 | pm = root.find("#" + css.prev).unbind("click").click(function(e) { 409 | if (!pm.hasClass(css.disabled)) { 410 | self.addMonth(-1); 411 | } 412 | return false; 413 | }); 414 | 415 | nm = root.find("#" + css.next).unbind("click").click(function(e) { 416 | if (!nm.hasClass(css.disabled)) { 417 | self.addMonth(); 418 | } 419 | return false; 420 | }); 421 | 422 | // set date 423 | self.setValue(value); 424 | 425 | // show calendar 426 | var pos = input.position(); 427 | 428 | root.css({ 429 | top: pos.top + input.outerHeight({margins: true}) + conf.offset[0], 430 | left: pos.left + conf.offset[1] 431 | }); 432 | 433 | if (conf.speed) { 434 | root.show(conf.speed, function() { 435 | onShow(e); 436 | }); 437 | } else { 438 | root.show(); 439 | onShow(e); 440 | } 441 | 442 | return self; 443 | }, 444 | //}}} 445 | 446 | 447 | //{{{ setValue 448 | 449 | setValue: function(year, month, day) { 450 | 451 | 452 | var date; 453 | 454 | if (parseInt(month, 10) >= -1) { 455 | // strings to numbers 456 | year = integer(year); 457 | month = integer(month); 458 | day = integer(day); 459 | date = new Date(year, month, day); 460 | 461 | } else { 462 | date = year || value; 463 | year = date.getFullYear(); 464 | month = date.getMonth(); 465 | day = date.getDate(); 466 | } 467 | 468 | 469 | // roll year & month 470 | if (month == -1) { 471 | month = 11; 472 | year--; 473 | } else if (month == 12) { 474 | month = 0; 475 | year++; 476 | } 477 | 478 | if (!opened) { 479 | select(date, conf); 480 | return self; 481 | } 482 | 483 | currMonth = month; 484 | currYear = year; 485 | 486 | // variables 487 | var tmp = new Date(year, month, 1 - conf.firstDay), begin = tmp.getDay(), 488 | days = dayAm(year, month), 489 | prevDays = dayAm(year, month - 1), 490 | week; 491 | 492 | // selectors 493 | if (conf.selectors) { 494 | 495 | // month selector 496 | monthSelector.empty(); 497 | $.each(labels.months, function(i, m) { 498 | if (min < new Date(year, i + 1, -1) && max > new Date(year, i, 0)) { 499 | monthSelector.append($("").html(m).attr("value", i)); 500 | } 501 | }); 502 | 503 | // year selector 504 | yearSelector.empty(); 505 | for (var i = year + conf.yearRange[0]; i < year + conf.yearRange[1]; i++) { 506 | if (min < new Date(i + 1, -1, 0) && max > new Date(i, 0, 0)) { 507 | yearSelector.append($("").text(i)); 508 | } 509 | } 510 | 511 | monthSelector.val(month); 512 | yearSelector.val(year); 513 | 514 | // title 515 | } else { 516 | title.html(labels.months[month] + " " + year); 517 | } 518 | 519 | // populate weeks 520 | weeks.empty(); 521 | pm.add(nm).removeClass(css.disabled); 522 | 523 | for (var j = 0, a, num; j < 42; j++) { 524 | 525 | a = $(""); 526 | 527 | if (j % 7 === 0) { 528 | week = $("").addClass(css.week); 529 | weeks.append(week); 530 | } 531 | 532 | if (j < begin) { 533 | a.addClass(css.off); 534 | num = prevDays - begin + j + 1; 535 | date = new Date(year, month-1, num); 536 | 537 | } else if (j >= begin + days) { 538 | a.addClass(css.off); 539 | num = j - days - begin + 1; 540 | date = new Date(year, month+1, num); 541 | 542 | } else { 543 | num = j - begin + 1; 544 | date = new Date(year, month, num); 545 | 546 | // current date 547 | if (isSameDay(value, date)) { 548 | a.attr("id", css.current).addClass(css.focus); 549 | 550 | // today 551 | } else if (isSameDay(now, date)) { 552 | a.attr("id", css.today); 553 | } 554 | } 555 | 556 | // disabled 557 | if (min && date < min) { 558 | a.add(pm).addClass(css.disabled); 559 | } 560 | 561 | if (max && date > max) { 562 | a.add(nm).addClass(css.disabled); 563 | } 564 | 565 | a.attr("href", "#" + num).text(num).data("date", date); 566 | 567 | week.append(a); 568 | 569 | // date picking 570 | a.click(function(e) { 571 | var el = $(this); 572 | if (!el.hasClass(css.disabled)) { 573 | $("#" + css.current).removeAttr("id"); 574 | el.attr("id", css.current); 575 | select(el.data("date"), conf, e); 576 | } 577 | return false; 578 | }); 579 | } 580 | 581 | // sunday 582 | if (css.sunday) { 583 | weeks.find(css.week).each(function() { 584 | var beg = conf.firstDay ? 7 - conf.firstDay : 0; 585 | $(this).children().slice(beg, beg + 1).addClass(css.sunday); 586 | }); 587 | } 588 | 589 | return self; 590 | }, 591 | //}}} 592 | 593 | setMin: function(val, fit) { 594 | min = parseDate(val); 595 | if (fit && value < min) { self.setValue(min); } 596 | return self; 597 | }, 598 | 599 | setMax: function(val, fit) { 600 | max = parseDate(val); 601 | if (fit && value > max) { self.setValue(max); } 602 | return self; 603 | }, 604 | 605 | today: function() { 606 | return self.setValue(now); 607 | }, 608 | 609 | addDay: function(amount) { 610 | return this.setValue(currYear, currMonth, currDay + (amount || 1)); 611 | }, 612 | 613 | addMonth: function(amount) { 614 | return this.setValue(currYear, currMonth + (amount || 1), currDay); 615 | }, 616 | 617 | addYear: function(amount) { 618 | return this.setValue(currYear + (amount || 1), currMonth, currDay); 619 | }, 620 | 621 | hide: function(e) { 622 | 623 | if (opened) { 624 | 625 | // onHide 626 | e = e || $.Event(); 627 | e.type = "onHide"; 628 | fire.trigger(e); 629 | 630 | $(document).unbind("click.d").unbind("keydown.d"); 631 | 632 | // cancelled ? 633 | if (e.isDefaultPrevented()) { return; } 634 | 635 | // do the hide 636 | root.hide(); 637 | opened = false; 638 | } 639 | 640 | return self; 641 | }, 642 | 643 | getConf: function() { 644 | return conf; 645 | }, 646 | 647 | getInput: function() { 648 | return input; 649 | }, 650 | 651 | getCalendar: function() { 652 | return root; 653 | }, 654 | 655 | getValue: function(dateFormat) { 656 | return dateFormat ? format(value, dateFormat, conf.lang) : value; 657 | }, 658 | 659 | isOpen: function() { 660 | return opened; 661 | } 662 | 663 | }); 664 | 665 | // callbacks 666 | $.each(['onBeforeShow','onShow','change','onHide'], function(i, name) { 667 | 668 | // configuration 669 | if ($.isFunction(conf[name])) { 670 | $(self).bind(name, conf[name]); 671 | } 672 | 673 | // API methods 674 | self[name] = function(fn) { 675 | $(self).bind(name, fn); 676 | return self; 677 | }; 678 | }); 679 | 680 | 681 | // show dateinput & assign keyboard shortcuts 682 | input.bind("focus click", self.show).keydown(function(e) { 683 | 684 | var key = e.keyCode; 685 | 686 | // open dateinput with navigation keyw 687 | if (!opened && $(KEYS).index(key) >= 0) { 688 | self.show(e); 689 | return e.preventDefault(); 690 | } 691 | 692 | // allow tab 693 | return e.shiftKey || e.ctrlKey || e.altKey || key == 9 ? true : e.preventDefault(); 694 | 695 | }); 696 | 697 | // initial value 698 | 699 | if (parseDate(input.val())) { 700 | select(value, conf); 701 | } 702 | 703 | } 704 | 705 | $.expr[':'].date = function(el) { 706 | var type = el.getAttribute("type"); 707 | return type && type == 'date' || !!$(el).data("dateinput"); 708 | }; 709 | 710 | 711 | $.fn.dateinput = function(conf) { 712 | 713 | // already instantiated 714 | if (this.data("dateinput")) { return this; } 715 | 716 | // configuration 717 | conf = $.extend(true, {}, tool.conf, conf); 718 | 719 | // CSS prefix 720 | $.each(conf.css, function(key, val) { 721 | if (!val && key != 'prefix') { 722 | conf.css[key] = (conf.css.prefix || '') + (val || key); 723 | } 724 | }); 725 | 726 | var els; 727 | 728 | this.each(function() { 729 | var el = new Dateinput($(this), conf); 730 | instances.push(el); 731 | var input = el.getInput().data("dateinput", el); 732 | els = els ? els.add(input) : input; 733 | }); 734 | 735 | return els ? els : this; 736 | }; 737 | 738 | 739 | }) (jQuery); 740 | 741 | 742 | --------------------------------------------------------------------------------