jquery-timepicker-rails 0.2.0 → 1.0.7.0

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,7 +1,7 @@
1
1
  module Jquery
2
2
  module Timepicker
3
3
  module Rails
4
- VERSION = "0.2.0"
4
+ VERSION = "1.0.7.0"
5
5
  end
6
6
  end
7
7
  end
@@ -1,687 +1,697 @@
1
- /************************
2
- jquery-timepicker
3
- http://jonthornton.github.com/jquery-timepicker/
4
-
5
- requires jQuery 1.7+
6
- ************************/
7
-
8
-
9
- (function (factory) {
10
- if (typeof define === 'function' && define.amd) {
11
- // AMD. Register as an anonymous module.
12
- define(['jquery'], factory);
13
- } else {
14
- // Browser globals
15
- factory(jQuery);
16
- }
17
- }(function ($) {
18
- var _baseDate = _generateBaseDate();
19
- 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
- timeFormat: 'g:ia',
28
- scrollDefaultNow: false,
29
- scrollDefaultTime: false,
30
- selectOnBlur: false,
31
- forceRoundTime: false,
32
- appendTo: 'body'
33
- };
34
- var _lang = {
35
- decimal: '.',
36
- mins: 'mins',
37
- hr: 'hr',
38
- hrs: 'hrs'
39
- };
40
-
41
- var methods =
42
- {
43
- init: function(options)
44
- {
45
- return this.each(function()
46
- {
47
- var self = $(this);
48
-
49
- // convert dropdowns to text input
50
- if (self[0].tagName == 'SELECT') {
51
- var attrs = { 'type': 'text', 'value': self.val() };
52
- var raw_attrs = self[0].attributes;
53
-
54
- for (var i=0; i < raw_attrs.length; i++) {
55
- attrs[raw_attrs[i].nodeName] = raw_attrs[i].nodeValue;
56
- }
57
-
58
- var input = $('<input />', attrs);
59
- self.replaceWith(input);
60
- self = input;
61
- }
62
-
63
- var settings = $.extend({}, _defaults);
64
-
65
- if (options) {
66
- settings = $.extend(settings, options);
67
- }
68
-
69
- if (settings.minTime) {
70
- settings.minTime = _time2int(settings.minTime);
71
- }
72
-
73
- if (settings.maxTime) {
74
- settings.maxTime = _time2int(settings.maxTime);
75
- }
76
-
77
- if (settings.durationTime) {
78
- settings.durationTime = _time2int(settings.durationTime);
79
- }
80
-
81
- if (settings.lang) {
82
- _lang = $.extend(_lang, settings.lang);
83
- }
84
-
85
- self.data('timepicker-settings', settings);
86
- self.prop('autocomplete', 'off');
87
- self.on('click.timepicker focus.timepicker', methods.show);
88
- self.on('blur.timepicker', _formatValue);
89
- self.on('keydown.timepicker', _keyhandler);
90
- self.addClass('ui-timepicker-input');
91
-
92
- _formatValue.call(self.get(0));
93
- });
94
- },
95
-
96
- show: function(e)
97
- {
98
- var self = $(this);
99
-
100
- if ('ontouchstart' in document) {
101
- // block the keyboard on mobile devices
102
- self.blur();
103
- }
104
-
105
- var list = self.data('timepicker-list');
106
-
107
- // check if input is readonly
108
- if (self.prop('readonly')) {
109
- return;
110
- }
111
-
112
- // check if list needs to be rendered
113
- if (!list || list.length === 0) {
114
- _render(self);
115
- list = self.data('timepicker-list');
116
- }
117
-
118
- // check if a flag was set to close this picker
119
- if (self.hasClass('ui-timepicker-hideme')) {
120
- self.removeClass('ui-timepicker-hideme');
121
- list.hide();
122
- return;
123
- }
124
-
125
- if (list.is(':visible')) {
126
- return;
127
- }
128
-
129
- // make sure other pickers are hidden
130
- methods.hide();
131
-
132
- if ((self.offset().top + self.outerHeight(true) + list.outerHeight()) > $(window).height() + $(window).scrollTop()) {
133
- // position the dropdown on top
134
- list.css({ 'left':(self.offset().left), 'top': self.offset().top - list.outerHeight() });
135
- } else {
136
- // put it under the input
137
- list.css({ 'left':(self.offset().left), 'top': self.offset().top + self.outerHeight() });
138
- }
139
-
140
- list.show();
141
-
142
- var settings = self.data('timepicker-settings');
143
- // position scrolling
144
- var selected = list.find('.ui-timepicker-selected');
145
-
146
- if (!selected.length) {
147
- if (self.val()) {
148
- selected = _findRow(self, list, _time2int(self.val()));
149
- } else if (settings.scrollDefaultNow) {
150
- selected = _findRow(self, list, _time2int(new Date()));
151
- } else if (settings.scrollDefaultTime !== false) {
152
- selected = _findRow(self, list, _time2int(settings.scrollDefaultTime));
153
- }
154
- }
155
-
156
- if (selected && selected.length) {
157
- var topOffset = list.scrollTop() + selected.position().top - selected.outerHeight();
158
- list.scrollTop(topOffset);
159
- } else {
160
- list.scrollTop(0);
161
- }
162
-
163
- _attachCloseHandler();
164
-
165
- self.trigger('showTimepicker');
166
- },
167
-
168
- hide: function(e)
169
- {
170
- $('.ui-timepicker-list:visible').each(function() {
171
- var list = $(this);
172
- var self = list.data('timepicker-input');
173
- var settings = self.data('timepicker-settings');
174
-
175
- if (settings && settings.selectOnBlur) {
176
- _selectValue(self);
177
- }
178
-
179
- list.hide();
180
- self.trigger('hideTimepicker');
181
- });
182
- },
183
-
184
- option: function(key, value)
185
- {
186
- var self = $(this);
187
- var settings = self.data('timepicker-settings');
188
- var list = self.data('timepicker-list');
189
-
190
- if (typeof key == 'object') {
191
- settings = $.extend(settings, key);
192
-
193
- } else if (typeof key == 'string' && typeof value != 'undefined') {
194
- settings[key] = value;
195
-
196
- } else if (typeof key == 'string') {
197
- return settings[key];
198
- }
199
-
200
- if (settings.minTime) {
201
- settings.minTime = _time2int(settings.minTime);
202
- }
203
-
204
- if (settings.maxTime) {
205
- settings.maxTime = _time2int(settings.maxTime);
206
- }
207
-
208
- if (settings.durationTime) {
209
- settings.durationTime = _time2int(settings.durationTime);
210
- }
211
-
212
- self.data('timepicker-settings', settings);
213
-
214
- if (list) {
215
- list.remove();
216
- self.data('timepicker-list', false);
217
- }
218
-
219
- },
220
-
221
- getSecondsFromMidnight: function()
222
- {
223
- return _time2int($(this).val());
224
- },
225
-
226
- getTime: function()
227
- {
228
- return new Date(_baseDate.valueOf() + (_time2int($(this).val())*1000));
229
- },
230
-
231
- setTime: function(value)
232
- {
233
- var self = $(this);
234
- var prettyTime = _int2time(_time2int(value), self.data('timepicker-settings').timeFormat);
235
- self.val(prettyTime);
236
- },
237
-
238
- remove: function()
239
- {
240
- var self = $(this);
241
-
242
- // check if this element is a timepicker
243
- if (!self.hasClass('ui-timepicker-input')) {
244
- return;
245
- }
246
-
247
- self.removeAttr('autocomplete', 'off');
248
- self.removeClass('ui-timepicker-input');
249
- self.removeData('timepicker-settings');
250
- self.off('.timepicker');
251
-
252
- // timepicker-list won't be present unless the user has interacted with this timepicker
253
- if (self.data('timepicker-list')) {
254
- self.data('timepicker-list').remove();
255
- }
256
-
257
- self.removeData('timepicker-list');
258
- }
259
- };
260
-
261
- // private methods
262
-
263
- function _render(self)
264
- {
265
- var settings = self.data('timepicker-settings');
266
- var list = self.data('timepicker-list');
267
-
268
- if (list && list.length) {
269
- list.remove();
270
- self.data('timepicker-list', false);
271
- }
272
-
273
- list = $('<ul />', {
274
- 'tabindex': -1,
275
- 'class': 'ui-timepicker-list'
276
- });
277
-
278
- if (settings.className) {
279
- list.addClass(settings.className);
280
- }
281
-
282
- list.css({'display':'none', 'position': 'absolute' });
283
-
284
- if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
285
- list.addClass('ui-timepicker-with-duration');
286
- }
287
-
288
- var durStart = (settings.durationTime !== null) ? settings.durationTime : settings.minTime;
289
- var start = (settings.minTime !== null) ? settings.minTime : 0;
290
- var end = (settings.maxTime !== null) ? settings.maxTime : (start + _ONE_DAY - 1);
291
-
292
- if (end <= start) {
293
- // make sure the end time is greater than start time, otherwise there will be no list to show
294
- end += _ONE_DAY;
295
- }
296
-
297
- for (var i=start; i <= end; i += settings.step*60) {
298
- var timeInt = i%_ONE_DAY;
299
- var row = $('<li />');
300
- row.data('time', timeInt);
301
- row.text(_int2time(timeInt, settings.timeFormat));
302
-
303
- if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
304
- var duration = $('<span />');
305
- duration.addClass('ui-timepicker-duration');
306
- duration.text(' ('+_int2duration(i - durStart)+')');
307
- row.append(duration);
308
- }
309
-
310
- list.append(row);
311
- }
312
-
313
- list.data('timepicker-input', self);
314
- self.data('timepicker-list', list);
315
-
316
- var appendTo = settings.appendTo;
317
- if (typeof appendTo === 'string') {
318
- appendTo = $(appendTo);
319
- } else if (typeof appendTo === 'function') {
320
- appendTo = appendTo(self);
321
- }
322
- appendTo.append(list);
323
- _setSelected(self, list);
324
-
325
- list.on('click', 'li', function(e) {
326
- self.addClass('ui-timepicker-hideme');
327
- self[0].focus();
328
-
329
- // make sure only the clicked row is selected
330
- list.find('li').removeClass('ui-timepicker-selected');
331
- $(this).addClass('ui-timepicker-selected');
332
-
333
- _selectValue(self);
334
- list.hide();
335
- });
336
- }
337
-
338
- function _generateBaseDate()
339
- {
340
- var _baseDate = new Date();
341
- var _currentTimezoneOffset = _baseDate.getTimezoneOffset()*60000;
342
- _baseDate.setHours(0); _baseDate.setMinutes(0); _baseDate.setSeconds(0);
343
- var _baseDateTimezoneOffset = _baseDate.getTimezoneOffset()*60000;
344
-
345
- return new Date(_baseDate.valueOf() - _baseDateTimezoneOffset + _currentTimezoneOffset);
346
- }
347
-
348
- function _attachCloseHandler()
349
- {
350
- if ('ontouchstart' in document) {
351
- $('body').on('touchstart.ui-timepicker', _closeHandler);
352
- } else {
353
- $('body').on('mousedown.ui-timepicker', _closeHandler);
354
- $(window).on('scroll.ui-timepicker', _closeHandler);
355
- }
356
- }
357
-
358
- // event handler to decide whether to close timepicker
359
- function _closeHandler(e)
360
- {
361
- var target = $(e.target);
362
- var input = target.closest('.ui-timepicker-input');
363
- if (input.length === 0 && target.closest('.ui-timepicker-list').length === 0) {
364
- methods.hide();
365
- }
366
-
367
- $('body').unbind('.ui-timepicker');
368
- $(window).unbind('.ui-timepicker');
369
- }
370
-
371
- function _findRow(self, list, value)
372
- {
373
- if (!value && value !== 0) {
374
- return false;
375
- }
376
-
377
- var settings = self.data('timepicker-settings');
378
- var out = false;
379
- var halfStep = settings.step*30;
380
-
381
- // loop through the menu items
382
- list.find('li').each(function(i, obj) {
383
- var jObj = $(obj);
384
-
385
- var offset = jObj.data('time') - value;
386
-
387
- // check if the value is less than half a step from each row
388
- if (Math.abs(offset) < halfStep || offset == halfStep) {
389
- out = jObj;
390
- return false;
391
- }
392
- });
393
-
394
- return out;
395
- }
396
-
397
- function _setSelected(self, list)
398
- {
399
- var timeValue = _time2int(self.val());
400
-
401
- var selected = _findRow(self, list, timeValue);
402
- if (selected) selected.addClass('ui-timepicker-selected');
403
- }
404
-
405
-
406
- function _formatValue()
407
- {
408
- if (this.value === '') {
409
- return;
410
- }
411
-
412
- var self = $(this);
413
- var seconds = _time2int(this.value);
414
-
415
- if (seconds === null) {
416
- self.trigger('timeFormatError');
417
- return;
418
- }
419
-
420
- var settings = self.data('timepicker-settings');
421
-
422
- if (settings.forceRoundTime) {
423
- var offset = seconds % (settings.step*60); // step is in minutes
424
-
425
- if (offset >= settings.step*30) {
426
- // if offset is larger than a half step, round up
427
- seconds += (settings.step*60) - offset;
428
- } else {
429
- // round down
430
- seconds -= offset;
431
- }
432
- }
433
-
434
- var prettyTime = _int2time(seconds, settings.timeFormat);
435
- self.val(prettyTime);
436
- }
437
-
438
- function _keyhandler(e)
439
- {
440
- var self = $(this);
441
- var list = self.data('timepicker-list');
442
-
443
- if (!list.is(':visible')) {
444
- if (e.keyCode == 40) {
445
- self.focus();
446
- } else {
447
- return true;
448
- }
449
- }
450
-
451
- switch (e.keyCode) {
452
-
453
- case 13: // return
454
- _selectValue(self);
455
- methods.hide.apply(this);
456
- e.preventDefault();
457
- return false;
458
-
459
- case 38: // up
460
- var selected = list.find('.ui-timepicker-selected');
461
-
462
- if (!selected.length) {
463
- list.children().each(function(i, obj) {
464
- if ($(obj).position().top > 0) {
465
- selected = $(obj);
466
- return false;
467
- }
468
- });
469
- selected.addClass('ui-timepicker-selected');
470
-
471
- } else if (!selected.is(':first-child')) {
472
- selected.removeClass('ui-timepicker-selected');
473
- selected.prev().addClass('ui-timepicker-selected');
474
-
475
- if (selected.prev().position().top < selected.outerHeight()) {
476
- list.scrollTop(list.scrollTop() - selected.outerHeight());
477
- }
478
- }
479
-
480
- break;
481
-
482
- case 40: // down
483
- selected = list.find('.ui-timepicker-selected');
484
-
485
- if (selected.length === 0) {
486
- list.children().each(function(i, obj) {
487
- if ($(obj).position().top > 0) {
488
- selected = $(obj);
489
- return false;
490
- }
491
- });
492
-
493
- selected.addClass('ui-timepicker-selected');
494
- } else if (!selected.is(':last-child')) {
495
- selected.removeClass('ui-timepicker-selected');
496
- selected.next().addClass('ui-timepicker-selected');
497
-
498
- if (selected.next().position().top + 2*selected.outerHeight() > list.outerHeight()) {
499
- list.scrollTop(list.scrollTop() + selected.outerHeight());
500
- }
501
- }
502
-
503
- break;
504
-
505
- case 27: // escape
506
- list.find('li').removeClass('ui-timepicker-selected');
507
- list.hide();
508
- break;
509
-
510
- case 9: //tab
511
- methods.hide();
512
- break;
513
-
514
- case 16:
515
- case 17:
516
- case 18:
517
- case 19:
518
- case 20:
519
- case 33:
520
- case 34:
521
- case 35:
522
- case 36:
523
- case 37:
524
- case 39:
525
- case 45:
526
- return;
527
-
528
- default:
529
- list.find('li').removeClass('ui-timepicker-selected');
530
- return;
531
- }
532
- }
533
-
534
- function _selectValue(self)
535
- {
536
- var settings = self.data('timepicker-settings');
537
- var list = self.data('timepicker-list');
538
- var timeValue = null;
539
-
540
- var cursor = list.find('.ui-timepicker-selected');
541
-
542
- if (cursor.length) {
543
- // selected value found
544
- timeValue = cursor.data('time');
545
-
546
- } else if (self.val()) {
547
-
548
- // no selected value; fall back on input value
549
- timeValue = _time2int(self.val());
550
-
551
- _setSelected(self, list);
552
- }
553
-
554
- if (timeValue !== null) {
555
- var timeString = _int2time(timeValue, settings.timeFormat);
556
- self.val(timeString);
557
- }
558
-
559
- self.trigger('change').trigger('changeTime');
560
- }
561
-
562
- function _int2duration(seconds)
563
- {
564
- var minutes = Math.round(seconds/60);
565
- var duration;
566
-
567
- if (Math.abs(minutes) < 60) {
568
- duration = [minutes, _lang.mins];
569
- } else if (minutes == 60) {
570
- duration = ['1', _lang.hr];
571
- } else {
572
- var hours = (minutes/60).toFixed(1);
573
- if (_lang.decimal != '.') hours = hours.replace('.', _lang.decimal);
574
- duration = [hours, _lang.hrs];
575
- }
576
-
577
- return duration.join(' ');
578
- }
579
-
580
- function _int2time(seconds, format)
581
- {
582
- if (seconds === null) {
583
- return;
584
- }
585
-
586
- var time = new Date(_baseDate.valueOf() + (seconds*1000));
587
- var output = '';
588
- var hour, code;
589
-
590
- for (var i=0; i<format.length; i++) {
591
-
592
- code = format.charAt(i);
593
- switch (code) {
594
-
595
- case 'a':
596
- output += (time.getHours() > 11) ? 'pm' : 'am';
597
- break;
598
-
599
- case 'A':
600
- output += (time.getHours() > 11) ? 'PM' : 'AM';
601
- break;
602
-
603
- case 'g':
604
- hour = time.getHours() % 12;
605
- output += (hour === 0) ? '12' : hour;
606
- break;
607
-
608
- case 'G':
609
- output += time.getHours();
610
- break;
611
-
612
- case 'h':
613
- hour = time.getHours() % 12;
614
-
615
- if (hour !== 0 && hour < 10) {
616
- hour = '0'+hour;
617
- }
618
-
619
- output += (hour === 0) ? '12' : hour;
620
- break;
621
-
622
- case 'H':
623
- hour = time.getHours();
624
- output += (hour > 9) ? hour : '0'+hour;
625
- break;
626
-
627
- case 'i':
628
- var minutes = time.getMinutes();
629
- output += (minutes > 9) ? minutes : '0'+minutes;
630
- break;
631
-
632
- case 's':
633
- seconds = time.getSeconds();
634
- output += (seconds > 9) ? seconds : '0'+seconds;
635
- break;
636
-
637
- default:
638
- output += code;
639
- }
640
- }
641
-
642
- return output;
643
- }
644
-
645
- function _time2int(timeString)
646
- {
647
- if (timeString === '') return null;
648
- if (timeString+0 == timeString) return timeString;
649
-
650
- if (typeof(timeString) == 'object') {
651
- timeString = timeString.getHours()+':'+timeString.getMinutes()+':'+timeString.getSeconds();
652
- }
653
-
654
- var d = new Date(0);
655
- var time = timeString.toLowerCase().match(/(\d{1,2})(?::(\d{1,2}))?(?::(\d{2}))?\s*([pa]?)/);
656
-
657
- if (!time) {
658
- return null;
659
- }
660
-
661
- var hour = parseInt(time[1]*1, 10);
662
- var hours;
663
-
664
- if (time[4]) {
665
- if (hour == 12) {
666
- hours = (time[4] == 'p') ? 12 : 0;
667
- } else {
668
- hours = (hour + (time[4] == 'p' ? 12 : 0));
669
- }
670
-
671
- } else {
672
- hours = hour;
673
- }
674
-
675
- var minutes = ( time[2]*1 || 0 );
676
- var seconds = ( time[3]*1 || 0 );
677
- return hours*3600 + minutes*60 + seconds;
678
- }
679
-
680
- // Plugin entry
681
- $.fn.timepicker = function(method)
682
- {
683
- if(methods[method]) { return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); }
684
- else if(typeof method === "object" || !method) { return methods.init.apply(this, arguments); }
685
- else { $.error("Method "+ method + " does not exist on jQuery.timepicker"); }
686
- };
687
- }));
1
+ /************************
2
+ jquery-timepicker
3
+ http://jonthornton.github.com/jquery-timepicker/
4
+
5
+ requires jQuery 1.7+
6
+ ************************/
7
+
8
+
9
+ (function (factory) {
10
+ if (typeof define === 'function' && define.amd) {
11
+ // AMD. Register as an anonymous module.
12
+ define(['jquery'], factory);
13
+ } else {
14
+ // Browser globals
15
+ factory(jQuery);
16
+ }
17
+ }(function ($) {
18
+ var _baseDate = _generateBaseDate();
19
+ 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
+ timeFormat: 'g:ia',
28
+ scrollDefaultNow: false,
29
+ scrollDefaultTime: false,
30
+ selectOnBlur: false,
31
+ disableTouchKeyboard: true,
32
+ forceRoundTime: false,
33
+ appendTo: 'body'
34
+ };
35
+ var _lang = {
36
+ decimal: '.',
37
+ mins: 'mins',
38
+ hr: 'hr',
39
+ hrs: 'hrs'
40
+ };
41
+
42
+ var methods =
43
+ {
44
+ init: function(options)
45
+ {
46
+ return this.each(function()
47
+ {
48
+ var self = $(this);
49
+
50
+ // convert dropdowns to text input
51
+ if (self[0].tagName == 'SELECT') {
52
+ var attrs = { 'type': 'text', 'value': self.val() };
53
+ var raw_attrs = self[0].attributes;
54
+
55
+ for (var i=0; i < raw_attrs.length; i++) {
56
+ attrs[raw_attrs[i].nodeName] = raw_attrs[i].nodeValue;
57
+ }
58
+
59
+ var input = $('<input />', attrs);
60
+ self.replaceWith(input);
61
+ self = input;
62
+ }
63
+
64
+ var settings = $.extend({}, _defaults);
65
+
66
+ if (options) {
67
+ settings = $.extend(settings, options);
68
+ }
69
+
70
+ if (settings.minTime) {
71
+ settings.minTime = _time2int(settings.minTime);
72
+ }
73
+
74
+ if (settings.maxTime) {
75
+ settings.maxTime = _time2int(settings.maxTime);
76
+ }
77
+
78
+ if (settings.durationTime) {
79
+ settings.durationTime = _time2int(settings.durationTime);
80
+ }
81
+
82
+ if (settings.lang) {
83
+ _lang = $.extend(_lang, settings.lang);
84
+ }
85
+
86
+ self.data('timepicker-settings', settings);
87
+ self.prop('autocomplete', 'off');
88
+ self.on('click.timepicker focus.timepicker', methods.show);
89
+ self.on('blur.timepicker', _formatValue);
90
+ self.on('keydown.timepicker', _keyhandler);
91
+ self.addClass('ui-timepicker-input');
92
+
93
+ _formatValue.call(self.get(0));
94
+ });
95
+ },
96
+
97
+ show: function(e)
98
+ {
99
+ var self = $(this);
100
+ var settings = self.data('timepicker-settings');
101
+
102
+ if ('ontouchstart' in document && settings.disableTouchKeyboard) {
103
+ // block the keyboard on mobile devices
104
+ self.blur();
105
+ }
106
+
107
+ var list = self.data('timepicker-list');
108
+
109
+ // check if input is readonly
110
+ if (self.prop('readonly')) {
111
+ return;
112
+ }
113
+
114
+ // check if list needs to be rendered
115
+ if (!list || list.length === 0) {
116
+ _render(self);
117
+ list = self.data('timepicker-list');
118
+ }
119
+
120
+ // check if a flag was set to close this picker
121
+ if (self.hasClass('ui-timepicker-hideme')) {
122
+ self.removeClass('ui-timepicker-hideme');
123
+ list.hide();
124
+ return;
125
+ }
126
+
127
+ if (list.is(':visible')) {
128
+ return;
129
+ }
130
+
131
+ // make sure other pickers are hidden
132
+ methods.hide();
133
+
134
+ if ((self.offset().top + self.outerHeight(true) + list.outerHeight()) > $(window).height() + $(window).scrollTop()) {
135
+ // position the dropdown on top
136
+ list.css({ 'left':(self.offset().left), 'top': self.offset().top - list.outerHeight() });
137
+ } else {
138
+ // put it under the input
139
+ list.css({ 'left':(self.offset().left), 'top': self.offset().top + self.outerHeight() });
140
+ }
141
+
142
+ list.show();
143
+
144
+ // position scrolling
145
+ var selected = list.find('.ui-timepicker-selected');
146
+
147
+ if (!selected.length) {
148
+ if (self.val()) {
149
+ selected = _findRow(self, list, _time2int(self.val()));
150
+ } else if (settings.scrollDefaultNow) {
151
+ selected = _findRow(self, list, _time2int(new Date()));
152
+ } else if (settings.scrollDefaultTime !== false) {
153
+ selected = _findRow(self, list, _time2int(settings.scrollDefaultTime));
154
+ }
155
+ }
156
+
157
+ if (selected && selected.length) {
158
+ var topOffset = list.scrollTop() + selected.position().top - selected.outerHeight();
159
+ list.scrollTop(topOffset);
160
+ } else {
161
+ list.scrollTop(0);
162
+ }
163
+
164
+ _attachCloseHandler();
165
+
166
+ self.trigger('showTimepicker');
167
+ },
168
+
169
+ hide: function(e)
170
+ {
171
+ $('.ui-timepicker-list:visible').each(function() {
172
+ var list = $(this);
173
+ var self = list.data('timepicker-input');
174
+ var settings = self.data('timepicker-settings');
175
+
176
+ if (settings && settings.selectOnBlur) {
177
+ _selectValue(self);
178
+ }
179
+
180
+ list.hide();
181
+ self.trigger('hideTimepicker');
182
+ });
183
+ },
184
+
185
+ option: function(key, value)
186
+ {
187
+ var self = $(this);
188
+ var settings = self.data('timepicker-settings');
189
+ var list = self.data('timepicker-list');
190
+
191
+ if (typeof key == 'object') {
192
+ settings = $.extend(settings, key);
193
+
194
+ } else if (typeof key == 'string' && typeof value != 'undefined') {
195
+ settings[key] = value;
196
+
197
+ } else if (typeof key == 'string') {
198
+ return settings[key];
199
+ }
200
+
201
+ if (settings.minTime) {
202
+ settings.minTime = _time2int(settings.minTime);
203
+ }
204
+
205
+ if (settings.maxTime) {
206
+ settings.maxTime = _time2int(settings.maxTime);
207
+ }
208
+
209
+ if (settings.durationTime) {
210
+ settings.durationTime = _time2int(settings.durationTime);
211
+ }
212
+
213
+ self.data('timepicker-settings', settings);
214
+
215
+ if (list) {
216
+ list.remove();
217
+ self.data('timepicker-list', false);
218
+ }
219
+
220
+ },
221
+
222
+ getSecondsFromMidnight: function()
223
+ {
224
+ return _time2int($(this).val());
225
+ },
226
+
227
+ getTime: function()
228
+ {
229
+ return new Date(_baseDate.valueOf() + (_time2int($(this).val())*1000));
230
+ },
231
+
232
+ setTime: function(value)
233
+ {
234
+ var self = $(this);
235
+ var prettyTime = _int2time(_time2int(value), self.data('timepicker-settings').timeFormat);
236
+ self.val(prettyTime);
237
+ },
238
+
239
+ remove: function()
240
+ {
241
+ var self = $(this);
242
+
243
+ // check if this element is a timepicker
244
+ if (!self.hasClass('ui-timepicker-input')) {
245
+ return;
246
+ }
247
+
248
+ self.removeAttr('autocomplete', 'off');
249
+ self.removeClass('ui-timepicker-input');
250
+ self.removeData('timepicker-settings');
251
+ self.off('.timepicker');
252
+
253
+ // timepicker-list won't be present unless the user has interacted with this timepicker
254
+ if (self.data('timepicker-list')) {
255
+ self.data('timepicker-list').remove();
256
+ }
257
+
258
+ self.removeData('timepicker-list');
259
+ }
260
+ };
261
+
262
+ // private methods
263
+
264
+ function _render(self)
265
+ {
266
+ var settings = self.data('timepicker-settings');
267
+ var list = self.data('timepicker-list');
268
+
269
+ if (list && list.length) {
270
+ list.remove();
271
+ self.data('timepicker-list', false);
272
+ }
273
+
274
+ list = $('<ul />', {
275
+ 'tabindex': -1,
276
+ 'class': 'ui-timepicker-list'
277
+ });
278
+
279
+ if (settings.className) {
280
+ list.addClass(settings.className);
281
+ }
282
+
283
+ list.css({'display':'none', 'position': 'absolute' });
284
+
285
+ if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
286
+ list.addClass('ui-timepicker-with-duration');
287
+ }
288
+
289
+ var durStart = (settings.durationTime !== null) ? settings.durationTime : settings.minTime;
290
+ var start = (settings.minTime !== null) ? settings.minTime : 0;
291
+ var end = (settings.maxTime !== null) ? settings.maxTime : (start + _ONE_DAY - 1);
292
+
293
+ if (end <= start) {
294
+ // make sure the end time is greater than start time, otherwise there will be no list to show
295
+ end += _ONE_DAY;
296
+ }
297
+
298
+ for (var i=start; i <= end; i += settings.step*60) {
299
+ var timeInt = i%_ONE_DAY;
300
+ var row = $('<li />');
301
+ row.data('time', timeInt);
302
+ row.text(_int2time(timeInt, settings.timeFormat));
303
+
304
+ if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
305
+ var duration = $('<span />');
306
+ duration.addClass('ui-timepicker-duration');
307
+ duration.text(' ('+_int2duration(i - durStart)+')');
308
+ row.append(duration);
309
+ }
310
+
311
+ list.append(row);
312
+ }
313
+
314
+ list.data('timepicker-input', self);
315
+ self.data('timepicker-list', list);
316
+
317
+ var appendTo = settings.appendTo;
318
+ if (typeof appendTo === 'string') {
319
+ appendTo = $(appendTo);
320
+ } else if (typeof appendTo === 'function') {
321
+ appendTo = appendTo(self);
322
+ }
323
+ appendTo.append(list);
324
+ _setSelected(self, list);
325
+
326
+ list.on('click', 'li', function(e) {
327
+ self.addClass('ui-timepicker-hideme');
328
+ self[0].focus();
329
+
330
+ // make sure only the clicked row is selected
331
+ list.find('li').removeClass('ui-timepicker-selected');
332
+ $(this).addClass('ui-timepicker-selected');
333
+
334
+ _selectValue(self);
335
+ list.hide();
336
+ });
337
+ }
338
+
339
+ function _generateBaseDate()
340
+ {
341
+ var _baseDate = new Date();
342
+ var _currentTimezoneOffset = _baseDate.getTimezoneOffset()*60000;
343
+ _baseDate.setHours(0); _baseDate.setMinutes(0); _baseDate.setSeconds(0);
344
+ var _baseDateTimezoneOffset = _baseDate.getTimezoneOffset()*60000;
345
+
346
+ return new Date(_baseDate.valueOf() - _baseDateTimezoneOffset + _currentTimezoneOffset);
347
+ }
348
+
349
+ function _attachCloseHandler()
350
+ {
351
+ if ('ontouchstart' in document) {
352
+ $('body').on('touchstart.ui-timepicker', _closeHandler);
353
+ } else {
354
+ $('body').on('mousedown.ui-timepicker', _closeHandler);
355
+ $(window).on('scroll.ui-timepicker', _closeHandler);
356
+ }
357
+ }
358
+
359
+ // event handler to decide whether to close timepicker
360
+ function _closeHandler(e)
361
+ {
362
+ var target = $(e.target);
363
+ var input = target.closest('.ui-timepicker-input');
364
+ if (input.length === 0 && target.closest('.ui-timepicker-list').length === 0) {
365
+ methods.hide();
366
+ $('body').unbind('.ui-timepicker');
367
+ $(window).unbind('.ui-timepicker');
368
+ }
369
+ }
370
+
371
+ function _findRow(self, list, value)
372
+ {
373
+ if (!value && value !== 0) {
374
+ return false;
375
+ }
376
+
377
+ var settings = self.data('timepicker-settings');
378
+ var out = false;
379
+ var halfStep = settings.step*30;
380
+
381
+ // loop through the menu items
382
+ list.find('li').each(function(i, obj) {
383
+ var jObj = $(obj);
384
+
385
+ var offset = jObj.data('time') - value;
386
+
387
+ // check if the value is less than half a step from each row
388
+ if (Math.abs(offset) < halfStep || offset == halfStep) {
389
+ out = jObj;
390
+ return false;
391
+ }
392
+ });
393
+
394
+ return out;
395
+ }
396
+
397
+ function _setSelected(self, list)
398
+ {
399
+ var timeValue = _time2int(self.val());
400
+
401
+ var selected = _findRow(self, list, timeValue);
402
+ if (selected) selected.addClass('ui-timepicker-selected');
403
+ }
404
+
405
+
406
+ function _formatValue()
407
+ {
408
+ if (this.value === '') {
409
+ return;
410
+ }
411
+
412
+ var self = $(this);
413
+ var seconds = _time2int(this.value);
414
+
415
+ if (seconds === null) {
416
+ self.trigger('timeFormatError');
417
+ return;
418
+ }
419
+
420
+ var settings = self.data('timepicker-settings');
421
+
422
+ if (settings.forceRoundTime) {
423
+ var offset = seconds % (settings.step*60); // step is in minutes
424
+
425
+ if (offset >= settings.step*30) {
426
+ // if offset is larger than a half step, round up
427
+ seconds += (settings.step*60) - offset;
428
+ } else {
429
+ // round down
430
+ seconds -= offset;
431
+ }
432
+ }
433
+
434
+ var prettyTime = _int2time(seconds, settings.timeFormat);
435
+ self.val(prettyTime);
436
+ }
437
+
438
+ function _keyhandler(e)
439
+ {
440
+ var self = $(this);
441
+ var list = self.data('timepicker-list');
442
+
443
+ if (!list.is(':visible')) {
444
+ if (e.keyCode == 40) {
445
+ self.focus();
446
+ } else {
447
+ return true;
448
+ }
449
+ }
450
+
451
+ switch (e.keyCode) {
452
+
453
+ case 13: // return
454
+ _selectValue(self);
455
+ methods.hide.apply(this);
456
+ e.preventDefault();
457
+ return false;
458
+
459
+ case 38: // up
460
+ var selected = list.find('.ui-timepicker-selected');
461
+
462
+ if (!selected.length) {
463
+ list.children().each(function(i, obj) {
464
+ if ($(obj).position().top > 0) {
465
+ selected = $(obj);
466
+ return false;
467
+ }
468
+ });
469
+ selected.addClass('ui-timepicker-selected');
470
+
471
+ } else if (!selected.is(':first-child')) {
472
+ selected.removeClass('ui-timepicker-selected');
473
+ selected.prev().addClass('ui-timepicker-selected');
474
+
475
+ if (selected.prev().position().top < selected.outerHeight()) {
476
+ list.scrollTop(list.scrollTop() - selected.outerHeight());
477
+ }
478
+ }
479
+
480
+ break;
481
+
482
+ case 40: // down
483
+ selected = list.find('.ui-timepicker-selected');
484
+
485
+ if (selected.length === 0) {
486
+ list.children().each(function(i, obj) {
487
+ if ($(obj).position().top > 0) {
488
+ selected = $(obj);
489
+ return false;
490
+ }
491
+ });
492
+
493
+ selected.addClass('ui-timepicker-selected');
494
+ } else if (!selected.is(':last-child')) {
495
+ selected.removeClass('ui-timepicker-selected');
496
+ selected.next().addClass('ui-timepicker-selected');
497
+
498
+ if (selected.next().position().top + 2*selected.outerHeight() > list.outerHeight()) {
499
+ list.scrollTop(list.scrollTop() + selected.outerHeight());
500
+ }
501
+ }
502
+
503
+ break;
504
+
505
+ case 27: // escape
506
+ list.find('li').removeClass('ui-timepicker-selected');
507
+ list.hide();
508
+ break;
509
+
510
+ case 9: //tab
511
+ methods.hide();
512
+ break;
513
+
514
+ case 16:
515
+ case 17:
516
+ case 18:
517
+ case 19:
518
+ case 20:
519
+ case 33:
520
+ case 34:
521
+ case 35:
522
+ case 36:
523
+ case 37:
524
+ case 39:
525
+ case 45:
526
+ return;
527
+
528
+ default:
529
+ list.find('li').removeClass('ui-timepicker-selected');
530
+ return;
531
+ }
532
+ }
533
+
534
+ function _selectValue(self)
535
+ {
536
+ var settings = self.data('timepicker-settings');
537
+ var list = self.data('timepicker-list');
538
+ var timeValue = null;
539
+
540
+ var cursor = list.find('.ui-timepicker-selected');
541
+
542
+ if (cursor.length) {
543
+ // selected value found
544
+ timeValue = cursor.data('time');
545
+
546
+ } else if (self.val()) {
547
+
548
+ // no selected value; fall back on input value
549
+ timeValue = _time2int(self.val());
550
+
551
+ _setSelected(self, list);
552
+ }
553
+
554
+ if (timeValue !== null) {
555
+ var timeString = _int2time(timeValue, settings.timeFormat);
556
+ self.val(timeString);
557
+ }
558
+
559
+ self.trigger('change').trigger('changeTime');
560
+ }
561
+
562
+ function _int2duration(seconds)
563
+ {
564
+ var minutes = Math.round(seconds/60);
565
+ var duration;
566
+
567
+ if (Math.abs(minutes) < 60) {
568
+ duration = [minutes, _lang.mins];
569
+ } else if (minutes == 60) {
570
+ duration = ['1', _lang.hr];
571
+ } else {
572
+ var hours = (minutes/60).toFixed(1);
573
+ if (_lang.decimal != '.') hours = hours.replace('.', _lang.decimal);
574
+ duration = [hours, _lang.hrs];
575
+ }
576
+
577
+ return duration.join(' ');
578
+ }
579
+
580
+ function _int2time(seconds, format)
581
+ {
582
+ if (seconds === null) {
583
+ return;
584
+ }
585
+
586
+ var time = new Date(_baseDate.valueOf() + (seconds*1000));
587
+ var output = '';
588
+ var hour, code;
589
+
590
+ for (var i=0; i<format.length; i++) {
591
+
592
+ code = format.charAt(i);
593
+ switch (code) {
594
+
595
+ case 'a':
596
+ output += (time.getHours() > 11) ? 'pm' : 'am';
597
+ break;
598
+
599
+ case 'A':
600
+ output += (time.getHours() > 11) ? 'PM' : 'AM';
601
+ break;
602
+
603
+ case 'g':
604
+ hour = time.getHours() % 12;
605
+ output += (hour === 0) ? '12' : hour;
606
+ break;
607
+
608
+ case 'G':
609
+ output += time.getHours();
610
+ break;
611
+
612
+ case 'h':
613
+ hour = time.getHours() % 12;
614
+
615
+ if (hour !== 0 && hour < 10) {
616
+ hour = '0'+hour;
617
+ }
618
+
619
+ output += (hour === 0) ? '12' : hour;
620
+ break;
621
+
622
+ case 'H':
623
+ hour = time.getHours();
624
+ output += (hour > 9) ? hour : '0'+hour;
625
+ break;
626
+
627
+ case 'i':
628
+ var minutes = time.getMinutes();
629
+ output += (minutes > 9) ? minutes : '0'+minutes;
630
+ break;
631
+
632
+ case 's':
633
+ seconds = time.getSeconds();
634
+ output += (seconds > 9) ? seconds : '0'+seconds;
635
+ break;
636
+
637
+ default:
638
+ output += code;
639
+ }
640
+ }
641
+
642
+ return output;
643
+ }
644
+
645
+ function _time2int(timeString)
646
+ {
647
+ if (timeString === '') return null;
648
+ if (timeString+0 == timeString) return timeString;
649
+
650
+ if (typeof(timeString) == 'object') {
651
+ timeString = timeString.getHours()+':'+timeString.getMinutes()+':'+timeString.getSeconds();
652
+ }
653
+
654
+ var d = new Date(0);
655
+
656
+ var timeRegex;
657
+ if (timeString.indexOf(":") !== -1) {
658
+ //colon-delimited version
659
+ timeRegex = /(\d{1,2})(?::(\d{1,2}))?(?::(\d{2}))?\s*([pa]?)/;
660
+ } else {
661
+ //zero-required, fixed-position version
662
+ timeRegex = /^([0-2][0-9]):?([0-5][0-9])?:?([0-5][0-9])?\s*([pa]?)$/;
663
+ }
664
+
665
+ var time = timeString.toLowerCase().match(timeRegex);
666
+
667
+ if (!time) {
668
+ return null;
669
+ }
670
+
671
+ var hour = parseInt(time[1]*1, 10);
672
+ var hours;
673
+
674
+ if (time[4]) {
675
+ if (hour == 12) {
676
+ hours = (time[4] == 'p') ? 12 : 0;
677
+ } else {
678
+ hours = (hour + (time[4] == 'p' ? 12 : 0));
679
+ }
680
+
681
+ } else {
682
+ hours = hour;
683
+ }
684
+
685
+ var minutes = ( time[2]*1 || 0 );
686
+ var seconds = ( time[3]*1 || 0 );
687
+ return hours*3600 + minutes*60 + seconds;
688
+ }
689
+
690
+ // Plugin entry
691
+ $.fn.timepicker = function(method)
692
+ {
693
+ if(methods[method]) { return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); }
694
+ else if(typeof method === "object" || !method) { return methods.init.apply(this, arguments); }
695
+ else { $.error("Method "+ method + " does not exist on jQuery.timepicker"); }
696
+ };
697
+ }));