1/*! 2 * jquery-timepicker v1.6.3 - A jQuery timepicker plugin inspired by Google Calendar. It supports both mouse and keyboard navigation. 3 * Copyright (c) 2015 Jon Thornton - http://jonthornton.github.com/jquery-timepicker/ 4 * License: MIT 5 */ 6 7 8(function (factory) { 9 if (typeof exports === "object" && exports && 10 typeof module === "object" && module && module.exports === exports) { 11 // Browserify. Attach to jQuery module. 12 factory(require("jquery")); 13 } else if (typeof define === 'function' && define.amd) { 14 // AMD. Register as an anonymous module. 15 define(['jquery'], factory); 16 } else { 17 // Browser globals 18 factory(jQuery); 19 } 20}(function ($) { 21 var _baseDate = _generateBaseDate(); 22 var _ONE_DAY = 86400; 23 var _lang = { 24 am: 'am', 25 pm: 'pm', 26 AM: 'AM', 27 PM: 'PM', 28 decimal: '.', 29 mins: 'mins', 30 hr: 'hr', 31 hrs: 'hrs' 32 }; 33 34 var methods = { 35 init: function(options) 36 { 37 return this.each(function() 38 { 39 var self = $(this); 40 41 // pick up settings from data attributes 42 var attributeOptions = []; 43 for (var key in $.fn.timepicker.defaults) { 44 if (self.data(key)) { 45 attributeOptions[key] = self.data(key); 46 } 47 } 48 49 var settings = $.extend({}, $.fn.timepicker.defaults, attributeOptions, options); 50 51 if (settings.lang) { 52 _lang = $.extend(_lang, settings.lang); 53 } 54 55 settings = _parseSettings(settings); 56 self.data('timepicker-settings', settings); 57 self.addClass('ui-timepicker-input'); 58 59 if (settings.useSelect) { 60 _render(self); 61 } else { 62 self.prop('autocomplete', 'off'); 63 self.on('click.timepicker focus.timepicker', methods.show); 64 self.on('change.timepicker', _formatValue); 65 self.on('keydown.timepicker', _keydownhandler); 66 self.on('keyup.timepicker', _keyuphandler); 67 68 _formatValue.call(self.get(0)); 69 } 70 }); 71 }, 72 73 show: function(e) 74 { 75 var self = $(this); 76 var settings = self.data('timepicker-settings'); 77 78 if (e) { 79 if (!settings.showOnFocus) { 80 return true; 81 } 82 83 e.preventDefault(); 84 } 85 86 if (settings.useSelect) { 87 self.data('timepicker-list').focus(); 88 return; 89 } 90 91 if (_hideKeyboard(self)) { 92 // block the keyboard on mobile devices 93 self.blur(); 94 } 95 96 var list = self.data('timepicker-list'); 97 98 // check if input is readonly 99 if (self.prop('readonly')) { 100 return; 101 } 102 103 // check if list needs to be rendered 104 if (!list || list.length === 0 || typeof settings.durationTime === 'function') { 105 _render(self); 106 list = self.data('timepicker-list'); 107 } 108 109 if (_isVisible(list)) { 110 return; 111 } 112 113 // make sure other pickers are hidden 114 methods.hide(); 115 116 // position the dropdown relative to the input 117 list.show(); 118 var listOffset = {}; 119 120 if (settings.orientation.match(/r/)) { 121 // right-align the dropdown 122 listOffset.left = self.offset().left + self.outerWidth() - list.outerWidth() + parseInt(list.css('marginLeft').replace('px', ''), 10); 123 } else { 124 // left-align the dropdown 125 listOffset.left = self.offset().left + parseInt(list.css('marginLeft').replace('px', ''), 10); 126 } 127 128 var verticalOrientation; 129 if (settings.orientation.match(/t/)) { 130 verticalOrientation = 't'; 131 } else if (settings.orientation.match(/b/)) { 132 verticalOrientation = 'b'; 133 } else if ((self.offset().top + self.outerHeight(true) + list.outerHeight()) > $(window).height() + $(window).scrollTop()) { 134 verticalOrientation = 't'; 135 } else { 136 verticalOrientation = 'b'; 137 } 138 139 if (verticalOrientation == 't') { 140 // position the dropdown on top 141 list.addClass('ui-timepicker-positioned-top'); 142 listOffset.top = self.offset().top - list.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10); 143 } else { 144 // put it under the input 145 list.removeClass('ui-timepicker-positioned-top'); 146 listOffset.top = self.offset().top + self.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10); 147 } 148 149 list.offset(listOffset); 150 151 // position scrolling 152 var selected = list.find('.ui-timepicker-selected'); 153 154 if (!selected.length) { 155 if (_getTimeValue(self)) { 156 selected = _findRow(self, list, _time2int(_getTimeValue(self))); 157 } else if (settings.scrollDefault) { 158 selected = _findRow(self, list, settings.scrollDefault); 159 } 160 } 161 162 if (selected && selected.length) { 163 var topOffset = list.scrollTop() + selected.position().top - selected.outerHeight(); 164 list.scrollTop(topOffset); 165 } else { 166 list.scrollTop(0); 167 } 168 169 // attach close handlers 170 $(document).on('touchstart.ui-timepicker mousedown.ui-timepicker', _closeHandler); 171 $(window).on('resize.ui-timepicker', _closeHandler); 172 if (settings.closeOnWindowScroll) { 173 $(document).on('scroll.ui-timepicker', _closeHandler); 174 } 175 176 self.trigger('showTimepicker'); 177 178 return this; 179 }, 180 181 hide: function(e) 182 { 183 var self = $(this); 184 var settings = self.data('timepicker-settings'); 185 186 if (settings && settings.useSelect) { 187 self.blur(); 188 } 189 190 $('.ui-timepicker-wrapper').each(function() { 191 var list = $(this); 192 if (!_isVisible(list)) { 193 return; 194 } 195 196 var self = list.data('timepicker-input'); 197 var settings = self.data('timepicker-settings'); 198 199 if (settings && settings.selectOnBlur) { 200 _selectValue(self); 201 } 202 203 list.hide(); 204 self.trigger('hideTimepicker'); 205 }); 206 207 return this; 208 }, 209 210 option: function(key, value) 211 { 212 return this.each(function(){ 213 var self = $(this); 214 var settings = self.data('timepicker-settings'); 215 var list = self.data('timepicker-list'); 216 217 if (typeof key == 'object') { 218 settings = $.extend(settings, key); 219 220 } else if (typeof key == 'string' && typeof value != 'undefined') { 221 settings[key] = value; 222 223 } else if (typeof key == 'string') { 224 return settings[key]; 225 } 226 227 settings = _parseSettings(settings); 228 229 self.data('timepicker-settings', settings); 230 231 if (list) { 232 list.remove(); 233 self.data('timepicker-list', false); 234 } 235 236 if (settings.useSelect) { 237 _render(self); 238 } 239 }); 240 }, 241 242 getSecondsFromMidnight: function() 243 { 244 return _time2int(_getTimeValue(this)); 245 }, 246 247 getTime: function(relative_date) 248 { 249 var self = this; 250 251 var time_string = _getTimeValue(self); 252 if (!time_string) { 253 return null; 254 } 255 256 if (!relative_date) { 257 relative_date = new Date(); 258 } 259 var offset = _time2int(time_string); 260 261 // construct a Date with today's date, and offset's time 262 var time = new Date(relative_date);
263 time.setHours(offset / 3600); 264 time.setMinutes(offset % 3600 / 60); 265 time.setSeconds(offset % 60); 266 time.setMilliseconds(0); 267 268 return time; 269 }, 270 271 setTime: function(value) 272 { 273 var self = this; 274 var settings = self.data('timepicker-settings'); 275 276 if (settings.forceRoundTime) { 277 var prettyTime = _roundAndFormatTime(_time2int(value), settings) 278 } else { 279 var prettyTime = _int2time(_time2int(value), settings); 280 } 281 282 _setTimeValue(self, prettyTime); 283 if (self.data('timepicker-list')) { 284 _setSelected(self, self.data('timepicker-list')); 285 } 286 287 return this; 288 }, 289 290 remove: function() 291 { 292 var self = this; 293 294 // check if this element is a timepicker 295 if (!self.hasClass('ui-timepicker-input')) { 296 return; 297 } 298 299 var settings = self.data('timepicker-settings'); 300 self.removeAttr('autocomplete', 'off'); 301 self.removeClass('ui-timepicker-input'); 302 self.removeData('timepicker-settings'); 303 self.off('.timepicker'); 304 305 // timepicker-list won't be present unless the user has interacted with this timepicker 306 if (self.data('timepicker-list')) { 307 self.data('timepicker-list').remove(); 308 } 309 310 if (settings.useSelect) { 311 self.show(); 312 } 313 314 self.removeData('timepicker-list'); 315 316 return this; 317 } 318 }; 319 320 // private methods 321 322 function _isVisible(elem) 323 { 324 var el = elem[0]; 325 return el.offsetWidth > 0 && el.offsetHeight > 0; 326 } 327 328 function _parseSettings(settings) 329 { 330 if (settings.minTime) { 331 settings.minTime = _time2int(settings.minTime); 332 } 333 334 if (settings.maxTime) { 335 settings.maxTime = _time2int(settings.maxTime); 336 } 337 338 if (settings.durationTime && typeof settings.durationTime !== 'function') { 339 settings.durationTime = _time2int(settings.durationTime); 340 } 341 342 if (settings.scrollDefault == 'now') { 343 settings.scrollDefault = _time2int(new Date()); 344 } else if (settings.scrollDefault) { 345 settings.scrollDefault = _time2int(settings.scrollDefault); 346 } else if (settings.minTime) { 347 settings.scrollDefault = settings.minTime; 348 } 349 350 if (settings.scrollDefault) { 351 settings.scrollDefault = settings.roundingFunction(settings.scrollDefault, settings); 352 } 353 354 if ($.type(settings.timeFormat) === "string" && settings.timeFormat.match(/[gh]/)) { 355 settings._twelveHourTime = true; 356 } 357 358 if (settings.disableTimeRanges.length > 0) { 359 // convert string times to integers 360 for (var i in settings.disableTimeRanges) { 361 settings.disableTimeRanges[i] = [ 362 _time2int(settings.disableTimeRanges[i][0]), 363 _time2int(settings.disableTimeRanges[i][1]) 364 ]; 365 } 366 367 // sort by starting time 368 settings.disableTimeRanges = settings.disableTimeRanges.sort(function(a, b){ 369 return a[0] - b[0]; 370 }); 371 372 // merge any overlapping ranges 373 for (var i = settings.disableTimeRanges.length-1; i > 0; i--) { 374 if (settings.disableTimeRanges[i][0] <= settings.disableTimeRanges[i-1][1]) { 375 settings.disableTimeRanges[i-1] = [ 376 Math.min(settings.disableTimeRanges[i][0], settings.disableTimeRanges[i-1][0]), 377 Math.max(settings.disableTimeRanges[i][1], settings.disableTimeRanges[i-1][1]) 378 ]; 379 settings.disableTimeRanges.splice(i, 1); 380 } 381 } 382 } 383 384 return settings; 385 } 386 387 function _render(self) 388 { 389 var settings = self.data('timepicker-settings'); 390 var list = self.data('timepicker-list'); 391 392 if (list && list.length) { 393 list.remove(); 394 self.data('timepicker-list', false); 395 } 396 397 if (settings.useSelect) { 398 list = $('<select />', { 'class': 'ui-timepicker-select' }); 399 var wrapped_list = list; 400 } else { 401 list = $('<ul />', { 'class': 'ui-timepicker-list' }); 402 403 var wrapped_list = $('<div />', { 'class': 'ui-timepicker-wrapper', 'tabindex': -1 }); 404 wrapped_list.css({'display':'none', 'position': 'absolute' }).append(list); 405 } 406 407 if (settings.noneOption) { 408 if (settings.noneOption === true) { 409 settings.noneOption = (settings.useSelect) ? 'Time...' : 'None'; 410 } 411 412 if ($.isArray(settings.noneOption)) { 413 for (var i in settings.noneOption) { 414 if (parseInt(i, 10) == i){ 415 var noneElement = _generateNoneElement(settings.noneOption[i], settings.useSelect); 416 list.append(noneElement); 417 } 418 } 419 } else { 420 var noneElement = _generateNoneElement(settings.noneOption, settings.useSelect); 421 list.append(noneElement); 422 } 423 } 424 425 if (settings.className) { 426 wrapped_list.addClass(settings.className); 427 } 428 429 if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) { 430 var stepval = typeof settings.step == 'function' ? 'function' : settings.step; 431 wrapped_list.addClass('ui-timepicker-with-duration'); 432 wrapped_list.addClass('ui-timepicker-step-'+settings.step); 433 } 434 435 var durStart = settings.minTime; 436 if (typeof settings.durationTime === 'function') {
437 durStart = _time2int(settings.durationTime()); 438 } else if (settings.durationTime !== null) { 439 durStart = settings.durationTime; 440 } 441 var start = (settings.minTime !== null) ? settings.minTime : 0; 442 var end = (settings.maxTime !== null) ? settings.maxTime : (start + _ONE_DAY - 1); 443 444 if (end < start) { 445 // make sure the end time is greater than start time, otherwise there will be no list to show 446 end += _ONE_DAY; 447 } 448 449 if (end === _ONE_DAY-1 && $.type(settings.timeFormat) === "string" && settings.show2400) { 450 // show a 24:00 option when using military time 451 end = _ONE_DAY; 452 } 453 454 var dr = settings.disableTimeRanges; 455 var drCur = 0; 456 var drLen = dr.length; 457 458 var stepFunc = settings.step; 459 if (typeof stepFunc != 'function') { 460 stepFunc = function() { 461 return settings.step; 462 } 463 } 464 465 for (var i=start, j=0; i <= end; j++, i += stepFunc(j)*60) { 466 var timeInt = i; 467 var timeString = _int2time(timeInt, settings); 468 469 if (settings.useSelect) { 470 var row = $('<option />', { 'value': timeString }); 471 row.text(timeString); 472 } else { 473 var row = $('<li />'); 474 row.data('time', (timeInt <= 86400 ? timeInt : timeInt % 86400)); 475 row.text(timeString); 476 } 477 478 if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) { 479 var durationString = _int2duration(i - durStart, settings.step); 480 if (settings.useSelect) { 481 row.text(row.text()+' ('+durationString+')'); 482 } else { 483 var duration = $('<span />', { 'class': 'ui-timepicker-duration' }); 484 duration.text(' ('+durationString+')'); 485 row.append(duration); 486 } 487 } 488 489 if (drCur < drLen) { 490 if (timeInt >= dr[drCur][1]) { 491 drCur += 1; 492 } 493 494 if (dr[drCur] && timeInt >= dr[drCur][0] && timeInt < dr[drCur][1]) { 495 if (settings.useSelect) { 496 row.prop('disabled', true); 497 } else { 498 row.addClass('ui-timepicker-disabled'); 499 } 500 } 501 } 502 503 list.append(row); 504 } 505 506 wrapped_list.data('timepicker-input', self); 507 self.data('timepicker-list', wrapped_list); 508 509 if (settings.useSelect) { 510 if (self.val()) { 511 list.val(_roundAndFormatTime(_time2int(self.val()), settings)); 512 } 513 514 list.on('focus', function(){ 515 $(this).data('timepicker-input').trigger('showTimepicker'); 516 }); 517 list.on('blur', function(){ 518 $(this).data('timepicker-input').trigger('hideTimepicker'); 519 }); 520 list.on('change', function(){ 521 _setTimeValue(self, $(this).val(), 'select'); 522 }); 523 524 _setTimeValue(self, list.val(), 'initial'); 525 self.hide().after(list); 526 } else { 527 var appendTo = settings.appendTo; 528 if (typeof appendTo === 'string') { 529 appendTo = $(appendTo); 530 } else if (typeof appendTo === 'function') { 531 appendTo = appendTo(self); 532 } 533 appendTo.append(wrapped_list); 534 _setSelected(self, list); 535 536 list.on('mousedown', 'li', function(e) { 537 538 // hack: temporarily disable the focus handler 539 // to deal with the fact that IE fires 'focus' 540 // events asynchronously 541 self.off('focus.timepicker'); 542 self.on('focus.timepicker-ie-hack', function(){ 543 self.off('focus.timepicker-ie-hack'); 544 self.on('focus.timepicker', methods.show); 545 }); 546 547 if (!_hideKeyboard(self)) { 548 self[0].focus(); 549 } 550 551 // make sure only the clicked row is selected 552 list.find('li').removeClass('ui-timepicker-selected'); 553 $(this).addClass('ui-timepicker-selected'); 554 555 if (_selectValue(self)) { 556 self.trigger('hideTimepicker'); 557 558 list.on('mouseup.timepicker', 'li', function(e) { 559 list.off('mouseup.timepicker'); 560 wrapped_list.hide(); 561 }); 562 } 563 }); 564 } 565 } 566 567 function _generateNoneElement(optionValue, useSelect) 568 { 569 var label, className, value; 570 571 if (typeof optionValue == 'object') { 572 label = optionValue.label; 573 className = optionValue.className; 574 value = optionValue.value; 575 } else if (typeof optionValue == 'string') { 576 label = optionValue; 577 } else { 578 $.error('Invalid noneOption value'); 579 } 580 581 if (useSelect) { 582 return $('<option />', { 583 'value': value, 584 'class': className, 585 'text': label 586 }); 587 } else { 588 return $('<li />', { 589 'class': className, 590 'text': label 591 }).data('time', value); 592 } 593 } 594 595 function _roundAndFormatTime(seconds, settings) 596 { 597 seconds = settings.roundingFunction(seconds, settings); 598 if (seconds !== null) { 599 return _int2time(seconds, settings); 600 } 601 } 602 603 function _generateBaseDate() 604 { 605 return new Date(1970, 1, 1, 0, 0, 0); 606 } 607 608 // event handler to decide whether to close timepicker 609 function _closeHandler(e) 610 { 611 var target = $(e.target); 612 var input = target.closest('.ui-timepicker-input'); 613 if (input.length === 0 && target.closest('.ui-timepicker-wrapper').length === 0) { 614 methods.hide(); 615 $(document).unbind('.ui-timepicker'); 616 $(window).unbind('.ui-timepicker'); 617 } 618 } 619 620 function _hideKeyboard(self) 621 { 622 var settings = self.data('timepicker-settings'); 623 return ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && settings.disableTouchKeyboard); 624 } 625 626 function _findRow(self, list, value) 627 { 628 if (!value && value !== 0) { 629 return false;
630 } 631 632 var settings = self.data('timepicker-settings'); 633 var out = false; 634 var value = settings.roundingFunction(value, settings); 635 636 // loop through the menu items 637 list.find('li').each(function(i, obj) { 638 var jObj = $(obj); 639 if (typeof jObj.data('time') != 'number') { 640 return; 641 } 642 643 if (jObj.data('time') == value) { 644 out = jObj; 645 return false; 646 } 647 }); 648 649 return out; 650 } 651 652 function _setSelected(self, list) 653 { 654 list.find('li').removeClass('ui-timepicker-selected'); 655 656 var timeValue = _time2int(_getTimeValue(self), self.data('timepicker-settings')); 657 if (timeValue === null) { 658 return; 659 } 660 661 var selected = _findRow(self, list, timeValue); 662 if (selected) { 663 664 var topDelta = selected.offset().top - list.offset().top; 665 666 if (topDelta + selected.outerHeight() > list.outerHeight() || topDelta < 0) { 667 list.scrollTop(list.scrollTop() + selected.position().top - selected.outerHeight()); 668 } 669 670 selected.addClass('ui-timepicker-selected'); 671 } 672 } 673 674 675 function _formatValue(e, origin) 676 { 677 if (this.value === '' || origin == 'timepicker') { 678 return; 679 } 680 681 var self = $(this); 682 683 if (self.is(':focus') && (!e || e.type != 'change')) { 684 return; 685 } 686 687 var settings = self.data('timepicker-settings'); 688 var seconds = _time2int(this.value, settings); 689 690 if (seconds === null) { 691 self.trigger('timeFormatError'); 692 return; 693 } 694 695 var rangeError = false;
696 // check that the time in within bounds 697 if (settings.minTime !== null && seconds < settings.minTime) { 698 rangeError = true; 699 } else if (settings.maxTime !== null && seconds > settings.maxTime) { 700 rangeError = true; 701 } 702 703 // check that time isn't within disabled time ranges 704 $.each(settings.disableTimeRanges, function(){ 705 if (seconds >= this[0] && seconds < this[1]) { 706 rangeError = true; 707 return false; 708 } 709 }); 710 711 if (settings.forceRoundTime) { 712 seconds = settings.roundingFunction(seconds, settings); 713 } 714 715 var prettyTime = _int2time(seconds, settings); 716 717 if (rangeError) { 718 if (_setTimeValue(self, prettyTime, 'error')) { 719 self.trigger('timeRangeError'); 720 } 721 } else { 722 _setTimeValue(self, prettyTime); 723 } 724 } 725 726 function _getTimeValue(self) 727 { 728 if (self.is('input')) { 729 return self.val(); 730 } else { 731 // use the element's data attributes to store values 732 return self.data('ui-timepicker-value'); 733 } 734 } 735 736 function _setTimeValue(self, value, source) 737 { 738 if (self.is('input')) { 739 self.val(value); 740 741 var settings = self.data('timepicker-settings'); 742 if (settings.useSelect && source != 'select' && source != 'initial') { 743 self.data('timepicker-list').val(_roundAndFormatTime(value, settings)); 744 } 745 } 746 747 if (self.data('ui-timepicker-value') != value) { 748 self.data('ui-timepicker-value', value); 749 if (source == 'select') { 750 self.trigger('selectTime').trigger('changeTime').trigger('change', 'timepicker'); 751 } else if (source != 'error') { 752 self.trigger('changeTime'); 753 } 754 755 return true; 756 } else { 757 self.trigger('selectTime'); 758 return false; 759 } 760 } 761 762 /* 763 * Keyboard navigation via arrow keys 764 */ 765 function _keydownhandler(e) 766 { 767 var self = $(this); 768 var list = self.data('timepicker-list'); 769 770 if (!list || !_isVisible(list)) { 771 if (e.keyCode == 40) { 772 // show the list! 773 methods.show.call(self.get(0)); 774 list = self.data('timepicker-list'); 775 if (!_hideKeyboard(self)) { 776 self.focus(); 777 } 778 } else { 779 return true; 780 } 781 } 782 783 switch (e.keyCode) { 784 785 case 13: // return 786 if (_selectValue(self)) { 787 methods.hide.apply(this); 788 } 789 790 e.preventDefault(); 791 return false; 792 793 case 38: // up 794 var selected = list.find('.ui-timepicker-selected'); 795 796 if (!selected.length) { 797 list.find('li').each(function(i, obj) { 798 if ($(obj).position().top > 0) { 799 selected = $(obj); 800 return false; 801 } 802 }); 803 selected.addClass('ui-timepicker-selected'); 804 805 } else if (!selected.is(':first-child')) { 806 selected.removeClass('ui-timepicker-selected'); 807 selected.prev().addClass('ui-timepicker-selected'); 808 809 if (selected.prev().position().top < selected.outerHeight()) { 810 list.scrollTop(list.scrollTop() - selected.outerHeight()); 811 } 812 } 813 814 return false; 815 816 case 40: // down 817 selected = list.find('.ui-timepicker-selected'); 818 819 if (selected.length === 0) { 820 list.find('li').each(function(i, obj) { 821 if ($(obj).position().top > 0) { 822 selected = $(obj); 823 return false; 824 } 825 }); 826 827 selected.addClass('ui-timepicker-selected'); 828 } else if (!selected.is(':last-child')) { 829 selected.removeClass('ui-timepicker-selected'); 830 selected.next().addClass('ui-timepicker-selected'); 831 832 if (selected.next().position().top + 2*selected.outerHeight() > list.outerHeight()) { 833 list.scrollTop(list.scrollTop() + selected.outerHeight()); 834 } 835 } 836 837 return false; 838 839 case 27: // escape 840 list.find('li').removeClass('ui-timepicker-selected'); 841 methods.hide(); 842 break; 843 844 case 9: //tab 845 methods.hide(); 846 break; 847 848 default: 849 return true; 850 } 851 } 852 853 /* 854 * Time typeahead 855 */ 856 function _keyuphandler(e) 857 { 858 var self = $(this); 859 var list = self.data('timepicker-list'); 860 861 if (!list || !_isVisible(list)) { 862 return true; 863 } 864 865 if (!self.data('timepicker-settings').typeaheadHighlight) { 866 list.find('li').removeClass('ui-timepicker-selected'); 867 return true; 868 } 869 870 switch (e.keyCode) { 871 872 case 96: // numpad numerals 873 case 97: 874 case 98: 875 case 99: 876 case 100: 877 case 101: 878 case 102: 879 case 103: 880 case 104: 881 case 105: 882 case 48: // numerals 883 case 49: 884 case 50: 885 case 51: 886 case 52: 887 case 53: 888 case 54: 889 case 55: 890 case 56: 891 case 57: 892 case 65: // a 893 case 77: // m 894 case 80: // p 895 case 186: // colon 896 case 8: // backspace 897 case 46: // delete 898 _setSelected(self, list); 899 break; 900 901 default: 902 // list.find('li').removeClass('ui-timepicker-selected'); 903 return; 904 } 905 } 906 907 function _selectValue(self) 908 { 909 var settings = self.data('timepicker-settings'); 910 var list = self.data('timepicker-list'); 911 var timeValue = null; 912 913 var cursor = list.find('.ui-timepicker-selected'); 914 915 if (cursor.hasClass('ui-timepicker-disabled')) { 916 return false;
917 } 918 919 if (cursor.length) { 920 // selected value found 921 timeValue = cursor.data('time'); 922 } 923 924 if (timeValue !== null) { 925 if (typeof timeValue == 'string') { 926 self.val(timeValue); 927 self.trigger('selectTime').trigger('changeTime').trigger('change', 'timepicker'); 928 } else { 929 var timeString = _int2time(timeValue, settings); 930 _setTimeValue(self, timeString, 'select'); 931 } 932 } 933 934 return true; 935 } 936 937 function _int2duration(seconds, step) 938 { 939 seconds = Math.abs(seconds); 940 var minutes = Math.round(seconds/60), 941 duration = [], 942 hours, mins; 943 944 if (minutes < 60) { 945 // Only show (x mins) under 1 hour 946 duration = [minutes, _lang.mins]; 947 } else { 948 hours = Math.floor(minutes/60); 949 mins = minutes%60; 950 951 // Show decimal notation (eg: 1.5 hrs) for 30 minute steps 952 if (step == 30 && mins == 30) { 953 hours += _lang.decimal + 5; 954 } 955 956 duration.push(hours); 957 duration.push(hours == 1 ? _lang.hr : _lang.hrs); 958 959 // Show remainder minutes notation (eg: 1 hr 15 mins) for non-30 minute steps 960 // and only if there are remainder minutes to show 961 if (step != 30 && mins) { 962 duration.push(mins); 963 duration.push(_lang.mins); 964 } 965 } 966 967 return duration.join(' '); 968 } 969 970 function _int2time(seconds, settings) 971 { 972 if (seconds === null) { 973 return; 974 } 975 976 var time = new Date(_baseDate.valueOf() + (seconds*1000)); 977 978 if (isNaN(time.getTime())) { 979 return; 980 } 981 982 if ($.type(settings.timeFormat) === "function") { 983 return settings.timeFormat(time); 984 } 985 986 var output = ''; 987 var hour, code; 988 for (var i=0; i<settings.timeFormat.length; i++) { 989 990 code = settings.timeFormat.charAt(i); 991 switch (code) { 992 993 case 'a': 994 output += (time.getHours() > 11) ? _lang.pm : _lang.am; 995 break; 996 997 case 'A': 998 output += (time.getHours() > 11) ? _lang.PM : _lang.AM; 999 break; 1000 1001 case 'g': 1002 hour = time.getHours() % 12; 1003 output += (hour === 0) ? '12' : hour; 1004 break; 1005 1006 case 'G': 1007 hour = time.getHours(); 1008 if (seconds === _ONE_DAY) hour = 24; 1009 output += hour; 1010 break; 1011 1012 case 'h': 1013 hour = time.getHours() % 12; 1014 1015 if (hour !== 0 && hour < 10) { 1016 hour = '0'+hour; 1017 } 1018 1019 output += (hour === 0) ? '12' : hour; 1020 break; 1021 1022 case 'H': 1023 hour = time.getHours(); 1024 if (seconds === _ONE_DAY) hour = 24; 1025 output += (hour > 9) ? hour : '0'+hour; 1026 break; 1027 1028 case 'i': 1029 var minutes = time.getMinutes(); 1030 output += (minutes > 9) ? minutes : '0'+minutes; 1031 break; 1032 1033 case 's': 1034 seconds = time.getSeconds(); 1035 output += (seconds > 9) ? seconds : '0'+seconds; 1036 break; 1037 1038 case '\\': 1039 // escape character; add the next character and skip ahead 1040 i++; 1041 output += settings.timeFormat.charAt(i); 1042 break; 1043 1044 default: 1045 output += code; 1046 } 1047 } 1048 1049 return output; 1050 } 1051 1052 function _time2int(timeString, settings) 1053 { 1054 if (timeString === '') return null; 1055 if (!timeString || timeString+0 == timeString) return timeString; 1056 1057 if (typeof(timeString) == 'object') { 1058 return timeString.getHours()*3600 + timeString.getMinutes()*60 + timeString.getSeconds(); 1059 } 1060 1061 timeString = timeString.toLowerCase().replace('.', ''); 1062 1063 // if the last character is an "a" or "p", add the "m" 1064 if (timeString.slice(-1) == 'a' || timeString.slice(-1) == 'p') { 1065 timeString += 'm'; 1066 } 1067 1068 var ampmRegex = '(' + 1069 _lang.am.replace('.', '')+'|' + 1070 _lang.pm.replace('.', '')+'|' + 1071 _lang.AM.replace('.', '')+'|' + 1072 _lang.PM.replace('.', '')+')?'; 1073 1074 // try to parse time input 1075 var pattern = new RegExp('^'+ampmRegex+'\\s*([0-2]?[0-9])\\W?([0-5][0-9])?\\W?([0-5][0-9])?\\s*'+ampmRegex+'$'); 1076
1077 var time = timeString.match(pattern); 1078 if (!time) { 1079 return null; 1080 } 1081 1082 var hour = parseInt(time[2]*1, 10); 1083 var ampm = time[1] || time[5]; 1084 var hours = hour; 1085 1086 if (hour <= 12 && ampm) { 1087 var isPm = (ampm == _lang.pm || ampm == _lang.PM); 1088 1089 if (hour == 12) { 1090 hours = isPm ? 12 : 0; 1091 } else { 1092 hours = (hour + (isPm ? 12 : 0)); 1093 } 1094 } 1095 1096 var minutes = ( time[3]*1 || 0 ); 1097 var seconds = ( time[4]*1 || 0 ); 1098 var timeInt = hours*3600 + minutes*60 + seconds; 1099 1100 // if no am/pm provided, intelligently guess based on the scrollDefault 1101 if (!ampm && settings && settings._twelveHourTime && settings.scrollDefault) { 1102 var delta = timeInt - settings.scrollDefault; 1103 if (delta < 0 && delta >= _ONE_DAY / -2) { 1104 timeInt = (timeInt + (_ONE_DAY / 2)) % _ONE_DAY; 1105 } 1106 } 1107 1108 return timeInt; 1109 } 1110 1111 function _pad2(n) { 1112 return ("0" + n).slice(-2); 1113 } 1114 1115 // Plugin entry 1116 $.fn.timepicker = function(method) 1117 { 1118 if (!this.length) return this; 1119 if (methods[method]) { 1120 // check if this element is a timepicker 1121 if (!this.hasClass('ui-timepicker-input')) { 1122 return this; 1123 } 1124 return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 1125 } 1126 else if(typeof method === "object" || !method) { return methods.init.apply(this, arguments); } 1127 else { $.error("Method "+ method + " does not exist on jQuery.timepicker"); } 1128 }; 1129 // Global defaults 1130 $.fn.timepicker.defaults = { 1131 className: null, 1132 minTime: null, 1133 maxTime: null, 1134 durationTime: null, 1135 step: 30, 1136 showDuration: false, 1137 showOnFocus: true, 1138 timeFormat: 'g:ia', 1139 scrollDefault: null, 1140 selectOnBlur: false, 1141 disableTouchKeyboard: false, 1142 forceRoundTime: false, 1143 roundingFunction: function(seconds, settings) { 1144 if (seconds === null) { 1145 return null; 1146 } else { 1147 var offset = seconds % (settings.step*60); // step is in minutes 1148 1149 if (offset >= settings.step*30) { 1150 // if offset is larger than a half step, round up 1151 seconds += (settings.step*60) - offset; 1152 } else { 1153 // round down 1154 seconds -= offset; 1155 } 1156 1157 return seconds; 1158 } 1159 }, 1160 appendTo: 'body', 1161 orientation: 'l', 1162 disableTimeRanges: [], 1163 closeOnWindowScroll: false, 1164 typeaheadHighlight: true, 1165 noneOption: false, 1166 show2400: false 1167 }; 1168}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.