jquery-timepicker-rails 0.2.0 → 1.0.7.0

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