jquery-timepicker-rails 1.4.3 → 1.11.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,16 @@
1
- /************************
2
- jquery-timepicker v1.4.3
3
- http://jonthornton.github.com/jquery-timepicker/
4
-
5
- requires jQuery 1.7+
6
- ************************/
1
+ /*!
2
+ * jquery-timepicker v1.11.4 - 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
+ */
7
6
 
8
7
 
9
8
  (function (factory) {
10
- if (typeof define === 'function' && define.amd) {
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) {
11
14
  // AMD. Register as an anonymous module.
12
15
  define(['jquery'], factory);
13
16
  } else {
@@ -15,28 +18,7 @@ requires jQuery 1.7+
15
18
  factory(jQuery);
16
19
  }
17
20
  }(function ($) {
18
- var _baseDate = _generateBaseDate();
19
21
  var _ONE_DAY = 86400;
20
- var _defaults = {
21
- className: null,
22
- minTime: null,
23
- maxTime: null,
24
- durationTime: null,
25
- step: 30,
26
- showDuration: false,
27
- showOnFocus: true,
28
- timeFormat: 'g:ia',
29
- scrollDefault: null,
30
- selectOnBlur: false,
31
- disableTouchKeyboard: false,
32
- forceRoundTime: false,
33
- appendTo: 'body',
34
- orientation: 'ltr',
35
- disableTimeRanges: [],
36
- closeOnWindowScroll: false,
37
- typeaheadHighlight: true,
38
- noneOption: false
39
- };
40
22
  var _lang = {
41
23
  am: 'am',
42
24
  pm: 'pm',
@@ -48,8 +30,7 @@ requires jQuery 1.7+
48
30
  hrs: 'hrs'
49
31
  };
50
32
 
51
- var methods =
52
- {
33
+ var methods = {
53
34
  init: function(options)
54
35
  {
55
36
  return this.each(function()
@@ -58,13 +39,13 @@ requires jQuery 1.7+
58
39
 
59
40
  // pick up settings from data attributes
60
41
  var attributeOptions = [];
61
- for (var key in _defaults) {
42
+ for (var key in $.fn.timepicker.defaults) {
62
43
  if (self.data(key)) {
63
44
  attributeOptions[key] = self.data(key);
64
45
  }
65
46
  }
66
47
 
67
- var settings = $.extend({}, _defaults, attributeOptions, options);
48
+ var settings = $.extend({}, $.fn.timepicker.defaults, attributeOptions, options);
68
49
 
69
50
  if (settings.lang) {
70
51
  _lang = $.extend(_lang, settings.lang);
@@ -78,10 +59,17 @@ requires jQuery 1.7+
78
59
  _render(self);
79
60
  } else {
80
61
  self.prop('autocomplete', 'off');
81
- self.on('click.timepicker focus.timepicker', methods.show);
62
+ if (settings.showOn) {
63
+ for (var i in settings.showOn) {
64
+ self.on(settings.showOn[i]+'.timepicker', methods.show);
65
+ }
66
+ }
82
67
  self.on('change.timepicker', _formatValue);
83
68
  self.on('keydown.timepicker', _keydownhandler);
84
69
  self.on('keyup.timepicker', _keyuphandler);
70
+ if (settings.disableTextInput) {
71
+ self.on('keydown.timepicker', _disableTextInputHandler);
72
+ }
85
73
 
86
74
  _formatValue.call(self.get(0));
87
75
  }
@@ -94,10 +82,6 @@ requires jQuery 1.7+
94
82
  var settings = self.data('timepicker-settings');
95
83
 
96
84
  if (e) {
97
- if (!settings.showOnFocus) {
98
- return true;
99
- }
100
-
101
85
  e.preventDefault();
102
86
  }
103
87
 
@@ -124,10 +108,13 @@ requires jQuery 1.7+
124
108
  list = self.data('timepicker-list');
125
109
  }
126
110
 
127
- if (list.is(':visible')) {
111
+ if (_isVisible(list)) {
128
112
  return;
129
113
  }
130
114
 
115
+ self.data('ui-timepicker-value', self.val());
116
+ _setSelected(self, list);
117
+
131
118
  // make sure other pickers are hidden
132
119
  methods.hide();
133
120
 
@@ -135,7 +122,7 @@ requires jQuery 1.7+
135
122
  list.show();
136
123
  var listOffset = {};
137
124
 
138
- if (settings.orientation == 'rtl') {
125
+ if (settings.orientation.match(/r/)) {
139
126
  // right-align the dropdown
140
127
  listOffset.left = self.offset().left + self.outerWidth() - list.outerWidth() + parseInt(list.css('marginLeft').replace('px', ''), 10);
141
128
  } else {
@@ -143,11 +130,24 @@ requires jQuery 1.7+
143
130
  listOffset.left = self.offset().left + parseInt(list.css('marginLeft').replace('px', ''), 10);
144
131
  }
145
132
 
146
- if ((self.offset().top + self.outerHeight(true) + list.outerHeight()) > $(window).height() + $(window).scrollTop()) {
133
+ var verticalOrientation;
134
+ if (settings.orientation.match(/t/)) {
135
+ verticalOrientation = 't';
136
+ } else if (settings.orientation.match(/b/)) {
137
+ verticalOrientation = 'b';
138
+ } else if ((self.offset().top + self.outerHeight(true) + list.outerHeight()) > $(window).height() + $(window).scrollTop()) {
139
+ verticalOrientation = 't';
140
+ } else {
141
+ verticalOrientation = 'b';
142
+ }
143
+
144
+ if (verticalOrientation == 't') {
147
145
  // position the dropdown on top
146
+ list.addClass('ui-timepicker-positioned-top');
148
147
  listOffset.top = self.offset().top - list.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10);
149
148
  } else {
150
149
  // put it under the input
150
+ list.removeClass('ui-timepicker-positioned-top');
151
151
  listOffset.top = self.offset().top + self.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10);
152
152
  }
153
153
 
@@ -157,10 +157,11 @@ requires jQuery 1.7+
157
157
  var selected = list.find('.ui-timepicker-selected');
158
158
 
159
159
  if (!selected.length) {
160
- if (_getTimeValue(self)) {
161
- selected = _findRow(self, list, _time2int(_getTimeValue(self)));
160
+ var timeInt = _time2int(_getTimeValue(self));
161
+ if (timeInt !== null) {
162
+ selected = _findRow(self, list, timeInt);
162
163
  } else if (settings.scrollDefault) {
163
- selected = _findRow(self, list, settings.scrollDefault);
164
+ selected = _findRow(self, list, settings.scrollDefault());
164
165
  }
165
166
  }
166
167
 
@@ -171,8 +172,18 @@ requires jQuery 1.7+
171
172
  list.scrollTop(0);
172
173
  }
173
174
 
175
+ // prevent scroll propagation
176
+ if(settings.stopScrollPropagation) {
177
+ $(document).on('wheel.ui-timepicker', '.ui-timepicker-wrapper', function(e){
178
+ e.preventDefault();
179
+ var currentScroll = $(this).scrollTop();
180
+ $(this).scrollTop(currentScroll + e.originalEvent.deltaY);
181
+ });
182
+ }
183
+
174
184
  // attach close handlers
175
185
  $(document).on('touchstart.ui-timepicker mousedown.ui-timepicker', _closeHandler);
186
+ $(window).on('resize.ui-timepicker', _closeHandler);
176
187
  if (settings.closeOnWindowScroll) {
177
188
  $(document).on('scroll.ui-timepicker', _closeHandler);
178
189
  }
@@ -191,8 +202,12 @@ requires jQuery 1.7+
191
202
  self.blur();
192
203
  }
193
204
 
194
- $('.ui-timepicker-wrapper:visible').each(function() {
205
+ $('.ui-timepicker-wrapper').each(function() {
195
206
  var list = $(this);
207
+ if (!_isVisible(list)) {
208
+ return;
209
+ }
210
+
196
211
  var self = list.data('timepicker-input');
197
212
  var settings = self.data('timepicker-settings');
198
213
 
@@ -209,6 +224,10 @@ requires jQuery 1.7+
209
224
 
210
225
  option: function(key, value)
211
226
  {
227
+ if (typeof key == 'string' && typeof value == 'undefined') {
228
+ return $(this).data('timepicker-settings')[key];
229
+ }
230
+
212
231
  return this.each(function(){
213
232
  var self = $(this);
214
233
  var settings = self.data('timepicker-settings');
@@ -216,12 +235,8 @@ requires jQuery 1.7+
216
235
 
217
236
  if (typeof key == 'object') {
218
237
  settings = $.extend(settings, key);
219
-
220
- } else if (typeof key == 'string' && typeof value != 'undefined') {
221
- settings[key] = value;
222
-
223
238
  } else if (typeof key == 'string') {
224
- return settings[key];
239
+ settings[key] = value;
225
240
  }
226
241
 
227
242
  settings = _parseSettings(settings);
@@ -253,12 +268,16 @@ requires jQuery 1.7+
253
268
  return null;
254
269
  }
255
270
 
271
+ var offset = _time2int(time_string);
272
+ if (offset === null) {
273
+ return null;
274
+ }
275
+
256
276
  if (!relative_date) {
257
277
  relative_date = new Date();
258
278
  }
259
- var offset = _time2int(time_string);
260
279
 
261
- // construct a Date with today's date, and offset's time
280
+ // construct a Date from relative date, and offset's time
262
281
  var time = new Date(relative_date);
263
282
  time.setHours(offset / 3600);
264
283
  time.setMinutes(offset % 3600 / 60);
@@ -268,10 +287,26 @@ requires jQuery 1.7+
268
287
  return time;
269
288
  },
270
289
 
290
+ isVisible: function() {
291
+ var self = this;
292
+ var list = self.data('timepicker-list');
293
+ return !!(list && _isVisible(list));
294
+ },
295
+
271
296
  setTime: function(value)
272
297
  {
273
298
  var self = this;
274
- var prettyTime = _int2time(_time2int(value), self.data('timepicker-settings').timeFormat);
299
+ var settings = self.data('timepicker-settings');
300
+
301
+ if (settings.forceRoundTime) {
302
+ var prettyTime = _roundAndFormatTime(_time2int(value), settings)
303
+ } else {
304
+ var prettyTime = _int2time(_time2int(value), settings);
305
+ }
306
+
307
+ if (value && prettyTime === null && settings.noneOption) {
308
+ prettyTime = value;
309
+ }
275
310
 
276
311
  _setTimeValue(self, prettyTime);
277
312
  if (self.data('timepicker-list')) {
@@ -313,6 +348,12 @@ requires jQuery 1.7+
313
348
 
314
349
  // private methods
315
350
 
351
+ function _isVisible(elem)
352
+ {
353
+ var el = elem[0];
354
+ return el.offsetWidth > 0 && el.offsetHeight > 0;
355
+ }
356
+
316
357
  function _parseSettings(settings)
317
358
  {
318
359
  if (settings.minTime) {
@@ -328,19 +369,26 @@ requires jQuery 1.7+
328
369
  }
329
370
 
330
371
  if (settings.scrollDefault == 'now') {
331
- settings.scrollDefault = _time2int(new Date());
332
- } else if (settings.scrollDefault) {
333
- settings.scrollDefault = _time2int(settings.scrollDefault);
372
+ settings.scrollDefault = function() {
373
+ return settings.roundingFunction(_time2int(new Date()), settings);
374
+ }
375
+ } else if (settings.scrollDefault && typeof settings.scrollDefault != 'function') {
376
+ var val = settings.scrollDefault;
377
+ settings.scrollDefault = function() {
378
+ return settings.roundingFunction(_time2int(val), settings);
379
+ }
334
380
  } else if (settings.minTime) {
335
- settings.scrollDefault = settings.minTime;
381
+ settings.scrollDefault = function() {
382
+ return settings.roundingFunction(settings.minTime, settings);
383
+ }
336
384
  }
337
385
 
338
- if (settings.scrollDefault) {
339
- settings.scrollDefault = _time2int(_roundTime(settings.scrollDefault, settings));
386
+ if ($.type(settings.timeFormat) === "string" && settings.timeFormat.match(/[gh]/)) {
387
+ settings._twelveHourTime = true;
340
388
  }
341
389
 
342
- if (settings.timeFormat.match(/[gh]/)) {
343
- settings._twelveHourTime = true;
390
+ if (settings.showOnFocus === false && settings.showOn.indexOf('focus') != -1) {
391
+ settings.showOn.splice(settings.showOn.indexOf('focus'), 1);
344
392
  }
345
393
 
346
394
  if (settings.disableTimeRanges.length > 0) {
@@ -399,7 +447,7 @@ requires jQuery 1.7+
399
447
 
400
448
  if ($.isArray(settings.noneOption)) {
401
449
  for (var i in settings.noneOption) {
402
- if (parseInt(i, 10) === i){
450
+ if (parseInt(i, 10) == i){
403
451
  var noneElement = _generateNoneElement(settings.noneOption[i], settings.useSelect);
404
452
  list.append(noneElement);
405
453
  }
@@ -415,6 +463,7 @@ requires jQuery 1.7+
415
463
  }
416
464
 
417
465
  if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
466
+ var stepval = typeof settings.step == 'function' ? 'function' : settings.step;
418
467
  wrapped_list.addClass('ui-timepicker-with-duration');
419
468
  wrapped_list.addClass('ui-timepicker-step-'+settings.step);
420
469
  }
@@ -428,12 +477,12 @@ requires jQuery 1.7+
428
477
  var start = (settings.minTime !== null) ? settings.minTime : 0;
429
478
  var end = (settings.maxTime !== null) ? settings.maxTime : (start + _ONE_DAY - 1);
430
479
 
431
- if (end <= start) {
480
+ if (end < start) {
432
481
  // make sure the end time is greater than start time, otherwise there will be no list to show
433
482
  end += _ONE_DAY;
434
483
  }
435
484
 
436
- if (end === _ONE_DAY-1 && settings.timeFormat.indexOf('H') !== -1) {
485
+ if (end === _ONE_DAY-1 && $.type(settings.timeFormat) === "string" && settings.show2400) {
437
486
  // show a 24:00 option when using military time
438
487
  end = _ONE_DAY;
439
488
  }
@@ -442,15 +491,23 @@ requires jQuery 1.7+
442
491
  var drCur = 0;
443
492
  var drLen = dr.length;
444
493
 
445
- for (var i=start; i <= end; i += settings.step*60) {
494
+ var stepFunc = settings.step;
495
+ if (typeof stepFunc != 'function') {
496
+ stepFunc = function() {
497
+ return settings.step;
498
+ }
499
+ }
500
+
501
+ for (var i=start, j=0; i <= end; j++, i += stepFunc(j)*60) {
446
502
  var timeInt = i;
447
- var timeString = _int2time(timeInt, settings.timeFormat);
503
+ var timeString = _int2time(timeInt, settings);
448
504
 
449
505
  if (settings.useSelect) {
450
506
  var row = $('<option />', { 'value': timeString });
451
507
  row.text(timeString);
452
508
  } else {
453
509
  var row = $('<li />');
510
+ row.addClass(timeInt % 86400 < 43200 ? 'ui-timepicker-am' : 'ui-timepicker-pm');
454
511
  row.data('time', (timeInt <= 86400 ? timeInt : timeInt % 86400));
455
512
  row.text(timeString);
456
513
  }
@@ -487,7 +544,10 @@ requires jQuery 1.7+
487
544
  self.data('timepicker-list', wrapped_list);
488
545
 
489
546
  if (settings.useSelect) {
490
- list.val(_roundTime(self.val(), settings));
547
+ if (self.val()) {
548
+ list.val(_roundAndFormatTime(_time2int(self.val()), settings));
549
+ }
550
+
491
551
  list.on('focus', function(){
492
552
  $(this).data('timepicker-input').trigger('showTimepicker');
493
553
  });
@@ -498,6 +558,7 @@ requires jQuery 1.7+
498
558
  _setTimeValue(self, $(this).val(), 'select');
499
559
  });
500
560
 
561
+ _setTimeValue(self, list.val(), 'initial');
501
562
  self.hide().after(list);
502
563
  } else {
503
564
  var appendTo = settings.appendTo;
@@ -509,7 +570,7 @@ requires jQuery 1.7+
509
570
  appendTo.append(wrapped_list);
510
571
  _setSelected(self, list);
511
572
 
512
- list.on('mousedown', 'li', function(e) {
573
+ list.on('mousedown click', 'li', function(e) {
513
574
 
514
575
  // hack: temporarily disable the focus handler
515
576
  // to deal with the fact that IE fires 'focus'
@@ -530,7 +591,11 @@ requires jQuery 1.7+
530
591
 
531
592
  if (_selectValue(self)) {
532
593
  self.trigger('hideTimepicker');
533
- wrapped_list.hide();
594
+
595
+ list.on('mouseup.timepicker click.timepicker', 'li', function(e) {
596
+ list.off('mouseup.timepicker click.timepicker');
597
+ wrapped_list.hide();
598
+ });
534
599
  }
535
600
  });
536
601
  }
@@ -560,39 +625,36 @@ requires jQuery 1.7+
560
625
  return $('<li />', {
561
626
  'class': className,
562
627
  'text': label
563
- }).data('time', value);
628
+ }).data('time', String(value));
564
629
  }
565
630
  }
566
631
 
567
- function _roundTime(time, settings)
632
+ function _roundAndFormatTime(seconds, settings)
568
633
  {
569
- if (!$.isNumeric(time)) {
570
- time = _time2int(time);
571
- }
572
-
573
- if (time === null) {
574
- return null;
575
- } else {
576
- var step = settings.step*60;
577
- // round to the nearest step
578
- return _int2time(Math.round(time / step) * step, settings.timeFormat);
634
+ seconds = settings.roundingFunction(seconds, settings);
635
+ if (seconds !== null) {
636
+ return _int2time(seconds, settings);
579
637
  }
580
638
  }
581
639
 
582
- function _generateBaseDate()
583
- {
584
- return new Date(1970, 1, 1, 0, 0, 0);
585
- }
586
-
587
640
  // event handler to decide whether to close timepicker
588
641
  function _closeHandler(e)
589
642
  {
643
+ if (e.target == window) {
644
+ // mobile Chrome fires focus events against window for some reason
645
+ return;
646
+ }
647
+
590
648
  var target = $(e.target);
591
- var input = target.closest('.ui-timepicker-input');
592
- if (input.length === 0 && target.closest('.ui-timepicker-wrapper').length === 0) {
593
- methods.hide();
594
- $(document).unbind('.ui-timepicker');
649
+
650
+ if (target.closest('.ui-timepicker-input').length || target.closest('.ui-timepicker-wrapper').length) {
651
+ // active timepicker was focused. ignore
652
+ return;
595
653
  }
654
+
655
+ methods.hide();
656
+ $(document).unbind('.ui-timepicker');
657
+ $(window).unbind('.ui-timepicker');
596
658
  }
597
659
 
598
660
  function _hideKeyboard(self)
@@ -609,7 +671,7 @@ requires jQuery 1.7+
609
671
 
610
672
  var settings = self.data('timepicker-settings');
611
673
  var out = false;
612
- var halfStep = settings.step*30;
674
+ var value = settings.roundingFunction(value, settings);
613
675
 
614
676
  // loop through the menu items
615
677
  list.find('li').each(function(i, obj) {
@@ -618,10 +680,7 @@ requires jQuery 1.7+
618
680
  return;
619
681
  }
620
682
 
621
- var offset = jObj.data('time') - value;
622
-
623
- // check if the value is less than half a step from each row
624
- if (Math.abs(offset) < halfStep || offset == halfStep) {
683
+ if (jObj.data('time') == value) {
625
684
  out = jObj;
626
685
  return false;
627
686
  }
@@ -653,32 +712,30 @@ requires jQuery 1.7+
653
712
  }
654
713
 
655
714
 
656
- function _formatValue(e)
715
+ function _formatValue(e, origin)
657
716
  {
658
- if (this.value === '') {
717
+ if (this.value === '' || origin == 'timepicker') {
659
718
  return;
660
719
  }
661
720
 
662
721
  var self = $(this);
663
- var list = self.data('timepicker-list');
664
722
 
665
723
  if (self.is(':focus') && (!e || e.type != 'change')) {
666
724
  return;
667
725
  }
668
726
 
669
- var seconds = _time2int(this.value);
727
+ var settings = self.data('timepicker-settings');
728
+ var seconds = _time2int(this.value, settings);
670
729
 
671
730
  if (seconds === null) {
672
731
  self.trigger('timeFormatError');
673
732
  return;
674
733
  }
675
734
 
676
- var settings = self.data('timepicker-settings');
677
735
  var rangeError = false;
678
736
  // check that the time in within bounds
679
- if (settings.minTime !== null && seconds < settings.minTime) {
680
- rangeError = true;
681
- } else if (settings.maxTime !== null && seconds > settings.maxTime) {
737
+ if ((settings.minTime !== null && settings.maxTime !== null)
738
+ && (seconds < settings.minTime || seconds > settings.maxTime)) {
682
739
  rangeError = true;
683
740
  }
684
741
 
@@ -691,18 +748,10 @@ requires jQuery 1.7+
691
748
  });
692
749
 
693
750
  if (settings.forceRoundTime) {
694
- var offset = seconds % (settings.step*60); // step is in minutes
695
-
696
- if (offset >= settings.step*30) {
697
- // if offset is larger than a half step, round up
698
- seconds += (settings.step*60) - offset;
699
- } else {
700
- // round down
701
- seconds -= offset;
702
- }
751
+ seconds = settings.roundingFunction(seconds, settings);
703
752
  }
704
753
 
705
- var prettyTime = _int2time(seconds, settings.timeFormat);
754
+ var prettyTime = _int2time(seconds, settings);
706
755
 
707
756
  if (rangeError) {
708
757
  if (_setTimeValue(self, prettyTime, 'error')) {
@@ -729,15 +778,15 @@ requires jQuery 1.7+
729
778
  self.val(value);
730
779
 
731
780
  var settings = self.data('timepicker-settings');
732
- if (settings.useSelect) {
733
- self.data('timepicker-list').val(_roundTime(value, settings));
781
+ if (settings.useSelect && source != 'select' && source != 'initial') {
782
+ self.data('timepicker-list').val(_roundAndFormatTime(_time2int(value), settings));
734
783
  }
735
784
  }
736
785
 
737
786
  if (self.data('ui-timepicker-value') != value) {
738
787
  self.data('ui-timepicker-value', value);
739
788
  if (source == 'select') {
740
- self.trigger('selectTime').trigger('changeTime').trigger('change');
789
+ self.trigger('selectTime').trigger('changeTime').trigger('change', 'timepicker');
741
790
  } else if (source != 'error') {
742
791
  self.trigger('changeTime');
743
792
  }
@@ -749,6 +798,21 @@ requires jQuery 1.7+
749
798
  }
750
799
  }
751
800
 
801
+ /*
802
+ * Filter freeform input
803
+ */
804
+ function _disableTextInputHandler(e)
805
+ {
806
+ switch (e.keyCode) {
807
+ case 13: // return
808
+ case 9: //tab
809
+ return;
810
+
811
+ default:
812
+ e.preventDefault();
813
+ }
814
+ }
815
+
752
816
  /*
753
817
  * Keyboard navigation via arrow keys
754
818
  */
@@ -757,7 +821,7 @@ requires jQuery 1.7+
757
821
  var self = $(this);
758
822
  var list = self.data('timepicker-list');
759
823
 
760
- if (!list || !list.is(':visible')) {
824
+ if (!list || !_isVisible(list)) {
761
825
  if (e.keyCode == 40) {
762
826
  // show the list!
763
827
  methods.show.call(self.get(0));
@@ -774,6 +838,7 @@ requires jQuery 1.7+
774
838
 
775
839
  case 13: // return
776
840
  if (_selectValue(self)) {
841
+ _formatValue.call(self.get(0), {'type':'change'});
777
842
  methods.hide.apply(this);
778
843
  }
779
844
 
@@ -847,13 +912,9 @@ requires jQuery 1.7+
847
912
  {
848
913
  var self = $(this);
849
914
  var list = self.data('timepicker-list');
915
+ var settings = self.data('timepicker-settings');
850
916
 
851
- if (!list || !list.is(':visible')) {
852
- return true;
853
- }
854
-
855
- if (!self.data('timepicker-settings').typeaheadHighlight) {
856
- list.find('li').removeClass('ui-timepicker-selected');
917
+ if (!list || !_isVisible(list) || settings.disableTextInput) {
857
918
  return true;
858
919
  }
859
920
 
@@ -885,12 +946,12 @@ requires jQuery 1.7+
885
946
  case 186: // colon
886
947
  case 8: // backspace
887
948
  case 46: // delete
888
- _setSelected(self, list);
949
+ if (settings.typeaheadHighlight) {
950
+ _setSelected(self, list);
951
+ } else {
952
+ list.hide();
953
+ }
889
954
  break;
890
-
891
- default:
892
- // list.find('li').removeClass('ui-timepicker-selected');
893
- return;
894
955
  }
895
956
  }
896
957
 
@@ -912,15 +973,13 @@ requires jQuery 1.7+
912
973
  }
913
974
 
914
975
  if (timeValue !== null) {
915
- if (typeof timeValue == 'string') {
916
- self.val(timeValue);
917
- } else {
918
- var timeString = _int2time(timeValue, settings.timeFormat);
919
- _setTimeValue(self, timeString, 'select');
976
+ if (typeof timeValue != 'string') {
977
+ timeValue = _int2time(timeValue, settings);
920
978
  }
979
+
980
+ _setTimeValue(self, timeValue, 'select');
921
981
  }
922
982
 
923
- //self.trigger('change').trigger('selectTime');
924
983
  return true;
925
984
  }
926
985
 
@@ -957,24 +1016,31 @@ requires jQuery 1.7+
957
1016
  return duration.join(' ');
958
1017
  }
959
1018
 
960
- function _int2time(seconds, format)
1019
+ function _int2time(timeInt, settings)
961
1020
  {
962
- if (seconds === null) {
963
- return;
1021
+ if (typeof timeInt != 'number') {
1022
+ return null;
964
1023
  }
965
1024
 
966
- var time = new Date(_baseDate.valueOf() + (seconds*1000));
1025
+ var seconds = parseInt(timeInt%60)
1026
+ , minutes = parseInt((timeInt/60)%60)
1027
+ , hours = parseInt((timeInt/(60*60))%24);
1028
+
1029
+ var time = new Date(1970, 0, 2, hours, minutes, seconds, 0);
967
1030
 
968
1031
  if (isNaN(time.getTime())) {
969
- return;
1032
+ return null;
1033
+ }
1034
+
1035
+ if ($.type(settings.timeFormat) === "function") {
1036
+ return settings.timeFormat(time);
970
1037
  }
971
1038
 
972
1039
  var output = '';
973
1040
  var hour, code;
1041
+ for (var i=0; i<settings.timeFormat.length; i++) {
974
1042
 
975
- for (var i=0; i<format.length; i++) {
976
-
977
- code = format.charAt(i);
1043
+ code = settings.timeFormat.charAt(i);
978
1044
  switch (code) {
979
1045
 
980
1046
  case 'a':
@@ -991,7 +1057,9 @@ requires jQuery 1.7+
991
1057
  break;
992
1058
 
993
1059
  case 'G':
994
- output += time.getHours();
1060
+ hour = time.getHours();
1061
+ if (timeInt === _ONE_DAY) hour = settings.show2400 ? 24 : 0;
1062
+ output += hour;
995
1063
  break;
996
1064
 
997
1065
  case 'h':
@@ -1006,7 +1074,7 @@ requires jQuery 1.7+
1006
1074
 
1007
1075
  case 'H':
1008
1076
  hour = time.getHours();
1009
- if (seconds === _ONE_DAY) hour = 24;
1077
+ if (timeInt === _ONE_DAY) hour = settings.show2400 ? 24 : 0;
1010
1078
  output += (hour > 9) ? hour : '0'+hour;
1011
1079
  break;
1012
1080
 
@@ -1020,6 +1088,12 @@ requires jQuery 1.7+
1020
1088
  output += (seconds > 9) ? seconds : '0'+seconds;
1021
1089
  break;
1022
1090
 
1091
+ case '\\':
1092
+ // escape character; add the next character and skip ahead
1093
+ i++;
1094
+ output += settings.timeFormat.charAt(i);
1095
+ break;
1096
+
1023
1097
  default:
1024
1098
  output += code;
1025
1099
  }
@@ -1030,59 +1104,70 @@ requires jQuery 1.7+
1030
1104
 
1031
1105
  function _time2int(timeString, settings)
1032
1106
  {
1033
- if (timeString === '') return null;
1034
- if (!timeString || timeString+0 == timeString) return timeString;
1035
-
1036
- if (typeof(timeString) == 'object') {
1037
- timeString = timeString.getHours()+':'+_pad2(timeString.getMinutes())+':'+_pad2(timeString.getSeconds());
1107
+ if (timeString === '' || timeString === null) return null;
1108
+ if (typeof timeString == 'object') {
1109
+ return timeString.getHours()*3600 + timeString.getMinutes()*60 + timeString.getSeconds();
1110
+ }
1111
+ if (typeof timeString != 'string') {
1112
+ return timeString;
1038
1113
  }
1039
1114
 
1040
- timeString = timeString.toLowerCase();
1115
+ timeString = timeString.toLowerCase().replace(/[\s\.]/g, '');
1041
1116
 
1042
- var d = new Date(0);
1043
- var time;
1117
+ // if the last character is an "a" or "p", add the "m"
1118
+ if (timeString.slice(-1) == 'a' || timeString.slice(-1) == 'p') {
1119
+ timeString += 'm';
1120
+ }
1044
1121
 
1045
- // try to parse time input
1046
- if (timeString.indexOf(":") === -1) {
1047
- // no colon present
1048
- time = timeString.match(/^([0-9]):?([0-5][0-9])?:?([0-5][0-9])?\s*([pa]?)m?$/);
1122
+ var ampmRegex = '(' +
1123
+ _lang.am.replace('.', '')+'|' +
1124
+ _lang.pm.replace('.', '')+'|' +
1125
+ _lang.AM.replace('.', '')+'|' +
1126
+ _lang.PM.replace('.', '')+')?';
1049
1127
 
1050
- if (!time) {
1051
- time = timeString.match(/^([0-2][0-9]):?([0-5][0-9])?:?([0-5][0-9])?\s*([pa]?)m?$/);
1052
- }
1053
- } else {
1054
- time = timeString.match(/^(\d{1,2})(?::([0-5][0-9]))?(?::([0-5][0-9]))?\s*([pa]?)m?$/);
1055
- }
1128
+ // try to parse time input
1129
+ var pattern = new RegExp('^'+ampmRegex+'([0-9]?[0-9])\\W?([0-5][0-9])?\\W?([0-5][0-9])?'+ampmRegex+'$');
1056
1130
 
1131
+ var time = timeString.match(pattern);
1057
1132
  if (!time) {
1058
1133
  return null;
1059
1134
  }
1060
1135
 
1061
- var hour = parseInt(time[1]*1, 10);
1062
- var ampm = time[4];
1136
+ var hour = parseInt(time[2]*1, 10);
1137
+ if (hour > 24) {
1138
+ if (settings && settings.wrapHours === false) {
1139
+ return null;
1140
+ } else {
1141
+ hour = hour % 24;
1142
+ }
1143
+ }
1144
+
1145
+ var ampm = time[1] || time[5];
1063
1146
  var hours = hour;
1064
1147
 
1065
- if (ampm) {
1148
+ if (hour <= 12 && ampm) {
1149
+ var isPm = (ampm == _lang.pm || ampm == _lang.PM);
1150
+
1066
1151
  if (hour == 12) {
1067
- hours = (time[4] == 'p') ? 12 : 0;
1152
+ hours = isPm ? 12 : 0;
1068
1153
  } else {
1069
- hours = (hour + (time[4] == 'p' ? 12 : 0));
1154
+ hours = (hour + (isPm ? 12 : 0));
1070
1155
  }
1071
1156
  }
1072
1157
 
1073
- var minutes = ( time[2]*1 || 0 );
1074
- var seconds = ( time[3]*1 || 0 );
1158
+ var minutes = ( time[3]*1 || 0 );
1159
+ var seconds = ( time[4]*1 || 0 );
1075
1160
  var timeInt = hours*3600 + minutes*60 + seconds;
1076
1161
 
1077
1162
  // if no am/pm provided, intelligently guess based on the scrollDefault
1078
- if (!ampm && settings && settings._twelveHourTime && settings.scrollDefault) {
1079
- var delta = timeInt - settings.scrollDefault;
1163
+ if (hour < 12 && !ampm && settings && settings._twelveHourTime && settings.scrollDefault) {
1164
+ var delta = timeInt - settings.scrollDefault();
1080
1165
  if (delta < 0 && delta >= _ONE_DAY / -2) {
1081
1166
  timeInt = (timeInt + (_ONE_DAY / 2)) % _ONE_DAY;
1082
1167
  }
1083
1168
  }
1084
1169
 
1085
- return timeInt
1170
+ return timeInt;
1086
1171
  }
1087
1172
 
1088
1173
  function _pad2(n) {
@@ -1103,4 +1188,55 @@ requires jQuery 1.7+
1103
1188
  else if(typeof method === "object" || !method) { return methods.init.apply(this, arguments); }
1104
1189
  else { $.error("Method "+ method + " does not exist on jQuery.timepicker"); }
1105
1190
  };
1191
+ // Global defaults
1192
+ $.fn.timepicker.defaults = {
1193
+ appendTo: 'body',
1194
+ className: null,
1195
+ closeOnWindowScroll: false,
1196
+ disableTextInput: false,
1197
+ disableTimeRanges: [],
1198
+ disableTouchKeyboard: false,
1199
+ durationTime: null,
1200
+ forceRoundTime: false,
1201
+ maxTime: null,
1202
+ minTime: null,
1203
+ noneOption: false,
1204
+ orientation: 'l',
1205
+ roundingFunction: function(seconds, settings) {
1206
+ if (seconds === null) {
1207
+ return null;
1208
+ } else if (typeof settings.step !== "number") {
1209
+ // TODO: nearest fit irregular steps
1210
+ return seconds;
1211
+ } else {
1212
+ var offset = seconds % (settings.step*60); // step is in minutes
1213
+
1214
+ if (offset >= settings.step*30) {
1215
+ // if offset is larger than a half step, round up
1216
+ seconds += (settings.step*60) - offset;
1217
+ } else {
1218
+ // round down
1219
+ seconds -= offset;
1220
+ }
1221
+
1222
+ if (seconds == _ONE_DAY && settings.show2400) {
1223
+ return seconds;
1224
+ }
1225
+
1226
+ return seconds%_ONE_DAY;
1227
+ }
1228
+ },
1229
+ scrollDefault: null,
1230
+ selectOnBlur: false,
1231
+ show2400: false,
1232
+ showDuration: false,
1233
+ showOn: ['click', 'focus'],
1234
+ showOnFocus: true,
1235
+ step: 30,
1236
+ stopScrollPropagation: false,
1237
+ timeFormat: 'g:ia',
1238
+ typeaheadHighlight: true,
1239
+ useSelect: false,
1240
+ wrapHours: true
1241
+ };
1106
1242
  }));