├── .gitignore ├── Gruntfile.js ├── MIT-LICENSE.txt ├── README.md ├── example ├── css │ ├── prism.css │ └── style.css ├── fonts │ ├── proximanova-light-webfont.eot │ ├── proximanova-light-webfont.svg │ ├── proximanova-light-webfont.ttf │ ├── proximanova-light-webfont.woff │ ├── proximanova-regular-webfont.eot │ ├── proximanova-regular-webfont.svg │ ├── proximanova-regular-webfont.ttf │ └── proximanova-regular-webfont.woff ├── img │ └── gray_jean.png ├── index.html ├── less │ ├── buttons.less │ ├── elements.less │ ├── fonts.less │ ├── forms.less │ ├── reset.less │ └── style.less └── lib │ ├── jquery-ui │ ├── css │ │ └── ui-lightness │ │ │ ├── images │ │ │ ├── animated-overlay.gif │ │ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png │ │ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png │ │ │ ├── ui-bg_flat_10_000000_40x100.png │ │ │ ├── ui-bg_glass_100_f6f6f6_1x400.png │ │ │ ├── ui-bg_glass_100_fdf5ce_1x400.png │ │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png │ │ │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png │ │ │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png │ │ │ ├── ui-icons_222222_256x240.png │ │ │ ├── ui-icons_228ef1_256x240.png │ │ │ ├── ui-icons_ef8c08_256x240.png │ │ │ ├── ui-icons_ffd27a_256x240.png │ │ │ └── ui-icons_ffffff_256x240.png │ │ │ ├── jquery-ui-1.10.2.custom.css │ │ │ └── jquery-ui-1.10.2.custom.min.css │ └── js │ │ └── jquery-ui-1.10.2.custom.min.js │ ├── jquery.min.js │ ├── less.js │ └── prism.js ├── jquery.timeAutocomplete.min.js ├── package.json ├── src ├── formatters │ ├── 24hr.js │ ├── ampm.js │ └── french.js └── jquery.timeAutocomplete.js ├── tests ├── index.html ├── lib │ ├── jasmine-1.3.1 │ │ ├── MIT.LICENSE │ │ ├── jasmine-html.js │ │ ├── jasmine.css │ │ └── jasmine.js │ └── jasmine-affix.js └── spec │ ├── formatters │ ├── 24hr.spec.js │ ├── ampm.spec.js │ └── french.spec.js │ └── timeAutocomplete.spec.js └── timeAutocomplete.jquery.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | node_modules -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt) { 4 | 5 | grunt.initConfig({ 6 | uglify: { 7 | build: { 8 | files: { 9 | 'jquery.timeAutocomplete.min.js': [ 10 | 'src/jquery.timeAutocomplete.js', 11 | 'src/formatters/ampm.js', 12 | 'src/formatters/24hr.js', 13 | 'src/formatters/french.js' 14 | ] 15 | } 16 | } 17 | } 18 | }); 19 | 20 | grunt.loadNpmTasks('grunt-contrib-uglify'); 21 | grunt.registerTask('default', ['uglify']); 22 | 23 | }; -------------------------------------------------------------------------------- /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2013 7shifts Online Employee Scheduling, 2 | http://www.7shifts.com 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jQuery timeAutocomplete Plugin 2 | 3 | ### What is this? 4 | 5 | It's a time picker similar to how Google Calendar's time picker works for events. It's meant to be smart, sexy and intuitive. 6 | 7 | Some things that make is super duper fantastic: 8 | 9 | * Start time defaults to users current time (within your set increment). 10 | * Tabbing out of the field without selecting a time will cause it to make an educated guess. Try typing a badly formatted time like 115 or 1 or 1pm or 28 then tabbing out. 11 | * If the end time is less than the start time, evaluate it to the opposite am/pm of the start time. Example: 7:00AM - 5... 5 will default to PM. 12 | * Fetch time in H:i:s format (13:30:00) for comparing/validating. Done so by calling $(input).data('timeAutocomplete').getTime() 13 | * Uses placeholder attribute if detected, if not, it uses our own placeholder text. 14 | * Oh, and it's tested :) - see tests/index.html to run tests 15 | 16 | ### Basic Usage 17 | ``` 18 | $('#basic-example').timeAutocomplete(); 19 | ``` 20 | 21 | ### Advanced usage #1 22 | 23 | Injecting an existing value and using 24hr as the formatter. 24 | 25 | ``` 26 | $('#from-24hr').timeAutocomplete({ 27 | formatter: '24hr', 28 | value: '07:00:00' 29 | }); 30 | ``` 31 | or 32 | ``` 33 | $('#to-24hr').val('09:30:00').timeAutocomplete({ 34 | formatter: '24hr' 35 | }); 36 | ``` 37 | 38 | ### More documentation and examples 39 | * http://7shifts.com/blog/better-time-drop-downs-for-scheduling-jquery-timeautocomplete/ 40 | 41 | ### Contributing 42 | * Run ```npm install``` to install dependencies (requires NodeJS). 43 | * Make changes to any of the .js files 44 | * Run ```grunt``` from the project root to compile 45 | * Commit and submit pull request -------------------------------------------------------------------------------- /example/css/prism.css: -------------------------------------------------------------------------------- 1 | /** 2 | * prism.js default theme for JavaScript, CSS and HTML 3 | * Based on dabblet (http://dabblet.com) 4 | * @author Lea Verou 5 | */ 6 | 7 | code[class*="language-"], 8 | pre[class*="language-"] { 9 | color: black; 10 | text-shadow: 0 1px white; 11 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 12 | direction: ltr; 13 | text-align: left; 14 | white-space: pre; 15 | word-spacing: normal; 16 | 17 | -moz-tab-size: 4; 18 | -o-tab-size: 4; 19 | tab-size: 4; 20 | 21 | -webkit-hyphens: none; 22 | -moz-hyphens: none; 23 | -ms-hyphens: none; 24 | hyphens: none; 25 | } 26 | 27 | @media print { 28 | code[class*="language-"], 29 | pre[class*="language-"] { 30 | text-shadow: none; 31 | } 32 | } 33 | 34 | /* Code blocks */ 35 | pre[class*="language-"] { 36 | padding: 1em; 37 | margin: .5em 0; 38 | overflow: auto; 39 | } 40 | 41 | :not(pre) > code[class*="language-"], 42 | pre[class*="language-"] { 43 | background: #f5f2f0; 44 | } 45 | 46 | /* Inline code */ 47 | :not(pre) > code[class*="language-"] { 48 | padding: .1em; 49 | border-radius: .3em; 50 | } 51 | 52 | .token.comment, 53 | .token.prolog, 54 | .token.doctype, 55 | .token.cdata { 56 | color: slategray; 57 | } 58 | 59 | .token.punctuation { 60 | color: #999; 61 | } 62 | 63 | .namespace { 64 | opacity: .7; 65 | } 66 | 67 | .token.property, 68 | .token.tag, 69 | .token.boolean, 70 | .token.number { 71 | color: #905; 72 | } 73 | 74 | .token.selector, 75 | .token.attr-name, 76 | .token.string { 77 | color: #690; 78 | } 79 | 80 | .token.operator, 81 | .token.entity, 82 | .token.url, 83 | .language-css .token.string, 84 | .style .token.string { 85 | color: #a67f59; 86 | background: hsla(0,0%,100%,.5); 87 | } 88 | 89 | .token.atrule, 90 | .token.attr-value, 91 | .token.keyword { 92 | color: #07a; 93 | } 94 | 95 | 96 | .token.regex, 97 | .token.important { 98 | color: #e90; 99 | } 100 | 101 | .token.important { 102 | font-weight: bold; 103 | } 104 | 105 | .token.entity { 106 | cursor: help; 107 | } -------------------------------------------------------------------------------- /example/css/style.css: -------------------------------------------------------------------------------- 1 | .clear { 2 | clear: both; 3 | } 4 | .clearfix:after { 5 | content: "."; 6 | display: block; 7 | clear: both; 8 | visibility: hidden; 9 | line-height: 0; 10 | height: 0; 11 | } 12 | .clearfix { 13 | display: inline-block; 14 | } 15 | html[xmlns] .clearfix { 16 | display: block; 17 | } 18 | * html .clearfix { 19 | height: 1%; 20 | } 21 | article, 22 | aside, 23 | details, 24 | figcaption, 25 | figure, 26 | footer, 27 | header, 28 | hgroup, 29 | nav, 30 | section { 31 | display: block; 32 | } 33 | table { 34 | width: 100%; 35 | font-size: 13px; 36 | } 37 | table thead th { 38 | background: #fff; 39 | border-bottom: 1px solid #ccc; 40 | } 41 | table th, 42 | table td { 43 | padding: 5px; 44 | } 45 | table tr td { 46 | border: 1px solid #ccc; 47 | } 48 | audio, 49 | canvas, 50 | video { 51 | display: inline-block; 52 | *display: inline; 53 | *zoom: 1; 54 | } 55 | audio:not([controls]) { 56 | display: none; 57 | } 58 | html { 59 | font-size: 100%; 60 | -webkit-text-size-adjust: 100%; 61 | -ms-text-size-adjust: 100%; 62 | } 63 | a:hover, 64 | a:active { 65 | outline: 0; 66 | } 67 | sub, 68 | sup { 69 | position: relative; 70 | font-size: 75%; 71 | line-height: 0; 72 | vertical-align: baseline; 73 | } 74 | sup { 75 | top: -0.5em; 76 | } 77 | sub { 78 | bottom: -0.25em; 79 | } 80 | img { 81 | /* Responsive images (ensure images don't scale beyond their parents) */ 82 | 83 | max-width: 100%; 84 | /* Part 1: Set a maxium relative to the parent */ 85 | 86 | width: auto\9; 87 | /* IE7-8 need help adjusting responsive images */ 88 | 89 | height: auto; 90 | /* Part 2: Scale the height according to the width, otherwise you get stretching */ 91 | 92 | vertical-align: middle; 93 | border: 0; 94 | -ms-interpolation-mode: bicubic; 95 | } 96 | #map_canvas img, 97 | .google-maps img { 98 | max-width: none; 99 | } 100 | button, 101 | input, 102 | select, 103 | textarea { 104 | margin: 0; 105 | font-size: 100%; 106 | vertical-align: middle; 107 | } 108 | button, 109 | input { 110 | *overflow: visible; 111 | line-height: normal; 112 | } 113 | button::-moz-focus-inner, 114 | input::-moz-focus-inner { 115 | padding: 0; 116 | border: 0; 117 | } 118 | button, 119 | html input[type="button"], 120 | input[type="reset"], 121 | input[type="submit"] { 122 | -webkit-appearance: button; 123 | cursor: pointer; 124 | } 125 | label, 126 | select, 127 | button, 128 | input[type="button"], 129 | input[type="reset"], 130 | input[type="submit"], 131 | input[type="radio"], 132 | input[type="checkbox"] { 133 | cursor: pointer; 134 | } 135 | input[type="search"] { 136 | -webkit-appearance: textfield; 137 | } 138 | input[type="search"]::-webkit-search-decoration, 139 | input[type="search"]::-webkit-search-cancel-button { 140 | -webkit-appearance: none; 141 | } 142 | textarea { 143 | overflow: auto; 144 | vertical-align: top; 145 | } 146 | @media print { 147 | * { 148 | text-shadow: none !important; 149 | color: #000 !important; 150 | background: transparent !important; 151 | box-shadow: none !important; 152 | } 153 | a, 154 | a:visited { 155 | text-decoration: underline; 156 | } 157 | a[href]:after { 158 | content: " (" attr(href) ")"; 159 | } 160 | abbr[title]:after { 161 | content: " (" attr(title) ")"; 162 | } 163 | .ir a:after, 164 | a[href^="javascript:"]:after, 165 | a[href^="#"]:after { 166 | content: ""; 167 | } 168 | pre, 169 | blockquote { 170 | border: 1px solid #999; 171 | page-break-inside: avoid; 172 | } 173 | thead { 174 | display: table-header-group; 175 | } 176 | tr, 177 | img { 178 | page-break-inside: avoid; 179 | } 180 | img { 181 | max-width: 100% !important; 182 | } 183 | @page { 184 | margin: 0.5cm; 185 | } 186 | p, 187 | h2, 188 | h3 { 189 | orphans: 3; 190 | widows: 3; 191 | } 192 | h2, 193 | h3 { 194 | page-break-after: avoid; 195 | } 196 | } 197 | /*--------------------------------------------------- 198 | LESS Elements 0.9 199 | --------------------------------------------------- 200 | A set of useful LESS mixins 201 | More info at: http://lesselements.com 202 | ---------------------------------------------------*/ 203 | /* This file was created to be share between the main site and marketing pages (restaurants.php, coffee.php etc) */ 204 | @font-face { 205 | font-family: 'ProximaNovaLight'; 206 | src: url('../fonts/proximanova-light-webfont.eot'); 207 | src: url('../fonts/proximanova-light-webfont.eot') format('embedded-opentype'), url('../fonts/proximanova-light-webfont.woff') format('woff'), url('../fonts/proximanova-light-webfont.ttf') format('truetype'), url('../fonts/proximanova-light-webfont.svg#proxima_novalight') format('svg'); 208 | font-weight: normal; 209 | font-style: normal; 210 | } 211 | @font-face { 212 | font-family: 'ProximaNovaRegular'; 213 | src: url('../fonts/proximanova-regular-webfont.eot'); 214 | src: url('../fonts/proximanova-regular-webfont.eot') format('embedded-opentype'), url('../fonts/proximanova-regular-webfont.woff') format('woff'), url('../proximanova-regular-webfont.ttf') format('truetype'), url('../proximanova-regular-webfont.svg#proxima_nova_rgregular') format('svg'); 215 | font-weight: normal; 216 | font-style: normal; 217 | } 218 | input[type="text"], 219 | button { 220 | margin: 5px 0; 221 | font-family: 'ProximaNovaLight', 'Helvetica Neue', 'Helvetica', 'Arial'; 222 | font-size: 15px; 223 | padding: 10px; 224 | -webkit-border-radius: 5px; 225 | -moz-border-radius: 5px; 226 | border-radius: 5px; 227 | border: 1px solid #ccc; 228 | } 229 | button { 230 | background: #aaaaaa; 231 | background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #ffffff)); 232 | background: -ms-linear-gradient(bottom, #eeeeee, #ffffff); 233 | background: -moz-linear-gradient(center bottom, #eeeeee 0%, #ffffff 100%); 234 | background: -o-linear-gradient(#ffffff, #eeeeee); 235 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0); 236 | } 237 | button:active { 238 | background: #ffffff; 239 | background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(1, #eeeeee)); 240 | background: -ms-linear-gradient(bottom, #eeeeee, #eeeeee); 241 | background: -moz-linear-gradient(center bottom, #eeeeee 0%, #eeeeee 100%); 242 | background: -o-linear-gradient(#eeeeee, #eeeeee); 243 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#eeeeee', GradientType=0); 244 | } 245 | button.green { 246 | background-color: #7fbf4d; 247 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #7fbf4d), color-stop(100%, #63a62f)); 248 | background-image: -webkit-linear-gradient(top, #7fbf4d, #63a62f); 249 | background-image: -moz-linear-gradient(top, #7fbf4d, #63a62f); 250 | background-image: -ms-linear-gradient(top, #7fbf4d, #63a62f); 251 | background-image: -o-linear-gradient(top, #7fbf4d, #63a62f); 252 | background-image: linear-gradient(top, #7fbf4d, #63a62f); 253 | border: 1px solid #63a62f; 254 | border-bottom: 1px solid #66a039; 255 | border-radius: 3px; 256 | -webkit-box-shadow: inset 0 1px 0 0 #9acc73; 257 | box-shadow: inset 0 1px 0 0 #9acc73; 258 | color: #fff; 259 | padding: 7px 0 8px 0; 260 | text-align: center; 261 | text-shadow: 0 -1px 0 #66a039; 262 | width: 100%; 263 | margin: 10px 0; 264 | } 265 | button.green:hover { 266 | background-color: #72b240; 267 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #72b240), color-stop(100%, #579229)); 268 | background-image: -webkit-linear-gradient(top, #72b240, #579229); 269 | background-image: -moz-linear-gradient(top, #72b240, #579229); 270 | background-image: -ms-linear-gradient(top, #72b240, #579229); 271 | background-image: -o-linear-gradient(top, #72b240, #579229); 272 | background-image: linear-gradient(top, #72b240, #579229); 273 | -webkit-box-shadow: inset 0 1px 0 0 #8cc660; 274 | box-shadow: inset 0 1px 0 0 #8cc660; 275 | cursor: pointer; 276 | } 277 | button.green:active { 278 | border: 1px solid #53822f; 279 | border-bottom: 1px solid #5a8d33; 280 | -webkit-box-shadow: inset 0 0 8px 4px #649c38, 0 1px 0 0 #eeeeee; 281 | box-shadow: inset 0 0 8px 4px #649c38, 0 1px 0 0 #eeeeee; 282 | } 283 | button.green[disabled="disabled"] { 284 | opacity: .5; 285 | } 286 | button.blue { 287 | background-color: #67a4e9; 288 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #67a4e9), color-stop(100%, #3587e4)); 289 | background-image: -webkit-linear-gradient(top, #67a4e9, #3587e4); 290 | background-image: -moz-linear-gradient(top, #67a4e9, #3587e4); 291 | background-image: -ms-linear-gradient(top, #67a4e9, #3587e4); 292 | background-image: -o-linear-gradient(top, #67a4e9, #3587e4); 293 | background-image: linear-gradient(top, #67a4e9, #3587e4); 294 | border: 1px solid #3587e4; 295 | border-bottom: 1px solid #3a89e3; 296 | border-radius: 3px; 297 | -webkit-box-shadow: inset 0 1px 0 0 #94bfef; 298 | box-shadow: inset 0 1px 0 0 #94bfef; 299 | color: #fff; 300 | padding: 7px 0 8px 0; 301 | text-align: center; 302 | text-shadow: 0 -1px 0 #3a89e3; 303 | width: 100%; 304 | } 305 | button.blue:hover { 306 | background-color: #5197e6; 307 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5197e6), color-stop(100%, #1f7ae1)); 308 | background-image: -webkit-linear-gradient(top, #5197e6, #1f7ae1); 309 | background-image: -moz-linear-gradient(top, #5197e6, #1f7ae1); 310 | background-image: -ms-linear-gradient(top, #5197e6, #1f7ae1); 311 | background-image: -o-linear-gradient(top, #5197e6, #1f7ae1); 312 | background-image: linear-gradient(top, #5197e6, #1f7ae1); 313 | -webkit-box-shadow: inset 0 1px 0 0 #7db1ec; 314 | box-shadow: inset 0 1px 0 0 #7db1ec; 315 | cursor: pointer; 316 | } 317 | button.blue:active { 318 | border: 1px solid #1f74d5; 319 | border-bottom: 1px solid #247cdf; 320 | -webkit-box-shadow: inset 0 0 8px 4px #3687e2, 0 1px 0 0 #eeeeee; 321 | box-shadow: inset 0 0 8px 4px #3687e2, 0 1px 0 0 #eeeeee; 322 | } 323 | button.blue[disabled="disabled"] { 324 | opacity: .5; 325 | } 326 | body { 327 | background: #ffffff url(../img/gray_jean.png); 328 | color: #333; 329 | font-size: 15px; 330 | line-height: 170%; 331 | font-family: 'ProximaNovaLight', 'Helvetica Neue', 'Helvetica', 'Arial'; 332 | margin: 0; 333 | text-shadow: 1px 1px 0 #fff; 334 | } 335 | a { 336 | color: #333; 337 | } 338 | #container { 339 | width: 700px; 340 | margin: 30px auto 50px auto; 341 | } 342 | h1 { 343 | text-align: center; 344 | } 345 | h1 span { 346 | display: block; 347 | margin: 10px 0; 348 | font-style: italic; 349 | font-size: 16px; 350 | } 351 | h3.grey-line { 352 | position: relative; 353 | text-align: center; 354 | z-index: 1; 355 | } 356 | h3.grey-line:before { 357 | border-top: 1px solid #ccc; 358 | content: ""; 359 | margin: 0 auto; 360 | position: absolute; 361 | top: 15px; 362 | left: 0; 363 | right: 0; 364 | bottom: 0; 365 | width: 100%; 366 | z-index: -1; 367 | } 368 | h3.grey-line span { 369 | background: url(../img/gray_jean.png); 370 | padding: 0 10px; 371 | } 372 | -------------------------------------------------------------------------------- /example/fonts/proximanova-light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/fonts/proximanova-light-webfont.eot -------------------------------------------------------------------------------- /example/fonts/proximanova-light-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/fonts/proximanova-light-webfont.ttf -------------------------------------------------------------------------------- /example/fonts/proximanova-light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/fonts/proximanova-light-webfont.woff -------------------------------------------------------------------------------- /example/fonts/proximanova-regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/fonts/proximanova-regular-webfont.eot -------------------------------------------------------------------------------- /example/fonts/proximanova-regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/fonts/proximanova-regular-webfont.ttf -------------------------------------------------------------------------------- /example/fonts/proximanova-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/fonts/proximanova-regular-webfont.woff -------------------------------------------------------------------------------- /example/img/gray_jean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/img/gray_jean.png -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jQuery TimeAutocomplete Example 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Fork me on GitHub 21 | 22 |
23 | 24 |

jQuery timeAutocomplete Plugin by 7shifts.com

25 | 26 |

What is this?

27 | 28 |

It's a time picker similar to how Google Calendar's time picker works for events. It's meant to be smart, sexy and intuitive.

29 | 30 |

Some things that make is super duper fantastic:

31 | 39 | 40 |

Basic usage

41 |
$('#basic-example').timeAutocomplete();
42 | 43 | 44 | 45 |

Advanced usage #1

46 |

Injecting an existing value and using 24hr as the formatter.

47 |
$('#from-24hr').timeAutocomplete({
 48 |     formatter: '24hr',
 49 |     value: '07:00:00'
 50 | });
 51 | 
 52 | $('#to-24hr').timeAutocomplete({
 53 |     formatter: '24hr',
 54 |     value: '09:30:00'
 55 | });
56 | 57 | From 58 | To 59 | 60 | 61 |

Advanced usage #2

62 |

Using a 'from' and 'to' input. We use a 'from_selector' argument in the set of options on the 'to' field. This makes the time autocomplete aware of the time in the other 63 | field. If the 'from' field is '8:00 AM' and we start typing into the 'to' field with '4', it will show us a list of 4 'PM' instead of 4 'AM' options.

64 |
$('#from-ampm').timeAutocomplete({
 65 |     increment: 5,
 66 |     value: '08:00:00'
 67 | });
 68 | 
 69 | $('#to-ampm').timeAutocomplete({
 70 |     increment: 5,
 71 |     from_selector: '#from-ampm',
 72 |     value: '17:30:00' // likely populated from your database.
 73 | });
74 | 75 | From 76 | To 77 | 78 |

Advanced usage #3

79 | 80 |
$('#from-french').timeAutocomplete({
 81 |     formatter: 'french'
 82 | });
 83 | 
 84 | $('#to-french').timeAutocomplete({
 85 |     formatter: 'french',
 86 |     value: '17:00:00'
 87 | });
88 | 89 | From 90 | To 91 | 92 |

Initialization options

93 |

Below is a set of options you can pass when you call $('#my-input').timeAutocomplete(options);

94 | 95 |
options = {
96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 131 | 132 | 133 | 134 | 135 | 136 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 172 | 173 | 174 | 175 | 176 |
Option keyDefault valuePossible valuesDescription
auto_complete{ delay: 0, autoFocus: true, minLength: 0 } (object)View here.Any options to over-ride jQuery UI autocomplete plugin.
formatterampm (string)ampm | 24hr | frenchThe formatter we want to use
value'' (string)'13:30:00'Allows you to pass in a 24hr (H:i:s) time to be formatted and displayed in the field. It's the same as calling $('#from').data('timeAutocomplete').setTime('13:30:00');
from_selector'' (string)#fromYou'll want to use this option on the #to element if you're using the 129 | 'ampm' formatter. It applies a level of 130 | "smartness" when dealing with both from/to inputs. If your #from input is 8:00 AM then the user types in "5" into the #to input, it will give them possible increments in PM.
increment15 (int)5, 10, 15, 30, 60 137 | The increment you want the time dropdown to appear in. A 15 minute increment would produce: ['7:15 AM', '7:30 AM', '7:45 AM']. 138 |
start_hour0 (int)Any number on or between 0 and 24What hour you want start the selectable time list to start at.
end_hour24 (int)Any number on or between 0 and 24What hour you want the end of the selectable time list to end at.
blur_empty_populatetruetrue | falseIf we blur from the input field and it's empty, populate it with our empty default value (see next line).
auto_valuetruetrue | falseIf false, it will not inject the current time as a value. Your input will be empty.
empty{ 167 | h: '12', 168 | m: '00', 169 | sep: ':', 170 | postfix: ' PM' 171 | } (object)The default empty value
177 | 178 |
}
179 | 180 |

API

181 |

Once you initialize timeAutocomplete() on an element, you have access to methods via data('timeAutocomplete').

182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 |
MethodArgumentsDescription

destroy()

NoneCompletely removes timeAutocomplete plugin from the input
$('#my-input').data('timeAutocomplete').destroy();

getTime()

NoneGets the time in H:i:s (13:30:00) format.
$('#my-input').data('timeAutocomplete').getTime();

setTime(time)

time: '13:30:00'Sets the time by passing in a 24hr format. This will be formatted appropriately before being displayed.
$('#my-input').data('timeAutocomplete').setTime('13:30:00');

setFormatter(formatter)

formatter: 'ampm' or '24hr' or 'french'Changes the formatter type on the fly.
$('#my-input').data('timeAutocomplete').setFormatter('24hr');
227 | 228 |

Requirements

229 | 233 | 234 | 235 |
236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 307 | 308 | 309 | -------------------------------------------------------------------------------- /example/less/buttons.less: -------------------------------------------------------------------------------- 1 | .button (@color1, @color2) { 2 | background-color: @color1; 3 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, @color1), color-stop(100%, @color2)); 4 | background-image: -webkit-linear-gradient(top, @color1, @color2); 5 | background-image: -moz-linear-gradient(top, @color1, @color2); 6 | background-image: -ms-linear-gradient(top, @color1, @color2); 7 | background-image: -o-linear-gradient(top, @color1, @color2); 8 | background-image: linear-gradient(top, @color1, @color2); 9 | border: 1px solid @color2; 10 | border-bottom: 1px solid darken(@color1, 10%); 11 | border-radius: 3px; 12 | -webkit-box-shadow: inset 0 1px 0 0 lighten(@color1, 10%); 13 | box-shadow: inset 0 1px 0 0 lighten(@color1, 10%); 14 | color: #fff; 15 | padding: 7px 0 8px 0; 16 | text-align: center; 17 | text-shadow: 0 -1px 0 darken(@color1, 10%); 18 | width: 100%; 19 | 20 | &:hover { 21 | background-color: darken(@color1, 5%); 22 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, darken(@color1, 5%)), color-stop(100%, darken(@color2, 5%))); 23 | background-image: -webkit-linear-gradient(top, darken(@color1, 5%), darken(@color2, 5%)); 24 | background-image: -moz-linear-gradient(top, darken(@color1, 5%), darken(@color2, 5%)); 25 | background-image: -ms-linear-gradient(top, darken(@color1, 5%), darken(@color2, 5%)); 26 | background-image: -o-linear-gradient(top, darken(@color1, 5%), darken(@color2, 5%)); 27 | background-image: linear-gradient(top, darken(@color1, 5%), darken(@color2, 5%)); 28 | -webkit-box-shadow: inset 0 1px 0 0 lighten(@color1, 5%); 29 | box-shadow: inset 0 1px 0 0 lighten(@color1, 5%); 30 | cursor: pointer; 31 | } 32 | 33 | &:active { 34 | border: 1px solid darken(@color1, 18%); 35 | border-bottom: 1px solid darken(@color1, 15%); 36 | -webkit-box-shadow: inset 0 0 8px 4px darken(@color1, 11%), 0 1px 0 0 #eeeeee; 37 | box-shadow: inset 0 0 8px 4px darken(@color1, 11%), 0 1px 0 0 #eeeeee; 38 | } 39 | 40 | &[disabled="disabled"] { 41 | opacity: .5; 42 | } 43 | 44 | } 45 | 46 | button.green { 47 | .button(#7fbf4d, #63a62f); 48 | 49 | margin: 10px 0; 50 | } 51 | button.blue { 52 | .button(#67a4e9, #3587e4); 53 | } -------------------------------------------------------------------------------- /example/less/elements.less: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------- 2 | LESS Elements 0.9 3 | --------------------------------------------------- 4 | A set of useful LESS mixins 5 | More info at: http://lesselements.com 6 | ---------------------------------------------------*/ 7 | 8 | .gradient(@color: #F5F5F5, @start: #EEE, @stop: #FFF) { 9 | background: @color; 10 | background: -webkit-gradient(linear, 11 | left bottom, 12 | left top, 13 | color-stop(0, @start), 14 | color-stop(1, @stop)); 15 | background: -ms-linear-gradient(bottom, 16 | @start, 17 | @stop); 18 | background: -moz-linear-gradient(center bottom, 19 | @start 0%, 20 | @stop 100%); 21 | background: -o-linear-gradient(@stop, 22 | @start); 23 | filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",@stop,@start)); 24 | } 25 | .bw-gradient(@color: #F5F5F5, @start: 0, @stop: 255) { 26 | background: @color; 27 | background: -webkit-gradient(linear, 28 | left bottom, 29 | left top, 30 | color-stop(0, rgb(@start,@start,@start)), 31 | color-stop(1, rgb(@stop,@stop,@stop))); 32 | background: -ms-linear-gradient(bottom, 33 | rgb(@start,@start,@start) 0%, 34 | rgb(@stop,@stop,@stop) 100%); 35 | background: -moz-linear-gradient(center bottom, 36 | rgb(@start,@start,@start) 0%, 37 | rgb(@stop,@stop,@stop) 100%); 38 | background: -o-linear-gradient(rgb(@stop,@stop,@stop), 39 | rgb(@start,@start,@start)); 40 | filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",rgb(@stop,@stop,@stop),rgb(@start,@start,@start))); 41 | } 42 | .bordered(@top-color: #EEE, @right-color: #EEE, @bottom-color: #EEE, @left-color: #EEE) { 43 | border-top: solid 1px @top-color; 44 | border-left: solid 1px @left-color; 45 | border-right: solid 1px @right-color; 46 | border-bottom: solid 1px @bottom-color; 47 | } 48 | .drop-shadow(@x-axis: 0, @y-axis: 1px, @blur: 2px, @alpha: 0.1) { 49 | -webkit-box-shadow: @x-axis @y-axis @blur rgba(0, 0, 0, @alpha); 50 | -moz-box-shadow: @x-axis @y-axis @blur rgba(0, 0, 0, @alpha); 51 | box-shadow: @x-axis @y-axis @blur rgba(0, 0, 0, @alpha); 52 | } 53 | .rounded(@radius: 2px) { 54 | -webkit-border-radius: @radius; 55 | -moz-border-radius: @radius; 56 | border-radius: @radius; 57 | } 58 | .border-radius(@topright: 0, @bottomright: 0, @bottomleft: 0, @topleft: 0) { 59 | -webkit-border-top-right-radius: @topright; 60 | -webkit-border-bottom-right-radius: @bottomright; 61 | -webkit-border-bottom-left-radius: @bottomleft; 62 | -webkit-border-top-left-radius: @topleft; 63 | -moz-border-radius-topright: @topright; 64 | -moz-border-radius-bottomright: @bottomright; 65 | -moz-border-radius-bottomleft: @bottomleft; 66 | -moz-border-radius-topleft: @topleft; 67 | border-top-right-radius: @topright; 68 | border-bottom-right-radius: @bottomright; 69 | border-bottom-left-radius: @bottomleft; 70 | border-top-left-radius: @topleft; 71 | .background-clip(padding-box); 72 | } 73 | .opacity(@opacity: 0.5) { 74 | -moz-opacity: @opacity; 75 | -khtml-opacity: @opacity; 76 | -webkit-opacity: @opacity; 77 | opacity: @opacity; 78 | @opperc: @opacity * 100; 79 | -ms-filter: ~"progid:DXImageTransform.Microsoft.Alpha(opacity=@{opperc})"; 80 | filter: ~"alpha(opacity=@{opperc})"; 81 | } 82 | .transition-duration(@duration: 0.2s) { 83 | -moz-transition-duration: @duration; 84 | -webkit-transition-duration: @duration; 85 | -o-transition-duration: @duration; 86 | transition-duration: @duration; 87 | } 88 | .transform(...) { 89 | -webkit-transform: @arguments; 90 | -moz-transform: @arguments; 91 | -o-transform: @arguments; 92 | -ms-transform: @arguments; 93 | transform: @arguments; 94 | } 95 | .rotation(@deg:5deg){ 96 | .transform(rotate(@deg)); 97 | } 98 | .scale(@ratio:1.5){ 99 | .transform(scale(@ratio)); 100 | } 101 | .transition(@duration:0.2s, @ease:ease-out) { 102 | -webkit-transition: all @duration @ease; 103 | -moz-transition: all @duration @ease; 104 | -o-transition: all @duration @ease; 105 | transition: all @duration @ease; 106 | } 107 | .inner-shadow(@horizontal:0, @vertical:1px, @blur:2px, @alpha: 0.4) { 108 | -webkit-box-shadow: inset @horizontal @vertical @blur rgba(0, 0, 0, @alpha); 109 | -moz-box-shadow: inset @horizontal @vertical @blur rgba(0, 0, 0, @alpha); 110 | box-shadow: inset @horizontal @vertical @blur rgba(0, 0, 0, @alpha); 111 | } 112 | .box-shadow(@arguments) { 113 | -webkit-box-shadow: @arguments; 114 | -moz-box-shadow: @arguments; 115 | box-shadow: @arguments; 116 | } 117 | .box-sizing(@sizing: border-box) { 118 | -ms-box-sizing: @sizing; 119 | -moz-box-sizing: @sizing; 120 | -webkit-box-sizing: @sizing; 121 | box-sizing: @sizing; 122 | } 123 | .user-select(@argument: none) { 124 | -webkit-user-select: @argument; 125 | -moz-user-select: @argument; 126 | -ms-user-select: @argument; 127 | user-select: @argument; 128 | } 129 | .columns(@colwidth: 250px, @colcount: 0, @colgap: 50px, @columnRuleColor: #EEE, @columnRuleStyle: solid, @columnRuleWidth: 1px) { 130 | -moz-column-width: @colwidth; 131 | -moz-column-count: @colcount; 132 | -moz-column-gap: @colgap; 133 | -moz-column-rule-color: @columnRuleColor; 134 | -moz-column-rule-style: @columnRuleStyle; 135 | -moz-column-rule-width: @columnRuleWidth; 136 | -webkit-column-width: @colwidth; 137 | -webkit-column-count: @colcount; 138 | -webkit-column-gap: @colgap; 139 | -webkit-column-rule-color: @columnRuleColor; 140 | -webkit-column-rule-style: @columnRuleStyle; 141 | -webkit-column-rule-width: @columnRuleWidth; 142 | column-width: @colwidth; 143 | column-count: @colcount; 144 | column-gap: @colgap; 145 | column-rule-color: @columnRuleColor; 146 | column-rule-style: @columnRuleStyle; 147 | column-rule-width: @columnRuleWidth; 148 | } 149 | .translate(@x:0, @y:0) { 150 | .transform(translate(@x, @y)); 151 | } 152 | .background-clip(@argument: padding-box) { 153 | -moz-background-clip: @argument; 154 | -webkit-background-clip: @argument; 155 | background-clip: @argument; 156 | } -------------------------------------------------------------------------------- /example/less/fonts.less: -------------------------------------------------------------------------------- 1 | /* This file was created to be share between the main site and marketing pages (restaurants.php, coffee.php etc) */ 2 | @font-face { 3 | font-family: 'ProximaNovaLight'; 4 | src: url('../fonts/proximanova-light-webfont.eot'); 5 | src: url('../fonts/proximanova-light-webfont.eot?#iefix') format('embedded-opentype'), 6 | url('../fonts/proximanova-light-webfont.woff') format('woff'), 7 | url('../fonts/proximanova-light-webfont.ttf') format('truetype'), 8 | url('../fonts/proximanova-light-webfont.svg#proxima_novalight') format('svg'); 9 | font-weight: normal; 10 | font-style: normal; 11 | 12 | } 13 | @font-face { 14 | font-family: 'ProximaNovaRegular'; 15 | src: url('../fonts/proximanova-regular-webfont.eot'); 16 | src: url('../fonts/proximanova-regular-webfont.eot?#iefix') format('embedded-opentype'), 17 | url('../fonts/proximanova-regular-webfont.woff') format('woff'), 18 | url('../proximanova-regular-webfont.ttf') format('truetype'), 19 | url('../proximanova-regular-webfont.svg#proxima_nova_rgregular') format('svg'); 20 | font-weight: normal; 21 | font-style: normal; 22 | } -------------------------------------------------------------------------------- /example/less/forms.less: -------------------------------------------------------------------------------- 1 | input[type="text"], 2 | button { 3 | margin: 5px 0; 4 | font-family: @font_family; 5 | font-size: @font_size; 6 | padding: 10px; 7 | .rounded(5px); 8 | border: 1px solid #ccc; 9 | } 10 | 11 | button { 12 | .gradient(#aaa, #eee, #fff); 13 | } 14 | button:active { 15 | .gradient(#fff, #eee, #eee); 16 | } -------------------------------------------------------------------------------- /example/less/reset.less: -------------------------------------------------------------------------------- 1 | // 2 | // Reset CSS 3 | // Adapted from http://github.com/necolas/normalize.css 4 | // -------------------------------------------------- 5 | .clear { 6 | clear: both; 7 | } 8 | 9 | .clearfix:after { 10 | content: "."; 11 | display: block; 12 | clear: both; 13 | visibility: hidden; 14 | line-height: 0; 15 | height: 0; 16 | } 17 | 18 | .clearfix { 19 | display: inline-block; 20 | } 21 | 22 | html[xmlns] .clearfix { 23 | display: block; 24 | } 25 | 26 | * html .clearfix { 27 | height: 1%; 28 | } 29 | 30 | // Display in IE6-9 and FF3 31 | // ------------------------- 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | nav, 42 | section { 43 | display: block; 44 | } 45 | 46 | table { 47 | width: 100%; 48 | font-size: 13px; 49 | } 50 | table thead th { 51 | background: #fff; 52 | border-bottom: 1px solid #ccc; 53 | } 54 | table th, 55 | table td { 56 | padding: 5px; 57 | } 58 | table tr td { 59 | border: 1px solid #ccc; 60 | } 61 | 62 | // Display block in IE6-9 and FF3 63 | // ------------------------- 64 | 65 | audio, 66 | canvas, 67 | video { 68 | display: inline-block; 69 | *display: inline; 70 | *zoom: 1; 71 | } 72 | 73 | // Prevents modern browsers from displaying 'audio' without controls 74 | // ------------------------- 75 | 76 | audio:not([controls]) { 77 | display: none; 78 | } 79 | 80 | // Base settings 81 | // ------------------------- 82 | 83 | html { 84 | font-size: 100%; 85 | -webkit-text-size-adjust: 100%; 86 | -ms-text-size-adjust: 100%; 87 | } 88 | // Hover & Active 89 | a:hover, 90 | a:active { 91 | outline: 0; 92 | } 93 | 94 | // Prevents sub and sup affecting line-height in all browsers 95 | // ------------------------- 96 | 97 | sub, 98 | sup { 99 | position: relative; 100 | font-size: 75%; 101 | line-height: 0; 102 | vertical-align: baseline; 103 | } 104 | sup { 105 | top: -0.5em; 106 | } 107 | sub { 108 | bottom: -0.25em; 109 | } 110 | 111 | // Img border in a's and image quality 112 | // ------------------------- 113 | 114 | img { 115 | /* Responsive images (ensure images don't scale beyond their parents) */ 116 | max-width: 100%; /* Part 1: Set a maxium relative to the parent */ 117 | width: auto\9; /* IE7-8 need help adjusting responsive images */ 118 | height: auto; /* Part 2: Scale the height according to the width, otherwise you get stretching */ 119 | 120 | vertical-align: middle; 121 | border: 0; 122 | -ms-interpolation-mode: bicubic; 123 | } 124 | 125 | // Prevent max-width from affecting Google Maps 126 | #map_canvas img, 127 | .google-maps img { 128 | max-width: none; 129 | } 130 | 131 | // Forms 132 | // ------------------------- 133 | 134 | // Font size in all browsers, margin changes, misc consistency 135 | button, 136 | input, 137 | select, 138 | textarea { 139 | margin: 0; 140 | font-size: 100%; 141 | vertical-align: middle; 142 | } 143 | button, 144 | input { 145 | *overflow: visible; // Inner spacing ie IE6/7 146 | line-height: normal; // FF3/4 have !important on line-height in UA stylesheet 147 | } 148 | button::-moz-focus-inner, 149 | input::-moz-focus-inner { // Inner padding and border oddities in FF3/4 150 | padding: 0; 151 | border: 0; 152 | } 153 | button, 154 | html input[type="button"], // Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. 155 | input[type="reset"], 156 | input[type="submit"] { 157 | -webkit-appearance: button; // Corrects inability to style clickable `input` types in iOS. 158 | cursor: pointer; // Improves usability and consistency of cursor style between image-type `input` and others. 159 | } 160 | label, 161 | select, 162 | button, 163 | input[type="button"], 164 | input[type="reset"], 165 | input[type="submit"], 166 | input[type="radio"], 167 | input[type="checkbox"] { 168 | cursor: pointer; // Improves usability and consistency of cursor style between image-type `input` and others. 169 | } 170 | input[type="search"] { // Appearance in Safari/Chrome 171 | -webkit-appearance: textfield; 172 | } 173 | input[type="search"]::-webkit-search-decoration, 174 | input[type="search"]::-webkit-search-cancel-button { 175 | -webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5 176 | } 177 | textarea { 178 | overflow: auto; // Remove vertical scrollbar in IE6-9 179 | vertical-align: top; // Readability and alignment cross-browser 180 | } 181 | 182 | 183 | // Printing 184 | // ------------------------- 185 | // Source: https://github.com/h5bp/html5-boilerplate/blob/master/css/main.css 186 | 187 | @media print { 188 | 189 | * { 190 | text-shadow: none !important; 191 | color: #000 !important; // Black prints faster: h5bp.com/s 192 | background: transparent !important; 193 | box-shadow: none !important; 194 | } 195 | 196 | a, 197 | a:visited { 198 | text-decoration: underline; 199 | } 200 | 201 | a[href]:after { 202 | content: " (" attr(href) ")"; 203 | } 204 | 205 | abbr[title]:after { 206 | content: " (" attr(title) ")"; 207 | } 208 | 209 | // Don't show links for images, or javascript/internal links 210 | .ir a:after, 211 | a[href^="javascript:"]:after, 212 | a[href^="#"]:after { 213 | content: ""; 214 | } 215 | 216 | pre, 217 | blockquote { 218 | border: 1px solid #999; 219 | page-break-inside: avoid; 220 | } 221 | 222 | thead { 223 | display: table-header-group; // h5bp.com/t 224 | } 225 | 226 | tr, 227 | img { 228 | page-break-inside: avoid; 229 | } 230 | 231 | img { 232 | max-width: 100% !important; 233 | } 234 | 235 | @page { 236 | margin: 0.5cm; 237 | } 238 | 239 | p, 240 | h2, 241 | h3 { 242 | orphans: 3; 243 | widows: 3; 244 | } 245 | 246 | h2, 247 | h3 { 248 | page-break-after: avoid; 249 | } 250 | } -------------------------------------------------------------------------------- /example/less/style.less: -------------------------------------------------------------------------------- 1 | @font_size: 15px; 2 | @font_family: 'ProximaNovaLight', 'Helvetica Neue', 'Helvetica', 'Arial'; 3 | @width: 700px; 4 | 5 | @import "reset.less"; 6 | @import "elements.less"; 7 | @import "fonts.less"; 8 | @import "forms.less"; 9 | @import "buttons.less"; 10 | 11 | body { 12 | background: #fff url(../img/gray_jean.png); 13 | color: #333; 14 | font-size: @font_size; 15 | line-height: 170%; 16 | font-family: @font_family; 17 | margin: 0; 18 | text-shadow: 1px 1px 0 #fff; 19 | } 20 | 21 | a { 22 | color: #333; 23 | } 24 | 25 | #container { 26 | width: @width; 27 | margin: 30px auto 50px auto; 28 | } 29 | 30 | h1 { 31 | text-align: center; 32 | 33 | span { 34 | display: block; 35 | margin: 10px 0; 36 | font-style: italic; 37 | font-size: 16px; 38 | } 39 | } 40 | 41 | h3.grey-line { 42 | position: relative; 43 | text-align: center; 44 | z-index: 1; 45 | } 46 | h3.grey-line:before { 47 | border-top: 1px solid #ccc; 48 | content:""; 49 | margin: 0 auto; 50 | position: absolute; 51 | top: 15px; left: 0; right: 0; bottom: 0; 52 | width: 100%; 53 | z-index: -1; 54 | } 55 | h3.grey-line span { 56 | background: url(../img/gray_jean.png); 57 | padding: 0 10px; 58 | } 59 | -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/images/animated-overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/lib/jquery-ui/css/ui-lightness/images/animated-overlay.gif -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/lib/jquery-ui/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/lib/jquery-ui/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/lib/jquery-ui/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/lib/jquery-ui/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/lib/jquery-ui/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/lib/jquery-ui/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/lib/jquery-ui/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/lib/jquery-ui/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/lib/jquery-ui/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/lib/jquery-ui/css/ui-lightness/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/images/ui-icons_228ef1_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/lib/jquery-ui/css/ui-lightness/images/ui-icons_228ef1_256x240.png -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/images/ui-icons_ef8c08_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/lib/jquery-ui/css/ui-lightness/images/ui-icons_ef8c08_256x240.png -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/images/ui-icons_ffd27a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/lib/jquery-ui/css/ui-lightness/images/ui-icons_ffd27a_256x240.png -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/example/lib/jquery-ui/css/ui-lightness/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/jquery-ui-1.10.2.custom.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.10.2 - 2013-03-22 2 | * http://jqueryui.com 3 | * Includes: jquery.ui.core.css, jquery.ui.autocomplete.css, jquery.ui.menu.css 4 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=gloss_wave&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=highlight_soft&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=glass&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=glass&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=diagonals_thick&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=diagonals_thick&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px 5 | * Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ 6 | 7 | /* Layout helpers 8 | ----------------------------------*/ 9 | .ui-helper-hidden { 10 | display: none; 11 | } 12 | .ui-helper-hidden-accessible { 13 | border: 0; 14 | clip: rect(0 0 0 0); 15 | height: 1px; 16 | margin: -1px; 17 | overflow: hidden; 18 | padding: 0; 19 | position: absolute; 20 | width: 1px; 21 | } 22 | .ui-helper-reset { 23 | margin: 0; 24 | padding: 0; 25 | border: 0; 26 | outline: 0; 27 | line-height: 1.3; 28 | text-decoration: none; 29 | font-size: 100%; 30 | list-style: none; 31 | } 32 | .ui-helper-clearfix:before, 33 | .ui-helper-clearfix:after { 34 | content: ""; 35 | display: table; 36 | border-collapse: collapse; 37 | } 38 | .ui-helper-clearfix:after { 39 | clear: both; 40 | } 41 | .ui-helper-clearfix { 42 | min-height: 0; /* support: IE7 */ 43 | } 44 | .ui-helper-zfix { 45 | width: 100%; 46 | height: 100%; 47 | top: 0; 48 | left: 0; 49 | position: absolute; 50 | opacity: 0; 51 | filter:Alpha(Opacity=0); 52 | } 53 | 54 | .ui-front { 55 | z-index: 100; 56 | } 57 | 58 | 59 | /* Interaction Cues 60 | ----------------------------------*/ 61 | .ui-state-disabled { 62 | cursor: default !important; 63 | } 64 | 65 | 66 | /* Icons 67 | ----------------------------------*/ 68 | 69 | /* states and images */ 70 | .ui-icon { 71 | display: block; 72 | text-indent: -99999px; 73 | overflow: hidden; 74 | background-repeat: no-repeat; 75 | } 76 | 77 | 78 | /* Misc visuals 79 | ----------------------------------*/ 80 | 81 | /* Overlays */ 82 | .ui-widget-overlay { 83 | position: fixed; 84 | top: 0; 85 | left: 0; 86 | width: 100%; 87 | height: 100%; 88 | } 89 | .ui-autocomplete { 90 | position: absolute; 91 | top: 0; 92 | left: 0; 93 | cursor: default; 94 | } 95 | .ui-menu { 96 | list-style: none; 97 | padding: 2px; 98 | margin: 0; 99 | display: block; 100 | outline: none; 101 | } 102 | .ui-menu .ui-menu { 103 | margin-top: -3px; 104 | position: absolute; 105 | } 106 | .ui-menu .ui-menu-item { 107 | margin: 0; 108 | padding: 0; 109 | width: 100%; 110 | } 111 | .ui-menu .ui-menu-divider { 112 | margin: 5px -2px 5px -2px; 113 | height: 0; 114 | font-size: 0; 115 | line-height: 0; 116 | border-width: 1px 0 0 0; 117 | } 118 | .ui-menu .ui-menu-item a { 119 | text-decoration: none; 120 | display: block; 121 | padding: 2px .4em; 122 | line-height: 1.5; 123 | min-height: 0; /* support: IE7 */ 124 | font-weight: normal; 125 | } 126 | .ui-menu .ui-menu-item a.ui-state-focus, 127 | .ui-menu .ui-menu-item a.ui-state-active { 128 | font-weight: normal; 129 | margin: -1px; 130 | } 131 | 132 | .ui-menu .ui-state-disabled { 133 | font-weight: normal; 134 | margin: .4em 0 .2em; 135 | line-height: 1.5; 136 | } 137 | .ui-menu .ui-state-disabled a { 138 | cursor: default; 139 | } 140 | 141 | /* icon support */ 142 | .ui-menu-icons { 143 | position: relative; 144 | } 145 | .ui-menu-icons .ui-menu-item a { 146 | position: relative; 147 | padding-left: 2em; 148 | } 149 | 150 | /* left-aligned */ 151 | .ui-menu .ui-icon { 152 | position: absolute; 153 | top: .2em; 154 | left: .2em; 155 | } 156 | 157 | /* right-aligned */ 158 | .ui-menu .ui-menu-icon { 159 | position: static; 160 | float: right; 161 | } 162 | 163 | /* Component containers 164 | ----------------------------------*/ 165 | .ui-widget { 166 | font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif; 167 | font-size: 1.1em; 168 | } 169 | .ui-widget .ui-widget { 170 | font-size: 1em; 171 | } 172 | .ui-widget input, 173 | .ui-widget select, 174 | .ui-widget textarea, 175 | .ui-widget button { 176 | font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif; 177 | font-size: 1em; 178 | } 179 | .ui-widget-content { 180 | border: 1px solid #dddddd; 181 | background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; 182 | color: #333333; 183 | } 184 | .ui-widget-content a { 185 | color: #333333; 186 | } 187 | .ui-widget-header { 188 | border: 1px solid #e78f08; 189 | background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; 190 | color: #ffffff; 191 | font-weight: bold; 192 | } 193 | .ui-widget-header a { 194 | color: #ffffff; 195 | } 196 | 197 | /* Interaction states 198 | ----------------------------------*/ 199 | .ui-state-default, 200 | .ui-widget-content .ui-state-default, 201 | .ui-widget-header .ui-state-default { 202 | border: 1px solid #cccccc; 203 | background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; 204 | font-weight: bold; 205 | color: #1c94c4; 206 | } 207 | .ui-state-default a, 208 | .ui-state-default a:link, 209 | .ui-state-default a:visited { 210 | color: #1c94c4; 211 | text-decoration: none; 212 | } 213 | .ui-state-hover, 214 | .ui-widget-content .ui-state-hover, 215 | .ui-widget-header .ui-state-hover, 216 | .ui-state-focus, 217 | .ui-widget-content .ui-state-focus, 218 | .ui-widget-header .ui-state-focus { 219 | border: 1px solid #fbcb09; 220 | background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; 221 | font-weight: bold; 222 | color: #c77405; 223 | } 224 | .ui-state-hover a, 225 | .ui-state-hover a:hover, 226 | .ui-state-hover a:link, 227 | .ui-state-hover a:visited { 228 | color: #c77405; 229 | text-decoration: none; 230 | } 231 | .ui-state-active, 232 | .ui-widget-content .ui-state-active, 233 | .ui-widget-header .ui-state-active { 234 | border: 1px solid #fbd850; 235 | background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; 236 | font-weight: bold; 237 | color: #eb8f00; 238 | } 239 | .ui-state-active a, 240 | .ui-state-active a:link, 241 | .ui-state-active a:visited { 242 | color: #eb8f00; 243 | text-decoration: none; 244 | } 245 | 246 | /* Interaction Cues 247 | ----------------------------------*/ 248 | .ui-state-highlight, 249 | .ui-widget-content .ui-state-highlight, 250 | .ui-widget-header .ui-state-highlight { 251 | border: 1px solid #fed22f; 252 | background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; 253 | color: #363636; 254 | } 255 | .ui-state-highlight a, 256 | .ui-widget-content .ui-state-highlight a, 257 | .ui-widget-header .ui-state-highlight a { 258 | color: #363636; 259 | } 260 | .ui-state-error, 261 | .ui-widget-content .ui-state-error, 262 | .ui-widget-header .ui-state-error { 263 | border: 1px solid #cd0a0a; 264 | background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; 265 | color: #ffffff; 266 | } 267 | .ui-state-error a, 268 | .ui-widget-content .ui-state-error a, 269 | .ui-widget-header .ui-state-error a { 270 | color: #ffffff; 271 | } 272 | .ui-state-error-text, 273 | .ui-widget-content .ui-state-error-text, 274 | .ui-widget-header .ui-state-error-text { 275 | color: #ffffff; 276 | } 277 | .ui-priority-primary, 278 | .ui-widget-content .ui-priority-primary, 279 | .ui-widget-header .ui-priority-primary { 280 | font-weight: bold; 281 | } 282 | .ui-priority-secondary, 283 | .ui-widget-content .ui-priority-secondary, 284 | .ui-widget-header .ui-priority-secondary { 285 | opacity: .7; 286 | filter:Alpha(Opacity=70); 287 | font-weight: normal; 288 | } 289 | .ui-state-disabled, 290 | .ui-widget-content .ui-state-disabled, 291 | .ui-widget-header .ui-state-disabled { 292 | opacity: .35; 293 | filter:Alpha(Opacity=35); 294 | background-image: none; 295 | } 296 | .ui-state-disabled .ui-icon { 297 | filter:Alpha(Opacity=35); /* For IE8 - See #6059 */ 298 | } 299 | 300 | /* Icons 301 | ----------------------------------*/ 302 | 303 | /* states and images */ 304 | .ui-icon { 305 | width: 16px; 306 | height: 16px; 307 | } 308 | .ui-icon, 309 | .ui-widget-content .ui-icon { 310 | background-image: url(images/ui-icons_222222_256x240.png); 311 | } 312 | .ui-widget-header .ui-icon { 313 | background-image: url(images/ui-icons_ffffff_256x240.png); 314 | } 315 | .ui-state-default .ui-icon { 316 | background-image: url(images/ui-icons_ef8c08_256x240.png); 317 | } 318 | .ui-state-hover .ui-icon, 319 | .ui-state-focus .ui-icon { 320 | background-image: url(images/ui-icons_ef8c08_256x240.png); 321 | } 322 | .ui-state-active .ui-icon { 323 | background-image: url(images/ui-icons_ef8c08_256x240.png); 324 | } 325 | .ui-state-highlight .ui-icon { 326 | background-image: url(images/ui-icons_228ef1_256x240.png); 327 | } 328 | .ui-state-error .ui-icon, 329 | .ui-state-error-text .ui-icon { 330 | background-image: url(images/ui-icons_ffd27a_256x240.png); 331 | } 332 | 333 | /* positioning */ 334 | .ui-icon-blank { background-position: 16px 16px; } 335 | .ui-icon-carat-1-n { background-position: 0 0; } 336 | .ui-icon-carat-1-ne { background-position: -16px 0; } 337 | .ui-icon-carat-1-e { background-position: -32px 0; } 338 | .ui-icon-carat-1-se { background-position: -48px 0; } 339 | .ui-icon-carat-1-s { background-position: -64px 0; } 340 | .ui-icon-carat-1-sw { background-position: -80px 0; } 341 | .ui-icon-carat-1-w { background-position: -96px 0; } 342 | .ui-icon-carat-1-nw { background-position: -112px 0; } 343 | .ui-icon-carat-2-n-s { background-position: -128px 0; } 344 | .ui-icon-carat-2-e-w { background-position: -144px 0; } 345 | .ui-icon-triangle-1-n { background-position: 0 -16px; } 346 | .ui-icon-triangle-1-ne { background-position: -16px -16px; } 347 | .ui-icon-triangle-1-e { background-position: -32px -16px; } 348 | .ui-icon-triangle-1-se { background-position: -48px -16px; } 349 | .ui-icon-triangle-1-s { background-position: -64px -16px; } 350 | .ui-icon-triangle-1-sw { background-position: -80px -16px; } 351 | .ui-icon-triangle-1-w { background-position: -96px -16px; } 352 | .ui-icon-triangle-1-nw { background-position: -112px -16px; } 353 | .ui-icon-triangle-2-n-s { background-position: -128px -16px; } 354 | .ui-icon-triangle-2-e-w { background-position: -144px -16px; } 355 | .ui-icon-arrow-1-n { background-position: 0 -32px; } 356 | .ui-icon-arrow-1-ne { background-position: -16px -32px; } 357 | .ui-icon-arrow-1-e { background-position: -32px -32px; } 358 | .ui-icon-arrow-1-se { background-position: -48px -32px; } 359 | .ui-icon-arrow-1-s { background-position: -64px -32px; } 360 | .ui-icon-arrow-1-sw { background-position: -80px -32px; } 361 | .ui-icon-arrow-1-w { background-position: -96px -32px; } 362 | .ui-icon-arrow-1-nw { background-position: -112px -32px; } 363 | .ui-icon-arrow-2-n-s { background-position: -128px -32px; } 364 | .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } 365 | .ui-icon-arrow-2-e-w { background-position: -160px -32px; } 366 | .ui-icon-arrow-2-se-nw { background-position: -176px -32px; } 367 | .ui-icon-arrowstop-1-n { background-position: -192px -32px; } 368 | .ui-icon-arrowstop-1-e { background-position: -208px -32px; } 369 | .ui-icon-arrowstop-1-s { background-position: -224px -32px; } 370 | .ui-icon-arrowstop-1-w { background-position: -240px -32px; } 371 | .ui-icon-arrowthick-1-n { background-position: 0 -48px; } 372 | .ui-icon-arrowthick-1-ne { background-position: -16px -48px; } 373 | .ui-icon-arrowthick-1-e { background-position: -32px -48px; } 374 | .ui-icon-arrowthick-1-se { background-position: -48px -48px; } 375 | .ui-icon-arrowthick-1-s { background-position: -64px -48px; } 376 | .ui-icon-arrowthick-1-sw { background-position: -80px -48px; } 377 | .ui-icon-arrowthick-1-w { background-position: -96px -48px; } 378 | .ui-icon-arrowthick-1-nw { background-position: -112px -48px; } 379 | .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } 380 | .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } 381 | .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } 382 | .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } 383 | .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } 384 | .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } 385 | .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } 386 | .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } 387 | .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } 388 | .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } 389 | .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } 390 | .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } 391 | .ui-icon-arrowreturn-1-w { background-position: -64px -64px; } 392 | .ui-icon-arrowreturn-1-n { background-position: -80px -64px; } 393 | .ui-icon-arrowreturn-1-e { background-position: -96px -64px; } 394 | .ui-icon-arrowreturn-1-s { background-position: -112px -64px; } 395 | .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } 396 | .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } 397 | .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } 398 | .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } 399 | .ui-icon-arrow-4 { background-position: 0 -80px; } 400 | .ui-icon-arrow-4-diag { background-position: -16px -80px; } 401 | .ui-icon-extlink { background-position: -32px -80px; } 402 | .ui-icon-newwin { background-position: -48px -80px; } 403 | .ui-icon-refresh { background-position: -64px -80px; } 404 | .ui-icon-shuffle { background-position: -80px -80px; } 405 | .ui-icon-transfer-e-w { background-position: -96px -80px; } 406 | .ui-icon-transferthick-e-w { background-position: -112px -80px; } 407 | .ui-icon-folder-collapsed { background-position: 0 -96px; } 408 | .ui-icon-folder-open { background-position: -16px -96px; } 409 | .ui-icon-document { background-position: -32px -96px; } 410 | .ui-icon-document-b { background-position: -48px -96px; } 411 | .ui-icon-note { background-position: -64px -96px; } 412 | .ui-icon-mail-closed { background-position: -80px -96px; } 413 | .ui-icon-mail-open { background-position: -96px -96px; } 414 | .ui-icon-suitcase { background-position: -112px -96px; } 415 | .ui-icon-comment { background-position: -128px -96px; } 416 | .ui-icon-person { background-position: -144px -96px; } 417 | .ui-icon-print { background-position: -160px -96px; } 418 | .ui-icon-trash { background-position: -176px -96px; } 419 | .ui-icon-locked { background-position: -192px -96px; } 420 | .ui-icon-unlocked { background-position: -208px -96px; } 421 | .ui-icon-bookmark { background-position: -224px -96px; } 422 | .ui-icon-tag { background-position: -240px -96px; } 423 | .ui-icon-home { background-position: 0 -112px; } 424 | .ui-icon-flag { background-position: -16px -112px; } 425 | .ui-icon-calendar { background-position: -32px -112px; } 426 | .ui-icon-cart { background-position: -48px -112px; } 427 | .ui-icon-pencil { background-position: -64px -112px; } 428 | .ui-icon-clock { background-position: -80px -112px; } 429 | .ui-icon-disk { background-position: -96px -112px; } 430 | .ui-icon-calculator { background-position: -112px -112px; } 431 | .ui-icon-zoomin { background-position: -128px -112px; } 432 | .ui-icon-zoomout { background-position: -144px -112px; } 433 | .ui-icon-search { background-position: -160px -112px; } 434 | .ui-icon-wrench { background-position: -176px -112px; } 435 | .ui-icon-gear { background-position: -192px -112px; } 436 | .ui-icon-heart { background-position: -208px -112px; } 437 | .ui-icon-star { background-position: -224px -112px; } 438 | .ui-icon-link { background-position: -240px -112px; } 439 | .ui-icon-cancel { background-position: 0 -128px; } 440 | .ui-icon-plus { background-position: -16px -128px; } 441 | .ui-icon-plusthick { background-position: -32px -128px; } 442 | .ui-icon-minus { background-position: -48px -128px; } 443 | .ui-icon-minusthick { background-position: -64px -128px; } 444 | .ui-icon-close { background-position: -80px -128px; } 445 | .ui-icon-closethick { background-position: -96px -128px; } 446 | .ui-icon-key { background-position: -112px -128px; } 447 | .ui-icon-lightbulb { background-position: -128px -128px; } 448 | .ui-icon-scissors { background-position: -144px -128px; } 449 | .ui-icon-clipboard { background-position: -160px -128px; } 450 | .ui-icon-copy { background-position: -176px -128px; } 451 | .ui-icon-contact { background-position: -192px -128px; } 452 | .ui-icon-image { background-position: -208px -128px; } 453 | .ui-icon-video { background-position: -224px -128px; } 454 | .ui-icon-script { background-position: -240px -128px; } 455 | .ui-icon-alert { background-position: 0 -144px; } 456 | .ui-icon-info { background-position: -16px -144px; } 457 | .ui-icon-notice { background-position: -32px -144px; } 458 | .ui-icon-help { background-position: -48px -144px; } 459 | .ui-icon-check { background-position: -64px -144px; } 460 | .ui-icon-bullet { background-position: -80px -144px; } 461 | .ui-icon-radio-on { background-position: -96px -144px; } 462 | .ui-icon-radio-off { background-position: -112px -144px; } 463 | .ui-icon-pin-w { background-position: -128px -144px; } 464 | .ui-icon-pin-s { background-position: -144px -144px; } 465 | .ui-icon-play { background-position: 0 -160px; } 466 | .ui-icon-pause { background-position: -16px -160px; } 467 | .ui-icon-seek-next { background-position: -32px -160px; } 468 | .ui-icon-seek-prev { background-position: -48px -160px; } 469 | .ui-icon-seek-end { background-position: -64px -160px; } 470 | .ui-icon-seek-start { background-position: -80px -160px; } 471 | /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ 472 | .ui-icon-seek-first { background-position: -80px -160px; } 473 | .ui-icon-stop { background-position: -96px -160px; } 474 | .ui-icon-eject { background-position: -112px -160px; } 475 | .ui-icon-volume-off { background-position: -128px -160px; } 476 | .ui-icon-volume-on { background-position: -144px -160px; } 477 | .ui-icon-power { background-position: 0 -176px; } 478 | .ui-icon-signal-diag { background-position: -16px -176px; } 479 | .ui-icon-signal { background-position: -32px -176px; } 480 | .ui-icon-battery-0 { background-position: -48px -176px; } 481 | .ui-icon-battery-1 { background-position: -64px -176px; } 482 | .ui-icon-battery-2 { background-position: -80px -176px; } 483 | .ui-icon-battery-3 { background-position: -96px -176px; } 484 | .ui-icon-circle-plus { background-position: 0 -192px; } 485 | .ui-icon-circle-minus { background-position: -16px -192px; } 486 | .ui-icon-circle-close { background-position: -32px -192px; } 487 | .ui-icon-circle-triangle-e { background-position: -48px -192px; } 488 | .ui-icon-circle-triangle-s { background-position: -64px -192px; } 489 | .ui-icon-circle-triangle-w { background-position: -80px -192px; } 490 | .ui-icon-circle-triangle-n { background-position: -96px -192px; } 491 | .ui-icon-circle-arrow-e { background-position: -112px -192px; } 492 | .ui-icon-circle-arrow-s { background-position: -128px -192px; } 493 | .ui-icon-circle-arrow-w { background-position: -144px -192px; } 494 | .ui-icon-circle-arrow-n { background-position: -160px -192px; } 495 | .ui-icon-circle-zoomin { background-position: -176px -192px; } 496 | .ui-icon-circle-zoomout { background-position: -192px -192px; } 497 | .ui-icon-circle-check { background-position: -208px -192px; } 498 | .ui-icon-circlesmall-plus { background-position: 0 -208px; } 499 | .ui-icon-circlesmall-minus { background-position: -16px -208px; } 500 | .ui-icon-circlesmall-close { background-position: -32px -208px; } 501 | .ui-icon-squaresmall-plus { background-position: -48px -208px; } 502 | .ui-icon-squaresmall-minus { background-position: -64px -208px; } 503 | .ui-icon-squaresmall-close { background-position: -80px -208px; } 504 | .ui-icon-grip-dotted-vertical { background-position: 0 -224px; } 505 | .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } 506 | .ui-icon-grip-solid-vertical { background-position: -32px -224px; } 507 | .ui-icon-grip-solid-horizontal { background-position: -48px -224px; } 508 | .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } 509 | .ui-icon-grip-diagonal-se { background-position: -80px -224px; } 510 | 511 | 512 | /* Misc visuals 513 | ----------------------------------*/ 514 | 515 | /* Corner radius */ 516 | .ui-corner-all, 517 | .ui-corner-top, 518 | .ui-corner-left, 519 | .ui-corner-tl { 520 | border-top-left-radius: 4px; 521 | } 522 | .ui-corner-all, 523 | .ui-corner-top, 524 | .ui-corner-right, 525 | .ui-corner-tr { 526 | border-top-right-radius: 4px; 527 | } 528 | .ui-corner-all, 529 | .ui-corner-bottom, 530 | .ui-corner-left, 531 | .ui-corner-bl { 532 | border-bottom-left-radius: 4px; 533 | } 534 | .ui-corner-all, 535 | .ui-corner-bottom, 536 | .ui-corner-right, 537 | .ui-corner-br { 538 | border-bottom-right-radius: 4px; 539 | } 540 | 541 | /* Overlays */ 542 | .ui-widget-overlay { 543 | background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; 544 | opacity: .5; 545 | filter: Alpha(Opacity=50); 546 | } 547 | .ui-widget-shadow { 548 | margin: -5px 0 0 -5px; 549 | padding: 5px; 550 | background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; 551 | opacity: .2; 552 | filter: Alpha(Opacity=20); 553 | border-radius: 5px; 554 | } 555 | -------------------------------------------------------------------------------- /example/lib/jquery-ui/css/ui-lightness/jquery-ui-1.10.2.custom.min.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.10.2 - 2013-03-22 2 | * http://jqueryui.com 3 | * Includes: jquery.ui.core.css, jquery.ui.autocomplete.css, jquery.ui.menu.css 4 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=gloss_wave&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=highlight_soft&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=glass&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=glass&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=diagonals_thick&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=diagonals_thick&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px 5 | * Copyright 2013 jQuery Foundation and other contributors Licensed MIT */.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:0}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;width:100%}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;min-height:0;font-weight:400}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:400;margin:-1px}.ui-menu .ui-state-disabled{font-weight:400;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right}.ui-widget{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #ddd;background:#eee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #e78f08;background:#f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x;color:#fff;font-weight:bold}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #ccc;background:#f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x;font-weight:bold;color:#1c94c4}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#1c94c4;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #fbcb09;background:#fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x;font-weight:bold;color:#c77405}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited{color:#c77405;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #fbd850;background:#fff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;font-weight:bold;color:#eb8f00}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#eb8f00;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fed22f;background:#ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat;color:#fff}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#fff}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#fff}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-header .ui-icon{background-image:url(images/ui-icons_ffffff_256x240.png)}.ui-state-default .ui-icon{background-image:url(images/ui-icons_ef8c08_256x240.png)}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(images/ui-icons_ef8c08_256x240.png)}.ui-state-active .ui-icon{background-image:url(images/ui-icons_ef8c08_256x240.png)}.ui-state-highlight .ui-icon{background-image:url(images/ui-icons_228ef1_256x240.png)}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(images/ui-icons_ffd27a_256x240.png)}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat;opacity:.5;filter:Alpha(Opacity=50)}.ui-widget-shadow{margin:-5px 0 0 -5px;padding:5px;background:#000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x;opacity:.2;filter:Alpha(Opacity=20);border-radius:5px} -------------------------------------------------------------------------------- /example/lib/prism.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Prism: Lightweight, robust, elegant syntax highlighting 3 | * MIT license http://www.opensource.org/licenses/mit-license.php/ 4 | * @author Lea Verou http://lea.verou.me 5 | */(function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},clone:function(e){var n=t.util.type(e);switch(n){case"Object":var r={};for(var i in e)e.hasOwnProperty(i)&&(r[i]=t.util.clone(e[i]));return r;case"Array":return e.slice()}return e}},languages:{extend:function(e,n){var r=t.util.clone(t.languages[e]);for(var i in n)r[i]=n[i];return r},insertBefore:function(e,n,r,i){i=i||t.languages;var s=i[e],o={};for(var u in s)if(s.hasOwnProperty(u)){if(u==n)for(var a in r)r.hasOwnProperty(a)&&(o[a]=r[a]);o[u]=s[u]}return i[e]=o},DFS:function(e,n){for(var r in e){n.call(e,r,e[r]);t.util.type(e)==="Object"&&t.languages.DFS(e[r],n)}}},highlightAll:function(e,n){var r=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');for(var i=0,s;s=r[i++];)t.highlightElement(s,e===!0,n)},highlightElement:function(r,i,s){var o,u,a=r;while(a&&!e.test(a.className))a=a.parentNode;if(a){o=(a.className.match(e)||[,""])[1];u=t.languages[o]}if(!u)return;r.className=r.className.replace(e,"").replace(/\s+/g," ")+" language-"+o;a=r.parentNode;/pre/i.test(a.nodeName)&&(a.className=a.className.replace(e,"").replace(/\s+/g," ")+" language-"+o);var f=r.textContent;if(!f)return;f=f.replace(/&/g,"&").replace(//g,">").replace(/\u00a0/g," ");var l={element:r,language:o,grammar:u,code:f};t.hooks.run("before-highlight",l);if(i&&self.Worker){var c=new Worker(t.filename);c.onmessage=function(e){l.highlightedCode=n.stringify(JSON.parse(e.data));l.element.innerHTML=l.highlightedCode;s&&s.call(l.element);t.hooks.run("after-highlight",l)};c.postMessage(JSON.stringify({language:l.language,code:l.code}))}else{l.highlightedCode=t.highlight(l.code,l.grammar);l.element.innerHTML=l.highlightedCode;s&&s.call(r);t.hooks.run("after-highlight",l)}},highlight:function(e,r){return n.stringify(t.tokenize(e,r))},tokenize:function(e,n){var r=t.Token,i=[e],s=n.rest;if(s){for(var o in s)n[o]=s[o];delete n.rest}e:for(var o in n){if(!n.hasOwnProperty(o)||!n[o])continue;var u=n[o],a=u.inside,f=!!u.lookbehind||0;u=u.pattern||u;for(var l=0;le.length)break e;if(c instanceof r)continue;u.lastIndex=0;var h=u.exec(c);if(h){f&&(f=h[1].length);var p=h.index-1+f,h=h[0].slice(f),d=h.length,v=p+d,m=c.slice(0,p+1),g=c.slice(v+1),y=[l,1];m&&y.push(m);var b=new r(o,a?t.tokenize(h,a):h);y.push(b);g&&y.push(g);Array.prototype.splice.apply(i,y)}}}return i},hooks:{all:{},add:function(e,n){var r=t.hooks.all;r[e]=r[e]||[];r[e].push(n)},run:function(e,n){var r=t.hooks.all[e];if(!r||!r.length)return;for(var i=0,s;s=r[i++];)s(n)}}},n=t.Token=function(e,t){this.type=e;this.content=t};n.stringify=function(e){if(typeof e=="string")return e;if(Object.prototype.toString.call(e)=="[object Array]")return e.map(n.stringify).join("");var r={type:e.type,content:n.stringify(e.content),tag:"span",classes:["token",e.type],attributes:{}};r.type=="comment"&&(r.attributes.spellcheck="true");t.hooks.run("wrap",r);var i="";for(var s in r.attributes)i+=s+'="'+(r.attributes[s]||"")+'"';return"<"+r.tag+' class="'+r.classes.join(" ")+'" '+i+">"+r.content+""};if(!self.document){self.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,i=n.code;self.postMessage(JSON.stringify(t.tokenize(i,t.languages[r])));self.close()},!1);return}var r=document.getElementsByTagName("script");r=r[r.length-1];if(r){t.filename=r.src;document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)}})();; 6 | Prism.languages.markup={comment:/<!--[\w\W]*?--(>|>)/g,prolog:/<\?.+?\?>/,doctype:/<!DOCTYPE.+?>/,cdata:/<!\[CDATA\[[\w\W]+?]]>/i,tag:{pattern:/<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|\w+))?\s*)*\/?>/gi,inside:{tag:{pattern:/^<\/?[\w:-]+/i,inside:{punctuation:/^<\/?/,namespace:/^[\w-]+?:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi,inside:{punctuation:/=|>|"/g}},punctuation:/\/?>/g,"attr-name":{pattern:/[\w:-]+/g,inside:{namespace:/^[\w-]+?:/}}}},entity:/&#?[\da-z]{1,8};/gi};Prism.hooks.add("wrap",function(e){e.type==="entity"&&(e.attributes.title=e.content.replace(/&/,"&"))});; 7 | Prism.languages.css={comment:/\/\*[\w\W]*?\*\//g,atrule:/@[\w-]+?(\s+[^;{]+)?(?=\s*{|\s*;)/gi,url:/url\((["']?).*?\1\)/gi,selector:/[^\{\}\s][^\{\}]*(?=\s*\{)/g,property:/(\b|\B)[a-z-]+(?=\s*:)/ig,string:/("|')(\\?.)*?\1/g,important:/\B!important\b/gi,ignore:/&(lt|gt|amp);/gi,punctuation:/[\{\};:]/g};Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{style:{pattern:/(<|<)style[\w\W]*?(>|>)[\w\W]*?(<|<)\/style(>|>)/ig,inside:{tag:{pattern:/(<|<)style[\w\W]*?(>|>)|(<|<)\/style(>|>)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.css}}});; 8 | Prism.languages.clike={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|[^:]\/\/.*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|catch|finally|null|break|continue)\b/g,"boolean":/\b(true|false)\b/g,number:/\b-?(0x)?\d*\.?[\da-f]+\b/g,operator:/[-+]{1,2}|!|=?<|=?>|={1,2}|(&){1,2}|\|?\||\?|\*|\//g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};; 9 | Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(var|let|if|else|while|do|for|return|in|instanceof|function|new|with|typeof|try|catch|finally|null|break|continue)\b/g,number:/\b(-?(0x)?\d*\.?[\da-f]+|NaN|-?Infinity)\b/g});Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,lookbehind:!0}});Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/(<|<)script[\w\W]*?(>|>)[\w\W]*?(<|<)\/script(>|>)/ig,inside:{tag:{pattern:/(<|<)script[\w\W]*?(>|>)|(<|<)\/script(>|>)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript}}});; 10 | -------------------------------------------------------------------------------- /jquery.timeAutocomplete.min.js: -------------------------------------------------------------------------------- 1 | (function(t){var e="timeAutocomplete",i=e+".time",o=function(){this.initialize.apply(this,arguments)};o.prototype={el:null,_formatter:null,_calling_from_init:!1,default_opts:{auto_complete:{delay:0,autoFocus:!0,minLength:0},auto_value:!0,value:"",formatter:"ampm"},initialize:function(e,i){this.options=t.extend(!0,{},this.default_opts,i),t.timeAutocompleteDefaults!==void 0&&(this.options=t.extend(!0,{},this.options,t.timeAutocompleteDefaults)),this.el=e},_callAutocomplete:function(){if(this.options.auto_complete.source=this._callFormatterMethod("filterSource",[this.el],function(){throw Error("You must set a hook_filterSource method in your formatter.")}),t.fn.autocomplete===void 0)throw Error("You need to include the jQuery UI bundle that has the Autocomplete plugin.");this.el.autocomplete(this.options.auto_complete)},_bindEvents:function(){var i=this,o=!0;t("body").on("click."+e,"ul.ui-autocomplete a",function(){o=!1,setTimeout(function(){o=!0},100)}),this.el.bind("keydown."+e,function(){i._keydownAutocomplete.apply(i,arguments)}).bind("keyup."+e,function(){i._keyupAutocomplete.apply(i,arguments)}).bind("blur."+e,function(){i._blurAutocomplete.apply(i,arguments)}).bind("focus."+e,function(){o&&i._focusAutocomplete.apply(i,arguments)}),this.options.auto_value&&this.el.trigger("blur."+e)},_setupPlaceholder:function(){this.el.attr("placeholder")===void 0&&this.el.attr("placeholder",this._callFormatterMethod("placeholderValue",[],""))},_focusAutocomplete:function(){var e=t.trim(this.el.val()).substr(0,2);this.el.data("uiAutocomplete")&&this.el.autocomplete("search",e)},_keydownAutocomplete:function(e){var i=t.trim(this.el.val()),o=[8,9,13,38,40];if(!~t.inArray(e.which,o)&&(8==e.which||i.length>1&&!~i.indexOf("h")&&!~i.indexOf(":")&&t.isNumeric(i)))try{this.el.autocomplete("close").autocomplete("disable")}catch(e){}},_keyupAutocomplete:function(){""==t.trim(this.el.val())&&this.el.data("uiAutocomplete")&&this.el.autocomplete("enable")},_blurAutocomplete:function(){var e=t.trim(this.el.val());e=this._callFormatterMethod("blur",[e],e);var i="";i=e?this._createStringFromFormat(this._readMind(e)):this._callFormatterMethod("blurEmpty",[e],e),this.el.val(i),this._attacheUsableTimeData()},_attacheUsableTimeData:function(){var e=t.trim(this.el.val());this.el.data(i,this._callFormatterMethod("getUsableTimeValue",[e]))},setFormatter:function(e){if(this.options.formatter=e||this.options.formatter,!t.timeAutocomplete.formatters[this.options.formatter])throw Error("Formatter: '"+e+"' was not found. Make sure you're loading it (formatters/"+this.options.formatter+".js) after you load src/TimeAutocomplete.js");this._formatter=new t.timeAutocomplete.formatters[this.options.formatter](this,this.options),this._calling_from_init||this._callAutocomplete(),this._calling_from_init=!1},getFormatter:function(){return this._formatter},getTime:function(){return this.el.data(i)||""},_callFormatterMethod:function(e,i,o){var s=this.getFormatter();return t.isFunction(s["hook_"+e])?s["hook_"+e].apply(s,i):o},_readMind:function(t){return this._callFormatterMethod("readMind",[t],t)},_createStringFromFormat:function(t){var e=""+t.h+t.sep+(""+t.m);return t.postfix&&(e+=t.postfix),e},_setValueAsTime:function(){var e=t.trim(this.el.val()),i=e.split(":");if(""==e&&this.options.value)this.setTime(this.options.value);else if(3==i.length&&this.isNumber(i[0])&&this.isNumber(i[1])&&this.isNumber(i[2]))this.setTime(e);else{var o=this._getCurrentTimeAsValue();this.el.val(o),this._attacheUsableTimeData()}},isNumber:function(t){return!isNaN(parseFloat(t))&&isFinite(t)},setTime:function(t){var e=t.replace(/[^0-9.]/g,""),i=e.match(/^[0-9]+$/);if(!i||!i.length||5!=i[0].length&&6!=i[0].length)throw Error("Setting a time must be in H:i:s format. Example: 03:30:00");var o=this._callFormatterMethod("getTimeObjectFromHis",[t]);o=this._createStringFromFormat(o),this.el.val(o),this._attacheUsableTimeData()},_getCurrentTimeAsValue:function(){for(var e=this.getFormatter(),i=[1987,1,17],o=this._getCurrentDate(),s=o.getHours(),n=o.getMinutes(),r=new Date(i[0],i[1],i[2],s,n).getTime(),a=e.options.times.slice().concat(e.options.times),p=[],m=0,h=a.length;h>m;m++){var l=this._callFormatterMethod("getTime",[a[m],i]),u=a[m+1]?this._callFormatterMethod("getTime",[a[m+1],i]):!1,c=!(-1===t.inArray(u,p));if(p.push(u),r>l&&(u&&u>=r||c))return a[m+1]}},_getCurrentDate:function(){return new Date},destroy:function(){this.el.removeData(e),this.el.removeData(i),this.el.unbind("."+e),this.el.data("uiAutocomplete")&&this.el.autocomplete("destroy")},render:function(){return this._calling_from_init=!0,this.setFormatter(),this._callAutocomplete(),this.options.auto_value&&this._setValueAsTime(),this._bindEvents(),this._setupPlaceholder(),this}},t.timeAutocomplete={formatters:{},_raw:o},t.fn.timeAutocomplete=function(i){return this.each(function(){var s=t(this);s.data(e)&&s.data(e).destroy();var n=new o(s,i).render();s.data(e,n)})}})(jQuery),function(t){t.timeAutocomplete.formatters.ampm=function(){this.initialize.apply(this,arguments)},t.timeAutocomplete.formatters.ampm.prototype={main_instance:null,options:{},default_opts:{from_selector:"",increment:15,start_hour:0,end_hour:24,pm_text:"PM",am_text:"AM",blur_empty_populate:!0,times:[],empty:{h:"12",m:"00",sep:":",postfix:" PM"}},initialize:function(e,i){this.main_instance=e,this.options=t.extend(!0,{},this.default_opts,i),this.generateTimes()},hook_placeholderValue:function(){return this.main_instance._createStringFromFormat(this.options.empty)},hook_filterSource:function(e){var i=this;return e=e[0],function(i,o){return function(s,n){var r=t.trim(e.value),a=t.ui.autocomplete.escapeRegex(s.term),p=~a.toLowerCase().indexOf("a"),m=~a.toLowerCase().indexOf("p"),h="",l=!(1!=r),u=(p||m)&&2>=a.replace(/a|m|p/gi,"").length;u&&(a=t.trim(a.replace(/a|m|p/gi,""))+":00 ",a+=p?o.options.am_text:o.options.pm_text),o.options.from_selector&&(h=o.detectAMPMFromInstanceOverlap()==o.options.am_text?o.options.pm_text:o.options.am_text);var c=RegExp("^"+a,"i"),f=[];r&&(f=t.grep(i,function(t){var e=h&&RegExp(h,"gi").test(t)||l&&"1:"!=t.substring(0,2)||~r.toLowerCase().indexOf("p")&&!~t.toLowerCase().indexOf("p")||~r.toLowerCase().indexOf("a")&&!~t.toLowerCase().indexOf("a");if(!e)return c.test(t)})),n(f)}}(i.options.times,i)},hook_blur:function(t){return 0==t.charAt(0)&&(t=t.substr(1)),t},hook_blurEmpty:function(){return this.options.blur_empty_populate?this.main_instance._createStringFromFormat(this.options.empty):""},hook_readMind:function(t){var e="";return t=t.toLowerCase(),!this.options.from_selector||~t.indexOf("a")||~t.indexOf("p")||(e=this.detectAMPMFromInstanceOverlap()),this.getTimeObject(t,e)},hook_getUsableTimeValue:function(t){return this.parseTime(t)},hook_getTime:function(t,e){var i=this.parseTime(t).split(this.options.empty.sep),o=i[0],s=i[1];return new Date(e[0],e[1],e[2],o,s).getTime()},hook_getTimeObjectFromHis:function(t){var e=t.split(":"),i=e[0],o=e[1],s=i>=12?this.options.pm_text:this.options.am_text;2==i.length&&10>parseInt(i,10)&&(i=i.substr(1)),i>12&&(i-=12),0==i&&(i=12);var n={h:parseInt(i,10),m:o,sep:this.options.empty.sep,postfix:" "+s};return n},detectAMPMFromInstanceOverlap:function(){var e="",i=this.getTimeObject(t(this.options.from_selector).val()),o=this.getTimeObject(t.trim(this.main_instance.el.val()));if(i.postfix&&(~i.postfix.toLowerCase().indexOf("a")||~i.postfix.toLowerCase().indexOf("p"))){var s=~i.postfix.toLowerCase().indexOf("a")?this.options.am_text:this.options.pm_text,n=o.h,r=i.h;e=12==r&&12!=n?s==this.options.am_text?this.options.am_text:this.options.pm_text:12==n&&12!=r?s==this.options.am_text?this.options.pm_text:this.options.am_text:r>n?s==this.options.am_text?this.options.pm_text:this.options.am_text:s==this.options.am_text?this.options.am_text:this.options.pm_text}return e},getTimeObject:function(t,e){var i,o=this.parseTime(t,"g:i:A").split(":"),s=o[0],n=o[1];return i=s||n?{h:s,m:n,sep:":",postfix:" "+(e?e:o[2])}:this.options.empty},generateTimes:function(){if(!this.options.times.length){var t=60,e=this.options.increment,i=new Date(2012,1,1,this.options.start_hour-1,t-e),o=[],s=60,n=this.options.end_hour,r=n-this.options.start_hour,a=!1;24==r&&(a=!0);for(var p=0,m=r*(s/e);m>=p;p++){i.setMinutes(i.getMinutes()+e);var h=i.getHours(),l=i.getMinutes(),u=h>11?this.options.pm_text:this.options.am_text;0==h&&(h=12),h>12&&(h-=12),1==(""+l).length&&(l="0"+l);var c=h+":"+l+" "+u;o.push(c)}a&&o.pop(),this.options.times=o}},parseTime:function(t,e){var i,o,e=e||"H:i:s",s=null!==t.match(/p/i),n=null!==t.match(/a/i),r=t.replace(/[^0-9]/g,"");switch(r.length){case 4:i=parseInt(r.charAt(0)+r.charAt(1),10),o=parseInt(r.charAt(2)+r.charAt(3),10);break;case 3:i=parseInt(r.charAt(0),10),o=parseInt(r.charAt(1)+r.charAt(2),10);break;case 2:case 1:i=parseInt(r.charAt(0)+(r.charAt(1)||""),10),o=0;break;default:return""}if(12==i&&s===!1&&n===!1?(i=12,s=!0):12==i&&s===!1?i=0:s===!0&&i>0&&12>i&&(i+=12),0>=i&&(i=0),i>=24&&2==(""+i).length){var a=(""+i).split("");i=parseInt(a[0],10),o=parseInt(a[1],10),6>o&&(o+="0")}return(0>o||o>59)&&(o=0),i>=13&&23>=i&&(s=!0),e.replace(/g/g,0===i?"12":"g").replace(/g/g,i>12?i-12:i).replace(/h/g,(""+i).length>1?i>12?i-12:i:"0"+(i>12?i-12:i)).replace(/H/g,(""+i).length>1?i:"0"+i).replace(/i/g,(""+o).length>1?o:"0"+o).replace(/s/g,"00").replace(/A/g,s?this.options.pm_text:this.options.am_text)}}}(jQuery),function(t){t.timeAutocomplete.formatters["24hr"]=function(){this.initialize.apply(this,arguments)},t.timeAutocomplete.formatters["24hr"].prototype={main_instance:null,options:{},default_opts:{increment:15,start_hour:"00",hour_max:24,blur_empty_populate:!0,times:[],empty:{h:"12",m:"00",sep:":",postfix:""}},initialize:function(e,i){this.main_instance=e,this.options=t.extend(!0,{},this.default_opts,i),this.generateTimes()},hook_placeholderValue:function(){return this.main_instance._createStringFromFormat(this.options.empty)},hook_getTime:function(t,e){var i=t.split(this.options.empty.sep),o=i[0],s=i[1];return new Date(e[0],e[1],e[2],o,s).getTime()},hook_getTimeObjectFromHis:function(t){var e=t.split(":"),i=e[0],o=e[1],s={h:i,m:o,sep:this.options.empty.sep};return s},hook_filterSource:function(e){var i=this;return e=e[0],function(i,o){return function(s,n){var r=t.trim(e.value);1==s.term.length&&10>s.term.substr(0,1)&&(s.term="0"+s.term);var a=t.ui.autocomplete.escapeRegex(s.term),p=RegExp("^"+a,"i"),m=[];r&&(m=t.grep(i,function(t){return 0==t.substr(0,1)&&1==t.length&&(t=t.substr(1)),p.test(t)})),n(m);var h=r.toLowerCase();!m.length&&h.length>5&&o.main_instance.el.val(h.substr(0,5))}}(i.options.times,i)},hook_blurEmpty:function(){return this.options.blur_empty_populate?this.main_instance._createStringFromFormat(this.options.empty):""},hook_readMind:function(t){return t=t.toLowerCase(),this.getTimeObject(t)},hook_getUsableTimeValue:function(t){return t+":00"},getTimeObject:function(t){var e="",i="",o="";if(~t.indexOf("h")){var s=t.split("h");e=s[0]?s[0]:this.options.empty.h,i=s[1]?s[1]:this.options.empty.m}else{var n=t.replace(/[^\d]/g,"");n=n.split(""),4==n.length?(e=n[0]+n[1],i=n[2]+n[3]):3==n.length?(e="0"+n[0],i=n[1]+n[2]):2==n.length?(e=n.join(""),i="00"):1==n.length&&(e=n.join(""),i="00")}return e>24&&"00"==i&&(e=e.split(""),i=e[1]+"0",e="0"+e[0]),1==e.length&&(e="0"+e),1==i.length&&(i+="0"),o=e||i?{h:e,m:i,sep:this.options.empty.sep}:this.options.empty},generateTimes:function(){if(!this.options.times.length){for(var t=60,e=this.options.increment,i=new Date(2012,1,1,this.options.start_hour-1,t-e),o=[],s=60,n=this.options.hour_max,r=0,a=n*(s/e);a>r;r++){i.setMinutes(i.getMinutes()+e);var p=i.getHours(),m=i.getMinutes();1==(""+p).length&&(p="0"+p),1==(""+m).length&&(m="0"+m);var h=p+this.options.empty.sep+m;o.push(h)}this.options.times=o}}}}(jQuery),function(t){t.timeAutocomplete.formatters.french=function(){this.initialize.apply(this,arguments)},t.timeAutocomplete.formatters.french.prototype=t.extend(!0,{},t.timeAutocomplete.formatters["24hr"].prototype,{default_opts:{empty:{sep:"h"}},hook_getUsableTimeValue:function(t){return t.replace(this.options.empty.sep,":")+":00"}})}(jQuery); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jQueryTimeAutocomplete", 3 | "title": "jQueryTimeAutocomplete", 4 | "description": "A time autocomplete plugin similar to how Google Calendar's time autocomplete works.", 5 | "version": "1.0.2", 6 | "homepage": "http://7shifts.com/blog/better-time-drop-downs-for-scheduling-jquery-timeautocomplete/", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/7shifts/jQueryTimeAutocomplete.git" 10 | }, 11 | "devDependencies": { 12 | "grunt": "0.4.1", 13 | "grunt-contrib-uglify": "0.2.0", 14 | "grunt-contrib-concat": "~0.3.0" 15 | } 16 | } -------------------------------------------------------------------------------- /src/formatters/24hr.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | 3 | $.timeAutocomplete.formatters['24hr'] = function(){ 4 | this.initialize.apply(this, arguments); 5 | }; 6 | 7 | $.timeAutocomplete.formatters['24hr'].prototype = { 8 | 9 | /* 10 | * The main instance that was created. Found on $('#el').data('timeAutocomplete') 11 | * of that specific element. Gets stuffed in on initialize(); 12 | */ 13 | main_instance: null, 14 | 15 | /* 16 | * These get merged in later. We take the default_opts and the formatter_opts from 17 | * initialize() and merge them into this options object. 18 | */ 19 | options: {}, 20 | 21 | /* 22 | * Some defaults to get over-ridden if needed. Can be done using 23 | * $('#el').timeAutocomplete({ formatter: '24hr' } }); 24 | */ 25 | default_opts: { 26 | increment: 15, 27 | start_hour: '00', 28 | hour_max: 24, 29 | blur_empty_populate: true, 30 | times: [], 31 | empty: { 32 | h: '12', 33 | m: '00', 34 | sep: ':', 35 | postfix: '' 36 | } 37 | }, 38 | 39 | /* 40 | * Initialize the formatter 41 | * 42 | * @param {Object} main_instance Instance of timeAutocomplete on that element 43 | * @param {Object} formatter_opts Any options passed... $('#el').timeAutocomplete({ formatter: 'ampm', from_selector: ... }); 44 | */ 45 | initialize: function(main_instance, formatter_opts){ 46 | 47 | this.main_instance = main_instance; 48 | this.options = $.extend(true, {}, this.default_opts, formatter_opts); 49 | this.generateTimes(); 50 | 51 | }, 52 | 53 | hook_placeholderValue: function(){ 54 | return this.main_instance._createStringFromFormat(this.options.empty); 55 | }, 56 | 57 | /* 58 | * Get the timestamp on a time value 59 | * 60 | * @param {String} t The time (2:00 PM) 61 | * @param {Array} fake_date_data [1987, 1, 17] 62 | */ 63 | hook_getTime: function(t, fake_date_data){ 64 | 65 | var time_parts = t.split(this.options.empty.sep); 66 | var h = time_parts[0]; 67 | var m = time_parts[1]; 68 | 69 | return (new Date(fake_date_data[0], fake_date_data[1], fake_date_data[2], h, m)).getTime(); 70 | 71 | }, 72 | 73 | /* 74 | * Get the H:is (13:30:00) time format and turn it into a time object 75 | * that we can pass back to the main view. 76 | * 77 | * @param {String} time_his 13:30:00 78 | */ 79 | hook_getTimeObjectFromHis: function(time_his){ 80 | 81 | var time = time_his.split(':'); 82 | var hour = time[0]; 83 | var min = time[1]; 84 | 85 | var time_obj = { 86 | h: hour, 87 | m: min, 88 | sep: this.options.empty.sep 89 | }; 90 | 91 | return time_obj; 92 | 93 | }, 94 | 95 | /* 96 | * Setup a filter when we type a key into this input. 97 | * 98 | * @param {Object} el The jQuery element 99 | */ 100 | hook_filterSource: function(el){ 101 | 102 | var self = this; 103 | el = el[0]; 104 | 105 | return (function(times, self){ 106 | return function(req, responseFn){ 107 | 108 | var self_val = $.trim(el.value); 109 | 110 | if(req.term.length == 1 && req.term.substr(0, 1) < 10){ 111 | req.term = '0' + req.term; 112 | } 113 | 114 | var re = $.ui.autocomplete.escapeRegex(req.term); 115 | 116 | var matcher = new RegExp("^" + re, "i"); 117 | var a = []; 118 | 119 | if(self_val){ 120 | a = $.grep(times, function(item){ 121 | 122 | if(item.substr(0, 1) == 0 && item.length == 1){ 123 | item = item.substr(1); 124 | } 125 | 126 | return matcher.test(item); 127 | }); 128 | } 129 | 130 | responseFn(a); 131 | 132 | var val = self_val.toLowerCase(); 133 | if(!a.length && val.length > 5){ 134 | // Should never be longer than 5 in french/24hr. Ie. 04h30 (5 characters), if it's longer, truncate it. 135 | self.main_instance.el.val(val.substr(0, 5)); 136 | } 137 | 138 | } 139 | })(self.options.times, self); 140 | }, 141 | 142 | /* 143 | * If we blurred and it was an empty value. 144 | */ 145 | hook_blurEmpty: function(){ 146 | 147 | if(this.options.blur_empty_populate){ 148 | return this.main_instance._createStringFromFormat(this.options.empty); 149 | } 150 | else { 151 | return ''; 152 | } 153 | 154 | }, 155 | 156 | /* 157 | * Where our formatting actually happens. 158 | * 159 | * @param {String} val The value we're formatting 160 | */ 161 | hook_readMind: function(val){ 162 | 163 | val = val.toLowerCase(); 164 | 165 | return this.getTimeObject(val); 166 | 167 | }, 168 | 169 | hook_getUsableTimeValue: function(val){ 170 | return val + ':00' 171 | }, 172 | 173 | /** 174 | * Format our numbers. 175 | * 176 | * @param {String} original_val The original value 177 | */ 178 | getTimeObject: function(original_val){ 179 | 180 | var h = ''; 181 | var m = ''; 182 | var new_num = ''; 183 | 184 | if(~original_val.indexOf('h')){ 185 | var parts = original_val.split('h'); 186 | h = (parts[0]) ? parts[0] : this.options.empty.h; // really? no hour. Must be jack-assery. 187 | m = (parts[1]) ? parts[1] : this.options.empty.m; 188 | } 189 | else { 190 | var numbers = original_val.replace(/[^\d]/g, ""); 191 | numbers = numbers.split(''); 192 | if(numbers.length == 4){ 193 | h = numbers[0] + numbers[1]; 194 | m = numbers[2] + numbers[3]; 195 | } 196 | else if(numbers.length == 3){ 197 | h = '0' + numbers[0]; 198 | m = numbers[1] + numbers[2]; 199 | } 200 | else if(numbers.length == 2){ 201 | h = numbers.join(''); 202 | m = '00'; 203 | } 204 | else if(numbers.length == 1){ 205 | h = numbers.join(''); 206 | m = '00'; 207 | } 208 | } 209 | 210 | // 91 entered.. format it to 09h10 211 | if(h > 24 && m == '00'){ 212 | h = h.split(''); 213 | m = h[1] + '0'; 214 | h = '0' + h[0]; 215 | } 216 | 217 | if(h.length == 1){ 218 | h = '0' + h; 219 | } 220 | 221 | if(m.length == 1){ 222 | m = m + '0'; 223 | } 224 | 225 | if(!h && !m){ 226 | new_num = this.options.empty; 227 | } 228 | else { 229 | new_num = { 230 | h: h, 231 | m: m, 232 | sep: this.options.empty.sep 233 | }; 234 | } 235 | 236 | return new_num; 237 | 238 | }, 239 | 240 | /* 241 | * Generate an array of times to pass to our autocomplete source. 242 | * ['12h00', '12h15'] etc. Totally depends on the increment options set. 243 | */ 244 | generateTimes: function(){ 245 | 246 | if(!this.options.times.length){ 247 | 248 | var start_minute = 60; 249 | var increment = this.options.increment; 250 | var date = new Date(2012, 1, 1, (this.options.start_hour - 1), (start_minute - increment)); 251 | var arr = []; 252 | var hour_len = 60; 253 | var hours = this.options.hour_max; 254 | 255 | for(var i = 0, loop_int = hours * (hour_len/increment); i < loop_int; i++){ 256 | 257 | date.setMinutes(date.getMinutes() + increment); 258 | var h = date.getHours(); 259 | var m = date.getMinutes(); 260 | 261 | if(("" + h).length == 1){ 262 | h = '0' + h; 263 | } 264 | 265 | if(("" + m).length == 1){ 266 | m = '0' + m; 267 | } 268 | 269 | var label = h + this.options.empty.sep + m; 270 | arr.push(label); 271 | } 272 | 273 | this.options.times = arr; 274 | } 275 | 276 | } 277 | 278 | }; 279 | 280 | })(jQuery); -------------------------------------------------------------------------------- /src/formatters/ampm.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | 3 | $.timeAutocomplete.formatters.ampm = function(){ 4 | this.initialize.apply(this, arguments); 5 | }; 6 | 7 | $.timeAutocomplete.formatters.ampm.prototype = { 8 | 9 | /* 10 | * The main instance that was created. Found on $('#el').data('timeAutocomplete') 11 | * of that specific element. Gets stuffed in on initialize(); 12 | */ 13 | main_instance: null, 14 | 15 | /* 16 | * These get merged in later. We take the default_opts and the formatter_opts from 17 | * initialize() and merge them into this options object. 18 | */ 19 | options: {}, 20 | 21 | /* 22 | * Some defaults to get over-ridden if needed. Can be done using 23 | * $('#el').timeAutocomplete({ formatter: 'ampm', from_selector: ... }); 24 | */ 25 | default_opts: { 26 | from_selector: '', 27 | increment: 15, 28 | start_hour: 0, 29 | end_hour: 24, 30 | pm_text: 'PM', 31 | am_text: 'AM', 32 | blur_empty_populate: true, 33 | times: [], // over-ride if not using built-in populator 34 | empty: { 35 | h: '12', 36 | m: '00', 37 | sep: ':', 38 | postfix: ' PM' 39 | } 40 | }, 41 | 42 | /* 43 | * Initialize the formatter. Called from within TimeAutocomplete file. 44 | * 45 | * @param {Object} main_instance Instance of timeAutocomplete on that element 46 | * @param {Object} formatter_opts Any options passed... $('#el').timeAutocomplete({ formatter: 'ampm', from_selector: ... }); 47 | */ 48 | initialize: function(main_instance, formatter_opts){ 49 | 50 | this.main_instance = main_instance; 51 | this.options = $.extend(true, {}, this.default_opts, formatter_opts); 52 | this.generateTimes(); 53 | 54 | }, 55 | 56 | hook_placeholderValue: function(){ 57 | return this.main_instance._createStringFromFormat(this.options.empty); 58 | }, 59 | 60 | /* 61 | * Setup a filter when we type a key into this input. 62 | * 63 | * @param {Object} el The jQuery element 64 | */ 65 | hook_filterSource: function(el){ 66 | 67 | var self = this; 68 | el = el[0]; 69 | 70 | return (function(times, self){ 71 | return function(req, responseFn){ 72 | 73 | var self_val = $.trim(el.value); 74 | var re = $.ui.autocomplete.escapeRegex(req.term); 75 | var has_am = ~re.toLowerCase().indexOf('a'); 76 | var has_pm = ~re.toLowerCase().indexOf('p'); 77 | var trim_ampm_possibilities = ''; 78 | var is_one = !!(self_val == 1); // if they type "1", don't show "11" and "12". 79 | var do_has_am_pm_mind_read = (has_am || has_pm) && re.replace(/a|m|p/gi, '').length <= 2; 80 | 81 | if(do_has_am_pm_mind_read){ 82 | re = $.trim(re.replace(/a|m|p/gi, '')) + ':00 '; 83 | re += (has_am) ? self.options.am_text : self.options.pm_text; 84 | } 85 | 86 | // If the starting (from) time was 9:00 AM, and they start to type 87 | // 2 in the (to) spot, default to 2 PM because 2 is less than 9. 88 | // Only works on english.. not french. 89 | if(self.options.from_selector){ 90 | trim_ampm_possibilities = self.detectAMPMFromInstanceOverlap() == self.options.am_text ? self.options.pm_text : self.options.am_text; 91 | } 92 | 93 | var matcher = new RegExp("^" + re, "i"); 94 | var a = []; 95 | 96 | if(self_val){ 97 | a = $.grep(times, function(item){ 98 | var return_nil = 99 | // If we want to trim out some AM/PM slots based on our mind reading 100 | (trim_ampm_possibilities && (new RegExp(trim_ampm_possibilities, "gi")).test(item)) 101 | // If we type in "1", don't show "11" and "12" possibilities 102 | || (is_one && item.substring(0, 2) != '1:') 103 | || (~self_val.toLowerCase().indexOf('p') && !~item.toLowerCase().indexOf('p')) 104 | || (~self_val.toLowerCase().indexOf('a') && !~item.toLowerCase().indexOf('a')); 105 | if(return_nil){ 106 | return; 107 | } 108 | return matcher.test(item); 109 | }); 110 | } 111 | 112 | responseFn(a); 113 | 114 | } 115 | })(self.options.times, self); 116 | 117 | }, 118 | 119 | /* 120 | * When we blur on the input field. Make any corrections/modifications to the value 121 | * 122 | * @param {String} val The input value 123 | */ 124 | hook_blur: function(val){ 125 | 126 | // Clean up 03:00 am 127 | if(val.charAt(0) == 0){ 128 | val = val.substr(1); 129 | } 130 | 131 | return val; 132 | 133 | }, 134 | 135 | /* 136 | * If we blurred and it was an empty value. 137 | */ 138 | hook_blurEmpty: function(){ 139 | 140 | if(this.options.blur_empty_populate){ 141 | return this.main_instance._createStringFromFormat(this.options.empty); 142 | } 143 | else { 144 | return ''; 145 | } 146 | 147 | }, 148 | 149 | /* 150 | * Where our formatting actually happens. 151 | * 152 | * @param {String} val The value we're formatting 153 | */ 154 | hook_readMind: function(val){ 155 | 156 | var am_pm = ''; 157 | 158 | val = val.toLowerCase(); 159 | if(this.options.from_selector && !~val.indexOf('a') && !~val.indexOf('p')) 160 | { 161 | am_pm = this.detectAMPMFromInstanceOverlap(); 162 | } 163 | 164 | return this.getTimeObject(val, am_pm); 165 | 166 | }, 167 | 168 | /* 169 | * Convert an '1:00 PM' to H:i:s so it's usable for storing in the DB. 170 | * 171 | * @param {String} val 172 | */ 173 | hook_getUsableTimeValue: function(val){ 174 | return this.parseTime(val); 175 | }, 176 | 177 | /* 178 | * Get the timestamp on a time value 179 | * 180 | * @param {String} t The time (2:00 PM) 181 | * @param {Array} fake_date_data [1987, 1, 17] 182 | */ 183 | hook_getTime: function(t, fake_date_data){ 184 | 185 | var time_parts = this.parseTime(t).split(this.options.empty.sep); 186 | var h = time_parts[0]; 187 | var m = time_parts[1]; 188 | 189 | return (new Date(fake_date_data[0], fake_date_data[1], fake_date_data[2], h, m)).getTime(); 190 | 191 | }, 192 | 193 | /* 194 | * Get the H:is (13:30:00) time format and turn it into a time object 195 | * that we can pass back to the main view. 196 | * 197 | * @param {String} time_his 13:30:00 198 | */ 199 | hook_getTimeObjectFromHis: function(time_his){ 200 | 201 | var time = time_his.split(':'); 202 | var hour = time[0]; 203 | var min = time[1]; 204 | var ampm = (hour >= 12) ? this.options.pm_text : this.options.am_text; 205 | 206 | if(hour.length == 2 && parseInt(hour, 10) < 10){ 207 | hour = hour.substr(1); 208 | } 209 | 210 | if(hour > 12){ 211 | hour -= 12; 212 | } 213 | 214 | if(hour == 0){ 215 | hour = 12; 216 | } 217 | 218 | var time_obj = { 219 | h: parseInt(hour, 10), 220 | m: min, 221 | sep: this.options.empty.sep, 222 | postfix: ' ' + ampm 223 | }; 224 | 225 | return time_obj; 226 | 227 | }, 228 | 229 | /** 230 | * If we have a $(self.options.from_selector), then we type '2' into the To field, 231 | * we should look at the From field to determine whether or not to make it 2pm 232 | * or 2am. Do awesome stuff to figure it out. 233 | */ 234 | detectAMPMFromInstanceOverlap: function(){ 235 | 236 | var trim_ampm_possibilities = ''; 237 | var from_obj = this.getTimeObject($(this.options.from_selector).val()); 238 | var to_obj = this.getTimeObject($.trim(this.main_instance.el.val())); 239 | 240 | if(from_obj.postfix && (~from_obj.postfix.toLowerCase().indexOf('a') || ~from_obj.postfix.toLowerCase().indexOf('p'))){ 241 | 242 | var from_ampm = (~from_obj.postfix.toLowerCase().indexOf('a')) ? this.options.am_text : this.options.pm_text; 243 | var to_hour = to_obj.h; 244 | var from_hour = from_obj.h; 245 | 246 | // If it's 11:00 PM - 12.. it should say 12 AM and not PM. 247 | if(from_hour == 12 && to_hour != 12){ 248 | trim_ampm_possibilities = (from_ampm == this.options.am_text) ? this.options.am_text : this.options.pm_text; 249 | } 250 | else if(to_hour == 12 && from_hour != 12){ 251 | trim_ampm_possibilities = (from_ampm == this.options.am_text) ? this.options.pm_text : this.options.am_text; 252 | } 253 | // 10:00 AM > 2:00 PM, 10:00 PM > 2:00 AM 254 | else if(from_hour > to_hour){ 255 | trim_ampm_possibilities = (from_ampm == this.options.am_text) ? this.options.pm_text : this.options.am_text; 256 | } 257 | // 10:00 AM < 11:00 AM, 5:00 PM < 7:00 PM 258 | else { 259 | trim_ampm_possibilities = (from_ampm == this.options.am_text) ? this.options.am_text : this.options.pm_text; 260 | } 261 | 262 | } 263 | 264 | return trim_ampm_possibilities; 265 | 266 | }, 267 | 268 | /** 269 | * Format what we've got into an english readable format. 270 | * So turn '1030' into '10:30 am' etc. 271 | * 272 | * @param {String} original_val The original value to format 273 | * @param {String} am_pm Whether or not it's 'am' or 'pm' 274 | */ 275 | getTimeObject: function(original_val, am_pm){ 276 | 277 | var t = this.parseTime(original_val, 'g:i:A').split(':'); 278 | var h = t[0]; 279 | var m = t[1]; 280 | var new_num; 281 | 282 | if(!h && !m){ 283 | new_num = this.options.empty; 284 | } 285 | else { 286 | new_num = { 287 | h: h, 288 | m: m, 289 | sep: ':', 290 | postfix: ' ' + (am_pm ? am_pm : t[2]) 291 | }; 292 | } 293 | 294 | return new_num; 295 | 296 | }, 297 | 298 | /* 299 | * Generate an array of times to pass to our autocomplete source. 300 | * ['12:00 AM', '12:15 AM'] etc. Totally depends on the start_hour and increment options set. 301 | */ 302 | generateTimes: function(){ 303 | 304 | if(!this.options.times.length){ 305 | 306 | var start_minute = 60; 307 | var increment = this.options.increment; 308 | var date = new Date(2012, 1, 1, (this.options.start_hour - 1), (start_minute - increment)); 309 | var arr = []; 310 | var hour_len = 60; 311 | var hours = this.options.end_hour; 312 | var hour_looper = (hours - this.options.start_hour); 313 | var pop_last = false; 314 | 315 | if(hour_looper == 24){ 316 | pop_last = true; 317 | } 318 | 319 | for(var i = 0, loop_int = hour_looper * (hour_len / increment); i <= loop_int; i++){ 320 | 321 | date.setMinutes(date.getMinutes() + increment); 322 | var h = date.getHours(); 323 | var m = date.getMinutes(); 324 | var ampm = h > 11 ? this.options.pm_text : this.options.am_text; 325 | 326 | if(h == 0){ 327 | h = 12; 328 | } 329 | 330 | if(h > 12){ 331 | h = h - 12; 332 | } 333 | 334 | if(("" + m).length == 1){ 335 | m = '0' + m; 336 | } 337 | 338 | var label = h + ':' + m + ' ' + ampm; 339 | arr.push(label); 340 | } 341 | 342 | if(pop_last){ 343 | arr.pop(); 344 | } 345 | 346 | this.options.times = arr; 347 | } 348 | 349 | }, 350 | 351 | parseTime: function(time, format){ 352 | 353 | var hour, 354 | minute, 355 | format = format || 'H:i:s', 356 | pm = time.match(/p/i) !== null, 357 | am = time.match(/a/i) !== null, 358 | num = time.replace(/[^0-9]/g, ''); 359 | 360 | // Parse for hour and minute 361 | switch(num.length){ 362 | case 4: 363 | hour = parseInt(num.charAt(0) + num.charAt(1), 10); 364 | minute = parseInt(num.charAt(2) + num.charAt(3), 10); 365 | break; 366 | case 3: 367 | hour = parseInt(num.charAt(0), 10); 368 | minute = parseInt(num.charAt(1) + num.charAt(2), 10); 369 | break; 370 | case 2: 371 | case 1: 372 | hour = parseInt(num.charAt(0) + (num.charAt(1) || ''), 10); 373 | minute = 0; 374 | break; 375 | default: 376 | return ''; 377 | } 378 | 379 | // if 12 and am/pm not specified assume pm 380 | if (hour == 12 && pm === false && am === false) { 381 | hour = 12; 382 | pm = true; 383 | } else if (hour == 12 && pm === false) { 384 | hour = 0; 385 | } else if (pm === true && hour > 0 && hour < 12) { 386 | hour += 12; 387 | } 388 | 389 | // Keep within range 390 | if(hour <= 0 ){ 391 | hour = 0; 392 | } 393 | 394 | if(hour >= 24 && ("" + hour + "").length == 2){ 395 | var parts = ("" + hour + "").split(''); 396 | hour = parseInt(parts[0], 10); 397 | minute = parseInt(parts[1], 10); 398 | if(minute < 6){ 399 | minute = minute + '0'; 400 | } 401 | } 402 | 403 | if(minute < 0 || minute > 59){ 404 | minute = 0; 405 | } 406 | 407 | if(hour >= 13 && hour <= 23){ 408 | pm = true; 409 | } 410 | 411 | return format 412 | // 12 hour without leading 0 413 | .replace(/g/g, hour === 0 ? '12' : 'g') 414 | .replace(/g/g, hour > 12 ? hour - 12 : hour) 415 | // 12 hour with leading 0 416 | .replace(/h/g, hour.toString().length > 1 ? (hour > 12 ? hour - 12 : hour) : '0' + (hour > 12 ? hour - 12 : hour)) 417 | // 24 hour with leading 0 418 | .replace(/H/g, hour.toString().length > 1 ? hour : '0' + hour) 419 | // minutes with leading zero 420 | .replace(/i/g, minute.toString().length > 1 ? minute : '0' + minute) 421 | // simulate seconds 422 | .replace(/s/g, '00') 423 | // lowercase am/pm 424 | .replace(/A/g, pm ? this.options.pm_text : this.options.am_text); 425 | 426 | } 427 | 428 | }; 429 | 430 | })(jQuery); -------------------------------------------------------------------------------- /src/formatters/french.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | 3 | $.timeAutocomplete.formatters.french = function(){ 4 | this.initialize.apply(this, arguments); 5 | }; 6 | 7 | $.timeAutocomplete.formatters.french.prototype = $.extend(true, {}, $.timeAutocomplete.formatters['24hr'].prototype, { 8 | default_opts: { 9 | empty: { 10 | sep: 'h' 11 | } 12 | }, 13 | 14 | hook_getUsableTimeValue: function(val){ 15 | return val.replace(this.options.empty.sep, ':') + ':00' 16 | } 17 | }); 18 | 19 | })(jQuery); -------------------------------------------------------------------------------- /src/jquery.timeAutocomplete.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TimeFromToAutocomplete 3 | * 4 | * The from -> to autocomplete inputs (on absences dialog) 5 | */ 6 | 7 | (function($){ 8 | 9 | /* 10 | * TimeAutcomplete 11 | * 12 | * @constructor 13 | * @param {Object} opts An object of options to over-ride the defaults 14 | */ 15 | var namespace = 'timeAutocomplete'; 16 | var time_data_prop = namespace + '.time'; 17 | 18 | var TimeAutocomplete = function(){ 19 | this.initialize.apply(this, arguments); 20 | }; 21 | 22 | TimeAutocomplete.prototype = { 23 | 24 | // Gets set in initialize 25 | el: null, 26 | 27 | // Instance of our formatter 28 | _formatter: null, 29 | 30 | _calling_from_init: false, 31 | 32 | // Default options 33 | default_opts: { 34 | auto_complete: { 35 | delay: 0, 36 | autoFocus: true, 37 | minLength: 0 38 | }, 39 | auto_value: true, 40 | value: '', 41 | formatter: 'ampm' 42 | }, 43 | 44 | /** 45 | * Init called when we create a new instance 46 | * of this view. First param of 'options' passed in by backbonejs 47 | */ 48 | initialize: function($el, opts){ 49 | this.options = $.extend(true, {}, this.default_opts, opts); 50 | 51 | // Some global options (if set) 52 | if(typeof($.timeAutocompleteDefaults) !== 'undefined'){ 53 | this.options = $.extend(true, {}, this.options, $.timeAutocompleteDefaults); 54 | } 55 | 56 | this.el = $el; 57 | }, 58 | 59 | _callAutocomplete: function(){ 60 | 61 | this.options.auto_complete.source = this._callFormatterMethod('filterSource', [this.el], function(req, responseFn){ 62 | throw new Error("You must set a hook_filterSource method in your formatter."); 63 | }); 64 | 65 | // Make sure we have loaded the autocomplete plugin 66 | if(typeof($.fn.autocomplete) === 'undefined'){ 67 | throw new Error("You need to include the jQuery UI bundle that has the Autocomplete plugin."); 68 | } 69 | 70 | // Call our autocomplete plugin 71 | this.el.autocomplete(this.options.auto_complete); 72 | }, 73 | 74 | /** 75 | * When we click on the element and there are no 76 | * initial values in there, make some to show the user 77 | * they have to start typing a number 78 | */ 79 | _bindEvents: function(){ 80 | 81 | var self = this; 82 | var allow_focus = true; /* IE fix */ 83 | 84 | $('body').on('click.' + namespace, 'ul.ui-autocomplete a', function(){ 85 | allow_focus = false; 86 | setTimeout(function(){ 87 | allow_focus = true; 88 | }, 100); 89 | }); 90 | 91 | this.el 92 | .bind('keydown.' + namespace, function(e){ 93 | self._keydownAutocomplete.apply(self, arguments); 94 | }) 95 | .bind('keyup.' + namespace, function(e){ 96 | self._keyupAutocomplete.apply(self, arguments); 97 | }) 98 | .bind('blur.' + namespace, function(e){ 99 | self._blurAutocomplete.apply(self, arguments); 100 | }) 101 | .bind('focus.' + namespace, function(e){ 102 | if(allow_focus){ 103 | self._focusAutocomplete.apply(self, arguments); 104 | } 105 | }); 106 | 107 | if(this.options.auto_value){ 108 | this.el.trigger('blur.' + namespace); 109 | } 110 | 111 | }, 112 | 113 | _setupPlaceholder: function(){ 114 | if(typeof(this.el.attr('placeholder')) === 'undefined'){ 115 | this.el.attr('placeholder', this._callFormatterMethod('placeholderValue', [], '')); 116 | } 117 | }, 118 | 119 | _focusAutocomplete: function(){ 120 | var val = $.trim(this.el.val()).substr(0, 2); 121 | if(this.el.data('uiAutocomplete')){ 122 | this.el.autocomplete('search', val); 123 | } 124 | }, 125 | 126 | /* 127 | * Keydown autocomplete event 128 | * 129 | * @param {Object} e Event object 130 | * @param {HTMLElement} input The input we had the event performed on 131 | */ 132 | _keydownAutocomplete: function(e){ 133 | 134 | var val = $.trim(this.el.val()); 135 | 136 | // If they hit any of these keys DO NOT disable the auto complete, these 137 | // are acceptable key strokes. 138 | var ignore_keydowns = [ 139 | 8, // backspace 140 | 9, // tab 141 | 13, // enter key 142 | 38, // up arrow key 143 | 40 // down arrow key 144 | ]; 145 | 146 | if(!~$.inArray(e.which, ignore_keydowns) && ((e.which == 8) || (val.length > 1 && !~val.indexOf('h') && !~val.indexOf(':') && $.isNumeric(val)))){ 147 | try { 148 | this.el.autocomplete('close').autocomplete('disable'); 149 | } catch(e){} 150 | } 151 | 152 | }, 153 | 154 | /* 155 | * Keyup autocomplete event 156 | * 157 | * @param {Object} e Event object 158 | * @param {HTMLElement} input The input we had the event performed on 159 | */ 160 | _keyupAutocomplete: function(e){ 161 | 162 | if($.trim(this.el.val()) == '' && this.el.data('uiAutocomplete')){ 163 | this.el.autocomplete('enable'); 164 | } 165 | 166 | }, 167 | 168 | /* 169 | * Blur autocomplete event 170 | * 171 | * @param {Object} e Event object 172 | * @param {HTMLElement} input The input we had the event performed on 173 | */ 174 | _blurAutocomplete: function(e){ 175 | 176 | var val = $.trim(this.el.val()); 177 | val = this._callFormatterMethod('blur', [val], val); 178 | var new_value = ''; 179 | 180 | if(val){ 181 | new_value = this._createStringFromFormat(this._readMind(val)); 182 | } 183 | else { 184 | new_value = this._callFormatterMethod('blurEmpty', [val], val); 185 | } 186 | 187 | this.el.val(new_value); 188 | 189 | this._attacheUsableTimeData(); 190 | 191 | }, 192 | 193 | /* 194 | * Hit a formatter hook to get at the date value, then store it in a data 195 | * attribute for later if need be 196 | */ 197 | _attacheUsableTimeData: function(){ 198 | var val = $.trim(this.el.val()); 199 | this.el.data(time_data_prop, this._callFormatterMethod('getUsableTimeValue', [val])); 200 | }, 201 | 202 | /** 203 | * Our 'ampm' formatter should be used by default. If we're adding a new 204 | * formatter, it will go into $.timeAutocomplete.formatters[formatter] 205 | * 206 | * @param {String} formatter The formater name we're setting to use. 207 | */ 208 | setFormatter: function(formatter){ 209 | 210 | this.options.formatter = formatter || this.options.formatter; 211 | 212 | if(!$.timeAutocomplete.formatters[this.options.formatter]){ 213 | throw new Error("Formatter: '" + formatter + "' was not found. Make sure you're loading it (formatters/" + this.options.formatter + ".js) after you load src/TimeAutocomplete.js"); 214 | } 215 | else { 216 | this._formatter = new $.timeAutocomplete.formatters[this.options.formatter](this, this.options); 217 | 218 | if(!this._calling_from_init){ 219 | this._callAutocomplete(); 220 | } 221 | 222 | this._calling_from_init = false; 223 | } 224 | 225 | }, 226 | 227 | /* 228 | * Gets the formatter 229 | */ 230 | getFormatter: function(){ 231 | return this._formatter; 232 | }, 233 | 234 | /* 235 | * Gets the time in H:i:s format 236 | */ 237 | getTime: function(){ 238 | return this.el.data(time_data_prop) || ''; 239 | }, 240 | 241 | /** 242 | * Call the formatter method (if it exists). If you look in formatters/ampm.js, all our hooks that 243 | * get called there are prefixed by "hook_". 244 | * 245 | * @param {String} method_name The method to call in the formatter file 246 | * @param {Array} args The arguments to pass to the formatter 247 | * @param {Array|Function|Object|String} default_val The default if the method_name does not exist in the formatter 248 | */ 249 | _callFormatterMethod: function(method_name, args, default_val){ 250 | 251 | var formatter = this.getFormatter(); 252 | 253 | if($.isFunction(formatter['hook_' + method_name])){ 254 | return formatter['hook_' + method_name].apply(formatter, args); 255 | } 256 | 257 | return default_val; 258 | 259 | }, 260 | 261 | /** 262 | * The person typed something in that wasn't to our satisfaction. 263 | * Like '10' or '13' or '135' or '1350' 264 | * 265 | * @param {String} val The value from our input 266 | */ 267 | _readMind: function(val){ 268 | return this._callFormatterMethod('readMind', [val], val); 269 | }, 270 | 271 | /** 272 | * Combine formatted things 273 | * 274 | * @param {Object} obj The object containing h, m, sep etc. 275 | */ 276 | _createStringFromFormat: function(obj){ 277 | 278 | var combined = ("" + obj.h + "") + obj.sep + ("" + obj.m + ""); 279 | 280 | if(obj.postfix){ 281 | combined += obj.postfix; 282 | } 283 | 284 | return combined; 285 | 286 | }, 287 | 288 | /* 289 | * Pass an H:i:s time format in as the value: '' attribute on the element or 'current' 290 | */ 291 | _setValueAsTime: function(){ 292 | 293 | var val = $.trim(this.el.val()); 294 | var val_parts = val.split(':'); 295 | 296 | if(val == '' && this.options.value){ 297 | this.setTime(this.options.value); 298 | } 299 | else if(val_parts.length == 3 && this.isNumber(val_parts[0]) && this.isNumber(val_parts[1]) && this.isNumber(val_parts[2])){ 300 | this.setTime(val); 301 | } 302 | else { 303 | var time = this._getCurrentTimeAsValue(); 304 | this.el.val(time); 305 | this._attacheUsableTimeData(); 306 | } 307 | 308 | }, 309 | 310 | /* 311 | * Check if its a number 312 | * 313 | * @param {String|Int} n 314 | */ 315 | isNumber: function(n) { 316 | return !isNaN(parseFloat(n)) && isFinite(n); 317 | }, 318 | 319 | /* 320 | * Set the time by passing it a H:i:s format (13:30:00) 321 | * 322 | * @param {String} time 13:30:00 323 | */ 324 | setTime: function(time){ 325 | 326 | var stripped_time = time.replace(/[^0-9.]/g, ""); 327 | var matched = stripped_time.match(/^[0-9]+$/); 328 | if(matched && matched.length && (matched[0].length == 5 || matched[0].length == 6)){ 329 | var val = this._callFormatterMethod('getTimeObjectFromHis', [time]); 330 | val = this._createStringFromFormat(val); 331 | this.el.val(val); 332 | this._attacheUsableTimeData(); 333 | } else { 334 | throw new Error('Setting a time must be in H:i:s format. Example: 03:30:00'); 335 | } 336 | 337 | }, 338 | 339 | /* 340 | * Populate the input with the current time value 341 | */ 342 | _getCurrentTimeAsValue: function(){ 343 | 344 | var formatter = this.getFormatter(); 345 | var fake_date_data = [1987, 1, 17]; 346 | var date = this._getCurrentDate(); 347 | var current_h = date.getHours(); 348 | var current_m = date.getMinutes(); 349 | var current_time = (new Date(fake_date_data[0], fake_date_data[1], fake_date_data[2], current_h, current_m)).getTime(); 350 | var bound_times = formatter.options.times.slice().concat(formatter.options.times); 351 | var entered_next_times = []; 352 | 353 | for(var i = 0, t = bound_times.length; i < t; i++){ 354 | 355 | var time = this._callFormatterMethod('getTime', [bound_times[i], fake_date_data]); 356 | var next_time = (bound_times[i + 1]) ? this._callFormatterMethod('getTime', [bound_times[i + 1], fake_date_data]) : false; 357 | var already_entered_next_times = !!($.inArray(next_time, entered_next_times) !== -1); 358 | entered_next_times.push(next_time); 359 | 360 | if(current_time > time && ((next_time && current_time <= next_time) || (already_entered_next_times))){ 361 | return bound_times[i + 1]; 362 | } 363 | } 364 | 365 | }, 366 | 367 | /* 368 | * Get the current date 369 | */ 370 | _getCurrentDate: function(){ 371 | return new Date(); 372 | }, 373 | 374 | /* 375 | * Destroy the bound event to the element 376 | */ 377 | destroy: function(){ 378 | this.el.removeData(namespace); 379 | this.el.removeData(time_data_prop); 380 | this.el.unbind('.' + namespace); 381 | if(this.el.data('uiAutocomplete')){ 382 | this.el.autocomplete('destroy'); 383 | } 384 | }, 385 | 386 | /* 387 | * Render it out to the page 388 | */ 389 | render: function(){ 390 | 391 | // Which formatter we're using.. 'ampm', 'french'? 392 | this._calling_from_init = true; 393 | this.setFormatter(); 394 | this._callAutocomplete(); 395 | 396 | if(this.options.auto_value){ 397 | this._setValueAsTime(); 398 | } 399 | 400 | this._bindEvents(); 401 | this._setupPlaceholder(); 402 | 403 | return this; 404 | 405 | } 406 | 407 | }; 408 | 409 | /** 410 | * Just slappin' on a global object to access some convenient formatters 411 | */ 412 | $.timeAutocomplete = { 413 | formatters: {}, 414 | _raw: TimeAutocomplete // exposed globally for the sake of testing it 415 | }; 416 | 417 | /* 418 | * Wrap it all into a nice jQuery function 419 | * 420 | * @param {Object} opts The options passed to it when called (optional) 421 | */ 422 | $.fn.timeAutocomplete = function(opts){ 423 | 424 | // Do the nasty on each one. 425 | return this.each(function(){ 426 | 427 | var $el = $(this); 428 | 429 | // If it already exists, tear it down before setting a new one up 430 | if($el.data(namespace)) 431 | { 432 | $el.data(namespace).destroy(); 433 | } 434 | 435 | // Set up a new instance of the time autocomplete 436 | var ta_instance = (new TimeAutocomplete($el, opts)).render(); 437 | $el.data(namespace, ta_instance); 438 | 439 | }); 440 | 441 | }; 442 | 443 | })(jQuery); -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | jQuery timeAutocomplete Tests 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /tests/lib/jasmine-1.3.1/MIT.LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2011 Pivotal Labs 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /tests/lib/jasmine-1.3.1/jasmine-html.js: -------------------------------------------------------------------------------- 1 | jasmine.HtmlReporterHelpers = {}; 2 | 3 | jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) { 4 | var el = document.createElement(type); 5 | 6 | for (var i = 2; i < arguments.length; i++) { 7 | var child = arguments[i]; 8 | 9 | if (typeof child === 'string') { 10 | el.appendChild(document.createTextNode(child)); 11 | } else { 12 | if (child) { 13 | el.appendChild(child); 14 | } 15 | } 16 | } 17 | 18 | for (var attr in attrs) { 19 | if (attr == "className") { 20 | el[attr] = attrs[attr]; 21 | } else { 22 | el.setAttribute(attr, attrs[attr]); 23 | } 24 | } 25 | 26 | return el; 27 | }; 28 | 29 | jasmine.HtmlReporterHelpers.getSpecStatus = function(child) { 30 | var results = child.results(); 31 | var status = results.passed() ? 'passed' : 'failed'; 32 | if (results.skipped) { 33 | status = 'skipped'; 34 | } 35 | 36 | return status; 37 | }; 38 | 39 | jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) { 40 | var parentDiv = this.dom.summary; 41 | var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite'; 42 | var parent = child[parentSuite]; 43 | 44 | if (parent) { 45 | if (typeof this.views.suites[parent.id] == 'undefined') { 46 | this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views); 47 | } 48 | parentDiv = this.views.suites[parent.id].element; 49 | } 50 | 51 | parentDiv.appendChild(childElement); 52 | }; 53 | 54 | 55 | jasmine.HtmlReporterHelpers.addHelpers = function(ctor) { 56 | for(var fn in jasmine.HtmlReporterHelpers) { 57 | ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn]; 58 | } 59 | }; 60 | 61 | jasmine.HtmlReporter = function(_doc) { 62 | var self = this; 63 | var doc = _doc || window.document; 64 | 65 | var reporterView; 66 | 67 | var dom = {}; 68 | 69 | // Jasmine Reporter Public Interface 70 | self.logRunningSpecs = false; 71 | 72 | self.reportRunnerStarting = function(runner) { 73 | var specs = runner.specs() || []; 74 | 75 | if (specs.length == 0) { 76 | return; 77 | } 78 | 79 | createReporterDom(runner.env.versionString()); 80 | doc.body.appendChild(dom.reporter); 81 | setExceptionHandling(); 82 | 83 | reporterView = new jasmine.HtmlReporter.ReporterView(dom); 84 | reporterView.addSpecs(specs, self.specFilter); 85 | }; 86 | 87 | self.reportRunnerResults = function(runner) { 88 | reporterView && reporterView.complete(); 89 | }; 90 | 91 | self.reportSuiteResults = function(suite) { 92 | reporterView.suiteComplete(suite); 93 | }; 94 | 95 | self.reportSpecStarting = function(spec) { 96 | if (self.logRunningSpecs) { 97 | self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); 98 | } 99 | }; 100 | 101 | self.reportSpecResults = function(spec) { 102 | reporterView.specComplete(spec); 103 | }; 104 | 105 | self.log = function() { 106 | var console = jasmine.getGlobal().console; 107 | if (console && console.log) { 108 | if (console.log.apply) { 109 | console.log.apply(console, arguments); 110 | } else { 111 | console.log(arguments); // ie fix: console.log.apply doesn't exist on ie 112 | } 113 | } 114 | }; 115 | 116 | self.specFilter = function(spec) { 117 | if (!focusedSpecName()) { 118 | return true; 119 | } 120 | 121 | return spec.getFullName().indexOf(focusedSpecName()) === 0; 122 | }; 123 | 124 | return self; 125 | 126 | function focusedSpecName() { 127 | var specName; 128 | 129 | (function memoizeFocusedSpec() { 130 | if (specName) { 131 | return; 132 | } 133 | 134 | var paramMap = []; 135 | var params = jasmine.HtmlReporter.parameters(doc); 136 | 137 | for (var i = 0; i < params.length; i++) { 138 | var p = params[i].split('='); 139 | paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); 140 | } 141 | 142 | specName = paramMap.spec; 143 | })(); 144 | 145 | return specName; 146 | } 147 | 148 | function createReporterDom(version) { 149 | dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' }, 150 | dom.banner = self.createDom('div', { className: 'banner' }, 151 | self.createDom('span', { className: 'title' }, "Jasmine "), 152 | self.createDom('span', { className: 'version' }, version)), 153 | 154 | dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}), 155 | dom.alert = self.createDom('div', {className: 'alert'}, 156 | self.createDom('span', { className: 'exceptions' }, 157 | self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'), 158 | self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))), 159 | dom.results = self.createDom('div', {className: 'results'}, 160 | dom.summary = self.createDom('div', { className: 'summary' }), 161 | dom.details = self.createDom('div', { id: 'details' })) 162 | ); 163 | } 164 | 165 | function noTryCatch() { 166 | return window.location.search.match(/catch=false/); 167 | } 168 | 169 | function searchWithCatch() { 170 | var params = jasmine.HtmlReporter.parameters(window.document); 171 | var removed = false; 172 | var i = 0; 173 | 174 | while (!removed && i < params.length) { 175 | if (params[i].match(/catch=/)) { 176 | params.splice(i, 1); 177 | removed = true; 178 | } 179 | i++; 180 | } 181 | if (jasmine.CATCH_EXCEPTIONS) { 182 | params.push("catch=false"); 183 | } 184 | 185 | return params.join("&"); 186 | } 187 | 188 | function setExceptionHandling() { 189 | var chxCatch = document.getElementById('no_try_catch'); 190 | 191 | if (noTryCatch()) { 192 | chxCatch.setAttribute('checked', true); 193 | jasmine.CATCH_EXCEPTIONS = false; 194 | } 195 | chxCatch.onclick = function() { 196 | window.location.search = searchWithCatch(); 197 | }; 198 | } 199 | }; 200 | jasmine.HtmlReporter.parameters = function(doc) { 201 | var paramStr = doc.location.search.substring(1); 202 | var params = []; 203 | 204 | if (paramStr.length > 0) { 205 | params = paramStr.split('&'); 206 | } 207 | return params; 208 | } 209 | jasmine.HtmlReporter.sectionLink = function(sectionName) { 210 | var link = '?'; 211 | var params = []; 212 | 213 | if (sectionName) { 214 | params.push('spec=' + encodeURIComponent(sectionName)); 215 | } 216 | if (!jasmine.CATCH_EXCEPTIONS) { 217 | params.push("catch=false"); 218 | } 219 | if (params.length > 0) { 220 | link += params.join("&"); 221 | } 222 | 223 | return link; 224 | }; 225 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter); 226 | jasmine.HtmlReporter.ReporterView = function(dom) { 227 | this.startedAt = new Date(); 228 | this.runningSpecCount = 0; 229 | this.completeSpecCount = 0; 230 | this.passedCount = 0; 231 | this.failedCount = 0; 232 | this.skippedCount = 0; 233 | 234 | this.createResultsMenu = function() { 235 | this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'}, 236 | this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'), 237 | ' | ', 238 | this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing')); 239 | 240 | this.summaryMenuItem.onclick = function() { 241 | dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, ''); 242 | }; 243 | 244 | this.detailsMenuItem.onclick = function() { 245 | showDetails(); 246 | }; 247 | }; 248 | 249 | this.addSpecs = function(specs, specFilter) { 250 | this.totalSpecCount = specs.length; 251 | 252 | this.views = { 253 | specs: {}, 254 | suites: {} 255 | }; 256 | 257 | for (var i = 0; i < specs.length; i++) { 258 | var spec = specs[i]; 259 | this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views); 260 | if (specFilter(spec)) { 261 | this.runningSpecCount++; 262 | } 263 | } 264 | }; 265 | 266 | this.specComplete = function(spec) { 267 | this.completeSpecCount++; 268 | 269 | if (isUndefined(this.views.specs[spec.id])) { 270 | this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom); 271 | } 272 | 273 | var specView = this.views.specs[spec.id]; 274 | 275 | switch (specView.status()) { 276 | case 'passed': 277 | this.passedCount++; 278 | break; 279 | 280 | case 'failed': 281 | this.failedCount++; 282 | break; 283 | 284 | case 'skipped': 285 | this.skippedCount++; 286 | break; 287 | } 288 | 289 | specView.refresh(); 290 | this.refresh(); 291 | }; 292 | 293 | this.suiteComplete = function(suite) { 294 | var suiteView = this.views.suites[suite.id]; 295 | if (isUndefined(suiteView)) { 296 | return; 297 | } 298 | suiteView.refresh(); 299 | }; 300 | 301 | this.refresh = function() { 302 | 303 | if (isUndefined(this.resultsMenu)) { 304 | this.createResultsMenu(); 305 | } 306 | 307 | // currently running UI 308 | if (isUndefined(this.runningAlert)) { 309 | this.runningAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "runningAlert bar" }); 310 | dom.alert.appendChild(this.runningAlert); 311 | } 312 | this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount); 313 | 314 | // skipped specs UI 315 | if (isUndefined(this.skippedAlert)) { 316 | this.skippedAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "skippedAlert bar" }); 317 | } 318 | 319 | this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; 320 | 321 | if (this.skippedCount === 1 && isDefined(dom.alert)) { 322 | dom.alert.appendChild(this.skippedAlert); 323 | } 324 | 325 | // passing specs UI 326 | if (isUndefined(this.passedAlert)) { 327 | this.passedAlert = this.createDom('span', { href: jasmine.HtmlReporter.sectionLink(), className: "passingAlert bar" }); 328 | } 329 | this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount); 330 | 331 | // failing specs UI 332 | if (isUndefined(this.failedAlert)) { 333 | this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"}); 334 | } 335 | this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount); 336 | 337 | if (this.failedCount === 1 && isDefined(dom.alert)) { 338 | dom.alert.appendChild(this.failedAlert); 339 | dom.alert.appendChild(this.resultsMenu); 340 | } 341 | 342 | // summary info 343 | this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount); 344 | this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing"; 345 | }; 346 | 347 | this.complete = function() { 348 | dom.alert.removeChild(this.runningAlert); 349 | 350 | this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; 351 | 352 | if (this.failedCount === 0) { 353 | dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount))); 354 | } else { 355 | showDetails(); 356 | } 357 | 358 | dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s")); 359 | }; 360 | 361 | return this; 362 | 363 | function showDetails() { 364 | if (dom.reporter.className.search(/showDetails/) === -1) { 365 | dom.reporter.className += " showDetails"; 366 | } 367 | } 368 | 369 | function isUndefined(obj) { 370 | return typeof obj === 'undefined'; 371 | } 372 | 373 | function isDefined(obj) { 374 | return !isUndefined(obj); 375 | } 376 | 377 | function specPluralizedFor(count) { 378 | var str = count + " spec"; 379 | if (count > 1) { 380 | str += "s" 381 | } 382 | return str; 383 | } 384 | 385 | }; 386 | 387 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView); 388 | 389 | 390 | jasmine.HtmlReporter.SpecView = function(spec, dom, views) { 391 | this.spec = spec; 392 | this.dom = dom; 393 | this.views = views; 394 | 395 | this.symbol = this.createDom('li', { className: 'pending' }); 396 | this.dom.symbolSummary.appendChild(this.symbol); 397 | 398 | this.summary = this.createDom('div', { className: 'specSummary' }, 399 | this.createDom('a', { 400 | className: 'description', 401 | href: jasmine.HtmlReporter.sectionLink(this.spec.getFullName()), 402 | title: this.spec.getFullName() 403 | }, this.spec.description) 404 | ); 405 | 406 | this.detail = this.createDom('div', { className: 'specDetail' }, 407 | this.createDom('a', { 408 | className: 'description', 409 | href: '?spec=' + encodeURIComponent(this.spec.getFullName()), 410 | title: this.spec.getFullName() 411 | }, this.spec.getFullName()) 412 | ); 413 | }; 414 | 415 | jasmine.HtmlReporter.SpecView.prototype.status = function() { 416 | return this.getSpecStatus(this.spec); 417 | }; 418 | 419 | jasmine.HtmlReporter.SpecView.prototype.refresh = function() { 420 | this.symbol.className = this.status(); 421 | 422 | switch (this.status()) { 423 | case 'skipped': 424 | break; 425 | 426 | case 'passed': 427 | this.appendSummaryToSuiteDiv(); 428 | break; 429 | 430 | case 'failed': 431 | this.appendSummaryToSuiteDiv(); 432 | this.appendFailureDetail(); 433 | break; 434 | } 435 | }; 436 | 437 | jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() { 438 | this.summary.className += ' ' + this.status(); 439 | this.appendToSummary(this.spec, this.summary); 440 | }; 441 | 442 | jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() { 443 | this.detail.className += ' ' + this.status(); 444 | 445 | var resultItems = this.spec.results().getItems(); 446 | var messagesDiv = this.createDom('div', { className: 'messages' }); 447 | 448 | for (var i = 0; i < resultItems.length; i++) { 449 | var result = resultItems[i]; 450 | 451 | if (result.type == 'log') { 452 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); 453 | } else if (result.type == 'expect' && result.passed && !result.passed()) { 454 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); 455 | 456 | if (result.trace.stack) { 457 | messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); 458 | } 459 | } 460 | } 461 | 462 | if (messagesDiv.childNodes.length > 0) { 463 | this.detail.appendChild(messagesDiv); 464 | this.dom.details.appendChild(this.detail); 465 | } 466 | }; 467 | 468 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) { 469 | this.suite = suite; 470 | this.dom = dom; 471 | this.views = views; 472 | 473 | this.element = this.createDom('div', { className: 'suite' }, 474 | this.createDom('a', { className: 'description', href: jasmine.HtmlReporter.sectionLink(this.suite.getFullName()) }, this.suite.description) 475 | ); 476 | 477 | this.appendToSummary(this.suite, this.element); 478 | }; 479 | 480 | jasmine.HtmlReporter.SuiteView.prototype.status = function() { 481 | return this.getSpecStatus(this.suite); 482 | }; 483 | 484 | jasmine.HtmlReporter.SuiteView.prototype.refresh = function() { 485 | this.element.className += " " + this.status(); 486 | }; 487 | 488 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView); 489 | 490 | /* @deprecated Use jasmine.HtmlReporter instead 491 | */ 492 | jasmine.TrivialReporter = function(doc) { 493 | this.document = doc || document; 494 | this.suiteDivs = {}; 495 | this.logRunningSpecs = false; 496 | }; 497 | 498 | jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) { 499 | var el = document.createElement(type); 500 | 501 | for (var i = 2; i < arguments.length; i++) { 502 | var child = arguments[i]; 503 | 504 | if (typeof child === 'string') { 505 | el.appendChild(document.createTextNode(child)); 506 | } else { 507 | if (child) { el.appendChild(child); } 508 | } 509 | } 510 | 511 | for (var attr in attrs) { 512 | if (attr == "className") { 513 | el[attr] = attrs[attr]; 514 | } else { 515 | el.setAttribute(attr, attrs[attr]); 516 | } 517 | } 518 | 519 | return el; 520 | }; 521 | 522 | jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { 523 | var showPassed, showSkipped; 524 | 525 | this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' }, 526 | this.createDom('div', { className: 'banner' }, 527 | this.createDom('div', { className: 'logo' }, 528 | this.createDom('span', { className: 'title' }, "Jasmine"), 529 | this.createDom('span', { className: 'version' }, runner.env.versionString())), 530 | this.createDom('div', { className: 'options' }, 531 | "Show ", 532 | showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }), 533 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "), 534 | showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }), 535 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped") 536 | ) 537 | ), 538 | 539 | this.runnerDiv = this.createDom('div', { className: 'runner running' }, 540 | this.createDom('a', { className: 'run_spec', href: '?' }, "run all"), 541 | this.runnerMessageSpan = this.createDom('span', {}, "Running..."), 542 | this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, "")) 543 | ); 544 | 545 | this.document.body.appendChild(this.outerDiv); 546 | 547 | var suites = runner.suites(); 548 | for (var i = 0; i < suites.length; i++) { 549 | var suite = suites[i]; 550 | var suiteDiv = this.createDom('div', { className: 'suite' }, 551 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"), 552 | this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description)); 553 | this.suiteDivs[suite.id] = suiteDiv; 554 | var parentDiv = this.outerDiv; 555 | if (suite.parentSuite) { 556 | parentDiv = this.suiteDivs[suite.parentSuite.id]; 557 | } 558 | parentDiv.appendChild(suiteDiv); 559 | } 560 | 561 | this.startedAt = new Date(); 562 | 563 | var self = this; 564 | showPassed.onclick = function(evt) { 565 | if (showPassed.checked) { 566 | self.outerDiv.className += ' show-passed'; 567 | } else { 568 | self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, ''); 569 | } 570 | }; 571 | 572 | showSkipped.onclick = function(evt) { 573 | if (showSkipped.checked) { 574 | self.outerDiv.className += ' show-skipped'; 575 | } else { 576 | self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, ''); 577 | } 578 | }; 579 | }; 580 | 581 | jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) { 582 | var results = runner.results(); 583 | var className = (results.failedCount > 0) ? "runner failed" : "runner passed"; 584 | this.runnerDiv.setAttribute("class", className); 585 | //do it twice for IE 586 | this.runnerDiv.setAttribute("className", className); 587 | var specs = runner.specs(); 588 | var specCount = 0; 589 | for (var i = 0; i < specs.length; i++) { 590 | if (this.specFilter(specs[i])) { 591 | specCount++; 592 | } 593 | } 594 | var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); 595 | message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; 596 | this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); 597 | 598 | this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString())); 599 | }; 600 | 601 | jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { 602 | var results = suite.results(); 603 | var status = results.passed() ? 'passed' : 'failed'; 604 | if (results.totalCount === 0) { // todo: change this to check results.skipped 605 | status = 'skipped'; 606 | } 607 | this.suiteDivs[suite.id].className += " " + status; 608 | }; 609 | 610 | jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { 611 | if (this.logRunningSpecs) { 612 | this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); 613 | } 614 | }; 615 | 616 | jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { 617 | var results = spec.results(); 618 | var status = results.passed() ? 'passed' : 'failed'; 619 | if (results.skipped) { 620 | status = 'skipped'; 621 | } 622 | var specDiv = this.createDom('div', { className: 'spec ' + status }, 623 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), 624 | this.createDom('a', { 625 | className: 'description', 626 | href: '?spec=' + encodeURIComponent(spec.getFullName()), 627 | title: spec.getFullName() 628 | }, spec.description)); 629 | 630 | 631 | var resultItems = results.getItems(); 632 | var messagesDiv = this.createDom('div', { className: 'messages' }); 633 | for (var i = 0; i < resultItems.length; i++) { 634 | var result = resultItems[i]; 635 | 636 | if (result.type == 'log') { 637 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); 638 | } else if (result.type == 'expect' && result.passed && !result.passed()) { 639 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); 640 | 641 | if (result.trace.stack) { 642 | messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); 643 | } 644 | } 645 | } 646 | 647 | if (messagesDiv.childNodes.length > 0) { 648 | specDiv.appendChild(messagesDiv); 649 | } 650 | 651 | this.suiteDivs[spec.suite.id].appendChild(specDiv); 652 | }; 653 | 654 | jasmine.TrivialReporter.prototype.log = function() { 655 | var console = jasmine.getGlobal().console; 656 | if (console && console.log) { 657 | if (console.log.apply) { 658 | console.log.apply(console, arguments); 659 | } else { 660 | console.log(arguments); // ie fix: console.log.apply doesn't exist on ie 661 | } 662 | } 663 | }; 664 | 665 | jasmine.TrivialReporter.prototype.getLocation = function() { 666 | return this.document.location; 667 | }; 668 | 669 | jasmine.TrivialReporter.prototype.specFilter = function(spec) { 670 | var paramMap = {}; 671 | var params = this.getLocation().search.substring(1).split('&'); 672 | for (var i = 0; i < params.length; i++) { 673 | var p = params[i].split('='); 674 | paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); 675 | } 676 | 677 | if (!paramMap.spec) { 678 | return true; 679 | } 680 | return spec.getFullName().indexOf(paramMap.spec) === 0; 681 | }; 682 | -------------------------------------------------------------------------------- /tests/lib/jasmine-1.3.1/jasmine.css: -------------------------------------------------------------------------------- 1 | body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; } 2 | 3 | #HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; } 4 | #HTMLReporter a { text-decoration: none; } 5 | #HTMLReporter a:hover { text-decoration: underline; } 6 | #HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; } 7 | #HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; } 8 | #HTMLReporter #jasmine_content { position: fixed; right: 100%; } 9 | #HTMLReporter .version { color: #aaaaaa; } 10 | #HTMLReporter .banner { margin-top: 14px; } 11 | #HTMLReporter .duration { color: #aaaaaa; float: right; } 12 | #HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; } 13 | #HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; } 14 | #HTMLReporter .symbolSummary li.passed { font-size: 14px; } 15 | #HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; } 16 | #HTMLReporter .symbolSummary li.failed { line-height: 9px; } 17 | #HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; } 18 | #HTMLReporter .symbolSummary li.skipped { font-size: 14px; } 19 | #HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; } 20 | #HTMLReporter .symbolSummary li.pending { line-height: 11px; } 21 | #HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; } 22 | #HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; } 23 | #HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; } 24 | #HTMLReporter .runningAlert { background-color: #666666; } 25 | #HTMLReporter .skippedAlert { background-color: #aaaaaa; } 26 | #HTMLReporter .skippedAlert:first-child { background-color: #333333; } 27 | #HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; } 28 | #HTMLReporter .passingAlert { background-color: #a6b779; } 29 | #HTMLReporter .passingAlert:first-child { background-color: #5e7d00; } 30 | #HTMLReporter .failingAlert { background-color: #cf867e; } 31 | #HTMLReporter .failingAlert:first-child { background-color: #b03911; } 32 | #HTMLReporter .results { margin-top: 14px; } 33 | #HTMLReporter #details { display: none; } 34 | #HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; } 35 | #HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; } 36 | #HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; } 37 | #HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; } 38 | #HTMLReporter.showDetails .summary { display: none; } 39 | #HTMLReporter.showDetails #details { display: block; } 40 | #HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; } 41 | #HTMLReporter .summary { margin-top: 14px; } 42 | #HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; } 43 | #HTMLReporter .summary .specSummary.passed a { color: #5e7d00; } 44 | #HTMLReporter .summary .specSummary.failed a { color: #b03911; } 45 | #HTMLReporter .description + .suite { margin-top: 0; } 46 | #HTMLReporter .suite { margin-top: 14px; } 47 | #HTMLReporter .suite a { color: #333333; } 48 | #HTMLReporter #details .specDetail { margin-bottom: 28px; } 49 | #HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; } 50 | #HTMLReporter .resultMessage { padding-top: 14px; color: #333333; } 51 | #HTMLReporter .resultMessage span.result { display: block; } 52 | #HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; } 53 | 54 | #TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ } 55 | #TrivialReporter a:visited, #TrivialReporter a { color: #303; } 56 | #TrivialReporter a:hover, #TrivialReporter a:active { color: blue; } 57 | #TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; } 58 | #TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; } 59 | #TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; } 60 | #TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; } 61 | #TrivialReporter .runner.running { background-color: yellow; } 62 | #TrivialReporter .options { text-align: right; font-size: .8em; } 63 | #TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; } 64 | #TrivialReporter .suite .suite { margin: 5px; } 65 | #TrivialReporter .suite.passed { background-color: #dfd; } 66 | #TrivialReporter .suite.failed { background-color: #fdd; } 67 | #TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; } 68 | #TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; } 69 | #TrivialReporter .spec.failed { background-color: #fbb; border-color: red; } 70 | #TrivialReporter .spec.passed { background-color: #bfb; border-color: green; } 71 | #TrivialReporter .spec.skipped { background-color: #bbb; } 72 | #TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; } 73 | #TrivialReporter .passed { background-color: #cfc; display: none; } 74 | #TrivialReporter .failed { background-color: #fbb; } 75 | #TrivialReporter .skipped { color: #777; background-color: #eee; display: none; } 76 | #TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; } 77 | #TrivialReporter .resultMessage .mismatch { color: black; } 78 | #TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; } 79 | #TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; } 80 | #TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; } 81 | #TrivialReporter #jasmine_content { position: fixed; right: 100%; } 82 | #TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; } 83 | -------------------------------------------------------------------------------- /tests/lib/jasmine-affix.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | jasmine-fixture 1.0.5 4 | Makes injecting HTML snippets into the DOM easy & clean! 5 | site: https://github.com/searls/jasmine-fixture 6 | */ 7 | 8 | 9 | (function() { 10 | var createHTMLBlock; 11 | 12 | (function($) { 13 | var jasmineFixture, originalAffix, originalInject, originalJasmineFixture, root, _; 14 | root = this; 15 | originalJasmineFixture = root.jasmineFixture; 16 | originalInject = root.inject; 17 | originalAffix = root.affix; 18 | _ = function(list) { 19 | return { 20 | inject: function(iterator, memo) { 21 | var item, _i, _len, _results; 22 | _results = []; 23 | for (_i = 0, _len = list.length; _i < _len; _i++) { 24 | item = list[_i]; 25 | _results.push(memo = iterator(memo, item)); 26 | } 27 | return _results; 28 | } 29 | }; 30 | }; 31 | root.jasmineFixture = function($) { 32 | var $whatsTheRootOf, applyAttributes, defaultConfiguration, defaults, init, injectContents, isReady, isString, itLooksLikeHtml, rootId, tidyUp; 33 | $.fn.affix = root.affix = function(selectorOptions) { 34 | var $top; 35 | $top = null; 36 | _(selectorOptions.split(/[ ](?=[^\]]*?(?:\[|$))/)).inject(function($parent, elementSelector) { 37 | var $el; 38 | if (elementSelector === ">") { 39 | return $parent; 40 | } 41 | $el = createHTMLBlock($, elementSelector).appendTo($parent); 42 | $top || ($top = $el); 43 | return $el; 44 | }, $whatsTheRootOf(this)); 45 | return $top; 46 | }; 47 | $whatsTheRootOf = function(that) { 48 | if (that.jquery != null) { 49 | return that; 50 | } else if ($('#jasmine_content').length > 0) { 51 | return $('#jasmine_content'); 52 | } else { 53 | return $('
').appendTo('body'); 54 | } 55 | }; 56 | afterEach(function() { 57 | return $('#jasmine_content').remove(); 58 | }); 59 | isReady = false; 60 | rootId = "specContainer"; 61 | defaultConfiguration = { 62 | el: "div", 63 | cssClass: "", 64 | id: "", 65 | text: "", 66 | html: "", 67 | defaultAttribute: "class", 68 | attrs: {} 69 | }; 70 | defaults = $.extend({}, defaultConfiguration); 71 | $.jasmine = { 72 | inject: function(arg, context) { 73 | var $toInject, config, parent; 74 | if (isReady !== true) { 75 | init(); 76 | } 77 | parent = (context ? context : $("#" + rootId)); 78 | $toInject = void 0; 79 | if (itLooksLikeHtml(arg)) { 80 | $toInject = $(arg); 81 | } else { 82 | config = $.extend({}, defaults, arg, { 83 | userString: arg 84 | }); 85 | $toInject = $("<" + config.el + ">"); 86 | applyAttributes($toInject, config); 87 | injectContents($toInject, config); 88 | } 89 | return $toInject.appendTo(parent); 90 | }, 91 | configure: function(config) { 92 | return $.extend(defaults, config); 93 | }, 94 | restoreDefaults: function() { 95 | return defaults = $.extend({}, defaultConfiguration); 96 | }, 97 | noConflict: function() { 98 | root.jasmineFixture = originalJasmineFixture; 99 | root.inject = originalInject; 100 | root.affix = originalAffix; 101 | return this; 102 | } 103 | }; 104 | $.fn.inject = function(html) { 105 | return $.jasmine.inject(html, $(this)); 106 | }; 107 | applyAttributes = function($html, config) { 108 | var attrs, key, _results; 109 | attrs = $.extend({}, { 110 | id: config.id, 111 | "class": config["class"] || config.cssClass 112 | }, config.attrs); 113 | if (isString(config.userString)) { 114 | attrs[config.defaultAttribute] = config.userString; 115 | } 116 | _results = []; 117 | for (key in attrs) { 118 | if (attrs[key]) { 119 | _results.push($html.attr(key, attrs[key])); 120 | } else { 121 | _results.push(void 0); 122 | } 123 | } 124 | return _results; 125 | }; 126 | injectContents = function($el, config) { 127 | if (config.text && config.html) { 128 | throw "Error: because they conflict, you may only configure inject() to set `html` or `text`, not both! \n\nHTML was: " + config.html + " \n\n Text was: " + config.text; 129 | } else if (config.text) { 130 | return $el.text(config.text); 131 | } else { 132 | if (config.html) { 133 | return $el.html(config.html); 134 | } 135 | } 136 | }; 137 | itLooksLikeHtml = function(arg) { 138 | return isString(arg) && arg.indexOf("<") !== -1; 139 | }; 140 | isString = function(arg) { 141 | return arg && arg.constructor === String; 142 | }; 143 | init = function() { 144 | $("body").append("
"); 145 | return isReady = true; 146 | }; 147 | tidyUp = function() { 148 | $("#" + rootId).remove(); 149 | return isReady = false; 150 | }; 151 | $(function($) { 152 | return init(); 153 | }); 154 | afterEach(function() { 155 | return tidyUp(); 156 | }); 157 | return $.jasmine; 158 | }; 159 | if ($) { 160 | jasmineFixture = root.jasmineFixture($); 161 | return root.inject = root.inject || jasmineFixture.inject; 162 | } 163 | })(window.jQuery); 164 | 165 | createHTMLBlock = (function() { 166 | var bindData, bindEvents, parseAttributes, parseClasses, parseContents, parseEnclosure, parseReferences, parseVariableScope, regAttr, regAttrDfn, regAttrs, regCBrace, regClass, regClasses, regData, regDatas, regEvent, regEvents, regExclamation, regId, regReference, regTag, regTagNotContent, regZenTagDfn; 167 | createHTMLBlock = function($, ZenObject, data, functions, indexes) { 168 | var ZenCode, arr, block, blockAttrs, blockClasses, blockHTML, blockId, blockTag, blocks, el, el2, els, forScope, indexName, inner, len, obj, origZenCode, paren, result, ret, zc, zo; 169 | if ($.isPlainObject(ZenObject)) { 170 | ZenCode = ZenObject.main; 171 | } else { 172 | ZenCode = ZenObject; 173 | ZenObject = { 174 | main: ZenCode 175 | }; 176 | } 177 | origZenCode = ZenCode; 178 | if (indexes === undefined) { 179 | indexes = {}; 180 | } 181 | if (ZenCode.charAt(0) === "!" || $.isArray(data)) { 182 | if ($.isArray(data)) { 183 | forScope = ZenCode; 184 | } else { 185 | obj = parseEnclosure(ZenCode, "!"); 186 | obj = obj.substring(obj.indexOf(":") + 1, obj.length - 1); 187 | forScope = parseVariableScope(ZenCode); 188 | } 189 | while (forScope.charAt(0) === "@") { 190 | forScope = parseVariableScope("!for:!" + parseReferences(forScope, ZenObject)); 191 | } 192 | zo = ZenObject; 193 | zo.main = forScope; 194 | el = $(); 195 | if (ZenCode.substring(0, 5) === "!for:" || $.isArray(data)) { 196 | if (!$.isArray(data) && obj.indexOf(":") > 0) { 197 | indexName = obj.substring(0, obj.indexOf(":")); 198 | obj = obj.substr(obj.indexOf(":") + 1); 199 | } 200 | arr = ($.isArray(data) ? data : data[obj]); 201 | zc = zo.main; 202 | if ($.isArray(arr) || $.isPlainObject(arr)) { 203 | $.map(arr, function(value, index) { 204 | var next; 205 | zo.main = zc; 206 | if (indexName !== undefined) { 207 | indexes[indexName] = index; 208 | } 209 | if (!$.isPlainObject(value)) { 210 | value = { 211 | value: value 212 | }; 213 | } 214 | next = createHTMLBlock($, zo, value, functions, indexes); 215 | if (el.length !== 0) { 216 | return $.each(next, function(index, value) { 217 | return el.push(value); 218 | }); 219 | } 220 | }); 221 | } 222 | if (!$.isArray(data)) { 223 | ZenCode = ZenCode.substr(obj.length + 6 + forScope.length); 224 | } else { 225 | ZenCode = ""; 226 | } 227 | } else if (ZenCode.substring(0, 4) === "!if:") { 228 | result = parseContents("!" + obj + "!", data, indexes); 229 | if (result !== "undefined" || result !== "false" || result !== "") { 230 | el = createHTMLBlock($, zo, data, functions, indexes); 231 | } 232 | ZenCode = ZenCode.substr(obj.length + 5 + forScope.length); 233 | } 234 | ZenObject.main = ZenCode; 235 | } else if (ZenCode.charAt(0) === "(") { 236 | paren = parseEnclosure(ZenCode, "(", ")"); 237 | inner = paren.substring(1, paren.length - 1); 238 | ZenCode = ZenCode.substr(paren.length); 239 | zo = ZenObject; 240 | zo.main = inner; 241 | el = createHTMLBlock($, zo, data, functions, indexes); 242 | } else { 243 | blocks = ZenCode.match(regZenTagDfn); 244 | block = blocks[0]; 245 | if (block.length === 0) { 246 | return ""; 247 | } 248 | if (block.indexOf("@") >= 0) { 249 | ZenCode = parseReferences(ZenCode, ZenObject); 250 | zo = ZenObject; 251 | zo.main = ZenCode; 252 | return createHTMLBlock($, zo, data, functions, indexes); 253 | } 254 | block = parseContents(block, data, indexes); 255 | blockClasses = parseClasses($, block); 256 | if (regId.test(block)) { 257 | blockId = regId.exec(block)[1]; 258 | } 259 | blockAttrs = parseAttributes(block, data); 260 | blockTag = (block.charAt(0) === "{" ? "span" : "div"); 261 | if (ZenCode.charAt(0) !== "#" && ZenCode.charAt(0) !== "." && ZenCode.charAt(0) !== "{") { 262 | blockTag = regTag.exec(block)[1]; 263 | } 264 | if (block.search(regCBrace) !== -1) { 265 | blockHTML = block.match(regCBrace)[1]; 266 | } 267 | blockAttrs = $.extend(blockAttrs, { 268 | id: blockId, 269 | "class": blockClasses, 270 | html: blockHTML 271 | }); 272 | el = $("<" + blockTag + ">", blockAttrs); 273 | el.attr(blockAttrs); 274 | el = bindEvents(block, el, functions); 275 | el = bindData(block, el, data); 276 | ZenCode = ZenCode.substr(blocks[0].length); 277 | ZenObject.main = ZenCode; 278 | } 279 | if (ZenCode.length > 0) { 280 | if (ZenCode.charAt(0) === ">") { 281 | if (ZenCode.charAt(1) === "(") { 282 | zc = parseEnclosure(ZenCode.substr(1), "(", ")"); 283 | ZenCode = ZenCode.substr(zc.length + 1); 284 | } else if (ZenCode.charAt(1) === "!") { 285 | obj = parseEnclosure(ZenCode.substr(1), "!"); 286 | forScope = parseVariableScope(ZenCode.substr(1)); 287 | zc = obj + forScope; 288 | ZenCode = ZenCode.substr(zc.length + 1); 289 | } else { 290 | len = Math.max(ZenCode.indexOf("+"), ZenCode.length); 291 | zc = ZenCode.substring(1, len); 292 | ZenCode = ZenCode.substr(len); 293 | } 294 | zo = ZenObject; 295 | zo.main = zc; 296 | els = $(createHTMLBlock($, zo, data, functions, indexes)); 297 | els.appendTo(el); 298 | } 299 | if (ZenCode.charAt(0) === "+") { 300 | zo = ZenObject; 301 | zo.main = ZenCode.substr(1); 302 | el2 = createHTMLBlock($, zo, data, functions, indexes); 303 | $.each(el2, function(index, value) { 304 | return el.push(value); 305 | }); 306 | } 307 | } 308 | ret = el; 309 | return ret; 310 | }; 311 | bindData = function(ZenCode, el, data) { 312 | var datas, i, split; 313 | if (ZenCode.search(regDatas) === 0) { 314 | return el; 315 | } 316 | datas = ZenCode.match(regDatas); 317 | if (datas === null) { 318 | return el; 319 | } 320 | i = 0; 321 | while (i < datas.length) { 322 | split = regData.exec(datas[i]); 323 | if (split[3] === undefined) { 324 | $(el).data(split[1], data[split[1]]); 325 | } else { 326 | $(el).data(split[1], data[split[3]]); 327 | } 328 | i++; 329 | } 330 | return el; 331 | }; 332 | bindEvents = function(ZenCode, el, functions) { 333 | var bindings, fn, i, split; 334 | if (ZenCode.search(regEvents) === 0) { 335 | return el; 336 | } 337 | bindings = ZenCode.match(regEvents); 338 | if (bindings === null) { 339 | return el; 340 | } 341 | i = 0; 342 | while (i < bindings.length) { 343 | split = regEvent.exec(bindings[i]); 344 | if (split[2] === undefined) { 345 | fn = functions[split[1]]; 346 | } else { 347 | fn = functions[split[2]]; 348 | } 349 | $(el).bind(split[1], fn); 350 | i++; 351 | } 352 | return el; 353 | }; 354 | parseAttributes = function(ZenBlock, data) { 355 | var attrStrs, attrs, i, parts; 356 | if (ZenBlock.search(regAttrDfn) === -1) { 357 | return undefined; 358 | } 359 | attrStrs = ZenBlock.match(regAttrDfn); 360 | attrs = {}; 361 | i = 0; 362 | while (i < attrStrs.length) { 363 | parts = regAttr.exec(attrStrs[i]); 364 | attrs[parts[1]] = ""; 365 | if (parts[3] !== undefined) { 366 | attrs[parts[1]] = parseContents(parts[3], data); 367 | } 368 | i++; 369 | } 370 | return attrs; 371 | }; 372 | parseClasses = function($, ZenBlock) { 373 | var classes, clsString, i; 374 | ZenBlock = ZenBlock.match(regTagNotContent)[0]; 375 | if (ZenBlock.search(regClasses) === -1) { 376 | return undefined; 377 | } 378 | classes = ZenBlock.match(regClasses); 379 | clsString = ""; 380 | i = 0; 381 | while (i < classes.length) { 382 | clsString += " " + regClass.exec(classes[i])[1]; 383 | i++; 384 | } 385 | return $.trim(clsString); 386 | }; 387 | parseContents = function(ZenBlock, data, indexes) { 388 | var html; 389 | if (indexes === undefined) { 390 | indexes = {}; 391 | } 392 | html = ZenBlock; 393 | if (data === undefined) { 394 | return html; 395 | } 396 | while (regExclamation.test(html)) { 397 | html = html.replace(regExclamation, function(str, str2) { 398 | var begChar, fn, val; 399 | begChar = ""; 400 | if (str.indexOf("!for:") > 0 || str.indexOf("!if:") > 0) { 401 | return str; 402 | } 403 | if (str.charAt(0) !== "!") { 404 | begChar = str.charAt(0); 405 | str = str.substring(2, str.length - 1); 406 | } 407 | fn = new Function("data", "indexes", "var r=undefined;" + "with(data){try{r=" + str + ";}catch(e){}}" + "with(indexes){try{if(r===undefined)r=" + str + ";}catch(e){}}" + "return r;"); 408 | val = unescape(fn(data, indexes)); 409 | return begChar + val; 410 | }); 411 | } 412 | html = html.replace(/\\./g, function(str) { 413 | return str.charAt(1); 414 | }); 415 | return unescape(html); 416 | }; 417 | parseEnclosure = function(ZenCode, open, close, count) { 418 | var index, ret; 419 | if (close === undefined) { 420 | close = open; 421 | } 422 | index = 1; 423 | if (count === undefined) { 424 | count = (ZenCode.charAt(0) === open ? 1 : 0); 425 | } 426 | if (count === 0) { 427 | return; 428 | } 429 | while (count > 0 && index < ZenCode.length) { 430 | if (ZenCode.charAt(index) === close && ZenCode.charAt(index - 1) !== "\\") { 431 | count--; 432 | } else { 433 | if (ZenCode.charAt(index) === open && ZenCode.charAt(index - 1) !== "\\") { 434 | count++; 435 | } 436 | } 437 | index++; 438 | } 439 | ret = ZenCode.substring(0, index); 440 | return ret; 441 | }; 442 | parseReferences = function(ZenCode, ZenObject) { 443 | ZenCode = ZenCode.replace(regReference, function(str) { 444 | var fn; 445 | str = str.substr(1); 446 | fn = new Function("objs", "var r=\"\";" + "with(objs){try{" + "r=" + str + ";" + "}catch(e){}}" + "return r;"); 447 | return fn(ZenObject, parseReferences); 448 | }); 449 | return ZenCode; 450 | }; 451 | parseVariableScope = function(ZenCode) { 452 | var forCode, rest, tag; 453 | if (ZenCode.substring(0, 5) !== "!for:" && ZenCode.substring(0, 4) !== "!if:") { 454 | return undefined; 455 | } 456 | forCode = parseEnclosure(ZenCode, "!"); 457 | ZenCode = ZenCode.substr(forCode.length); 458 | if (ZenCode.charAt(0) === "(") { 459 | return parseEnclosure(ZenCode, "(", ")"); 460 | } 461 | tag = ZenCode.match(regZenTagDfn)[0]; 462 | ZenCode = ZenCode.substr(tag.length); 463 | if (ZenCode.length === 0 || ZenCode.charAt(0) === "+") { 464 | return tag; 465 | } else if (ZenCode.charAt(0) === ">") { 466 | rest = ""; 467 | rest = parseEnclosure(ZenCode.substr(1), "(", ")", 1); 468 | return tag + ">" + rest; 469 | } 470 | return undefined; 471 | }; 472 | regZenTagDfn = /([#\.\@]?[\w-]+|\[([\w-!?=:"']+(="([^"]|\\")+")? {0,})+\]|\~[\w$]+=[\w$]+|&[\w$]+(=[\w$]+)?|[#\.\@]?!([^!]|\\!)+!){0,}(\{([^\}]|\\\})+\})?/i; 473 | regTag = /(\w+)/i; 474 | regId = /#([\w-!]+)/i; 475 | regTagNotContent = /((([#\.]?[\w-]+)?(\[([\w!]+(="([^"]|\\")+")? {0,})+\])?)+)/i; 476 | regClasses = /(\.[\w-]+)/g; 477 | regClass = /\.([\w-]+)/i; 478 | regReference = /(@[\w$_][\w$_\d]+)/i; 479 | regAttrDfn = /(\[([\w-!]+(="?([^"]|\\")+"?)? {0,})+\])/ig; 480 | regAttrs = /([\w-!]+(="([^"]|\\")+")?)/g; 481 | regAttr = /([\w-!]+)(="?(([^"\]]|\\")+)"?)?/i; 482 | regCBrace = /\{(([^\}]|\\\})+)\}/i; 483 | regExclamation = /(?:([^\\]|^))!([^!]|\\!)+!/g; 484 | regEvents = /\~[\w$]+(=[\w$]+)?/g; 485 | regEvent = /\~([\w$]+)=([\w$]+)/i; 486 | regDatas = /&[\w$]+(=[\w$]+)?/g; 487 | regData = /&([\w$]+)(=([\w$]+))?/i; 488 | return createHTMLBlock; 489 | })(); 490 | 491 | }).call(this); -------------------------------------------------------------------------------- /tests/spec/formatters/24hr.spec.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/tests/spec/formatters/24hr.spec.js -------------------------------------------------------------------------------- /tests/spec/formatters/ampm.spec.js: -------------------------------------------------------------------------------- 1 | describe('formatter/ampm', function(){ 2 | 3 | var view; 4 | 5 | beforeEach(function(){ 6 | view = new $.timeAutocomplete.formatters.ampm(null, {}); 7 | }); 8 | 9 | describe('times', function(){ 10 | 11 | it('should use times passed to it', function(){ 12 | 13 | var times = [ 14 | '1:00 AM', 15 | '1:30 AM', 16 | '1:50 AM', 17 | '1:00 PM', 18 | '3:00 PM' 19 | ]; 20 | 21 | var Formatter = new $.timeAutocomplete.formatters.ampm(null, { 22 | times: times 23 | }); 24 | 25 | expect(Formatter.options.times).toEqual(times); 26 | 27 | }); 28 | 29 | it('should generate times when no times are passed in', function(){ 30 | 31 | expect(view.options.times.length).toEqual(96); 32 | expect(view.options.times[0]).toEqual('12:00 AM'); 33 | expect(view.options.times[1]).toEqual('12:15 AM'); 34 | expect(view.options.times[2]).toEqual('12:30 AM'); 35 | expect(view.options.times[3]).toEqual('12:45 AM'); 36 | expect(view.options.times[4]).toEqual('1:00 AM'); 37 | 38 | }); 39 | 40 | }); 41 | 42 | 43 | describe('increment', function(){ 44 | 45 | it('should start with a different hour and use a 10 increment', function(){ 46 | 47 | var Formatter = new $.timeAutocomplete.formatters.ampm(null, { 48 | increment: 10, 49 | start_hour: 23, 50 | end_hour: 24 51 | }); 52 | 53 | expect(Formatter.options.times.length).toEqual(7); 54 | expect(Formatter.options.times[0]).toEqual('11:00 PM'); 55 | expect(Formatter.options.times[1]).toEqual('11:10 PM'); 56 | expect(Formatter.options.times[2]).toEqual('11:20 PM'); 57 | expect(Formatter.options.times[3]).toEqual('11:30 PM'); 58 | expect(Formatter.options.times[4]).toEqual('11:40 PM'); 59 | expect(Formatter.options.times[5]).toEqual('11:50 PM'); 60 | expect(Formatter.options.times[6]).toEqual('12:00 AM'); 61 | 62 | }); 63 | 64 | it('should start with a different hour and use a 10 increment', function(){ 65 | 66 | var Formatter = new $.timeAutocomplete.formatters.ampm(null, { 67 | increment: 30, 68 | start_hour: 1, 69 | end_hour: 3 70 | }); 71 | 72 | expect(Formatter.options.times.length).toEqual(5); 73 | expect(Formatter.options.times[0]).toEqual('1:00 AM'); 74 | expect(Formatter.options.times[1]).toEqual('1:30 AM'); 75 | expect(Formatter.options.times[2]).toEqual('2:00 AM'); 76 | expect(Formatter.options.times[3]).toEqual('2:30 AM'); 77 | expect(Formatter.options.times[4]).toEqual('3:00 AM'); 78 | 79 | }); 80 | 81 | }); 82 | 83 | describe('am/pm text', function(){ 84 | 85 | it('should change the am/pm text', function(){ 86 | 87 | var Formatter = new $.timeAutocomplete.formatters.ampm(null, { 88 | pm_text: 'pee-em', 89 | am_text: 'eh-em', 90 | start_hour: 11, 91 | end_hour: 13 92 | }); 93 | 94 | var result = ["11:00 eh-em", "11:15 eh-em", "11:30 eh-em", "11:45 eh-em", "12:00 pee-em", "12:15 pee-em", "12:30 pee-em", "12:45 pee-em", "1:00 pee-em"]; 95 | 96 | expect(Formatter.options.times).toEqual(result); 97 | 98 | }); 99 | 100 | }); 101 | 102 | describe('hook_getTimeObjectFromHis', function(){ 103 | 104 | it('should return the proper formatted time when over 12pm', function(){ 105 | 106 | var Formatter = new $.timeAutocomplete.formatters.ampm(null, {}); 107 | expect(Formatter.hook_getTimeObjectFromHis('19:00:00')).toEqual({ 108 | h: 7, 109 | m: '00', 110 | sep: ':', 111 | postfix : ' PM' 112 | }); 113 | 114 | }); 115 | 116 | it('should return the proper formatted time when under 12pm', function(){ 117 | 118 | var Formatter = new $.timeAutocomplete.formatters.ampm(null, {}); 119 | expect(Formatter.hook_getTimeObjectFromHis('05:43:00')).toEqual({ 120 | h: 5, 121 | m: '43', 122 | sep: ':', 123 | postfix : ' AM' 124 | }); 125 | 126 | }); 127 | 128 | it('should return the proper formatted time when under 12pm', function(){ 129 | 130 | var Formatter = new $.timeAutocomplete.formatters.ampm(null, {}); 131 | expect(Formatter.hook_getTimeObjectFromHis('00:43:00')).toEqual({ 132 | h: 12, 133 | m: '43', 134 | sep: ':', 135 | postfix : ' AM' 136 | }); 137 | 138 | }); 139 | 140 | }); 141 | 142 | describe('parseTime', function(){ 143 | 144 | it('should parse any time into H:i:s format', function(){ 145 | 146 | var re = { 147 | '01:00pm': '13:00:00', 148 | '12am': '00:00:00', 149 | '12 a': '00:00:00', 150 | '123 am': '01:23:00', 151 | '13': '13:00:00', 152 | '2330': '23:30:00', 153 | '2:3': '23:00:00', 154 | '2:15am': '02:15:00', 155 | '15:30am': '15:30:00', 156 | '6:30 PM': '18:30:00', 157 | '6:60 PM': '18:00:00', 158 | '25:60 PM': '02:50:00', 159 | '83': '08:30:00', 160 | '27': '02:07:00', 161 | '33': '03:30:00' 162 | }; 163 | 164 | for(var k in re){ 165 | expect(view.parseTime(k)).toEqual(re[k]); 166 | } 167 | 168 | }); 169 | 170 | it('should parse any time into g:i A format', function(){ 171 | 172 | var re = { 173 | '01:00pm': '1:00 PM', 174 | '12am': '12:00 AM', 175 | '12 a': '12:00 AM', 176 | '123 am': '1:23 AM', 177 | '13': '1:00 PM', 178 | '2330': '11:30 PM', 179 | '2:3': '11:00 PM', 180 | '2:15am': '2:15 AM', 181 | '15:30am': '3:30 PM', 182 | '6:30 PM': '6:30 PM', 183 | '12:60 PM': '12:00 PM', 184 | '25:60 PM': '2:50 PM', 185 | '83 PM': '8:30 PM', 186 | '27 PM': '2:07 PM', 187 | '33 PM': '3:30 PM', 188 | '23': '11:00 PM', 189 | '00': '12:00 AM', 190 | '12': '12:00 PM' 191 | }; 192 | 193 | for(var k in re){ 194 | expect(view.parseTime(k, 'g:i A')).toEqual(re[k]); 195 | } 196 | 197 | }); 198 | 199 | }); 200 | 201 | }); -------------------------------------------------------------------------------- /tests/spec/formatters/french.spec.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7shifts/jQueryTimeAutocomplete/3e761d5b60318b9e4b5a1c33305da3f00e318e8f/tests/spec/formatters/french.spec.js -------------------------------------------------------------------------------- /tests/spec/timeAutocomplete.spec.js: -------------------------------------------------------------------------------- 1 | describe("timeAutocomplete", function() { 2 | 3 | var sut, 4 | $el; 5 | 6 | beforeEach(function(){ 7 | $el = affix('input'); 8 | sut = new $.timeAutocomplete._raw($el); 9 | }); 10 | 11 | describe('initialize', function(){ 12 | 13 | it('should merge in default_opts with opts passed in', function(){ 14 | var opts = { passed: 'options', formatter: 'bleh' }; 15 | sut.initialize($el, opts); 16 | expect(sut.options).toEqual($.extend(true, {}, sut.default_opts, opts)); 17 | }); 18 | 19 | }); 20 | 21 | describe('render', function(){ 22 | 23 | beforeEach(function(){ 24 | spyOn(sut, 'setFormatter'); 25 | spyOn(sut, '_callFormatterMethod'); 26 | spyOn(sut, '_callAutocomplete'); 27 | spyOn(sut, '_bindEvents'); 28 | spyOn(sut, '_setupPlaceholder'); 29 | spyOn(sut, '_setValueAsTime'); 30 | 31 | sut.render(); 32 | }); 33 | 34 | it('should call setFormatter', function(){ 35 | expect(sut.setFormatter).toHaveBeenCalled(); 36 | }); 37 | 38 | it('should call _setValueAsTime', function(){ 39 | expect(sut._setValueAsTime).toHaveBeenCalled(); 40 | }); 41 | 42 | it('should call_bindEvents', function(){ 43 | expect(sut._bindEvents).toHaveBeenCalled(); 44 | }); 45 | 46 | it('should call _callAutocomplete', function(){ 47 | expect(sut._callAutocomplete).toHaveBeenCalled(); 48 | }); 49 | 50 | it('should call _setupPlaceholder', function(){ 51 | expect(sut._setupPlaceholder).toHaveBeenCalled(); 52 | }); 53 | 54 | it('should not call _setValueAsTime if this.options.auto_value is false', function(){ 55 | var $ta_el = affix('input'); 56 | var TimeAutocompleteInstance = new $.timeAutocomplete._raw($ta_el); 57 | spyOn(TimeAutocompleteInstance, 'setFormatter'); 58 | spyOn(TimeAutocompleteInstance, '_callFormatterMethod'); 59 | spyOn(TimeAutocompleteInstance, '_callAutocomplete'); 60 | spyOn(TimeAutocompleteInstance, '_bindEvents'); 61 | spyOn(TimeAutocompleteInstance, '_setupPlaceholder'); 62 | spyOn(TimeAutocompleteInstance, '_setValueAsTime'); 63 | 64 | TimeAutocompleteInstance.options.auto_value = false; 65 | TimeAutocompleteInstance.render(); 66 | 67 | expect(TimeAutocompleteInstance._setValueAsTime).not.toHaveBeenCalled(); 68 | }); 69 | 70 | }); 71 | 72 | describe('_setValueAsTime', function(){ 73 | 74 | beforeEach(function(){ 75 | spyOn(sut, 'setTime'); 76 | spyOn(sut, '_attacheUsableTimeData'); 77 | spyOn(sut, '_getCurrentTimeAsValue'); 78 | 79 | }); 80 | 81 | it('should not set time with options.value', function(){ 82 | sut.el = affix('input[value=""]'); 83 | sut.options.value = '03:40:00'; 84 | sut._setValueAsTime(); 85 | expect(sut.setTime).toHaveBeenCalledWith(sut.options.value); 86 | }); 87 | 88 | it('should not set time (string)', function(){ 89 | sut.el = affix('input[value="some thing"]'); 90 | sut._setValueAsTime(); 91 | expect(sut.setTime).not.toHaveBeenCalled(); 92 | }); 93 | 94 | it('should not set the time (badly formed number)', function(){ 95 | sut.el = affix('input[value="03:00:"]'); 96 | sut._setValueAsTime(); 97 | expect(sut.setTime).not.toHaveBeenCalled(); 98 | }); 99 | 100 | it('should set the time', function(){ 101 | sut.el = affix('input[value="03:00:00"]'); 102 | sut._setValueAsTime(); 103 | expect(sut.setTime).toHaveBeenCalledWith('03:00:00'); 104 | }); 105 | 106 | }); 107 | 108 | describe('_callAutocomplete', function(){ 109 | 110 | beforeEach(function(){ 111 | spyOn(sut, '_callFormatterMethod'); 112 | spyOn(sut.el, 'autocomplete'); 113 | sut.options.auto_complete = { wee: 'data' }; 114 | sut._callAutocomplete(); 115 | }); 116 | 117 | it('should call our callFormatterMethod with args', function(){ 118 | expect(sut._callFormatterMethod.argsForCall[0][0]).toEqual('filterSource'); 119 | expect(sut._callFormatterMethod.argsForCall[0][1]).toEqual([$el]); 120 | expect(function(){ sut._callFormatterMethod.argsForCall[0][2]() }).toThrow('You must set a hook_filterSource method in your formatter.'); 121 | }); 122 | 123 | it('should call autocomplete', function(){ 124 | expect(sut.el.autocomplete).toHaveBeenCalledWith(sut.options.auto_complete); 125 | }); 126 | 127 | }); 128 | 129 | describe('_bindEvents', function(){ 130 | 131 | beforeEach(function(){ 132 | sut.el = affix('input'); 133 | spyOn($.fn, 'bind').andCallThrough(); 134 | spyOn($.fn, 'trigger'); 135 | sut._bindEvents(); 136 | }); 137 | 138 | it('should bind keydown', function(){ 139 | spyOn(sut, '_keydownAutocomplete'); 140 | expect($.fn.bind.argsForCall[0][0]).toEqual('keydown.timeAutocomplete'); 141 | var e = { target: 'a' }; 142 | var ctx = {}; 143 | $.fn.bind.argsForCall[0][1].call(ctx, e); 144 | expect(sut._keydownAutocomplete).toHaveBeenCalledWith(e); 145 | }); 146 | 147 | it('should bind keyup', function(){ 148 | spyOn(sut, '_keyupAutocomplete'); 149 | expect($.fn.bind.argsForCall[1][0]).toEqual('keyup.timeAutocomplete'); 150 | var e = { target: 'a' }; 151 | var ctx = {}; 152 | $.fn.bind.argsForCall[1][1].call(ctx, e); 153 | expect(sut._keyupAutocomplete).toHaveBeenCalledWith(e); 154 | }); 155 | 156 | it('should bind blur', function(){ 157 | spyOn(sut, '_blurAutocomplete'); 158 | expect($.fn.bind.argsForCall[2][0]).toEqual('blur.timeAutocomplete'); 159 | var e = { target: 'a' }; 160 | var ctx = {}; 161 | $.fn.bind.argsForCall[2][1].call(ctx, e); 162 | expect(sut._blurAutocomplete).toHaveBeenCalledWith(e); 163 | }); 164 | 165 | it('should trigger a blur event', function(){ 166 | expect($.fn.trigger).toHaveBeenCalledWith('blur.timeAutocomplete'); 167 | }); 168 | 169 | }); 170 | 171 | describe('_callFormatterMethod', function(){ 172 | 173 | it('should call formatter if it exists', function(){ 174 | var method = 'myMethod'; 175 | sut._formatter = { 176 | hook_myMethod: jasmine.createSpy() 177 | }; 178 | sut._callFormatterMethod(method, ['some', 'args'], 1); 179 | expect(sut._formatter.hook_myMethod).toHaveBeenCalledWith('some', 'args'); 180 | }); 181 | 182 | it('should return default val', function(){ 183 | var method = 'myMethod'; 184 | sut._formatter = {}; 185 | expect(sut._callFormatterMethod(method, ['some', 'args'], 1)).toEqual(1); 186 | }); 187 | 188 | }); 189 | 190 | describe('_readMind', function(){ 191 | 192 | it('should call callFormatterMethod with proper params', function(){ 193 | spyOn(sut, '_callFormatterMethod'); 194 | var v = 'my default val'; 195 | sut._readMind(v); 196 | expect(sut._callFormatterMethod).toHaveBeenCalledWith('readMind', [v], v); 197 | }); 198 | 199 | }); 200 | 201 | describe('_getCurrentTimeAsValue', function(){ 202 | 203 | var _24hr, 204 | times; 205 | 206 | beforeEach(function(){ 207 | times = [ 208 | '12:00 AM', 209 | '12:15 AM', 210 | '11:00 PM', 211 | '11:15 PM', 212 | '11:30 PM', 213 | '11:45 PM', 214 | '12:00 AM' 215 | ]; 216 | 217 | _24hr = { 218 | '12:00 AM': '00:00:00', 219 | '12:15 AM': '00:15:00', 220 | '11:00 PM': '23:00:00', 221 | '11:15 PM': '23:15:00', 222 | '11:30 PM': '23:30:00', 223 | '11:45 PM': '23:45:00' 224 | }; 225 | 226 | spyOn(sut, 'getFormatter').andReturn({ 227 | options: { 228 | times: times 229 | } 230 | }); 231 | 232 | spyOn(sut, '_callFormatterMethod').andCallFake(function(method, args){ 233 | 234 | var time_parts = _24hr[args[0]].split(':'); 235 | var h = time_parts[0]; 236 | var m = time_parts[1]; 237 | 238 | return (new Date(args[1][0], args[1][1], args[1][2], h, m)).getTime(); 239 | }); 240 | }); 241 | 242 | it('should set the proper start time based on the users current time: 11:23 PM', function(){ 243 | 244 | spyOn(sut, '_getCurrentDate').andReturn(new Date(1999, 1, 1, 23, 23)); 245 | var val = sut._getCurrentTimeAsValue(); 246 | expect(val).toEqual('11:30 PM'); 247 | 248 | }); 249 | 250 | it('should set the proper start time based on the users current time 11:58 PM', function(){ 251 | 252 | spyOn(sut, '_getCurrentDate').andReturn(new Date(1999, 1, 1, 23, 58)); 253 | var val = sut._getCurrentTimeAsValue(); 254 | expect(val).toEqual('12:00 AM'); 255 | 256 | }); 257 | 258 | it('should set the proper start time based on the users current time 11:45 PM', function(){ 259 | 260 | spyOn(sut, '_getCurrentDate').andReturn(new Date(1999, 1, 1, 23, 45)); 261 | var val = sut._getCurrentTimeAsValue(); 262 | expect(val).toEqual('11:45 PM'); 263 | 264 | }); 265 | 266 | }); 267 | 268 | }); -------------------------------------------------------------------------------- /timeAutocomplete.jquery.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "timeAutocomplete", 3 | "title": "jQuery Time Autocomplete", 4 | "description": "A time autocomplete plugin similar to how Google Calendar's time autocomplete works.", 5 | "keywords": [ 6 | "time", 7 | "autocomplete" 8 | ], 9 | "version": "1.0.2", 10 | "author": { 11 | "name": "Jordan Boesch" 12 | }, 13 | "licenses": [ 14 | { 15 | "type": "MIT", 16 | "url": "https://github.com/7shifts/jQueryTimeAutocomplete/blob/master/MIT-LICENSE.txt" 17 | } 18 | ], 19 | "bugs": "https://github.com/7shifts/jQueryTimeAutocomplete/issues", 20 | "homepage": "http://7shifts.com/blog/better-time-drop-downs-jquery-timeautocomplete/", 21 | "docs": "http://7shifts.com/blog/better-time-drop-downs-jquery-timeautocomplete/", 22 | "download": "http://7shifts.com/blog/better-time-drop-downs-jquery-timeautocomplete/", 23 | "dependencies": { 24 | "jquery": ">=1.10" 25 | } 26 | } --------------------------------------------------------------------------------