PluginProbe ʕ •ᴥ•ʔ
WP All Export – Drag & Drop Export to Any Custom CSV, XML & Excel / 1.3.1
WP All Export – Drag & Drop Export to Any Custom CSV, XML & Excel v1.3.1
trunk 0.9.0 0.9.1 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2.0 1.2.1 1.2.10 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 1.4.13 1.4.14 1.4.15 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0
wp-all-export / static / js / jquery / jquery.timepicker.js
wp-all-export / static / js / jquery Last commit date
css 8 years ago chosen.jquery.js 8 years ago chosen.jquery.min.js 10 years ago jquery.ddslick.min.js 10 years ago jquery.mjs.pmxe_nestedSortable.js 7 years ago jquery.timepicker.js 8 years ago jquery.tipsy.js 5 years ago moment.js 9 years ago select2.min.js 12 years ago ui.autocomplete.js 12 years ago ui.datepicker.js 12 years ago
jquery.timepicker.js
1247 lines
1 /*!
2 * jquery-timepicker v1.11.5 - 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 */
6
7
8 (function (factory) {
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) {
14 // AMD. Register as an anonymous module.
15 define(['jquery'], factory);
16 } else {
17 // Browser globals
18 factory(jQuery);
19 }
20 }(function ($) {
21 var _ONE_DAY = 86400;
22 var _lang = {
23 am: 'am',
24 pm: 'pm',
25 AM: 'AM',
26 PM: 'PM',
27 decimal: '.',
28 mins: 'mins',
29 hr: 'hr',
30 hrs: 'hrs'
31 };
32
33 var methods = {
34 init: function(options)
35 {
36 return this.each(function()
37 {
38 var self = $(this);
39
40 // pick up settings from data attributes
41 var attributeOptions = [];
42 for (var key in $.fn.timepicker.defaults) {
43 if (self.data(key)) {
44 attributeOptions[key] = self.data(key);
45 }
46 }
47
48 var settings = $.extend({}, $.fn.timepicker.defaults, attributeOptions, options);
49
50 if (settings.lang) {
51 _lang = $.extend(_lang, settings.lang);
52 }
53
54 settings = _parseSettings(settings);
55 self.data('timepicker-settings', settings);
56 self.addClass('ui-timepicker-input');
57
58 if (settings.useSelect) {
59 _render(self);
60 } else {
61 self.prop('autocomplete', 'off');
62 if (settings.showOn) {
63 for (var i in settings.showOn) {
64 self.on(settings.showOn[i]+'.timepicker', methods.show);
65 }
66 }
67 self.on('change.timepicker', _formatValue);
68 self.on('keydown.timepicker', _keydownhandler);
69 self.on('keyup.timepicker', _keyuphandler);
70 if (settings.disableTextInput) {
71 self.on('keydown.timepicker', _disableTextInputHandler);
72 }
73
74 _formatValue.call(self.get(0), null, 'initial');
75 }
76 });
77 },
78
79 show: function(e)
80 {
81 var self = $(this);
82 var settings = self.data('timepicker-settings');
83
84 if (e) {
85 e.preventDefault();
86 }
87
88 if (settings.useSelect) {
89 self.data('timepicker-list').focus();
90 return;
91 }
92
93 if (_hideKeyboard(self)) {
94 // block the keyboard on mobile devices
95 self.blur();
96 }
97
98 var list = self.data('timepicker-list');
99
100 // check if input is readonly
101 if (self.prop('readonly')) {
102 return;
103 }
104
105 // check if list needs to be rendered
106 if (!list || list.length === 0 || typeof settings.durationTime === 'function') {
107 _render(self);
108 list = self.data('timepicker-list');
109 }
110
111 if (_isVisible(list)) {
112 return;
113 }
114
115 self.data('ui-timepicker-value', self.val());
116 _setSelected(self, list);
117
118 // make sure other pickers are hidden
119 methods.hide();
120
121 // position the dropdown relative to the input
122 list.show();
123 var listOffset = {};
124
125 if (settings.orientation.match(/r/)) {
126 // right-align the dropdown
127 listOffset.left = self.offset().left + self.outerWidth() - list.outerWidth() + parseInt(list.css('marginLeft').replace('px', ''), 10);
128 } else {
129 // left-align the dropdown
130 listOffset.left = self.offset().left + parseInt(list.css('marginLeft').replace('px', ''), 10);
131 }
132
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') {
145 // position the dropdown on top
146 list.addClass('ui-timepicker-positioned-top');
147 listOffset.top = self.offset().top - list.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10);
148 } else {
149 // put it under the input
150 list.removeClass('ui-timepicker-positioned-top');
151 listOffset.top = self.offset().top + self.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10);
152 }
153
154 list.offset(listOffset);
155
156 // position scrolling
157 var selected = list.find('.ui-timepicker-selected');
158
159 if (!selected.length) {
160 var timeInt = _time2int(_getTimeValue(self));
161 if (timeInt !== null) {
162 selected = _findRow(self, list, timeInt);
163 } else if (settings.scrollDefault) {
164 selected = _findRow(self, list, settings.scrollDefault());
165 }
166 }
167
168 if (selected && selected.length) {
169 var topOffset = list.scrollTop() + selected.position().top - selected.outerHeight();
170 list.scrollTop(topOffset);
171 } else {
172 list.scrollTop(0);
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
184 // attach close handlers
185 $(document).on('touchstart.ui-timepicker mousedown.ui-timepicker', _closeHandler);
186 $(window).on('resize.ui-timepicker', _closeHandler);
187 if (settings.closeOnWindowScroll) {
188 $(document).on('scroll.ui-timepicker', _closeHandler);
189 }
190
191 self.trigger('showTimepicker');
192
193 return this;
194 },
195
196 hide: function(e)
197 {
198 var self = $(this);
199 var settings = self.data('timepicker-settings');
200
201 if (settings && settings.useSelect) {
202 self.blur();
203 }
204
205 $('.ui-timepicker-wrapper').each(function() {
206 var list = $(this);
207 if (!_isVisible(list)) {
208 return;
209 }
210
211 var self = list.data('timepicker-input');
212 var settings = self.data('timepicker-settings');
213
214 if (settings && settings.selectOnBlur) {
215 _selectValue(self);
216 }
217
218 list.hide();
219 self.trigger('hideTimepicker');
220 });
221
222 return this;
223 },
224
225 option: function(key, value)
226 {
227 if (typeof key == 'string' && typeof value == 'undefined') {
228 return $(this).data('timepicker-settings')[key];
229 }
230
231 return this.each(function(){
232 var self = $(this);
233 var settings = self.data('timepicker-settings');
234 var list = self.data('timepicker-list');
235
236 if (typeof key == 'object') {
237 settings = $.extend(settings, key);
238 } else if (typeof key == 'string') {
239 settings[key] = value;
240 }
241
242 settings = _parseSettings(settings);
243
244 self.data('timepicker-settings', settings);
245
246 if (list) {
247 list.remove();
248 self.data('timepicker-list', false);
249 }
250
251 if (settings.useSelect) {
252 _render(self);
253 }
254 });
255 },
256
257 getSecondsFromMidnight: function()
258 {
259 return _time2int(_getTimeValue(this));
260 },
261
262 getTime: function(relative_date)
263 {
264 var self = this;
265
266 var time_string = _getTimeValue(self);
267 if (!time_string) {
268 return null;
269 }
270
271 var offset = _time2int(time_string);
272 if (offset === null) {
273 return null;
274 }
275
276 if (!relative_date) {
277 relative_date = new Date();
278 }
279
280 // construct a Date from relative date, and offset's time
281 var time = new Date(relative_date);
282 time.setHours(offset / 3600);
283 time.setMinutes(offset % 3600 / 60);
284 time.setSeconds(offset % 60);
285 time.setMilliseconds(0);
286
287 return time;
288 },
289
290 isVisible: function() {
291 var self = this;
292 var list = self.data('timepicker-list');
293 return !!(list && _isVisible(list));
294 },
295
296 setTime: function(value)
297 {
298 var self = this;
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 }
310
311 _setTimeValue(self, prettyTime);
312 if (self.data('timepicker-list')) {
313 _setSelected(self, self.data('timepicker-list'));
314 }
315
316 return this;
317 },
318
319 remove: function()
320 {
321 var self = this;
322
323 // check if this element is a timepicker
324 if (!self.hasClass('ui-timepicker-input')) {
325 return;
326 }
327
328 var settings = self.data('timepicker-settings');
329 self.removeAttr('autocomplete', 'off');
330 self.removeClass('ui-timepicker-input');
331 self.removeData('timepicker-settings');
332 self.off('.timepicker');
333
334 // timepicker-list won't be present unless the user has interacted with this timepicker
335 if (self.data('timepicker-list')) {
336 self.data('timepicker-list').remove();
337 }
338
339 if (settings.useSelect) {
340 self.show();
341 }
342
343 self.removeData('timepicker-list');
344
345 return this;
346 }
347 };
348
349 // private methods
350
351 function _isVisible(elem)
352 {
353 var el = elem[0];
354 return el.offsetWidth > 0 && el.offsetHeight > 0;
355 }
356
357 function _parseSettings(settings)
358 {
359 if (settings.minTime) {
360 settings.minTime = _time2int(settings.minTime);
361 }
362
363 if (settings.maxTime) {
364 settings.maxTime = _time2int(settings.maxTime);
365 }
366
367 if (settings.durationTime && typeof settings.durationTime !== 'function') {
368 settings.durationTime = _time2int(settings.durationTime);
369 }
370
371 if (settings.scrollDefault == 'now') {
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 }
380 } else if (settings.minTime) {
381 settings.scrollDefault = function() {
382 return settings.roundingFunction(settings.minTime, settings);
383 }
384 }
385
386 if ($.type(settings.timeFormat) === "string" && settings.timeFormat.match(/[gh]/)) {
387 settings._twelveHourTime = true;
388 }
389
390 if (settings.showOnFocus === false && settings.showOn.indexOf('focus') != -1) {
391 settings.showOn.splice(settings.showOn.indexOf('focus'), 1);
392 }
393
394 if (settings.disableTimeRanges.length > 0) {
395 // convert string times to integers
396 for (var i in settings.disableTimeRanges) {
397 settings.disableTimeRanges[i] = [
398 _time2int(settings.disableTimeRanges[i][0]),
399 _time2int(settings.disableTimeRanges[i][1])
400 ];
401 }
402
403 // sort by starting time
404 settings.disableTimeRanges = settings.disableTimeRanges.sort(function(a, b){
405 return a[0] - b[0];
406 });
407
408 // merge any overlapping ranges
409 for (var i = settings.disableTimeRanges.length-1; i > 0; i--) {
410 if (settings.disableTimeRanges[i][0] <= settings.disableTimeRanges[i-1][1]) {
411 settings.disableTimeRanges[i-1] = [
412 Math.min(settings.disableTimeRanges[i][0], settings.disableTimeRanges[i-1][0]),
413 Math.max(settings.disableTimeRanges[i][1], settings.disableTimeRanges[i-1][1])
414 ];
415 settings.disableTimeRanges.splice(i, 1);
416 }
417 }
418 }
419
420 return settings;
421 }
422
423 function _render(self)
424 {
425 var settings = self.data('timepicker-settings');
426 var list = self.data('timepicker-list');
427
428 if (list && list.length) {
429 list.remove();
430 self.data('timepicker-list', false);
431 }
432
433 if (settings.useSelect) {
434 list = $('<select />', { 'class': 'ui-timepicker-select' });
435 var wrapped_list = list;
436 } else {
437 list = $('<ul />', { 'class': 'ui-timepicker-list' });
438
439 var wrapped_list = $('<div />', { 'class': 'ui-timepicker-wrapper', 'tabindex': -1 });
440 wrapped_list.css({'display':'none', 'position': 'absolute' }).append(list);
441 }
442
443 if (settings.noneOption) {
444 if (settings.noneOption === true) {
445 settings.noneOption = (settings.useSelect) ? 'Time...' : 'None';
446 }
447
448 if ($.isArray(settings.noneOption)) {
449 for (var i in settings.noneOption) {
450 if (parseInt(i, 10) == i){
451 var noneElement = _generateNoneElement(settings.noneOption[i], settings.useSelect);
452 list.append(noneElement);
453 }
454 }
455 } else {
456 var noneElement = _generateNoneElement(settings.noneOption, settings.useSelect);
457 list.append(noneElement);
458 }
459 }
460
461 if (settings.className) {
462 wrapped_list.addClass(settings.className);
463 }
464
465 if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
466 var stepval = typeof settings.step == 'function' ? 'function' : settings.step;
467 wrapped_list.addClass('ui-timepicker-with-duration');
468 wrapped_list.addClass('ui-timepicker-step-'+settings.step);
469 }
470
471 var durStart = settings.minTime;
472 if (typeof settings.durationTime === 'function') {
473 durStart = _time2int(settings.durationTime());
474 } else if (settings.durationTime !== null) {
475 durStart = settings.durationTime;
476 }
477 var start = (settings.minTime !== null) ? settings.minTime : 0;
478 var end = (settings.maxTime !== null) ? settings.maxTime : (start + _ONE_DAY - 1);
479
480 if (end < start) {
481 // make sure the end time is greater than start time, otherwise there will be no list to show
482 end += _ONE_DAY;
483 }
484
485 if (end === _ONE_DAY-1 && $.type(settings.timeFormat) === "string" && settings.show2400) {
486 // show a 24:00 option when using military time
487 end = _ONE_DAY;
488 }
489
490 var dr = settings.disableTimeRanges;
491 var drCur = 0;
492 var drLen = dr.length;
493
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) {
502 var timeInt = i;
503 var timeString = _int2time(timeInt, settings);
504
505 if (settings.useSelect) {
506 var row = $('<option />', { 'value': timeString });
507 row.text(timeString);
508 } else {
509 var row = $('<li />');
510 row.addClass(timeInt % 86400 < 43200 ? 'ui-timepicker-am' : 'ui-timepicker-pm');
511 row.data('time', (timeInt <= 86400 ? timeInt : timeInt % 86400));
512 row.text(timeString);
513 }
514
515 if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
516 var durationString = _int2duration(i - durStart, settings.step);
517 if (settings.useSelect) {
518 row.text(row.text()+' ('+durationString+')');
519 } else {
520 var duration = $('<span />', { 'class': 'ui-timepicker-duration' });
521 duration.text(' ('+durationString+')');
522 row.append(duration);
523 }
524 }
525
526 if (drCur < drLen) {
527 if (timeInt >= dr[drCur][1]) {
528 drCur += 1;
529 }
530
531 if (dr[drCur] && timeInt >= dr[drCur][0] && timeInt < dr[drCur][1]) {
532 if (settings.useSelect) {
533 row.prop('disabled', true);
534 } else {
535 row.addClass('ui-timepicker-disabled');
536 }
537 }
538 }
539
540 list.append(row);
541 }
542
543 wrapped_list.data('timepicker-input', self);
544 self.data('timepicker-list', wrapped_list);
545
546 if (settings.useSelect) {
547 if (self.val()) {
548 list.val(_roundAndFormatTime(_time2int(self.val()), settings));
549 }
550
551 list.on('focus', function(){
552 $(this).data('timepicker-input').trigger('showTimepicker');
553 });
554 list.on('blur', function(){
555 $(this).data('timepicker-input').trigger('hideTimepicker');
556 });
557 list.on('change', function(){
558 _setTimeValue(self, $(this).val(), 'select');
559 });
560
561 _setTimeValue(self, list.val(), 'initial');
562 self.hide().after(list);
563 } else {
564 var appendTo = settings.appendTo;
565 if (typeof appendTo === 'string') {
566 appendTo = $(appendTo);
567 } else if (typeof appendTo === 'function') {
568 appendTo = appendTo(self);
569 }
570 appendTo.append(wrapped_list);
571 _setSelected(self, list);
572
573 list.on('mousedown click', 'li', function(e) {
574
575 // hack: temporarily disable the focus handler
576 // to deal with the fact that IE fires 'focus'
577 // events asynchronously
578 self.off('focus.timepicker');
579 self.on('focus.timepicker-ie-hack', function(){
580 self.off('focus.timepicker-ie-hack');
581 self.on('focus.timepicker', methods.show);
582 });
583
584 if (!_hideKeyboard(self)) {
585 self[0].focus();
586 }
587
588 // make sure only the clicked row is selected
589 list.find('li').removeClass('ui-timepicker-selected');
590 $(this).addClass('ui-timepicker-selected');
591
592 if (_selectValue(self)) {
593 self.trigger('hideTimepicker');
594
595 list.on('mouseup.timepicker click.timepicker', 'li', function(e) {
596 list.off('mouseup.timepicker click.timepicker');
597 wrapped_list.hide();
598 });
599 }
600 });
601 }
602 }
603
604 function _generateNoneElement(optionValue, useSelect)
605 {
606 var label, className, value;
607
608 if (typeof optionValue == 'object') {
609 label = optionValue.label;
610 className = optionValue.className;
611 value = optionValue.value;
612 } else if (typeof optionValue == 'string') {
613 label = optionValue;
614 } else {
615 $.error('Invalid noneOption value');
616 }
617
618 if (useSelect) {
619 return $('<option />', {
620 'value': value,
621 'class': className,
622 'text': label
623 });
624 } else {
625 return $('<li />', {
626 'class': className,
627 'text': label
628 }).data('time', String(value));
629 }
630 }
631
632 function _roundAndFormatTime(seconds, settings)
633 {
634 seconds = settings.roundingFunction(seconds, settings);
635 if (seconds !== null) {
636 return _int2time(seconds, settings);
637 }
638 }
639
640 // event handler to decide whether to close timepicker
641 function _closeHandler(e)
642 {
643 if (e.target == window) {
644 // mobile Chrome fires focus events against window for some reason
645 return;
646 }
647
648 var target = $(e.target);
649
650 if (target.closest('.ui-timepicker-input').length || target.closest('.ui-timepicker-wrapper').length) {
651 // active timepicker was focused. ignore
652 return;
653 }
654
655 methods.hide();
656 $(document).unbind('.ui-timepicker');
657 $(window).unbind('.ui-timepicker');
658 }
659
660 function _hideKeyboard(self)
661 {
662 var settings = self.data('timepicker-settings');
663 return ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && settings.disableTouchKeyboard);
664 }
665
666 function _findRow(self, list, value)
667 {
668 if (!value && value !== 0) {
669 return false;
670 }
671
672 var settings = self.data('timepicker-settings');
673 var out = false;
674 var value = settings.roundingFunction(value, settings);
675
676 // loop through the menu items
677 list.find('li').each(function(i, obj) {
678 var jObj = $(obj);
679 if (typeof jObj.data('time') != 'number') {
680 return;
681 }
682
683 if (jObj.data('time') == value) {
684 out = jObj;
685 return false;
686 }
687 });
688
689 return out;
690 }
691
692 function _setSelected(self, list)
693 {
694 list.find('li').removeClass('ui-timepicker-selected');
695
696 var timeValue = _time2int(_getTimeValue(self), self.data('timepicker-settings'));
697 if (timeValue === null) {
698 return;
699 }
700
701 var selected = _findRow(self, list, timeValue);
702 if (selected) {
703
704 var topDelta = selected.offset().top - list.offset().top;
705
706 if (topDelta + selected.outerHeight() > list.outerHeight() || topDelta < 0) {
707 list.scrollTop(list.scrollTop() + selected.position().top - selected.outerHeight());
708 }
709
710 selected.addClass('ui-timepicker-selected');
711 }
712 }
713
714
715 function _formatValue(e, origin)
716 {
717 if (this.value === '' || origin == 'timepicker') {
718 return;
719 }
720
721 var self = $(this);
722
723 if (self.is(':focus') && (!e || e.type != 'change')) {
724 return;
725 }
726
727 var settings = self.data('timepicker-settings');
728 var seconds = _time2int(this.value, settings);
729
730 if (seconds === null) {
731 self.trigger('timeFormatError');
732 return;
733 }
734
735 var rangeError = false;
736 // check that the time in within bounds
737 if ((settings.minTime !== null && settings.maxTime !== null)
738 && (seconds < settings.minTime || seconds > settings.maxTime)) {
739 rangeError = true;
740 }
741
742 // check that time isn't within disabled time ranges
743 $.each(settings.disableTimeRanges, function(){
744 if (seconds >= this[0] && seconds < this[1]) {
745 rangeError = true;
746 return false;
747 }
748 });
749
750 if (settings.forceRoundTime) {
751 var roundSeconds = settings.roundingFunction(seconds, settings);
752 if (roundSeconds != seconds) {
753 seconds = roundSeconds;
754 origin = null;
755 }
756 }
757
758 var prettyTime = _int2time(seconds, settings);
759
760 if (rangeError) {
761 if (_setTimeValue(self, prettyTime, 'error')) {
762 self.trigger('timeRangeError');
763 }
764 } else {
765 _setTimeValue(self, prettyTime, origin);
766 }
767 }
768
769 function _getTimeValue(self)
770 {
771 if (self.is('input')) {
772 return self.val();
773 } else {
774 // use the element's data attributes to store values
775 return self.data('ui-timepicker-value');
776 }
777 }
778
779 function _setTimeValue(self, value, source)
780 {
781 if (self.is('input')) {
782 self.val(value);
783
784 var settings = self.data('timepicker-settings');
785 if (settings.useSelect && source != 'select' && source != 'initial') {
786 self.data('timepicker-list').val(_roundAndFormatTime(_time2int(value), settings));
787 }
788 }
789
790 if (self.data('ui-timepicker-value') != value) {
791 self.data('ui-timepicker-value', value);
792 if (source == 'select') {
793 self.trigger('selectTime').trigger('changeTime').trigger('change', 'timepicker');
794 } else if (['error', 'initial'].indexOf(source) == -1) {
795 self.trigger('changeTime');
796 }
797
798 return true;
799 } else {
800 self.trigger('selectTime');
801 return false;
802 }
803 }
804
805 /*
806 * Filter freeform input
807 */
808 function _disableTextInputHandler(e)
809 {
810 switch (e.keyCode) {
811 case 13: // return
812 case 9: //tab
813 return;
814
815 default:
816 e.preventDefault();
817 }
818 }
819
820 /*
821 * Keyboard navigation via arrow keys
822 */
823 function _keydownhandler(e)
824 {
825 var self = $(this);
826 var list = self.data('timepicker-list');
827
828 if (!list || !_isVisible(list)) {
829 if (e.keyCode == 40) {
830 // show the list!
831 methods.show.call(self.get(0));
832 list = self.data('timepicker-list');
833 if (!_hideKeyboard(self)) {
834 self.focus();
835 }
836 } else {
837 return true;
838 }
839 }
840
841 switch (e.keyCode) {
842
843 case 13: // return
844 if (_selectValue(self)) {
845 _formatValue.call(self.get(0), {'type':'change'});
846 methods.hide.apply(this);
847 }
848
849 e.preventDefault();
850 return false;
851
852 case 38: // up
853 var selected = list.find('.ui-timepicker-selected');
854
855 if (!selected.length) {
856 list.find('li').each(function(i, obj) {
857 if ($(obj).position().top > 0) {
858 selected = $(obj);
859 return false;
860 }
861 });
862 selected.addClass('ui-timepicker-selected');
863
864 } else if (!selected.is(':first-child')) {
865 selected.removeClass('ui-timepicker-selected');
866 selected.prev().addClass('ui-timepicker-selected');
867
868 if (selected.prev().position().top < selected.outerHeight()) {
869 list.scrollTop(list.scrollTop() - selected.outerHeight());
870 }
871 }
872
873 return false;
874
875 case 40: // down
876 selected = list.find('.ui-timepicker-selected');
877
878 if (selected.length === 0) {
879 list.find('li').each(function(i, obj) {
880 if ($(obj).position().top > 0) {
881 selected = $(obj);
882 return false;
883 }
884 });
885
886 selected.addClass('ui-timepicker-selected');
887 } else if (!selected.is(':last-child')) {
888 selected.removeClass('ui-timepicker-selected');
889 selected.next().addClass('ui-timepicker-selected');
890
891 if (selected.next().position().top + 2*selected.outerHeight() > list.outerHeight()) {
892 list.scrollTop(list.scrollTop() + selected.outerHeight());
893 }
894 }
895
896 return false;
897
898 case 27: // escape
899 list.find('li').removeClass('ui-timepicker-selected');
900 methods.hide();
901 break;
902
903 case 9: //tab
904 methods.hide();
905 break;
906
907 default:
908 return true;
909 }
910 }
911
912 /*
913 * Time typeahead
914 */
915 function _keyuphandler(e)
916 {
917 var self = $(this);
918 var list = self.data('timepicker-list');
919 var settings = self.data('timepicker-settings');
920
921 if (!list || !_isVisible(list) || settings.disableTextInput) {
922 return true;
923 }
924
925 switch (e.keyCode) {
926
927 case 96: // numpad numerals
928 case 97:
929 case 98:
930 case 99:
931 case 100:
932 case 101:
933 case 102:
934 case 103:
935 case 104:
936 case 105:
937 case 48: // numerals
938 case 49:
939 case 50:
940 case 51:
941 case 52:
942 case 53:
943 case 54:
944 case 55:
945 case 56:
946 case 57:
947 case 65: // a
948 case 77: // m
949 case 80: // p
950 case 186: // colon
951 case 8: // backspace
952 case 46: // delete
953 if (settings.typeaheadHighlight) {
954 _setSelected(self, list);
955 } else {
956 list.hide();
957 }
958 break;
959 }
960 }
961
962 function _selectValue(self)
963 {
964 var settings = self.data('timepicker-settings');
965 var list = self.data('timepicker-list');
966 var timeValue = null;
967
968 var cursor = list.find('.ui-timepicker-selected');
969
970 if (cursor.hasClass('ui-timepicker-disabled')) {
971 return false;
972 }
973
974 if (cursor.length) {
975 // selected value found
976 timeValue = cursor.data('time');
977 }
978
979 if (timeValue !== null) {
980 if (typeof timeValue != 'string') {
981 timeValue = _int2time(timeValue, settings);
982 }
983
984 _setTimeValue(self, timeValue, 'select');
985 }
986
987 return true;
988 }
989
990 function _int2duration(seconds, step)
991 {
992 seconds = Math.abs(seconds);
993 var minutes = Math.round(seconds/60),
994 duration = [],
995 hours, mins;
996
997 if (minutes < 60) {
998 // Only show (x mins) under 1 hour
999 duration = [minutes, _lang.mins];
1000 } else {
1001 hours = Math.floor(minutes/60);
1002 mins = minutes%60;
1003
1004 // Show decimal notation (eg: 1.5 hrs) for 30 minute steps
1005 if (step == 30 && mins == 30) {
1006 hours += _lang.decimal + 5;
1007 }
1008
1009 duration.push(hours);
1010 duration.push(hours == 1 ? _lang.hr : _lang.hrs);
1011
1012 // Show remainder minutes notation (eg: 1 hr 15 mins) for non-30 minute steps
1013 // and only if there are remainder minutes to show
1014 if (step != 30 && mins) {
1015 duration.push(mins);
1016 duration.push(_lang.mins);
1017 }
1018 }
1019
1020 return duration.join(' ');
1021 }
1022
1023 function _int2time(timeInt, settings)
1024 {
1025 if (typeof timeInt != 'number') {
1026 return null;
1027 }
1028
1029 var seconds = parseInt(timeInt%60)
1030 , minutes = parseInt((timeInt/60)%60)
1031 , hours = parseInt((timeInt/(60*60))%24);
1032
1033 var time = new Date(1970, 0, 2, hours, minutes, seconds, 0);
1034
1035 if (isNaN(time.getTime())) {
1036 return null;
1037 }
1038
1039 if ($.type(settings.timeFormat) === "function") {
1040 return settings.timeFormat(time);
1041 }
1042
1043 var output = '';
1044 var hour, code;
1045 for (var i=0; i<settings.timeFormat.length; i++) {
1046
1047 code = settings.timeFormat.charAt(i);
1048 switch (code) {
1049
1050 case 'a':
1051 output += (time.getHours() > 11) ? _lang.pm : _lang.am;
1052 break;
1053
1054 case 'A':
1055 output += (time.getHours() > 11) ? _lang.PM : _lang.AM;
1056 break;
1057
1058 case 'g':
1059 hour = time.getHours() % 12;
1060 output += (hour === 0) ? '12' : hour;
1061 break;
1062
1063 case 'G':
1064 hour = time.getHours();
1065 if (timeInt === _ONE_DAY) hour = settings.show2400 ? 24 : 0;
1066 output += hour;
1067 break;
1068
1069 case 'h':
1070 hour = time.getHours() % 12;
1071
1072 if (hour !== 0 && hour < 10) {
1073 hour = '0'+hour;
1074 }
1075
1076 output += (hour === 0) ? '12' : hour;
1077 break;
1078
1079 case 'H':
1080 hour = time.getHours();
1081 if (timeInt === _ONE_DAY) hour = settings.show2400 ? 24 : 0;
1082 output += (hour > 9) ? hour : '0'+hour;
1083 break;
1084
1085 case 'i':
1086 var minutes = time.getMinutes();
1087 output += (minutes > 9) ? minutes : '0'+minutes;
1088 break;
1089
1090 case 's':
1091 seconds = time.getSeconds();
1092 output += (seconds > 9) ? seconds : '0'+seconds;
1093 break;
1094
1095 case '\\':
1096 // escape character; add the next character and skip ahead
1097 i++;
1098 output += settings.timeFormat.charAt(i);
1099 break;
1100
1101 default:
1102 output += code;
1103 }
1104 }
1105
1106 return output;
1107 }
1108
1109 function _time2int(timeString, settings)
1110 {
1111 if (timeString === '' || timeString === null) return null;
1112 if (typeof timeString == 'object') {
1113 return timeString.getHours()*3600 + timeString.getMinutes()*60 + timeString.getSeconds();
1114 }
1115 if (typeof timeString != 'string') {
1116 return timeString;
1117 }
1118
1119 timeString = timeString.toLowerCase().replace(/[\s\.]/g, '');
1120
1121 // if the last character is an "a" or "p", add the "m"
1122 if (timeString.slice(-1) == 'a' || timeString.slice(-1) == 'p') {
1123 timeString += 'm';
1124 }
1125
1126 var ampmRegex = '(' +
1127 _lang.am.replace('.', '')+'|' +
1128 _lang.pm.replace('.', '')+'|' +
1129 _lang.AM.replace('.', '')+'|' +
1130 _lang.PM.replace('.', '')+')?';
1131
1132 // try to parse time input
1133 var pattern = new RegExp('^'+ampmRegex+'([0-9]?[0-9])\\W?([0-5][0-9])?\\W?([0-5][0-9])?'+ampmRegex+'$');
1134
1135 var time = timeString.match(pattern);
1136 if (!time) {
1137 return null;
1138 }
1139
1140 var hour = parseInt(time[2]*1, 10);
1141 if (hour > 24) {
1142 if (settings && settings.wrapHours === false) {
1143 return null;
1144 } else {
1145 hour = hour % 24;
1146 }
1147 }
1148
1149 var ampm = time[1] || time[5];
1150 var hours = hour;
1151
1152 if (hour <= 12 && ampm) {
1153 var isPm = (ampm == _lang.pm || ampm == _lang.PM);
1154
1155 if (hour == 12) {
1156 hours = isPm ? 12 : 0;
1157 } else {
1158 hours = (hour + (isPm ? 12 : 0));
1159 }
1160 }
1161
1162 var minutes = ( time[3]*1 || 0 );
1163 var seconds = ( time[4]*1 || 0 );
1164 var timeInt = hours*3600 + minutes*60 + seconds;
1165
1166 // if no am/pm provided, intelligently guess based on the scrollDefault
1167 if (hour < 12 && !ampm && settings && settings._twelveHourTime && settings.scrollDefault) {
1168 var delta = timeInt - settings.scrollDefault();
1169 if (delta < 0 && delta >= _ONE_DAY / -2) {
1170 timeInt = (timeInt + (_ONE_DAY / 2)) % _ONE_DAY;
1171 }
1172 }
1173
1174 return timeInt;
1175 }
1176
1177 function _pad2(n) {
1178 return ("0" + n).slice(-2);
1179 }
1180
1181 // Plugin entry
1182 $.fn.timepicker = function(method)
1183 {
1184 if (!this.length) return this;
1185 if (methods[method]) {
1186 // check if this element is a timepicker
1187 if (!this.hasClass('ui-timepicker-input')) {
1188 return this;
1189 }
1190 return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
1191 }
1192 else if(typeof method === "object" || !method) { return methods.init.apply(this, arguments); }
1193 else { $.error("Method "+ method + " does not exist on jQuery.timepicker"); }
1194 };
1195 // Global defaults
1196 $.fn.timepicker.defaults = {
1197 appendTo: 'body',
1198 className: null,
1199 closeOnWindowScroll: false,
1200 disableTextInput: false,
1201 disableTimeRanges: [],
1202 disableTouchKeyboard: false,
1203 durationTime: null,
1204 forceRoundTime: false,
1205 maxTime: null,
1206 minTime: null,
1207 noneOption: false,
1208 orientation: 'l',
1209 roundingFunction: function(seconds, settings) {
1210 if (seconds === null) {
1211 return null;
1212 } else if (typeof settings.step !== "number") {
1213 // TODO: nearest fit irregular steps
1214 return seconds;
1215 } else {
1216 var offset = seconds % (settings.step*60); // step is in minutes
1217
1218 if (offset >= settings.step*30) {
1219 // if offset is larger than a half step, round up
1220 seconds += (settings.step*60) - offset;
1221 } else {
1222 // round down
1223 seconds -= offset;
1224 }
1225
1226 if (seconds == _ONE_DAY && settings.show2400) {
1227 return seconds;
1228 }
1229
1230 return seconds%_ONE_DAY;
1231 }
1232 },
1233 scrollDefault: null,
1234 selectOnBlur: false,
1235 show2400: false,
1236 showDuration: false,
1237 showOn: ['click', 'focus'],
1238 showOnFocus: true,
1239 step: 30,
1240 stopScrollPropagation: false,
1241 timeFormat: 'g:ia',
1242 typeaheadHighlight: true,
1243 useSelect: false,
1244 wrapHours: true
1245 };
1246 }));
1247