jquery-timepicker-rails 1.4.3 → 1.11.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  }));