PageSourceSearch

https://calcasieulibrary.org/js/lib/bootstrap-timepicker.js?v=1480

js calcasieulibrary.org collected 2026-09-25 19:15:20 UTC 34,374 bytes, 1,177 lines download raw bytes

1/*!
2 * Timepicker Component for Twitter Bootstrap
3 *
4 * Copyright 2013 Joris de Wit and bootstrap-timepicker contributors
5 *
6 * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11(function($, window, document) {
12  'use strict';
13
14  // TIMEPICKER PUBLIC CLASS DEFINITION
15  var Timepicker = function(element, options) {
16    this.widget = '';
17    this.$element = $(element);
18    this.defaultTime = options.defaultTime;
19    this.disableFocus = options.disableFocus;
20    this.disableMousewheel = options.disableMousewheel;
21    this.isOpen = options.isOpen;
22    this.minuteStep = options.minuteStep;
23    this.modalBackdrop = options.modalBackdrop;
24    this.orientation = options.orientation;
25    this.secondStep = options.secondStep;
26    this.snapToStep = options.snapToStep;
27    this.showInputs = options.showInputs;
28    this.showMeridian = options.showMeridian;
29    this.showSeconds = options.showSeconds;
30    this.template = options.template;
31    this.appendWidgetTo = options.appendWidgetTo;
32    this.showWidgetOnAddonClick = options.showWidgetOnAddonClick;
33    this.icons = options.icons;
34    this.maxHours = options.maxHours;
35    this.explicitMode = options.explicitMode; // If true 123 = 1:23, 12345 = 1:23:45, else invalid.
36
37    this.handleDocumentClick = function (e) {
38      var self = e.data.scope;
39      // This condition was inspired by bootstrap-datepicker.
40      // The element the timepicker is invoked on is the input but it has a sibling for addon/button.
41      if (!(self.$element.parent().find(e.target).length ||
42          self.$widget.is(e.target) ||
43          self.$widget.find(e.target).length)) {
44        self.hideWidget();
45      }
46    };
47
48    this._init();
49  };
50
51  Timepicker.prototype = {
52
53    constructor: Timepicker,
54    _init: function() {
55      var self = this;
56
57      if (this.showWidgetOnAddonClick && (this.$element.parent().hasClass('input-group') && this.$element.parent().hasClass('bootstrap-timepicker'))) {
58        this.$element.parent('.input-group.bootstrap-timepicker').find('.input-group-addon').on({
59          'click.timepicker': $.proxy(this.showWidget, this)
60        });
61        this.$element.on({
62          'focus.timepicker': $.proxy(this.highlightUnit, this),
63          'click.timepicker': $.proxy(this.highlightUnit, this),
64          'keydown.timepicker': $.proxy(this.elementKeydown, this),
65          'blur.timepicker': $.proxy(this.blurElement, this),
66          'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this)
67        });
68      } else {
69        if (this.template) {
70          this.$element.on({
71            'focus.timepicker': $.proxy(this.showWidget, this),
72            'click.timepicker': $.proxy(this.showWidget, this),
73            'blur.timepicker': $.proxy(this.blurElement, this),
74            'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this)
75          });
76        } else {
77          this.$element.on({
78            'focus.timepicker': $.proxy(this.highlightUnit, this),
79            'click.timepicker': $.proxy(this.highlightUnit, this),
80            'keydown.timepicker': $.proxy(this.elementKeydown, this),
81            'blur.timepicker': $.proxy(this.blurElement, this),
82            'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this)
83          });
84        }
85      }
86
87      if (this.template !== false) {
88        this.$widget = $(this.getTemplate()).on('click', $.proxy(this.widgetClick, this));
89      } else {
90        this.$widget = false;
91      }
92
93      if (this.showInputs && this.$widget !== false) {
94        this.$widget.find('input').each(function() {
95          $(this).on({
96            'click.timepicker': function() { $(this).select(); },
97            'keydown.timepicker': $.proxy(self.widgetKeydown, self),
98            'keyup.timepicker': $.proxy(self.widgetKeyup, self)
99          });
100        });
101      }
102
103      this.setDefaultTime(this.defaultTime);
104    },
105
106    blurElement: function() {
107      this.highlightedUnit = null;
108      this.updateFromElementVal();
109    },
110
111    clear: function() {
112      this.hour = '';
113      this.minute = '';
114      this.second = '';
115      this.meridian = '';
116
117      this.$element.val('');
118    },
119
120    decrementHour: function() {
121      if (this.showMeridian) {
122        if (this.hour === 1) {
123          this.hour = 12;
124        } else if (this.hour === 12) {
125          this.hour--;
126
127          return this.toggleMeridian();
128        } else if (this.hour === 0) {
129          this.hour = 11;
130
131          return this.toggleMeridian();
132        } else {
133          this.hour--;
134        }
135      } else {
136        if (this.hour <= 0) {
137          this.hour = this.maxHours - 1;
138        } else {
139          this.hour--;
140        }
141      }
142    },
143
144    decrementMinute: function(step) {
145      var newVal;
146
147      if (step) {
148        newVal = this.minute - step;
149      } else {
150        newVal = this.minute - this.minuteStep;
151      }
152
153      if (newVal < 0) {
154        this.decrementHour();
155        this.minute = newVal + 60;
156      } else {
157        this.minute = newVal;
158      }
159    },
160
161    decrementSecond: function() {
162      var newVal = this.second - this.secondStep;
163
164      if (newVal < 0) {
165        this.decrementMinute(true);
166        this.second = newVal + 60;
167      } else {
168        this.second = newVal;
169      }
170    },
171
172    elementKeydown: function(e) {
173      switch (e.which) {
174      case 9: //tab
175        if (e.shiftKey) {
176          if (this.highlightedUnit === 'hour') {
177            this.hideWidget();
178            break;
179          }
180          this.highlightPrevUnit();
181        } else if ((this.showMeridian && this.highlightedUnit === 'meridian') || (this.showSeconds && this.highlightedUnit === 'second') || (!this.showMeridian && !this.showSeconds && this.highlightedUnit ==='minute')) {
182          this.hideWidget();
183          break;
184        } else {
185          this.highlightNextUnit();
186        }
187        e.preventDefault();
188        this.updateFromElementVal();
189        break;
190      case 27: // escape
191        this.updateFromElementVal();
192        break;
193      case 37: // left arrow
194        e.preventDefault();
195        this.highlightPrevUnit();
196        this.updateFromElementVal();
197        break;
198      case 38: // up arrow
199        e.preventDefault();
200        switch (this.highlightedUnit) {
201        case 'hour':
202          this.incrementHour();
203          this.highlightHour();
204          break;
205        case 'minute':
206          this.incrementMinute();
207          this.highlightMinute();
208          break;
209        case 'second':
210          this.incrementSecond();
211          this.highlightSecond();
212          break;
213        case 'meridian':
214          this.toggleMeridian();
215          this.highlightMeridian();
216          break;
217        }
218        this.update();
219        break;
220      case 39: // right arrow
221        e.preventDefault();
222        this.highlightNextUnit();
223        this.updateFromElementVal();
224        break;
225      case 40: // down arrow
226        e.preventDefault();
227        switch (this.highlightedUnit) {
228        case 'hour':
229          this.decrementHour();
230          this.highlightHour();
231          break;
232        case 'minute':
233          this.decrementMinute();
234          this.highlightMinute();
235          break;
236        case 'second':
237          this.decrementSecond();
238          this.highlightSecond();
239          break;
240        case 'meridian':
241          this.toggleMeridian();
242          this.highlightMeridian();
243          break;
244        }
245
246        this.update();
247        break;
248      }
249    },
250
251    getCursorPosition: function() {
252      var input = this.$element.get(0);
253
254      if ('selectionStart' in input) {// Standard-compliant browsers
255
256        return input.selectionStart;
257      } else if (document.selection) {// IE fix
258        input.focus();
259        var sel = document.selection.createRange(),
260          selLen = document.selection.createRange().text.length;
261
262        sel.moveStart('character', - input.value.length);
263
264        return sel.text.length - selLen;
265      }
266    },
267
268    getTemplate: function() {
269      var template,
270        hourTemplate,
271        minuteTemplate,
272        secondTemplate,
273        meridianTemplate,
274        templateContent;
275
276      if (this.showInputs) {
277        hourTemplate = '<input type="text" class="bootstrap-timepicker-hour" maxlength="2"/>';
278        minuteTemplate = '<input type="text" class="bootstrap-timepicker-minute" maxlength="2"/>';
279        secondTemplate = '<input type="text" class="bootstrap-timepicker-second" maxlength="2"/>';
280        meridianTemplate = '<input type="text" class="bootstrap-timepicker-meridian" maxlength="2"/>';
281      } else {
282        hourTemplate = '<span class="bootstrap-timepicker-hour"></span>';
283        minuteTemplate = '<span class="bootstrap-timepicker-minute"></span>';
284        secondTemplate = '<span class="bootstrap-timepicker-second"></span>';
285        meridianTemplate = '<span class="bootstrap-timepicker-meridian"></span>';
286      }
287
288      templateContent = '<table>'+
289         '<tr>'+
290           '<td><a href="#" data-action="incrementHour"><span class="'+ this.icons.up +'"></span></a></td>'+
291           '<td class="separator">&nbsp;</td>'+
292           '<td><a href="#" data-action="incrementMinute"><span class="'+ this.icons.up +'"></span></a></td>'+
293           (this.showSeconds ?
294             '<td class="separator">&nbsp;</td>'+
295             '<td><a href="#" data-action="incrementSecond"><span class="'+ this.icons.up +'"></span></a></td>'
296           : '') +
297           (this.showMeridian ?
298             '<td class="separator">&nbsp;</td>'+
299             '<td class="meridian-column"><a href="#" data-action="toggleMeridian"><span class="'+ this.icons.up +'"></span></a></td>'
300           : '') +
301         '</tr>'+
302         '<tr>'+
303           '<td>'+ hourTemplate +'</td> '+
304           '<td class="separator">:</td>'+
305           '<td>'+ minuteTemplate +'</td> '+
306           (this.showSeconds ?
307            '<td class="separator">:</td>'+
308            '<td>'+ secondTemplate +'</td>'
309           : '') +
310           (this.showMeridian ?
311            '<td class="separator">&nbsp;</td>'+
312            '<td>'+ meridianTemplate +'</td>'
313           : '') +
314         '</tr>'+
315         '<tr>'+
316           '<td><a href="#" data-action="decrementHour"><span class="'+ this.icons.down +'"></span></a></td>'+
317           '<td class="separator"></td>'+
318           '<td><a href="#" data-action="decrementMinute"><span class="'+ this.icons.down +'"></span></a></td>'+
319           (this.showSeconds ?
320            '<td class="separator">&nbsp;</td>'+
321            '<td><a href="#" data-action="decrementSecond"><span class="'+ this.icons.down +'"></span></a></td>'
322           : '') +
323           (this.showMeridian ?
324            '<td class="separator">&nbsp;</td>'+
325            '<td><a href="#" data-action="toggleMeridian"><span class="'+ this.icons.down +'"></span></a></td>'
326           : '') +
327         '</tr>'+
328       '</table>';
329
330      switch(this.template) {
331      case 'modal':
332        template = '<div class="bootstrap-timepicker-widget modal hide fade in" data-backdrop="'+ (this.modalBackdrop ? 'true' : 'false') +'">'+
333          '<div class="modal-header">'+
334            '<a href="#" class="close" data-dismiss="modal">&times;</a>'+
335            '<h3>
335Pick a Time</h3>'+
336          '</div>'+
337          '<div class="modal-content">'+
338            templateContent +
339          '</div>'+
340          '<div class="modal-footer">'+
341            '<a href="#" class="btn btn-primary" data-dismiss="modal">OK</a>'+
342          '</div>'+
343        '</div>';
344        break;
345      case 'dropdown':
346        template = '<div class="bootstrap-timepicker-widget dropdown-menu">'+ templateContent +'</div>';
347        break;
348      }
349
350      return template;
351    },
352
353    getTime: function() {
354      if (this.hour === '') {
355        return '';
356      }
357
358      return this.hour + ':' + (this.minute.toString().length === 1 ? '0' + this.minute : this.minute) + (this.showSeconds ? ':' + (this.second.toString().length === 1 ? '0' + this.second : this.second) : '') + (this.showMeridian ? ' ' + this.meridian : '');
359    },
360
361    hideWidget: function() {
362      if (this.isOpen === false) {
363        return;
364      }
365
366      this.$element.trigger({
367        'type': 'hide.timepicker',
368        'time': {
369          'value': this.getTime(),
370          'hours': this.hour,
371          'minutes': this.minute,
372          'seconds': this.second,
373          'meridian': this.meridian
374        }
375      });
376
377      if (this.template === 'modal' && this.$widget.modal) {
378        this.$widget.modal('hide');
379      } else {
380        this.$widget.removeClass('open');
381      }
382
383      $(document).off('mousedown.timepicker, touchend.timepicker', this.handleDocumentClick);
384
385      this.isOpen = false;
386      // show/hide approach taken by datepicker
387      this.$widget.detach();
388    },
389
390    highlightUnit: function() {
391      this.position = this.getCursorPosition();
392      if (this.position >= 0 && this.position <= 2) {
393        this.highlightHour();
394      } else if (this.position >= 3 && this.position <= 5) {
395        this.highlightMinute();
396      } else if (this.position >= 6 && this.position <= 8) {
397        if (this.showSeconds) {
398          this.highlightSecond();
399        } else {
400          this.highlightMeridian();
401        }
402      } else if (this.position >= 9 && this.position <= 11) {
403        this.highlightMeridian();
404      }
405    },
406
407    highlightNextUnit: function() {
408      switch (this.highlightedUnit) {
409      case 'hour':
410        this.highlightMinute();
411        break;
412      case 'minute':
413        if (this.showSeconds) {
414          this.highlightSecond();
415        } else if (this.showMeridian){
416          this.highlightMeridian();
417        } else {
418          this.highlightHour();
419        }
420        break;
421      case 'second':
422        if (this.showMeridian) {
423          this.highlightMeridian();
424        } else {
425          this.highlightHour();
426        }
427        break;
428      case 'meridian':
429        this.highlightHour();
430        break;
431      }
432    },
433
434    highlightPrevUnit: function() {
435      switch (this.highlightedUnit) {
436      case 'hour':
437        if(this.showMeridian){
438          this.highlightMeridian();
439        } else if (this.showSeconds) {
440          this.highlightSecond();
441        } else {
442          this.highlightMinute();
443        }
444        break;
445      case 'minute':
446        this.highlightHour();
447        break;
448      case 'second':
449        this.highlightMinute();
450        break;
451      case 'meridian':
452        if (this.showSeconds) {
453          this.highlightSecond();
454        } else {
455          this.highlightMinute();
456        }
457        break;
458      }
459    },
460
461    highlightHour: function() {
462      var $element = this.$element.get(0),
463          self = this;
464
465      this.highlightedUnit = 'hour';
466
467      if ($element.setSelectionRange) {
468        setTimeout(function() {
469          if (self.hour < 10) {
470            $element.setSelectionRange(0,1);
471          } else {
472            $element.setSelectionRange(0,2);
473          }
474        }, 0);
475      }
476    },
477
478    highlightMinute: function() {
479      var $element = this.$element.get(0),
480          self = this;
481
482      this.highlightedUnit = 'minute';
483
484      if ($element.setSelectionRange) {
485        setTimeout(function() {
486          if (self.hour < 10) {
487            $element.setSelectionRange(2,4);
488          } else {
489            $element.setSelectionRange(3,5);
490          }
491        }, 0);
492      }
493    },
494
495    highlightSecond: function() {
496      var $element = this.$element.get(0),
497          self = this;
498
499      this.highlightedUnit = 'second';
500
501      if ($element.setSelectionRange) {
502        setTimeout(function() {
503          if (self.hour < 10) {
504            $element.setSelectionRange(5,7);
505          } else {
506            $element.setSelectionRange(6,8);
507          }
508        }, 0);
509      }
510    },
511
512    highlightMeridian: function() {
513      var $element = this.$element.get(0),
514          self = this;
515
516      this.highlightedUnit = 'meridian';
517
518      if ($element.setSelectionRange) {
519        if (this.showSeconds) {
520          setTimeout(function() {
521            if (self.hour < 10) {
522              $element.setSelectionRange(8,10);
523            } else {
524              $element.setSelectionRange(9,11);
525            }
526          }, 0);
527        } else {
528          setTimeout(function() {
529            if (self.hour < 10) {
530              $element.setSelectionRange(5,7);
531            } else {
532              $element.setSelectionRange(6,8);
533            }
534          }, 0);
535        }
536      }
537    },
538
539    incrementHour: function() {
540      if (this.showMeridian) {
541        if (this.hour === 11) {
542          this.hour++;
543          return this.toggleMeridian();
544        } else if (this.hour === 12) {
545          this.hour = 0;
546        }
547      }
548      if (this.hour === this.maxHours - 1) {
549        this.hour = 0;
550
551        return;
552      }
553      this.hour++;
554    },
555
556    incrementMinute: function(step) {
557      var newVal;
558
559      if (step) {
560        newVal = this.minute + step;
561      } else {
562        newVal = this.minute + this.minuteStep - (this.minute % this.minuteStep);
563      }
564
565      if (newVal > 59) {
566        this.incrementHour();
567        this.minute = newVal - 60;
568      } else {
569        this.minute = newVal;
570      }
571    },
572
573    incrementSecond: function() {
574      var newVal = this.second + this.secondStep - (this.second % this.secondStep);
575
576      if (newVal > 59) {
577        this.incrementMinute(true);
578        this.second = newVal - 60;
579      } else {
580        this.second = newVal;
581      }
582    },
583
584    mousewheel: function(e) {
585      if (this.disableMousewheel) {
586        return;
587      }
588
589      e.preventDefault();
590      e.stopPropagation();
591
592      var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail,
593          scrollTo = null;
594
595      if (e.type === 'mousewheel') {
596        scrollTo = (e.originalEvent.wheelDelta * -1);
597      }
598      else if (e.type === 'DOMMouseScroll') {
599        scrollTo = 40 * e.originalEvent.detail;
600      }
601
602      if (scrollTo) {
603        e.preventDefault();
604        $(this).scrollTop(scrollTo + $(this).scrollTop());
605      }
606
607      switch (this.highlightedUnit) {
608      case 'minute':
609        if (delta > 0) {
610          this.incrementMinute();
611        } else {
612          this.decrementMinute();
613        }
614        this.highlightMinute();
615        break;
616      case 'second':
617        if (delta > 0) {
618          this.incrementSecond();
619        } else {
620          this.decrementSecond();
621        }
622        this.highlightSecond();
623        break;
624      case 'meridian':
625        this.toggleMeridian();
626        this.highlightMeridian();
627        break;
628      default:
629        if (delta > 0) {
630          this.incrementHour();
631        } else {
632          this.decrementHour();
633        }
634        this.highlightHour();
635        break;
636      }
637
638      return false;
639    },
640
641    /**
642     * Given a segment value like 43, will round and snap the segment
643     * to the nearest "step", like 45 if step is 15. Segment will
644     * "overflow" to 0 if it's larger than 59 or would otherwise
645     * round up to 60.
646     */
647    changeToNearestStep: function (segment, step) {
648      if (segment % step === 0) {
649        return segment;
650      }
651      if (Math.round((segment % step) / step)) {
652        return (segment + (step - segment % step)) % 60;
653      } else {
654        return segment - segment % step;
655      }
656    },
657
658    // This method was adapted from bootstrap-datepicker.
659    place : function() {
660      if (this.isInline) {
661        return;
662      }
663      var widgetWidth = this.$widget.outerWidth(), widgetHeight = this.$widget.outerHeight(), visualPadding = 10, windowWidth =
664        $(window).width(), windowHeight = $(window).height(), scrollTop = $(window).scrollTop();
665
666      var zIndex = parseInt(this.$element.parents().filter(function() { return $(this).css('z-index') !== 'auto'; }).first().css('z-index'), 10) + 10;
667      var offset = this.component ? this.component.parent().offset() : this.$element.offset();
668      var height = this.component ? this.component.outerHeight(true) : this.$element.outerHeight(false);
669      var width = this.component ? this.component.outerWidth(true) : this.$element.outerWidth(false);
670      var left = offset.left, top = offset.top;
671
672      this.$widget.removeClass('timepicker-orient-top timepicker-orient-bottom timepicker-orient-right timepicker-orient-left');
673
674      if (this.orientation.x !== 'auto') {
675        this.$widget.addClass('timepicker-orient-' + this.orientation.x);
676        if (this.orientation.x === 'right') {
677          left -= widgetWidth - width;
678        }
679      } else{
680        // auto x orientation is best-placement: if it crosses a window edge, fudge it sideways
681        // Default to left
682        this.$widget.addClass('timepicker-orient-left');
683        if (offset.left < 0) {
684          left -= offset.left - visualPadding;
685        } else if (offset.left + widgetWidth > windowWidth) {
686          left = windowWidth - widgetWidth - visualPadding;
687        }
688      }
689      // auto y orientation is best-situation: top or bottom, no fudging, decision based on which shows more of the widget
690      var yorient = this.orientation.y, topOverflow, bottomOverflow;
691      if (yorient === 'auto') {
692        topOverflow = -scrollTop + offset.top - widgetHeight;
693        bottomOverflow = scrollTop + windowHeight - (offset.top + height + widgetHeight);
694        if (Math.max(topOverflow, bottomOverflow) === bottomOverflow) {
695          yorient = 'top';
696        } else {
697          yorient = 'bottom';
698        }
699      }
700      this.$widget.addClass('timepicker-orient-' + yorient);
701      if (yorient === 'top'){
702        top += height;
703      } else{
704        top -= widgetHeight + parseInt(this.$widget.css('padding-top'), 10);
705      }
706
707      this.$widget.css({
708        top : top,
709        left : left,
710        zIndex : zIndex
711      });
712    },
713
714    remove: function() {
715      $('document').off('.timepicker');
716      if (this.$widget) {
717        this.$widget.remove();
718      }
719      delete this.$element.data().timepicker;
720    },
721
722    setDefaultTime: function(defaultTime) {
723      if (!this.$element.val()) {
724        if (defaultTime === 'current') {
725          var dTime = new Date(),
726            hours = dTime.getHours(),
727            minutes = dTime.getMinutes(),
728            seconds = dTime.getSeconds(),
729            meridian = 'AM';
730
731          if (seconds !== 0) {
732            seconds = Math.ceil(dTime.getSeconds() / this.secondStep) * this.secondStep;
733            if (seconds === 60) {
734              minutes += 1;
735              seconds = 0;
736            }
737          }
738
739          if (minutes !== 0) {
740            minutes = Math.ceil(dTime.getMinutes() / this.minuteStep) * this.minuteStep;
741            if (minutes === 60) {
742              hours += 1;
743              minutes = 0;
744            }
745          }
746
747          if (this.showMeridian) {
748            if (hours === 0) {
749              hours = 12;
750            } else if (hours >= 12) {
751              if (hours > 12) {
752                hours = hours - 12;
753              }
754              meridian = 'PM';
755            } else {
756              meridian = 'AM';
757            }
758          }
759
760          this.hour = hours;
761          this.minute = minutes;
762          this.second = seconds;
763          this.meridian = meridian;
764
765          this.update();
766
767        } else if (defaultTime === false) {
768          this.hour = 0;
769          this.minute = 0;
770          this.second = 0;
771          this.meridian = 'AM';
772        } else {
773          this.setTime(defaultTime);
774        }
775      } else {
776        this.updateFromElementVal();
777      }
778    },
779
780    setTime: function(time, ignoreWidget) {
781      if (!time) {
782        this.clear();
783        return;
784      }
785
786      var timeMode,
787          timeArray,
788          hour,
789          minute,
790          second,
791          meridian;
792
793      if (typeof time === 'object' && time.getMonth){
794        // this is a date object
795        hour    = time.getHours();
796        minute  = time.getMinutes();
797        second  = time.getSeconds();
798
799        if (this.showMeridian){
800          meridian = 'AM';
801          if (hour > 12){
802            meridian = 'PM';
803            hour = hour % 12;
804          }
805
806          if (hour === 12){
807            meridian = 'PM';
808          }
809        }
810      } else {
811        timeMode = ((/a/i).test(time) ? 1 : 0) + ((/p/i).test(time) ? 2 : 0); // 0 = none, 1 = AM, 2 = PM, 3 = BOTH.
812        if (timeMode > 2) { // If both are present, fail.
813          this.clear();
814          return;
815        }
816
817        timeArray = time.replace(/[^0-9\:]/g, '').split(':');
818
819        hour = timeArray[0] ? timeArray[0].toString() : timeArray.toString();
820
821        if(this.explicitMode && hour.length > 2 && (hour.length % 2) !== 0 ) {
822          this.clear();
823          return;
824        }
825
826        minute = timeArray[1] ? timeArray[1].toString() : '';
827        second = timeArray[2] ? timeArray[2].toString() : '';
828
829        // adaptive time parsing
830        if (hour.length > 4) {
831          second = hour.slice(-2);
832          hour = hour.slice(0, -2);
833        }
834
835        if (hour.length > 2) {
836          minute = hour.slice(-2);
837          hour = hour.slice(0, -2);
838        }
839
840        if (minute.length > 2) {
841          second = minute.slice(-2);
842          minute = minute.slice(0, -2);
843        }
844
845        hour = parseInt(hour, 10);
846        minute = parseInt(minute, 10);
847        second = parseInt(second, 10);
848
849        if (isNaN(hour)) {
850          hour = 0;
851        }
852        if (isNaN(minute)) {
853          minute = 0;
854        }
855        if (isNaN(second)) {
856          second = 0;
857        }
858
859        // Adjust the time based upon unit boundary.
860        // NOTE: Negatives will never occur due to time.replace() above.
861        if (second > 59) {
862          second = 59;
863        }
864
865        if (minute > 59) {
866          minute = 59;
867        }
868
869        if (hour >= this.maxHours) {
870          // No day/date handling.
871          hour = this.maxHours - 1;
872        }
873
874        if (this.showMeridian) {
875          if (hour > 12) {
876            // Force PM.
877            timeMode = 2;
878            hour -= 12;
879          }
880          if (!timeMode) {
881            timeMode = 1;
882          }
883          if (hour === 0) {
884            hour = 12; // AM or PM, reset to 12.  0 AM = 12 AM.  0 PM = 12 PM, etc.
885          }
886          meridian = timeMode === 1 ? 'AM' : 'PM';
887        } else if (hour < 12 && timeMode === 2) {
888          hour += 12;
889        } else {
890          if (hour >= this.maxHours) {
891            hour = this.maxHours - 1;
892          } else if ((hour < 0) || (hour === 12 && timeMode === 1)){
893            hour = 0;
894          }
895        }
896      }
897
898      this.hour = hour;
899      if (this.snapToStep) {
900        this.minute = this.changeToNearestStep(minute, this.minuteStep);
901        this.second = this.changeToNearestStep(second, this.secondStep);
902      } else {
903        this.minute = minute;
904        this.second = second;
905      }
906      this.meridian = meridian;
907
908      this.update(ignoreWidget);
909    },
910
911    showWidget: function() {
912      if (this.isOpen) {
913        return;
914      }
915
916      if (this.$element.is(':disabled')) {
917        return;
918      }
919
920      // show/hide approach taken by datepicker
921      this.$widget.appendTo(this.appendWidgetTo);
922      $(document).on('mousedown.timepicker, touchend.timepicker', {scope: this}, this.handleDocumentClick);
923
924      this.$element.trigger({
925        'type': 'show.timepicker',
926        'time': {
927          'value': this.getTime(),
928          'hours': this.hour,
929          'minutes': this.minute,
930          'seconds': this.second,
931          'meridian': this.meridian
932        }
933      });
934
935      this.place();
936      if (this.disableFocus) {
937        this.$element.blur();
938      }
939
940      // widget shouldn't be empty on open
941      if (this.hour === '') {
942        if (this.defaultTime) {
943          this.setDefaultTime(this.defaultTime);
944        } else {
945          this.setTime('0:0:0');
946        }
947      }
948
949      if (this.template === 'modal' && this.$widget.modal) {
950        this.$widget.modal('show').on('hidden', $.proxy(this.hideWidget, this));
951      } else {
952        if (this.isOpen === false) {
953          this.$widget.addClass('open');
954        }
955      }
956
957      this.isOpen = true;
958    },
959
960    toggleMeridian: function() {
961      this.meridian = this.meridian === 'AM' ? 'PM' : 'AM';
962    },
963
964    update: function(ignoreWidget) {
965      this.updateElement();
966      if (!ignoreWidget) {
967        this.updateWidget();
968      }
969
970      this.$element.trigger({
971        'type': 'changeTime.timepicker',
972        'time': {
973          'value': this.getTime(),
974          'hours': this.hour,
975          'minutes': this.minute,
976          'seconds': this.second,
977          'meridian': this.meridian
978        }
979      });
980    },
981
982    updateElement: function() {
983      this.$element.val(this.getTime()).change();
984    },
985
986    updateFromElementVal: function() {
987      this.setTime(this.$element.val());
988    },
989
990    updateWidget: function() {
991      if (this.$widget === false) {
992        return;
993      }
994
995      var hour = this.hour,
996          minute = this.minute.toString().length === 1 ? '0' + this.minute : this.minute,
997          second = this.second.toString().length === 1 ? '0' + this.second : this.second;
998
999      if (this.showInputs) {
1000        this.$widget.find('input.bootstrap-timepicker-hour').val(hour);
1001        this.$widget.find('input.bootstrap-timepicker-minute').val(minute);
1002
1003        if (this.showSeconds) {
1004          this.$widget.find('input.bootstrap-timepicker-second').val(second);
1005        }
1006        if (this.showMeridian) {
1007          this.$widget.find('input.bootstrap-timepicker-meridian').val(this.meridian);
1008        }
1009      } else {
1010        this.$widget.find('span.bootstrap-timepicker-hour').text(hour);
1011        this.$widget.find('span.bootstrap-timepicker-minute').text(minute);
1012
1013        if (this.showSeconds) {
1014          this.$widget.find('span.bootstrap-timepicker-second').text(second);
1015        }
1016        if (this.showMeridian) {
1017          this.$widget.find('span.bootstrap-timepicker-meridian').text(this.meridian);
1018        }
1019      }
1020    },
1021
1022    updateFromWidgetInputs: function() {
1023      if (this.$widget === false) {
1024        return;
1025      }
1026
1027      var t = this.$widget.find('input.bootstrap-timepicker-hour').val() + ':' +
1028              this.$widget.find('input.bootstrap-timepicker-minute').val() +
1029              (this.showSeconds ? ':' + this.$widget.find('input.bootstrap-timepicker-second').val() : '') +
1030              (this.showMeridian ? this.$widget.find('input.bootstrap-timepicker-meridian').val() : '')
1031      ;
1032
1033      this.setTime(t, true);
1034    },
1035
1036    widgetClick: function(e) {
1037      e.stopPropagation();
1038      e.preventDefault();
1039
1040      var $input = $(e.target),
1041          action = $input.closest('a').data('action');
1042
1043      if (action) {
1044        this[action]();
1045      }
1046      this.update();
1047
1048      if ($input.is('input')) {
1049        $input.get(0).setSelectionRange(0,2);
1050      }
1051    },
1052
1053    widgetKeydown: function(e) {
1054      var $input = $(e.target),
1055          name = $input.attr('class').replace('bootstrap-timepicker-', '');
1056
1057      switch (e.which) {
1058      case 9: //tab
1059        if (e.shiftKey) {
1060          if (name === 'hour') {
1061            return this.hideWidget();
1062          }
1063        } else if ((this.showMeridian && name === 'meridian') || (this.showSeconds && name === 'second') || (!this.showMeridian && !this.showSeconds && name === 'minute')) {
1064          return this.hideWidget();
1065        }
1066        break;
1067      case 27: // escape
1068        this.hideWidget();
1069        break;
1070      case 38: // up arrow
1071        e.preventDefault();
1072        switch (name) {
1073        case 'hour':
1074          this.incrementHour();
1075          break;
1076        case 'minute':
1077          this.incrementMinute();
1078          break;
1079        case 'second':
1080          this.incrementSecond();
1081          break;
1082        case 'meridian':
1083          this.toggleMeridian();
1084          break;
1085        }
1086        this.setTime(this.getTime());
1087        $input.get(0).setSelectionRange(0,2);
1088        break;
1089      case 40: // down arrow
1090        e.preventDefault();
1091        switch (name) {
1092        case 'hour':
1093          this.decrementHour();
1094          break;
1095        case 'minute':
1096          this.decrementMinute();
1097          break;
1098        case 'second':
1099          this.decrementSecond();
1100          break;
1101        case 'meridian':
1102          this.toggleMeridian();
1103          break;
1104        }
1105        this.setTime(this.getTime());
1106        $input.get(0).setSelectionRange(0,2);
1107        break;
1108      }
1109    },
1110
1111    widgetKeyup: function(e) {
1112      if ((e.which === 65) || (e.which === 77) || (e.which === 80) || (e.which === 46) || (e.which === 8) || (e.which >= 48 && e.which <= 57) || (e.which >= 96 && e.which <= 105)) {
1113        this.updateFromWidgetInputs();
1114      }
1115    }
1116  };
1117
1118  //TIMEPICKER PLUGIN DEFINITION
1119  $.fn.timepicker = function(option) {
1120    var args = Array.apply(null, arguments);
1121    args.shift();
1122    return this.each(function() {
1123      var $this = $(this),
1124        data = $this.data('timepicker'),
1125        options = typeof option === 'object' && option;
1126
1127      if (!data) {
1128        $this.data('timepicker', (data = new Timepicker(this, $.extend({}, $.fn.timepicker.defaults, options, $(this).data()))));
1129      }
1130
1131      if (typeof option === 'string') {
1132        data[option].apply(data, args);
1133      }
1134    });
1135  };
1136
1137  $.fn.timepicker.defaults = {
1138    defaultTime: 'current',
1139    disableFocus: false,
1140    disableMousewheel: false,
1141    isOpen: false,
1142    minuteStep: 15,
1143    modalBackdrop: false,
1144    orientation: { x: 'auto', y: 'auto'},
1145    secondStep: 15,
1146    snapToStep: false,
1147    showSeconds: false,
1148    showInputs: true,
1149    showMeridian: true,
1150    template: 'dropdown',
1151    appendWidgetTo: 'body',
1152    showWidgetOnAddonClick: true,
1153    icons: {
1154      up: 'glyphicon glyphicon-chevron-up',
1155      down: 'glyphicon glyphicon-chevron-down'
1156    },
1157    maxHours: 24,
1158    explicitMode: false
1159  };
1160
1161  $.fn.timepicker.Constructor = Timepicker;
1162
1163  $(document).on(
1164    'focus.timepicker.data-api click.timepicker.data-api',
1165    '[data-provide="timepicker"]',
1166    function(e){
1167      var $this = $(this);
1168      if ($this.data('timepicker')) {
1169        return;
1170      }
1171      e.preventDefault();
1172      // component click requires us to explicitly show it
1173      $this.timepicker();
1174    }
1175  );
1176
1177})(jQuery, window, document);

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.