PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.9.3
Secure Custom Fields v6.9.3
6.9.5 6.9.4 6.9.3 6.9.2 6.9.1 6.9.0 6.8.9 6.8.7 6.8.8 6.8.6 6.8.4 6.8.5 trunk 6.4.0-beta1 6.4.0-beta2 6.4.1 6.4.1-beta3 6.4.1-beta4 6.4.1-beta5 6.4.1-beta6 6.4.1-beta7 6.4.2 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6 6.5.7 6.6.0 6.7.0 6.7.1 6.8.0 6.8.1 6.8.2 6.8.3
secure-custom-fields / assets / inc / timepicker / jquery-ui-timepicker-addon.js
secure-custom-fields / assets / inc / timepicker Last commit date
index.php 1 year ago jquery-ui-timepicker-addon.css 1 year ago jquery-ui-timepicker-addon.js 1 year ago jquery-ui-timepicker-addon.min.css 1 year ago jquery-ui-timepicker-addon.min.js 1 year ago
jquery-ui-timepicker-addon.js
3195 lines
1 /*! jQuery Timepicker Addon - v1.6.3 - 2016-04-20
2 * http://trentrichardson.com/examples/timepicker
3 * Copyright (c) 2016 Trent Richardson; Licensed MIT */
4 ( function ( factory ) {
5 if ( typeof define === 'function' && define.amd ) {
6 define( [ 'jquery', 'jquery-ui' ], factory );
7 } else {
8 factory( jQuery );
9 }
10 } )( function ( $ ) {
11 /*
12 * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
13 */
14 $.ui.timepicker = $.ui.timepicker || {};
15 if ( $.ui.timepicker.version ) {
16 return;
17 }
18
19 /*
20 * Extend jQueryUI, get it started with our version number
21 */
22 $.extend( $.ui, {
23 timepicker: {
24 version: '1.6.3',
25 },
26 } );
27
28 /*
29 * Timepicker manager.
30 * Use the singleton instance of this class, $.timepicker, to interact with the time picker.
31 * Settings for (groups of) time pickers are maintained in an instance object,
32 * allowing multiple different settings on the same page.
33 */
34 var Timepicker = function () {
35 this.regional = []; // Available regional settings, indexed by language code
36 this.regional[ '' ] = {
37 // Default regional settings
38 currentText: 'Now',
39 closeText: 'Done',
40 amNames: [ 'AM', 'A' ],
41 pmNames: [ 'PM', 'P' ],
42 timeFormat: 'HH:mm',
43 timeSuffix: '',
44 timeOnlyTitle: 'Choose Time',
45 timeText: 'Time',
46 hourText: 'Hour',
47 minuteText: 'Minute',
48 secondText: 'Second',
49 millisecText: 'Millisecond',
50 microsecText: 'Microsecond',
51 timezoneText: 'Time Zone',
52 isRTL: false,
53 };
54 this._defaults = {
55 // Global defaults for all the datetime picker instances
56 showButtonPanel: true,
57 timeOnly: false,
58 timeOnlyShowDate: false,
59 showHour: null,
60 showMinute: null,
61 showSecond: null,
62 showMillisec: null,
63 showMicrosec: null,
64 showTimezone: null,
65 showTime: true,
66 stepHour: 1,
67 stepMinute: 1,
68 stepSecond: 1,
69 stepMillisec: 1,
70 stepMicrosec: 1,
71 hour: 0,
72 minute: 0,
73 second: 0,
74 millisec: 0,
75 microsec: 0,
76 timezone: null,
77 hourMin: 0,
78 minuteMin: 0,
79 secondMin: 0,
80 millisecMin: 0,
81 microsecMin: 0,
82 hourMax: 23,
83 minuteMax: 59,
84 secondMax: 59,
85 millisecMax: 999,
86 microsecMax: 999,
87 minDateTime: null,
88 maxDateTime: null,
89 maxTime: null,
90 minTime: null,
91 onSelect: null,
92 hourGrid: 0,
93 minuteGrid: 0,
94 secondGrid: 0,
95 millisecGrid: 0,
96 microsecGrid: 0,
97 alwaysSetTime: true,
98 separator: ' ',
99 altFieldTimeOnly: true,
100 altTimeFormat: null,
101 altSeparator: null,
102 altTimeSuffix: null,
103 altRedirectFocus: true,
104 pickerTimeFormat: null,
105 pickerTimeSuffix: null,
106 showTimepicker: true,
107 timezoneList: null,
108 addSliderAccess: false,
109 sliderAccessArgs: null,
110 controlType: 'slider',
111 oneLine: false,
112 defaultValue: null,
113 parse: 'strict',
114 afterInject: null,
115 };
116 $.extend( this._defaults, this.regional[ '' ] );
117 };
118
119 $.extend( Timepicker.prototype, {
120 $input: null,
121 $altInput: null,
122 $timeObj: null,
123 inst: null,
124 hour_slider: null,
125 minute_slider: null,
126 second_slider: null,
127 millisec_slider: null,
128 microsec_slider: null,
129 timezone_select: null,
130 maxTime: null,
131 minTime: null,
132 hour: 0,
133 minute: 0,
134 second: 0,
135 millisec: 0,
136 microsec: 0,
137 timezone: null,
138 hourMinOriginal: null,
139 minuteMinOriginal: null,
140 secondMinOriginal: null,
141 millisecMinOriginal: null,
142 microsecMinOriginal: null,
143 hourMaxOriginal: null,
144 minuteMaxOriginal: null,
145 secondMaxOriginal: null,
146 millisecMaxOriginal: null,
147 microsecMaxOriginal: null,
148 ampm: '',
149 formattedDate: '',
150 formattedTime: '',
151 formattedDateTime: '',
152 timezoneList: null,
153 units: [ 'hour', 'minute', 'second', 'millisec', 'microsec' ],
154 support: {},
155 control: null,
156
157 /*
158 * Override the default settings for all instances of the time picker.
159 * @param {Object} settings object - the new settings to use as defaults (anonymous object)
160 * @return {Object} the manager object
161 */
162 setDefaults: function ( settings ) {
163 extendRemove( this._defaults, settings || {} );
164 return this;
165 },
166
167 /*
168 * Create a new Timepicker instance
169 */
170 _newInst: function ( $input, opts ) {
171 var tp_inst = new Timepicker(),
172 inlineSettings = {},
173 fns = {},
174 overrides,
175 i;
176
177 for ( var attrName in this._defaults ) {
178 if ( this._defaults.hasOwnProperty( attrName ) ) {
179 var attrValue = $input.attr( 'time:' + attrName );
180 if ( attrValue ) {
181 try {
182 inlineSettings[ attrName ] = eval( attrValue );
183 } catch ( err ) {
184 inlineSettings[ attrName ] = attrValue;
185 }
186 }
187 }
188 }
189
190 overrides = {
191 beforeShow: function ( input, dp_inst ) {
192 if ( $.isFunction( tp_inst._defaults.evnts.beforeShow ) ) {
193 return tp_inst._defaults.evnts.beforeShow.call(
194 $input[ 0 ],
195 input,
196 dp_inst,
197 tp_inst
198 );
199 }
200 },
201 onChangeMonthYear: function ( year, month, dp_inst ) {
202 // Update the time as well : this prevents the time from disappearing from the $input field.
203 // tp_inst._updateDateTime(dp_inst);
204 if (
205 $.isFunction(
206 tp_inst._defaults.evnts.onChangeMonthYear
207 )
208 ) {
209 tp_inst._defaults.evnts.onChangeMonthYear.call(
210 $input[ 0 ],
211 year,
212 month,
213 dp_inst,
214 tp_inst
215 );
216 }
217 },
218 onClose: function ( dateText, dp_inst ) {
219 if ( tp_inst.timeDefined === true && $input.val() !== '' ) {
220 tp_inst._updateDateTime( dp_inst );
221 }
222 if ( $.isFunction( tp_inst._defaults.evnts.onClose ) ) {
223 tp_inst._defaults.evnts.onClose.call(
224 $input[ 0 ],
225 dateText,
226 dp_inst,
227 tp_inst
228 );
229 }
230 },
231 };
232 for ( i in overrides ) {
233 if ( overrides.hasOwnProperty( i ) ) {
234 fns[ i ] = opts[ i ] || this._defaults[ i ] || null;
235 }
236 }
237
238 tp_inst._defaults = $.extend(
239 {},
240 this._defaults,
241 inlineSettings,
242 opts,
243 overrides,
244 {
245 evnts: fns,
246 timepicker: tp_inst, // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
247 }
248 );
249 tp_inst.amNames = $.map(
250 tp_inst._defaults.amNames,
251 function ( val ) {
252 return val.toUpperCase();
253 }
254 );
255 tp_inst.pmNames = $.map(
256 tp_inst._defaults.pmNames,
257 function ( val ) {
258 return val.toUpperCase();
259 }
260 );
261
262 // detect which units are supported
263 tp_inst.support = detectSupport(
264 tp_inst._defaults.timeFormat +
265 ( tp_inst._defaults.pickerTimeFormat
266 ? tp_inst._defaults.pickerTimeFormat
267 : '' ) +
268 ( tp_inst._defaults.altTimeFormat
269 ? tp_inst._defaults.altTimeFormat
270 : '' )
271 );
272
273 // controlType is string - key to our this._controls
274 if ( typeof tp_inst._defaults.controlType === 'string' ) {
275 if (
276 tp_inst._defaults.controlType === 'slider' &&
277 typeof $.ui.slider === 'undefined'
278 ) {
279 tp_inst._defaults.controlType = 'select';
280 }
281 tp_inst.control =
282 tp_inst._controls[ tp_inst._defaults.controlType ];
283 }
284 // controlType is an object and must implement create, options, value methods
285 else {
286 tp_inst.control = tp_inst._defaults.controlType;
287 }
288
289 // prep the timezone options
290 var timezoneList = [
291 -720,
292 -660,
293 -600,
294 -570,
295 -540,
296 -480,
297 -420,
298 -360,
299 -300,
300 -270,
301 -240,
302 -210,
303 -180,
304 -120,
305 -60,
306 0,
307 60,
308 120,
309 180,
310 210,
311 240,
312 270,
313 300,
314 330,
315 345,
316 360,
317 390,
318 420,
319 480,
320 525,
321 540,
322 570,
323 600,
324 630,
325 660,
326 690,
327 720,
328 765,
329 780,
330 840,
331 ];
332 if ( tp_inst._defaults.timezoneList !== null ) {
333 timezoneList = tp_inst._defaults.timezoneList;
334 }
335 var tzl = timezoneList.length,
336 tzi = 0,
337 tzv = null;
338 if ( tzl > 0 && typeof timezoneList[ 0 ] !== 'object' ) {
339 for ( ; tzi < tzl; tzi++ ) {
340 tzv = timezoneList[ tzi ];
341 timezoneList[ tzi ] = {
342 value: tzv,
343 label: $.timepicker.timezoneOffsetString(
344 tzv,
345 tp_inst.support.iso8601
346 ),
347 };
348 }
349 }
350 tp_inst._defaults.timezoneList = timezoneList;
351
352 // set the default units
353 tp_inst.timezone =
354 tp_inst._defaults.timezone !== null
355 ? $.timepicker.timezoneOffsetNumber(
356 tp_inst._defaults.timezone
357 )
358 : new Date().getTimezoneOffset() * -1;
359 tp_inst.hour =
360 tp_inst._defaults.hour < tp_inst._defaults.hourMin
361 ? tp_inst._defaults.hourMin
362 : tp_inst._defaults.hour > tp_inst._defaults.hourMax
363 ? tp_inst._defaults.hourMax
364 : tp_inst._defaults.hour;
365 tp_inst.minute =
366 tp_inst._defaults.minute < tp_inst._defaults.minuteMin
367 ? tp_inst._defaults.minuteMin
368 : tp_inst._defaults.minute > tp_inst._defaults.minuteMax
369 ? tp_inst._defaults.minuteMax
370 : tp_inst._defaults.minute;
371 tp_inst.second =
372 tp_inst._defaults.second < tp_inst._defaults.secondMin
373 ? tp_inst._defaults.secondMin
374 : tp_inst._defaults.second > tp_inst._defaults.secondMax
375 ? tp_inst._defaults.secondMax
376 : tp_inst._defaults.second;
377 tp_inst.millisec =
378 tp_inst._defaults.millisec < tp_inst._defaults.millisecMin
379 ? tp_inst._defaults.millisecMin
380 : tp_inst._defaults.millisec > tp_inst._defaults.millisecMax
381 ? tp_inst._defaults.millisecMax
382 : tp_inst._defaults.millisec;
383 tp_inst.microsec =
384 tp_inst._defaults.microsec < tp_inst._defaults.microsecMin
385 ? tp_inst._defaults.microsecMin
386 : tp_inst._defaults.microsec > tp_inst._defaults.microsecMax
387 ? tp_inst._defaults.microsecMax
388 : tp_inst._defaults.microsec;
389 tp_inst.ampm = '';
390 tp_inst.$input = $input;
391
392 if ( tp_inst._defaults.altField ) {
393 tp_inst.$altInput = $( tp_inst._defaults.altField );
394 if ( tp_inst._defaults.altRedirectFocus === true ) {
395 tp_inst.$altInput
396 .css( {
397 cursor: 'pointer',
398 } )
399 .focus( function () {
400 $input.trigger( 'focus' );
401 } );
402 }
403 }
404
405 if (
406 tp_inst._defaults.minDate === 0 ||
407 tp_inst._defaults.minDateTime === 0
408 ) {
409 tp_inst._defaults.minDate = new Date();
410 }
411 if (
412 tp_inst._defaults.maxDate === 0 ||
413 tp_inst._defaults.maxDateTime === 0
414 ) {
415 tp_inst._defaults.maxDate = new Date();
416 }
417
418 // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
419 if (
420 tp_inst._defaults.minDate !== undefined &&
421 tp_inst._defaults.minDate instanceof Date
422 ) {
423 tp_inst._defaults.minDateTime = new Date(
424 tp_inst._defaults.minDate.getTime()
425 );
426 }
427 if (
428 tp_inst._defaults.minDateTime !== undefined &&
429 tp_inst._defaults.minDateTime instanceof Date
430 ) {
431 tp_inst._defaults.minDate = new Date(
432 tp_inst._defaults.minDateTime.getTime()
433 );
434 }
435 if (
436 tp_inst._defaults.maxDate !== undefined &&
437 tp_inst._defaults.maxDate instanceof Date
438 ) {
439 tp_inst._defaults.maxDateTime = new Date(
440 tp_inst._defaults.maxDate.getTime()
441 );
442 }
443 if (
444 tp_inst._defaults.maxDateTime !== undefined &&
445 tp_inst._defaults.maxDateTime instanceof Date
446 ) {
447 tp_inst._defaults.maxDate = new Date(
448 tp_inst._defaults.maxDateTime.getTime()
449 );
450 }
451 tp_inst.$input.bind( 'focus', function () {
452 tp_inst._onFocus();
453 } );
454
455 return tp_inst;
456 },
457
458 /*
459 * add our sliders to the calendar
460 */
461 _addTimePicker: function ( dp_inst ) {
462 var currDT = $.trim(
463 this.$altInput && this._defaults.altFieldTimeOnly
464 ? this.$input.val() + ' ' + this.$altInput.val()
465 : this.$input.val()
466 );
467
468 this.timeDefined = this._parseTime( currDT );
469 this._limitMinMaxDateTime( dp_inst, false );
470 this._injectTimePicker();
471 this._afterInject();
472 },
473
474 /*
475 * parse the time string from input value or _setTime
476 */
477 _parseTime: function ( timeString, withDate ) {
478 if ( ! this.inst ) {
479 this.inst = $.datepicker._getInst( this.$input[ 0 ] );
480 }
481
482 if ( withDate || ! this._defaults.timeOnly ) {
483 var dp_dateFormat = $.datepicker._get(
484 this.inst,
485 'dateFormat'
486 );
487 try {
488 var parseRes = parseDateTimeInternal(
489 dp_dateFormat,
490 this._defaults.timeFormat,
491 timeString,
492 $.datepicker._getFormatConfig( this.inst ),
493 this._defaults
494 );
495 if ( ! parseRes.timeObj ) {
496 return false;
497 }
498 $.extend( this, parseRes.timeObj );
499 } catch ( err ) {
500 $.timepicker.log(
501 'Error parsing the date/time string: ' +
502 err +
503 '\ndate/time string = ' +
504 timeString +
505 '\ntimeFormat = ' +
506 this._defaults.timeFormat +
507 '\ndateFormat = ' +
508 dp_dateFormat
509 );
510 return false;
511 }
512 return true;
513 } else {
514 var timeObj = $.datepicker.parseTime(
515 this._defaults.timeFormat,
516 timeString,
517 this._defaults
518 );
519 if ( ! timeObj ) {
520 return false;
521 }
522 $.extend( this, timeObj );
523 return true;
524 }
525 },
526
527 /*
528 * Handle callback option after injecting timepicker
529 */
530 _afterInject: function () {
531 var o = this.inst.settings;
532 if ( $.isFunction( o.afterInject ) ) {
533 o.afterInject.call( this );
534 }
535 },
536
537 /*
538 * generate and inject html for timepicker into ui datepicker
539 */
540 _injectTimePicker: function () {
541 var $dp = this.inst.dpDiv,
542 o = this.inst.settings,
543 tp_inst = this,
544 litem = '',
545 uitem = '',
546 show = null,
547 max = {},
548 gridSize = {},
549 size = null,
550 i = 0,
551 l = 0;
552
553 // Prevent displaying twice
554 if (
555 $dp.find( 'div.ui-timepicker-div' ).length === 0 &&
556 o.showTimepicker
557 ) {
558 var noDisplay = ' ui_tpicker_unit_hide',
559 html =
560 '<div class="ui-timepicker-div' +
561 ( o.isRTL ? ' ui-timepicker-rtl' : '' ) +
562 ( o.oneLine && o.controlType === 'select'
563 ? ' ui-timepicker-oneLine'
564 : '' ) +
565 '"><dl>' +
566 '<dt class="ui_tpicker_time_label' +
567 ( o.showTime ? '' : noDisplay ) +
568 '">' +
569 o.timeText +
570 '</dt>' +
571 '<dd class="ui_tpicker_time ' +
572 ( o.showTime ? '' : noDisplay ) +
573 '"><input class="ui_tpicker_time_input" ' +
574 ( o.timeInput ? '' : 'disabled' ) +
575 '/></dd>';
576
577 // Create the markup
578 for ( i = 0, l = this.units.length; i < l; i++ ) {
579 litem = this.units[ i ];
580 uitem =
581 litem.substr( 0, 1 ).toUpperCase() + litem.substr( 1 );
582 show =
583 o[ 'show' + uitem ] !== null
584 ? o[ 'show' + uitem ]
585 : this.support[ litem ];
586
587 // Added by Peter Medeiros:
588 // - Figure out what the hour/minute/second max should be based on the step values.
589 // - Example: if stepMinute is 15, then minMax is 45.
590 max[ litem ] = parseInt(
591 o[ litem + 'Max' ] -
592 ( ( o[ litem + 'Max' ] - o[ litem + 'Min' ] ) %
593 o[ 'step' + uitem ] ),
594 10
595 );
596 gridSize[ litem ] = 0;
597
598 html +=
599 '<dt class="ui_tpicker_' +
600 litem +
601 '_label' +
602 ( show ? '' : noDisplay ) +
603 '">' +
604 o[ litem + 'Text' ] +
605 '</dt>' +
606 '<dd class="ui_tpicker_' +
607 litem +
608 ( show ? '' : noDisplay ) +
609 '"><div class="ui_tpicker_' +
610 litem +
611 '_slider' +
612 ( show ? '' : noDisplay ) +
613 '"></div>';
614
615 if ( show && o[ litem + 'Grid' ] > 0 ) {
616 html +=
617 '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
618
619 if ( litem === 'hour' ) {
620 for (
621 var h = o[ litem + 'Min' ];
622 h <= max[ litem ];
623 h += parseInt( o[ litem + 'Grid' ], 10 )
624 ) {
625 gridSize[ litem ]++;
626 var tmph = $.datepicker.formatTime(
627 this.support.ampm ? 'hht' : 'HH',
628 { hour: h },
629 o
630 );
631 html +=
632 '<td data-for="' +
633 litem +
634 '">' +
635 tmph +
636 '</td>';
637 }
638 } else {
639 for (
640 var m = o[ litem + 'Min' ];
641 m <= max[ litem ];
642 m += parseInt( o[ litem + 'Grid' ], 10 )
643 ) {
644 gridSize[ litem ]++;
645 html +=
646 '<td data-for="' +
647 litem +
648 '">' +
649 ( m < 10 ? '0' : '' ) +
650 m +
651 '</td>';
652 }
653 }
654
655 html += '</tr></table></div>';
656 }
657 html += '</dd>';
658 }
659
660 // Timezone
661 var showTz =
662 o.showTimezone !== null
663 ? o.showTimezone
664 : this.support.timezone;
665 html +=
666 '<dt class="ui_tpicker_timezone_label' +
667 ( showTz ? '' : noDisplay ) +
668 '">' +
669 o.timezoneText +
670 '</dt>';
671 html +=
672 '<dd class="ui_tpicker_timezone' +
673 ( showTz ? '' : noDisplay ) +
674 '"></dd>';
675
676 // Create the elements from string
677 html += '</dl></div>';
678 var $tp = $( html );
679
680 // if we only want time picker...
681 if ( o.timeOnly === true ) {
682 $tp.prepend(
683 '<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' +
684 '<div class="ui-datepicker-title">' +
685 o.timeOnlyTitle +
686 '</div>' +
687 '</div>'
688 );
689 $dp.find(
690 '.ui-datepicker-header, .ui-datepicker-calendar'
691 ).hide();
692 }
693
694 // add sliders, adjust grids, add events
695 for ( i = 0, l = tp_inst.units.length; i < l; i++ ) {
696 litem = tp_inst.units[ i ];
697 uitem =
698 litem.substr( 0, 1 ).toUpperCase() + litem.substr( 1 );
699 show =
700 o[ 'show' + uitem ] !== null
701 ? o[ 'show' + uitem ]
702 : this.support[ litem ];
703
704 // add the slider
705 tp_inst[ litem + '_slider' ] = tp_inst.control.create(
706 tp_inst,
707 $tp.find( '.ui_tpicker_' + litem + '_slider' ),
708 litem,
709 tp_inst[ litem ],
710 o[ litem + 'Min' ],
711 max[ litem ],
712 o[ 'step' + uitem ]
713 );
714
715 // adjust the grid and add click event
716 if ( show && o[ litem + 'Grid' ] > 0 ) {
717 size =
718 ( 100 * gridSize[ litem ] * o[ litem + 'Grid' ] ) /
719 ( max[ litem ] - o[ litem + 'Min' ] );
720 $tp.find( '.ui_tpicker_' + litem + ' table' )
721 .css( {
722 width: size + '%',
723 marginLeft: o.isRTL
724 ? '0'
725 : size / ( -2 * gridSize[ litem ] ) + '%',
726 marginRight: o.isRTL
727 ? size / ( -2 * gridSize[ litem ] ) + '%'
728 : '0',
729 borderCollapse: 'collapse',
730 } )
731 .find( 'td' )
732 .click( function ( e ) {
733 var $t = $( this ),
734 h = $t.html(),
735 n = parseInt( h.replace( /[^0-9]/g ), 10 ),
736 ap = h.replace( /[^apm]/gi ),
737 f = $t.data( 'for' ); // loses scope, so we use data-for
738
739 if ( f === 'hour' ) {
740 if ( ap.indexOf( 'p' ) !== -1 && n < 12 ) {
741 n += 12;
742 } else {
743 if (
744 ap.indexOf( 'a' ) !== -1 &&
745 n === 12
746 ) {
747 n = 0;
748 }
749 }
750 }
751
752 tp_inst.control.value(
753 tp_inst,
754 tp_inst[ f + '_slider' ],
755 litem,
756 n
757 );
758
759 tp_inst._onTimeChange();
760 tp_inst._onSelectHandler();
761 } )
762 .css( {
763 cursor: 'pointer',
764 width: 100 / gridSize[ litem ] + '%',
765 textAlign: 'center',
766 overflow: 'hidden',
767 } );
768 } // end if grid > 0
769 } // end for loop
770
771 // Add timezone options
772 this.timezone_select = $tp
773 .find( '.ui_tpicker_timezone' )
774 .append( '<select></select>' )
775 .find( 'select' );
776 $.fn.append.apply(
777 this.timezone_select,
778 $.map( o.timezoneList, function ( val, idx ) {
779 return $( '<option />' )
780 .val( typeof val === 'object' ? val.value : val )
781 .text( typeof val === 'object' ? val.label : val );
782 } )
783 );
784 if (
785 typeof this.timezone !== 'undefined' &&
786 this.timezone !== null &&
787 this.timezone !== ''
788 ) {
789 var local_timezone =
790 new Date(
791 this.inst.selectedYear,
792 this.inst.selectedMonth,
793 this.inst.selectedDay,
794 12
795 ).getTimezoneOffset() * -1;
796 if ( local_timezone === this.timezone ) {
797 selectLocalTimezone( tp_inst );
798 } else {
799 this.timezone_select.val( this.timezone );
800 }
801 } else {
802 if (
803 typeof this.hour !== 'undefined' &&
804 this.hour !== null &&
805 this.hour !== ''
806 ) {
807 this.timezone_select.val( o.timezone );
808 } else {
809 selectLocalTimezone( tp_inst );
810 }
811 }
812 this.timezone_select.change( function () {
813 tp_inst._onTimeChange();
814 tp_inst._onSelectHandler();
815 tp_inst._afterInject();
816 } );
817 // End timezone options
818
819 // inject timepicker into datepicker
820 var $buttonPanel = $dp.find( '.ui-datepicker-buttonpane' );
821 if ( $buttonPanel.length ) {
822 $buttonPanel.before( $tp );
823 } else {
824 $dp.append( $tp );
825 }
826
827 this.$timeObj = $tp.find( '.ui_tpicker_time_input' );
828 this.$timeObj.change( function () {
829 var timeFormat = tp_inst.inst.settings.timeFormat;
830 var parsedTime = $.datepicker.parseTime(
831 timeFormat,
832 this.value
833 );
834 var update = new Date();
835 if ( parsedTime ) {
836 update.setHours( parsedTime.hour );
837 update.setMinutes( parsedTime.minute );
838 update.setSeconds( parsedTime.second );
839 $.datepicker._setTime( tp_inst.inst, update );
840 } else {
841 this.value = tp_inst.formattedTime;
842 this.blur();
843 }
844 } );
845
846 if ( this.inst !== null ) {
847 var timeDefined = this.timeDefined;
848 this._onTimeChange();
849 this.timeDefined = timeDefined;
850 }
851
852 // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
853 if ( this._defaults.addSliderAccess ) {
854 var sliderAccessArgs = this._defaults.sliderAccessArgs,
855 rtl = this._defaults.isRTL;
856 sliderAccessArgs.isRTL = rtl;
857
858 setTimeout( function () {
859 // fix for inline mode
860 if ( $tp.find( '.ui-slider-access' ).length === 0 ) {
861 $tp.find( '.ui-slider:visible' ).sliderAccess(
862 sliderAccessArgs
863 );
864
865 // fix any grids since sliders are shorter
866 var sliderAccessWidth = $tp
867 .find( '.ui-slider-access:eq(0)' )
868 .outerWidth( true );
869 if ( sliderAccessWidth ) {
870 $tp.find( 'table:visible' ).each( function () {
871 var $g = $( this ),
872 oldWidth = $g.outerWidth(),
873 oldMarginLeft = $g
874 .css(
875 rtl
876 ? 'marginRight'
877 : 'marginLeft'
878 )
879 .toString()
880 .replace( '%', '' ),
881 newWidth = oldWidth - sliderAccessWidth,
882 newMarginLeft =
883 ( oldMarginLeft * newWidth ) /
884 oldWidth +
885 '%',
886 css = {
887 width: newWidth,
888 marginRight: 0,
889 marginLeft: 0,
890 };
891 css[
892 rtl ? 'marginRight' : 'marginLeft'
893 ] = newMarginLeft;
894 $g.css( css );
895 } );
896 }
897 }
898 }, 10 );
899 }
900 // end slideAccess integration
901
902 tp_inst._limitMinMaxDateTime( this.inst, true );
903 }
904 },
905
906 /*
907 * This function tries to limit the ability to go outside the
908 * min/max date range
909 */
910 _limitMinMaxDateTime: function ( dp_inst, adjustSliders ) {
911 var o = this._defaults,
912 dp_date = new Date(
913 dp_inst.selectedYear,
914 dp_inst.selectedMonth,
915 dp_inst.selectedDay
916 );
917
918 if ( ! this._defaults.showTimepicker ) {
919 return;
920 } // No time so nothing to check here
921
922 if (
923 $.datepicker._get( dp_inst, 'minDateTime' ) !== null &&
924 $.datepicker._get( dp_inst, 'minDateTime' ) !== undefined &&
925 dp_date
926 ) {
927 var minDateTime = $.datepicker._get( dp_inst, 'minDateTime' ),
928 minDateTimeDate = new Date(
929 minDateTime.getFullYear(),
930 minDateTime.getMonth(),
931 minDateTime.getDate(),
932 0,
933 0,
934 0,
935 0
936 );
937
938 if (
939 this.hourMinOriginal === null ||
940 this.minuteMinOriginal === null ||
941 this.secondMinOriginal === null ||
942 this.millisecMinOriginal === null ||
943 this.microsecMinOriginal === null
944 ) {
945 this.hourMinOriginal = o.hourMin;
946 this.minuteMinOriginal = o.minuteMin;
947 this.secondMinOriginal = o.secondMin;
948 this.millisecMinOriginal = o.millisecMin;
949 this.microsecMinOriginal = o.microsecMin;
950 }
951
952 if (
953 dp_inst.settings.timeOnly ||
954 minDateTimeDate.getTime() === dp_date.getTime()
955 ) {
956 this._defaults.hourMin = minDateTime.getHours();
957 if ( this.hour <= this._defaults.hourMin ) {
958 this.hour = this._defaults.hourMin;
959 this._defaults.minuteMin = minDateTime.getMinutes();
960 if ( this.minute <= this._defaults.minuteMin ) {
961 this.minute = this._defaults.minuteMin;
962 this._defaults.secondMin = minDateTime.getSeconds();
963 if ( this.second <= this._defaults.secondMin ) {
964 this.second = this._defaults.secondMin;
965 this._defaults.millisecMin = minDateTime.getMilliseconds();
966 if (
967 this.millisec <= this._defaults.millisecMin
968 ) {
969 this.millisec = this._defaults.millisecMin;
970 this._defaults.microsecMin = minDateTime.getMicroseconds();
971 } else {
972 if (
973 this.microsec <
974 this._defaults.microsecMin
975 ) {
976 this.microsec = this._defaults.microsecMin;
977 }
978 this._defaults.microsecMin = this.microsecMinOriginal;
979 }
980 } else {
981 this._defaults.millisecMin = this.millisecMinOriginal;
982 this._defaults.microsecMin = this.microsecMinOriginal;
983 }
984 } else {
985 this._defaults.secondMin = this.secondMinOriginal;
986 this._defaults.millisecMin = this.millisecMinOriginal;
987 this._defaults.microsecMin = this.microsecMinOriginal;
988 }
989 } else {
990 this._defaults.minuteMin = this.minuteMinOriginal;
991 this._defaults.secondMin = this.secondMinOriginal;
992 this._defaults.millisecMin = this.millisecMinOriginal;
993 this._defaults.microsecMin = this.microsecMinOriginal;
994 }
995 } else {
996 this._defaults.hourMin = this.hourMinOriginal;
997 this._defaults.minuteMin = this.minuteMinOriginal;
998 this._defaults.secondMin = this.secondMinOriginal;
999 this._defaults.millisecMin = this.millisecMinOriginal;
1000 this._defaults.microsecMin = this.microsecMinOriginal;
1001 }
1002 }
1003
1004 if (
1005 $.datepicker._get( dp_inst, 'maxDateTime' ) !== null &&
1006 $.datepicker._get( dp_inst, 'maxDateTime' ) !== undefined &&
1007 dp_date
1008 ) {
1009 var maxDateTime = $.datepicker._get( dp_inst, 'maxDateTime' ),
1010 maxDateTimeDate = new Date(
1011 maxDateTime.getFullYear(),
1012 maxDateTime.getMonth(),
1013 maxDateTime.getDate(),
1014 0,
1015 0,
1016 0,
1017 0
1018 );
1019
1020 if (
1021 this.hourMaxOriginal === null ||
1022 this.minuteMaxOriginal === null ||
1023 this.secondMaxOriginal === null ||
1024 this.millisecMaxOriginal === null
1025 ) {
1026 this.hourMaxOriginal = o.hourMax;
1027 this.minuteMaxOriginal = o.minuteMax;
1028 this.secondMaxOriginal = o.secondMax;
1029 this.millisecMaxOriginal = o.millisecMax;
1030 this.microsecMaxOriginal = o.microsecMax;
1031 }
1032
1033 if (
1034 dp_inst.settings.timeOnly ||
1035 maxDateTimeDate.getTime() === dp_date.getTime()
1036 ) {
1037 this._defaults.hourMax = maxDateTime.getHours();
1038 if ( this.hour >= this._defaults.hourMax ) {
1039 this.hour = this._defaults.hourMax;
1040 this._defaults.minuteMax = maxDateTime.getMinutes();
1041 if ( this.minute >= this._defaults.minuteMax ) {
1042 this.minute = this._defaults.minuteMax;
1043 this._defaults.secondMax = maxDateTime.getSeconds();
1044 if ( this.second >= this._defaults.secondMax ) {
1045 this.second = this._defaults.secondMax;
1046 this._defaults.millisecMax = maxDateTime.getMilliseconds();
1047 if (
1048 this.millisec >= this._defaults.millisecMax
1049 ) {
1050 this.millisec = this._defaults.millisecMax;
1051 this._defaults.microsecMax = maxDateTime.getMicroseconds();
1052 } else {
1053 if (
1054 this.microsec >
1055 this._defaults.microsecMax
1056 ) {
1057 this.microsec = this._defaults.microsecMax;
1058 }
1059 this._defaults.microsecMax = this.microsecMaxOriginal;
1060 }
1061 } else {
1062 this._defaults.millisecMax = this.millisecMaxOriginal;
1063 this._defaults.microsecMax = this.microsecMaxOriginal;
1064 }
1065 } else {
1066 this._defaults.secondMax = this.secondMaxOriginal;
1067 this._defaults.millisecMax = this.millisecMaxOriginal;
1068 this._defaults.microsecMax = this.microsecMaxOriginal;
1069 }
1070 } else {
1071 this._defaults.minuteMax = this.minuteMaxOriginal;
1072 this._defaults.secondMax = this.secondMaxOriginal;
1073 this._defaults.millisecMax = this.millisecMaxOriginal;
1074 this._defaults.microsecMax = this.microsecMaxOriginal;
1075 }
1076 } else {
1077 this._defaults.hourMax = this.hourMaxOriginal;
1078 this._defaults.minuteMax = this.minuteMaxOriginal;
1079 this._defaults.secondMax = this.secondMaxOriginal;
1080 this._defaults.millisecMax = this.millisecMaxOriginal;
1081 this._defaults.microsecMax = this.microsecMaxOriginal;
1082 }
1083 }
1084
1085 if ( dp_inst.settings.minTime !== null ) {
1086 var tempMinTime = new Date(
1087 '01/01/1970 ' + dp_inst.settings.minTime
1088 );
1089 if ( this.hour < tempMinTime.getHours() ) {
1090 this.hour = this._defaults.hourMin = tempMinTime.getHours();
1091 this.minute = this._defaults.minuteMin = tempMinTime.getMinutes();
1092 } else if (
1093 this.hour === tempMinTime.getHours() &&
1094 this.minute < tempMinTime.getMinutes()
1095 ) {
1096 this.minute = this._defaults.minuteMin = tempMinTime.getMinutes();
1097 } else {
1098 if ( this._defaults.hourMin < tempMinTime.getHours() ) {
1099 this._defaults.hourMin = tempMinTime.getHours();
1100 this._defaults.minuteMin = tempMinTime.getMinutes();
1101 } else if (
1102 ( this._defaults.hourMin ===
1103 tempMinTime.getHours() ) ===
1104 this.hour &&
1105 this._defaults.minuteMin < tempMinTime.getMinutes()
1106 ) {
1107 this._defaults.minuteMin = tempMinTime.getMinutes();
1108 } else {
1109 this._defaults.minuteMin = 0;
1110 }
1111 }
1112 }
1113
1114 if ( dp_inst.settings.maxTime !== null ) {
1115 var tempMaxTime = new Date(
1116 '01/01/1970 ' + dp_inst.settings.maxTime
1117 );
1118 if ( this.hour > tempMaxTime.getHours() ) {
1119 this.hour = this._defaults.hourMax = tempMaxTime.getHours();
1120 this.minute = this._defaults.minuteMax = tempMaxTime.getMinutes();
1121 } else if (
1122 this.hour === tempMaxTime.getHours() &&
1123 this.minute > tempMaxTime.getMinutes()
1124 ) {
1125 this.minute = this._defaults.minuteMax = tempMaxTime.getMinutes();
1126 } else {
1127 if ( this._defaults.hourMax > tempMaxTime.getHours() ) {
1128 this._defaults.hourMax = tempMaxTime.getHours();
1129 this._defaults.minuteMax = tempMaxTime.getMinutes();
1130 } else if (
1131 ( this._defaults.hourMax ===
1132 tempMaxTime.getHours() ) ===
1133 this.hour &&
1134 this._defaults.minuteMax > tempMaxTime.getMinutes()
1135 ) {
1136 this._defaults.minuteMax = tempMaxTime.getMinutes();
1137 } else {
1138 this._defaults.minuteMax = 59;
1139 }
1140 }
1141 }
1142
1143 if ( adjustSliders !== undefined && adjustSliders === true ) {
1144 var hourMax = parseInt(
1145 this._defaults.hourMax -
1146 ( ( this._defaults.hourMax -
1147 this._defaults.hourMin ) %
1148 this._defaults.stepHour ),
1149 10
1150 ),
1151 minMax = parseInt(
1152 this._defaults.minuteMax -
1153 ( ( this._defaults.minuteMax -
1154 this._defaults.minuteMin ) %
1155 this._defaults.stepMinute ),
1156 10
1157 ),
1158 secMax = parseInt(
1159 this._defaults.secondMax -
1160 ( ( this._defaults.secondMax -
1161 this._defaults.secondMin ) %
1162 this._defaults.stepSecond ),
1163 10
1164 ),
1165 millisecMax = parseInt(
1166 this._defaults.millisecMax -
1167 ( ( this._defaults.millisecMax -
1168 this._defaults.millisecMin ) %
1169 this._defaults.stepMillisec ),
1170 10
1171 ),
1172 microsecMax = parseInt(
1173 this._defaults.microsecMax -
1174 ( ( this._defaults.microsecMax -
1175 this._defaults.microsecMin ) %
1176 this._defaults.stepMicrosec ),
1177 10
1178 );
1179
1180 if ( this.hour_slider ) {
1181 this.control.options( this, this.hour_slider, 'hour', {
1182 min: this._defaults.hourMin,
1183 max: hourMax,
1184 step: this._defaults.stepHour,
1185 } );
1186 this.control.value(
1187 this,
1188 this.hour_slider,
1189 'hour',
1190 this.hour - ( this.hour % this._defaults.stepHour )
1191 );
1192 }
1193 if ( this.minute_slider ) {
1194 this.control.options( this, this.minute_slider, 'minute', {
1195 min: this._defaults.minuteMin,
1196 max: minMax,
1197 step: this._defaults.stepMinute,
1198 } );
1199 this.control.value(
1200 this,
1201 this.minute_slider,
1202 'minute',
1203 this.minute -
1204 ( this.minute % this._defaults.stepMinute )
1205 );
1206 }
1207 if ( this.second_slider ) {
1208 this.control.options( this, this.second_slider, 'second', {
1209 min: this._defaults.secondMin,
1210 max: secMax,
1211 step: this._defaults.stepSecond,
1212 } );
1213 this.control.value(
1214 this,
1215 this.second_slider,
1216 'second',
1217 this.second -
1218 ( this.second % this._defaults.stepSecond )
1219 );
1220 }
1221 if ( this.millisec_slider ) {
1222 this.control.options(
1223 this,
1224 this.millisec_slider,
1225 'millisec',
1226 {
1227 min: this._defaults.millisecMin,
1228 max: millisecMax,
1229 step: this._defaults.stepMillisec,
1230 }
1231 );
1232 this.control.value(
1233 this,
1234 this.millisec_slider,
1235 'millisec',
1236 this.millisec -
1237 ( this.millisec % this._defaults.stepMillisec )
1238 );
1239 }
1240 if ( this.microsec_slider ) {
1241 this.control.options(
1242 this,
1243 this.microsec_slider,
1244 'microsec',
1245 {
1246 min: this._defaults.microsecMin,
1247 max: microsecMax,
1248 step: this._defaults.stepMicrosec,
1249 }
1250 );
1251 this.control.value(
1252 this,
1253 this.microsec_slider,
1254 'microsec',
1255 this.microsec -
1256 ( this.microsec % this._defaults.stepMicrosec )
1257 );
1258 }
1259 }
1260 },
1261
1262 /*
1263 * when a slider moves, set the internal time...
1264 * on time change is also called when the time is updated in the text field
1265 */
1266 _onTimeChange: function () {
1267 if ( ! this._defaults.showTimepicker ) {
1268 return;
1269 }
1270 var hour = this.hour_slider
1271 ? this.control.value( this, this.hour_slider, 'hour' )
1272 : false,
1273 minute = this.minute_slider
1274 ? this.control.value( this, this.minute_slider, 'minute' )
1275 : false,
1276 second = this.second_slider
1277 ? this.control.value( this, this.second_slider, 'second' )
1278 : false,
1279 millisec = this.millisec_slider
1280 ? this.control.value(
1281 this,
1282 this.millisec_slider,
1283 'millisec'
1284 )
1285 : false,
1286 microsec = this.microsec_slider
1287 ? this.control.value(
1288 this,
1289 this.microsec_slider,
1290 'microsec'
1291 )
1292 : false,
1293 timezone = this.timezone_select
1294 ? this.timezone_select.val()
1295 : false,
1296 o = this._defaults,
1297 pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,
1298 pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;
1299
1300 if ( typeof hour === 'object' ) {
1301 hour = false;
1302 }
1303 if ( typeof minute === 'object' ) {
1304 minute = false;
1305 }
1306 if ( typeof second === 'object' ) {
1307 second = false;
1308 }
1309 if ( typeof millisec === 'object' ) {
1310 millisec = false;
1311 }
1312 if ( typeof microsec === 'object' ) {
1313 microsec = false;
1314 }
1315 if ( typeof timezone === 'object' ) {
1316 timezone = false;
1317 }
1318
1319 if ( hour !== false ) {
1320 hour = parseInt( hour, 10 );
1321 }
1322 if ( minute !== false ) {
1323 minute = parseInt( minute, 10 );
1324 }
1325 if ( second !== false ) {
1326 second = parseInt( second, 10 );
1327 }
1328 if ( millisec !== false ) {
1329 millisec = parseInt( millisec, 10 );
1330 }
1331 if ( microsec !== false ) {
1332 microsec = parseInt( microsec, 10 );
1333 }
1334 if ( timezone !== false ) {
1335 timezone = timezone.toString();
1336 }
1337
1338 var ampm = o[ hour < 12 ? 'amNames' : 'pmNames' ][ 0 ];
1339
1340 // If the update was done in the input field, the input field should not be updated.
1341 // If the update was done using the sliders, update the input field.
1342 var hasChanged =
1343 hour !== parseInt( this.hour, 10 ) || // sliders should all be numeric
1344 minute !== parseInt( this.minute, 10 ) ||
1345 second !== parseInt( this.second, 10 ) ||
1346 millisec !== parseInt( this.millisec, 10 ) ||
1347 microsec !== parseInt( this.microsec, 10 ) ||
1348 ( this.ampm.length > 0 &&
1349 hour < 12 !==
1350 ( $.inArray( this.ampm.toUpperCase(), this.amNames ) !==
1351 -1 ) ) ||
1352 ( this.timezone !== null &&
1353 timezone !== this.timezone.toString() ); // could be numeric or "EST" format, so use toString()
1354
1355 if ( hasChanged ) {
1356 if ( hour !== false ) {
1357 this.hour = hour;
1358 }
1359 if ( minute !== false ) {
1360 this.minute = minute;
1361 }
1362 if ( second !== false ) {
1363 this.second = second;
1364 }
1365 if ( millisec !== false ) {
1366 this.millisec = millisec;
1367 }
1368 if ( microsec !== false ) {
1369 this.microsec = microsec;
1370 }
1371 if ( timezone !== false ) {
1372 this.timezone = timezone;
1373 }
1374
1375 if ( ! this.inst ) {
1376 this.inst = $.datepicker._getInst( this.$input[ 0 ] );
1377 }
1378
1379 this._limitMinMaxDateTime( this.inst, true );
1380 }
1381 if ( this.support.ampm ) {
1382 this.ampm = ampm;
1383 }
1384
1385 // Updates the time within the timepicker
1386 this.formattedTime = $.datepicker.formatTime(
1387 o.timeFormat,
1388 this,
1389 o
1390 );
1391 if ( this.$timeObj ) {
1392 if ( pickerTimeFormat === o.timeFormat ) {
1393 this.$timeObj.val( this.formattedTime + pickerTimeSuffix );
1394 } else {
1395 this.$timeObj.val(
1396 $.datepicker.formatTime( pickerTimeFormat, this, o ) +
1397 pickerTimeSuffix
1398 );
1399 }
1400 /*
1401 // Input loses focus when typing with picker open
1402 // https://github.com/trentrichardson/jQuery-Timepicker-Addon/issues/848
1403 if (this.$timeObj[0].setSelectionRange) {
1404 var sPos = this.$timeObj[0].selectionStart;
1405 var ePos = this.$timeObj[0].selectionEnd;
1406 this.$timeObj[0].setSelectionRange(sPos, ePos);
1407 }
1408 */
1409 }
1410
1411 this.timeDefined = true;
1412 if ( hasChanged ) {
1413 this._updateDateTime();
1414 //this.$input.focus(); // may automatically open the picker on setDate
1415 }
1416 },
1417
1418 /*
1419 * call custom onSelect.
1420 * bind to sliders slidestop, and grid click.
1421 */
1422 _onSelectHandler: function () {
1423 var onSelect =
1424 this._defaults.onSelect || this.inst.settings.onSelect;
1425 var inputEl = this.$input ? this.$input[ 0 ] : null;
1426 if ( onSelect && inputEl ) {
1427 onSelect.apply( inputEl, [ this.formattedDateTime, this ] );
1428 }
1429 },
1430
1431 /*
1432 * update our input with the new date time..
1433 */
1434 _updateDateTime: function ( dp_inst ) {
1435 dp_inst = this.inst || dp_inst;
1436 var dtTmp =
1437 dp_inst.currentYear > 0
1438 ? new Date(
1439 dp_inst.currentYear,
1440 dp_inst.currentMonth,
1441 dp_inst.currentDay
1442 )
1443 : new Date(
1444 dp_inst.selectedYear,
1445 dp_inst.selectedMonth,
1446 dp_inst.selectedDay
1447 ),
1448 dt = $.datepicker._daylightSavingAdjust( dtTmp ),
1449 //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
1450 //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay)),
1451 dateFmt = $.datepicker._get( dp_inst, 'dateFormat' ),
1452 formatCfg = $.datepicker._getFormatConfig( dp_inst ),
1453 timeAvailable = dt !== null && this.timeDefined;
1454 this.formattedDate = $.datepicker.formatDate(
1455 dateFmt,
1456 dt === null ? new Date() : dt,
1457 formatCfg
1458 );
1459 var formattedDateTime = this.formattedDate;
1460
1461 // if a slider was changed but datepicker doesn't have a value yet, set it
1462 if ( dp_inst.lastVal === '' ) {
1463 dp_inst.currentYear = dp_inst.selectedYear;
1464 dp_inst.currentMonth = dp_inst.selectedMonth;
1465 dp_inst.currentDay = dp_inst.selectedDay;
1466 }
1467
1468 /*
1469 * remove following lines to force every changes in date picker to change the input value
1470 * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.
1471 * If the user manually empty the value in the input field, the date picker will never change selected value.
1472 */
1473 //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {
1474 // return;
1475 //}
1476
1477 if (
1478 this._defaults.timeOnly === true &&
1479 this._defaults.timeOnlyShowDate === false
1480 ) {
1481 formattedDateTime = this.formattedTime;
1482 } else if (
1483 ( this._defaults.timeOnly !== true &&
1484 ( this._defaults.alwaysSetTime || timeAvailable ) ) ||
1485 ( this._defaults.timeOnly === true &&
1486 this._defaults.timeOnlyShowDate === true )
1487 ) {
1488 formattedDateTime +=
1489 this._defaults.separator +
1490 this.formattedTime +
1491 this._defaults.timeSuffix;
1492 }
1493
1494 this.formattedDateTime = formattedDateTime;
1495
1496 if ( ! this._defaults.showTimepicker ) {
1497 this.$input.val( this.formattedDate );
1498 } else if (
1499 this.$altInput &&
1500 this._defaults.timeOnly === false &&
1501 this._defaults.altFieldTimeOnly === true
1502 ) {
1503 this.$altInput.val( this.formattedTime );
1504 this.$input.val( this.formattedDate );
1505 } else if ( this.$altInput ) {
1506 this.$input.val( formattedDateTime );
1507 var altFormattedDateTime = '',
1508 altSeparator =
1509 this._defaults.altSeparator !== null
1510 ? this._defaults.altSeparator
1511 : this._defaults.separator,
1512 altTimeSuffix =
1513 this._defaults.altTimeSuffix !== null
1514 ? this._defaults.altTimeSuffix
1515 : this._defaults.timeSuffix;
1516
1517 if ( ! this._defaults.timeOnly ) {
1518 if ( this._defaults.altFormat ) {
1519 altFormattedDateTime = $.datepicker.formatDate(
1520 this._defaults.altFormat,
1521 dt === null ? new Date() : dt,
1522 formatCfg
1523 );
1524 } else {
1525 altFormattedDateTime = this.formattedDate;
1526 }
1527
1528 if ( altFormattedDateTime ) {
1529 altFormattedDateTime += altSeparator;
1530 }
1531 }
1532
1533 if ( this._defaults.altTimeFormat !== null ) {
1534 altFormattedDateTime +=
1535 $.datepicker.formatTime(
1536 this._defaults.altTimeFormat,
1537 this,
1538 this._defaults
1539 ) + altTimeSuffix;
1540 } else {
1541 altFormattedDateTime += this.formattedTime + altTimeSuffix;
1542 }
1543 this.$altInput.val( altFormattedDateTime );
1544 } else {
1545 this.$input.val( formattedDateTime );
1546 }
1547
1548 this.$input.trigger( 'change' );
1549 },
1550
1551 _onFocus: function () {
1552 if ( ! this.$input.val() && this._defaults.defaultValue ) {
1553 this.$input.val( this._defaults.defaultValue );
1554 var inst = $.datepicker._getInst( this.$input.get( 0 ) ),
1555 tp_inst = $.datepicker._get( inst, 'timepicker' );
1556 if ( tp_inst ) {
1557 if (
1558 tp_inst._defaults.timeOnly &&
1559 inst.input.val() !== inst.lastVal
1560 ) {
1561 try {
1562 $.datepicker._updateDatepicker( inst );
1563 } catch ( err ) {
1564 $.timepicker.log( err );
1565 }
1566 }
1567 }
1568 }
1569 },
1570
1571 /*
1572 * Small abstraction to control types
1573 * We can add more, just be sure to follow the pattern: create, options, value
1574 */
1575 _controls: {
1576 // slider methods
1577 slider: {
1578 create: function ( tp_inst, obj, unit, val, min, max, step ) {
1579 var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60
1580 return obj.prop( 'slide', null ).slider( {
1581 orientation: 'horizontal',
1582 value: rtl ? val * -1 : val,
1583 min: rtl ? max * -1 : min,
1584 max: rtl ? min * -1 : max,
1585 step: step,
1586 slide: function ( event, ui ) {
1587 tp_inst.control.value(
1588 tp_inst,
1589 $( this ),
1590 unit,
1591 rtl ? ui.value * -1 : ui.value
1592 );
1593 tp_inst._onTimeChange();
1594 },
1595 stop: function ( event, ui ) {
1596 tp_inst._onSelectHandler();
1597 },
1598 } );
1599 },
1600 options: function ( tp_inst, obj, unit, opts, val ) {
1601 if ( tp_inst._defaults.isRTL ) {
1602 if ( typeof opts === 'string' ) {
1603 if ( opts === 'min' || opts === 'max' ) {
1604 if ( val !== undefined ) {
1605 return obj.slider( opts, val * -1 );
1606 }
1607 return Math.abs( obj.slider( opts ) );
1608 }
1609 return obj.slider( opts );
1610 }
1611 var min = opts.min,
1612 max = opts.max;
1613 opts.min = opts.max = null;
1614 if ( min !== undefined ) {
1615 opts.max = min * -1;
1616 }
1617 if ( max !== undefined ) {
1618 opts.min = max * -1;
1619 }
1620 return obj.slider( opts );
1621 }
1622 if ( typeof opts === 'string' && val !== undefined ) {
1623 return obj.slider( opts, val );
1624 }
1625 return obj.slider( opts );
1626 },
1627 value: function ( tp_inst, obj, unit, val ) {
1628 if ( tp_inst._defaults.isRTL ) {
1629 if ( val !== undefined ) {
1630 return obj.slider( 'value', val * -1 );
1631 }
1632 return Math.abs( obj.slider( 'value' ) );
1633 }
1634 if ( val !== undefined ) {
1635 return obj.slider( 'value', val );
1636 }
1637 return obj.slider( 'value' );
1638 },
1639 },
1640 // select methods
1641 select: {
1642 create: function ( tp_inst, obj, unit, val, min, max, step ) {
1643 var sel =
1644 '<select class="ui-timepicker-select ui-state-default ui-corner-all" data-unit="' +
1645 unit +
1646 '" data-min="' +
1647 min +
1648 '" data-max="' +
1649 max +
1650 '" data-step="' +
1651 step +
1652 '">',
1653 format =
1654 tp_inst._defaults.pickerTimeFormat ||
1655 tp_inst._defaults.timeFormat;
1656
1657 for ( var i = min; i <= max; i += step ) {
1658 sel +=
1659 '<option value="' +
1660 i +
1661 '"' +
1662 ( i === val ? ' selected' : '' ) +
1663 '>';
1664 if ( unit === 'hour' ) {
1665 sel += $.datepicker.formatTime(
1666 $.trim( format.replace( /[^ht ]/gi, '' ) ),
1667 { hour: i },
1668 tp_inst._defaults
1669 );
1670 } else if (
1671 unit === 'millisec' ||
1672 unit === 'microsec' ||
1673 i >= 10
1674 ) {
1675 sel += i;
1676 } else {
1677 sel += '0' + i.toString();
1678 }
1679 sel += '</option>';
1680 }
1681 sel += '</select>';
1682
1683 obj.children( 'select' ).remove();
1684
1685 $( sel )
1686 .appendTo( obj )
1687 .change( function ( e ) {
1688 tp_inst._onTimeChange();
1689 tp_inst._onSelectHandler();
1690 tp_inst._afterInject();
1691 } );
1692
1693 return obj;
1694 },
1695 options: function ( tp_inst, obj, unit, opts, val ) {
1696 var o = {},
1697 $t = obj.children( 'select' );
1698 if ( typeof opts === 'string' ) {
1699 if ( val === undefined ) {
1700 return $t.data( opts );
1701 }
1702 o[ opts ] = val;
1703 } else {
1704 o = opts;
1705 }
1706 return tp_inst.control.create(
1707 tp_inst,
1708 obj,
1709 $t.data( 'unit' ),
1710 $t.val(),
1711 o.min >= 0 ? o.min : $t.data( 'min' ),
1712 o.max || $t.data( 'max' ),
1713 o.step || $t.data( 'step' )
1714 );
1715 },
1716 value: function ( tp_inst, obj, unit, val ) {
1717 var $t = obj.children( 'select' );
1718 if ( val !== undefined ) {
1719 return $t.val( val );
1720 }
1721 return $t.val();
1722 },
1723 },
1724 }, // end _controls
1725 } );
1726
1727 $.fn.extend( {
1728 /*
1729 * shorthand just to use timepicker.
1730 */
1731 timepicker: function ( o ) {
1732 o = o || {};
1733 var tmp_args = Array.prototype.slice.call( arguments );
1734
1735 if ( typeof o === 'object' ) {
1736 tmp_args[ 0 ] = $.extend( o, {
1737 timeOnly: true,
1738 } );
1739 }
1740
1741 return $( this ).each( function () {
1742 $.fn.datetimepicker.apply( $( this ), tmp_args );
1743 } );
1744 },
1745
1746 /*
1747 * extend timepicker to datepicker
1748 */
1749 datetimepicker: function ( o ) {
1750 o = o || {};
1751 var tmp_args = arguments;
1752
1753 if ( typeof o === 'string' ) {
1754 if (
1755 o === 'getDate' ||
1756 ( o === 'option' &&
1757 tmp_args.length === 2 &&
1758 typeof tmp_args[ 1 ] === 'string' )
1759 ) {
1760 return $.fn.datepicker.apply( $( this[ 0 ] ), tmp_args );
1761 } else {
1762 return this.each( function () {
1763 var $t = $( this );
1764 $t.datepicker.apply( $t, tmp_args );
1765 } );
1766 }
1767 } else {
1768 return this.each( function () {
1769 var $t = $( this );
1770 $t.datepicker( $.timepicker._newInst( $t, o )._defaults );
1771 } );
1772 }
1773 },
1774 } );
1775
1776 /*
1777 * Public Utility to parse date and time
1778 */
1779 $.datepicker.parseDateTime = function (
1780 dateFormat,
1781 timeFormat,
1782 dateTimeString,
1783 dateSettings,
1784 timeSettings
1785 ) {
1786 var parseRes = parseDateTimeInternal(
1787 dateFormat,
1788 timeFormat,
1789 dateTimeString,
1790 dateSettings,
1791 timeSettings
1792 );
1793 if ( parseRes.timeObj ) {
1794 var t = parseRes.timeObj;
1795 parseRes.date.setHours( t.hour, t.minute, t.second, t.millisec );
1796 parseRes.date.setMicroseconds( t.microsec );
1797 }
1798
1799 return parseRes.date;
1800 };
1801
1802 /*
1803 * Public utility to parse time
1804 */
1805 $.datepicker.parseTime = function ( timeFormat, timeString, options ) {
1806 var o = extendRemove(
1807 extendRemove( {}, $.timepicker._defaults ),
1808 options || {}
1809 ),
1810 iso8601 =
1811 timeFormat.replace( /\'.*?\'/g, '' ).indexOf( 'Z' ) !== -1;
1812
1813 // Strict parse requires the timeString to match the timeFormat exactly
1814 var strictParse = function ( f, s, o ) {
1815 // pattern for standard and localized AM/PM markers
1816 var getPatternAmpm = function ( amNames, pmNames ) {
1817 var markers = [];
1818 if ( amNames ) {
1819 $.merge( markers, amNames );
1820 }
1821 if ( pmNames ) {
1822 $.merge( markers, pmNames );
1823 }
1824 markers = $.map( markers, function ( val ) {
1825 return val.replace( /[.*+?|()\[\]{}\\]/g, '\\$&' );
1826 } );
1827 return '(' + markers.join( '|' ) + ')?';
1828 };
1829
1830 // figure out position of time elements.. cause js cant do named captures
1831 var getFormatPositions = function ( timeFormat ) {
1832 var finds = timeFormat
1833 .toLowerCase()
1834 .match(
1835 /(h{1,2}|m{1,2}|s{1,2}|l{1}|c{1}|t{1,2}|z|'.*?')/g
1836 ),
1837 orders = {
1838 h: -1,
1839 m: -1,
1840 s: -1,
1841 l: -1,
1842 c: -1,
1843 t: -1,
1844 z: -1,
1845 };
1846
1847 if ( finds ) {
1848 for ( var i = 0; i < finds.length; i++ ) {
1849 if (
1850 orders[ finds[ i ].toString().charAt( 0 ) ] === -1
1851 ) {
1852 orders[ finds[ i ].toString().charAt( 0 ) ] = i + 1;
1853 }
1854 }
1855 }
1856 return orders;
1857 };
1858
1859 var regstr =
1860 '^' +
1861 f
1862 .toString()
1863 .replace(
1864 /([hH]{1,2}|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g,
1865 function ( match ) {
1866 var ml = match.length;
1867 switch ( match.charAt( 0 ).toLowerCase() ) {
1868 case 'h':
1869 return ml === 1
1870 ? '(\\d?\\d)'
1871 : '(\\d{' + ml + '})';
1872 case 'm':
1873 return ml === 1
1874 ? '(\\d?\\d)'
1875 : '(\\d{' + ml + '})';
1876 case 's':
1877 return ml === 1
1878 ? '(\\d?\\d)'
1879 : '(\\d{' + ml + '})';
1880 case 'l':
1881 return '(\\d?\\d?\\d)';
1882 case 'c':
1883 return '(\\d?\\d?\\d)';
1884 case 'z':
1885 return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?';
1886 case 't':
1887 return getPatternAmpm(
1888 o.amNames,
1889 o.pmNames
1890 );
1891 default:
1892 // literal escaped in quotes
1893 return (
1894 '(' +
1895 match
1896 .replace( /\'/g, '' )
1897 .replace(
1898 /(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g,
1899 function ( m ) {
1900 return '\\' + m;
1901 }
1902 ) +
1903 ')?'
1904 );
1905 }
1906 }
1907 )
1908 .replace( /\s/g, '\\s?' ) +
1909 o.timeSuffix +
1910 '$',
1911 order = getFormatPositions( f ),
1912 ampm = '',
1913 treg;
1914
1915 treg = s.match( new RegExp( regstr, 'i' ) );
1916
1917 var resTime = {
1918 hour: 0,
1919 minute: 0,
1920 second: 0,
1921 millisec: 0,
1922 microsec: 0,
1923 };
1924
1925 if ( treg ) {
1926 if ( order.t !== -1 ) {
1927 if (
1928 treg[ order.t ] === undefined ||
1929 treg[ order.t ].length === 0
1930 ) {
1931 ampm = '';
1932 resTime.ampm = '';
1933 } else {
1934 ampm =
1935 $.inArray(
1936 treg[ order.t ].toUpperCase(),
1937 $.map( o.amNames, function ( x, i ) {
1938 return x.toUpperCase();
1939 } )
1940 ) !== -1
1941 ? 'AM'
1942 : 'PM';
1943 resTime.ampm =
1944 o[ ampm === 'AM' ? 'amNames' : 'pmNames' ][ 0 ];
1945 }
1946 }
1947
1948 if ( order.h !== -1 ) {
1949 if ( ampm === 'AM' && treg[ order.h ] === '12' ) {
1950 resTime.hour = 0; // 12am = 0 hour
1951 } else {
1952 if ( ampm === 'PM' && treg[ order.h ] !== '12' ) {
1953 resTime.hour = parseInt( treg[ order.h ], 10 ) + 12; // 12pm = 12 hour, any other pm = hour + 12
1954 } else {
1955 resTime.hour = Number( treg[ order.h ] );
1956 }
1957 }
1958 }
1959
1960 if ( order.m !== -1 ) {
1961 resTime.minute = Number( treg[ order.m ] );
1962 }
1963 if ( order.s !== -1 ) {
1964 resTime.second = Number( treg[ order.s ] );
1965 }
1966 if ( order.l !== -1 ) {
1967 resTime.millisec = Number( treg[ order.l ] );
1968 }
1969 if ( order.c !== -1 ) {
1970 resTime.microsec = Number( treg[ order.c ] );
1971 }
1972 if ( order.z !== -1 && treg[ order.z ] !== undefined ) {
1973 resTime.timezone = $.timepicker.timezoneOffsetNumber(
1974 treg[ order.z ]
1975 );
1976 }
1977
1978 return resTime;
1979 }
1980 return false;
1981 }; // end strictParse
1982
1983 // First try JS Date, if that fails, use strictParse
1984 var looseParse = function ( f, s, o ) {
1985 try {
1986 var d = new Date( '2012-01-01 ' + s );
1987 if ( isNaN( d.getTime() ) ) {
1988 d = new Date( '2012-01-01T' + s );
1989 if ( isNaN( d.getTime() ) ) {
1990 d = new Date( '01/01/2012 ' + s );
1991 if ( isNaN( d.getTime() ) ) {
1992 throw 'Unable to parse time with native Date: ' + s;
1993 }
1994 }
1995 }
1996
1997 return {
1998 hour: d.getHours(),
1999 minute: d.getMinutes(),
2000 second: d.getSeconds(),
2001 millisec: d.getMilliseconds(),
2002 microsec: d.getMicroseconds(),
2003 timezone: d.getTimezoneOffset() * -1,
2004 };
2005 } catch ( err ) {
2006 try {
2007 return strictParse( f, s, o );
2008 } catch ( err2 ) {
2009 $.timepicker.log(
2010 'Unable to parse \ntimeString: ' +
2011 s +
2012 '\ntimeFormat: ' +
2013 f
2014 );
2015 }
2016 }
2017 return false;
2018 }; // end looseParse
2019
2020 if ( typeof o.parse === 'function' ) {
2021 return o.parse( timeFormat, timeString, o );
2022 }
2023 if ( o.parse === 'loose' ) {
2024 return looseParse( timeFormat, timeString, o );
2025 }
2026 return strictParse( timeFormat, timeString, o );
2027 };
2028
2029 /**
2030 * Public utility to format the time
2031 * @param {string} format format of the time
2032 * @param {Object} time Object not a Date for timezones
2033 * @param {Object} [options] essentially the regional[].. amNames, pmNames, ampm
2034 * @returns {string} the formatted time
2035 */
2036 $.datepicker.formatTime = function ( format, time, options ) {
2037 options = options || {};
2038 options = $.extend( {}, $.timepicker._defaults, options );
2039 time = $.extend(
2040 {
2041 hour: 0,
2042 minute: 0,
2043 second: 0,
2044 millisec: 0,
2045 microsec: 0,
2046 timezone: null,
2047 },
2048 time
2049 );
2050
2051 var tmptime = format,
2052 ampmName = options.amNames[ 0 ],
2053 hour = parseInt( time.hour, 10 );
2054
2055 if ( hour > 11 ) {
2056 ampmName = options.pmNames[ 0 ];
2057 }
2058
2059 tmptime = tmptime.replace(
2060 /(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g,
2061 function ( match ) {
2062 switch ( match ) {
2063 case 'HH':
2064 return ( '0' + hour ).slice( -2 );
2065 case 'H':
2066 return hour;
2067 case 'hh':
2068 return ( '0' + convert24to12( hour ) ).slice( -2 );
2069 case 'h':
2070 return convert24to12( hour );
2071 case 'mm':
2072 return ( '0' + time.minute ).slice( -2 );
2073 case 'm':
2074 return time.minute;
2075 case 'ss':
2076 return ( '0' + time.second ).slice( -2 );
2077 case 's':
2078 return time.second;
2079 case 'l':
2080 return ( '00' + time.millisec ).slice( -3 );
2081 case 'c':
2082 return ( '00' + time.microsec ).slice( -3 );
2083 case 'z':
2084 return $.timepicker.timezoneOffsetString(
2085 time.timezone === null
2086 ? options.timezone
2087 : time.timezone,
2088 false
2089 );
2090 case 'Z':
2091 return $.timepicker.timezoneOffsetString(
2092 time.timezone === null
2093 ? options.timezone
2094 : time.timezone,
2095 true
2096 );
2097 case 'T':
2098 return ampmName.charAt( 0 ).toUpperCase();
2099 case 'TT':
2100 return ampmName.toUpperCase();
2101 case 't':
2102 return ampmName.charAt( 0 ).toLowerCase();
2103 case 'tt':
2104 return ampmName.toLowerCase();
2105 default:
2106 return match.replace( /'/g, '' );
2107 }
2108 }
2109 );
2110
2111 return tmptime;
2112 };
2113
2114 /*
2115 * the bad hack :/ override datepicker so it doesn't close on select
2116 // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
2117 */
2118 $.datepicker._base_selectDate = $.datepicker._selectDate;
2119 $.datepicker._selectDate = function ( id, dateStr ) {
2120 var inst = this._getInst( $( id )[ 0 ] ),
2121 tp_inst = this._get( inst, 'timepicker' ),
2122 was_inline;
2123
2124 if ( tp_inst && inst.settings.showTimepicker ) {
2125 tp_inst._limitMinMaxDateTime( inst, true );
2126 was_inline = inst.inline;
2127 inst.inline = inst.stay_open = true;
2128 //This way the onSelect handler called from calendarpicker get the full dateTime
2129 this._base_selectDate( id, dateStr );
2130 inst.inline = was_inline;
2131 inst.stay_open = false;
2132 this._notifyChange( inst );
2133 this._updateDatepicker( inst );
2134 } else {
2135 this._base_selectDate( id, dateStr );
2136 }
2137 };
2138
2139 /*
2140 * second bad hack :/ override datepicker so it triggers an event when changing the input field
2141 * and does not redraw the datepicker on every selectDate event
2142 */
2143 $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
2144 $.datepicker._updateDatepicker = function ( inst ) {
2145 // don't popup the datepicker if there is another instance already opened
2146 var input = inst.input[ 0 ];
2147 if (
2148 $.datepicker._curInst &&
2149 $.datepicker._curInst !== inst &&
2150 $.datepicker._datepickerShowing &&
2151 $.datepicker._lastInput !== input
2152 ) {
2153 return;
2154 }
2155
2156 if ( typeof inst.stay_open !== 'boolean' || inst.stay_open === false ) {
2157 this._base_updateDatepicker( inst );
2158
2159 // Reload the time control when changing something in the input text field.
2160 var tp_inst = this._get( inst, 'timepicker' );
2161 if ( tp_inst ) {
2162 tp_inst._addTimePicker( inst );
2163 }
2164 }
2165 };
2166
2167 /*
2168 * third bad hack :/ override datepicker so it allows spaces and colon in the input field
2169 */
2170 $.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
2171 $.datepicker._doKeyPress = function ( event ) {
2172 var inst = $.datepicker._getInst( event.target ),
2173 tp_inst = $.datepicker._get( inst, 'timepicker' );
2174
2175 if ( tp_inst ) {
2176 if ( $.datepicker._get( inst, 'constrainInput' ) ) {
2177 var ampm = tp_inst.support.ampm,
2178 tz =
2179 tp_inst._defaults.showTimezone !== null
2180 ? tp_inst._defaults.showTimezone
2181 : tp_inst.support.timezone,
2182 dateChars = $.datepicker._possibleChars(
2183 $.datepicker._get( inst, 'dateFormat' )
2184 ),
2185 datetimeChars =
2186 tp_inst._defaults.timeFormat
2187 .toString()
2188 .replace( /[hms]/g, '' )
2189 .replace( /TT/g, ampm ? 'APM' : '' )
2190 .replace( /Tt/g, ampm ? 'AaPpMm' : '' )
2191 .replace( /tT/g, ampm ? 'AaPpMm' : '' )
2192 .replace( /T/g, ampm ? 'AP' : '' )
2193 .replace( /tt/g, ampm ? 'apm' : '' )
2194 .replace( /t/g, ampm ? 'ap' : '' ) +
2195 ' ' +
2196 tp_inst._defaults.separator +
2197 tp_inst._defaults.timeSuffix +
2198 ( tz
2199 ? tp_inst._defaults.timezoneList.join( '' )
2200 : '' ) +
2201 tp_inst._defaults.amNames.join( '' ) +
2202 tp_inst._defaults.pmNames.join( '' ) +
2203 dateChars,
2204 chr = String.fromCharCode(
2205 event.charCode === undefined
2206 ? event.keyCode
2207 : event.charCode
2208 );
2209 return (
2210 event.ctrlKey ||
2211 chr < ' ' ||
2212 ! dateChars ||
2213 datetimeChars.indexOf( chr ) > -1
2214 );
2215 }
2216 }
2217
2218 return $.datepicker._base_doKeyPress( event );
2219 };
2220
2221 /*
2222 * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField
2223 * Update any alternate field to synchronise with the main field.
2224 */
2225 $.datepicker._base_updateAlternate = $.datepicker._updateAlternate;
2226 $.datepicker._updateAlternate = function ( inst ) {
2227 var tp_inst = this._get( inst, 'timepicker' );
2228 if ( tp_inst ) {
2229 var altField = tp_inst._defaults.altField;
2230 if ( altField ) {
2231 // update alternate field too
2232 var altFormat =
2233 tp_inst._defaults.altFormat ||
2234 tp_inst._defaults.dateFormat,
2235 date = this._getDate( inst ),
2236 formatCfg = $.datepicker._getFormatConfig( inst ),
2237 altFormattedDateTime = '',
2238 altSeparator = tp_inst._defaults.altSeparator
2239 ? tp_inst._defaults.altSeparator
2240 : tp_inst._defaults.separator,
2241 altTimeSuffix = tp_inst._defaults.altTimeSuffix
2242 ? tp_inst._defaults.altTimeSuffix
2243 : tp_inst._defaults.timeSuffix,
2244 altTimeFormat =
2245 tp_inst._defaults.altTimeFormat !== null
2246 ? tp_inst._defaults.altTimeFormat
2247 : tp_inst._defaults.timeFormat;
2248
2249 altFormattedDateTime +=
2250 $.datepicker.formatTime(
2251 altTimeFormat,
2252 tp_inst,
2253 tp_inst._defaults
2254 ) + altTimeSuffix;
2255 if (
2256 ! tp_inst._defaults.timeOnly &&
2257 ! tp_inst._defaults.altFieldTimeOnly &&
2258 date !== null
2259 ) {
2260 if ( tp_inst._defaults.altFormat ) {
2261 altFormattedDateTime =
2262 $.datepicker.formatDate(
2263 tp_inst._defaults.altFormat,
2264 date,
2265 formatCfg
2266 ) +
2267 altSeparator +
2268 altFormattedDateTime;
2269 } else {
2270 altFormattedDateTime =
2271 tp_inst.formattedDate +
2272 altSeparator +
2273 altFormattedDateTime;
2274 }
2275 }
2276 $( altField ).val(
2277 inst.input.val() ? altFormattedDateTime : ''
2278 );
2279 }
2280 } else {
2281 $.datepicker._base_updateAlternate( inst );
2282 }
2283 };
2284
2285 /*
2286 * Override key up event to sync manual input changes.
2287 */
2288 $.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
2289 $.datepicker._doKeyUp = function ( event ) {
2290 var inst = $.datepicker._getInst( event.target ),
2291 tp_inst = $.datepicker._get( inst, 'timepicker' );
2292
2293 if ( tp_inst ) {
2294 if (
2295 tp_inst._defaults.timeOnly &&
2296 inst.input.val() !== inst.lastVal
2297 ) {
2298 try {
2299 $.datepicker._updateDatepicker( inst );
2300 } catch ( err ) {
2301 $.timepicker.log( err );
2302 }
2303 }
2304 }
2305
2306 return $.datepicker._base_doKeyUp( event );
2307 };
2308
2309 /*
2310 * override "Today" button to also grab the time and set it to input field.
2311 */
2312 $.datepicker._base_gotoToday = $.datepicker._gotoToday;
2313 $.datepicker._gotoToday = function ( id ) {
2314 var inst = this._getInst( $( id )[ 0 ] );
2315 this._base_gotoToday( id );
2316 var tp_inst = this._get( inst, 'timepicker' );
2317 if ( ! tp_inst ) {
2318 return;
2319 }
2320
2321 var tzoffset = $.timepicker.timezoneOffsetNumber( tp_inst.timezone );
2322 var now = new Date();
2323 now.setMinutes(
2324 now.getMinutes() +
2325 now.getTimezoneOffset() +
2326 parseInt( tzoffset, 10 )
2327 );
2328 this._setTime( inst, now );
2329 this._setDate( inst, now );
2330 tp_inst._onSelectHandler();
2331 };
2332
2333 /*
2334 * Disable & enable the Time in the datetimepicker
2335 */
2336 $.datepicker._disableTimepickerDatepicker = function ( target ) {
2337 var inst = this._getInst( target );
2338 if ( ! inst ) {
2339 return;
2340 }
2341
2342 var tp_inst = this._get( inst, 'timepicker' );
2343 $( target ).datepicker( 'getDate' ); // Init selected[Year|Month|Day]
2344 if ( tp_inst ) {
2345 inst.settings.showTimepicker = false;
2346 tp_inst._defaults.showTimepicker = false;
2347 tp_inst._updateDateTime( inst );
2348 }
2349 };
2350
2351 $.datepicker._enableTimepickerDatepicker = function ( target ) {
2352 var inst = this._getInst( target );
2353 if ( ! inst ) {
2354 return;
2355 }
2356
2357 var tp_inst = this._get( inst, 'timepicker' );
2358 $( target ).datepicker( 'getDate' ); // Init selected[Year|Month|Day]
2359 if ( tp_inst ) {
2360 inst.settings.showTimepicker = true;
2361 tp_inst._defaults.showTimepicker = true;
2362 tp_inst._addTimePicker( inst ); // Could be disabled on page load
2363 tp_inst._updateDateTime( inst );
2364 }
2365 };
2366
2367 /*
2368 * Create our own set time function
2369 */
2370 $.datepicker._setTime = function ( inst, date ) {
2371 var tp_inst = this._get( inst, 'timepicker' );
2372 if ( tp_inst ) {
2373 var defaults = tp_inst._defaults;
2374
2375 // calling _setTime with no date sets time to defaults
2376 tp_inst.hour = date ? date.getHours() : defaults.hour;
2377 tp_inst.minute = date ? date.getMinutes() : defaults.minute;
2378 tp_inst.second = date ? date.getSeconds() : defaults.second;
2379 tp_inst.millisec = date
2380 ? date.getMilliseconds()
2381 : defaults.millisec;
2382 tp_inst.microsec = date
2383 ? date.getMicroseconds()
2384 : defaults.microsec;
2385
2386 //check if within min/max times..
2387 tp_inst._limitMinMaxDateTime( inst, true );
2388
2389 tp_inst._onTimeChange();
2390 tp_inst._updateDateTime( inst );
2391 }
2392 };
2393
2394 /*
2395 * Create new public method to set only time, callable as $().datepicker('setTime', date)
2396 */
2397 $.datepicker._setTimeDatepicker = function ( target, date, withDate ) {
2398 var inst = this._getInst( target );
2399 if ( ! inst ) {
2400 return;
2401 }
2402
2403 var tp_inst = this._get( inst, 'timepicker' );
2404
2405 if ( tp_inst ) {
2406 this._setDateFromField( inst );
2407 var tp_date;
2408 if ( date ) {
2409 if ( typeof date === 'string' ) {
2410 tp_inst._parseTime( date, withDate );
2411 tp_date = new Date();
2412 tp_date.setHours(
2413 tp_inst.hour,
2414 tp_inst.minute,
2415 tp_inst.second,
2416 tp_inst.millisec
2417 );
2418 tp_date.setMicroseconds( tp_inst.microsec );
2419 } else {
2420 tp_date = new Date( date.getTime() );
2421 tp_date.setMicroseconds( date.getMicroseconds() );
2422 }
2423 if ( tp_date.toString() === 'Invalid Date' ) {
2424 tp_date = undefined;
2425 }
2426 this._setTime( inst, tp_date );
2427 }
2428 }
2429 };
2430
2431 /*
2432 * override setDate() to allow setting time too within Date object
2433 */
2434 $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
2435 $.datepicker._setDateDatepicker = function ( target, _date ) {
2436 var inst = this._getInst( target );
2437 var date = _date;
2438 if ( ! inst ) {
2439 return;
2440 }
2441
2442 if ( typeof _date === 'string' ) {
2443 date = new Date( _date );
2444 if ( ! date.getTime() ) {
2445 this._base_setDateDatepicker.apply( this, arguments );
2446 date = $( target ).datepicker( 'getDate' );
2447 }
2448 }
2449
2450 var tp_inst = this._get( inst, 'timepicker' );
2451 var tp_date;
2452 if ( date instanceof Date ) {
2453 tp_date = new Date( date.getTime() );
2454 tp_date.setMicroseconds( date.getMicroseconds() );
2455 } else {
2456 tp_date = date;
2457 }
2458
2459 // This is important if you are using the timezone option, javascript's Date
2460 // object will only return the timezone offset for the current locale, so we
2461 // adjust it accordingly. If not using timezone option this won't matter..
2462 // If a timezone is different in tp, keep the timezone as is
2463 if ( tp_inst && tp_date ) {
2464 // look out for DST if tz wasn't specified
2465 if (
2466 ! tp_inst.support.timezone &&
2467 tp_inst._defaults.timezone === null
2468 ) {
2469 tp_inst.timezone = tp_date.getTimezoneOffset() * -1;
2470 }
2471 date = $.timepicker.timezoneAdjust(
2472 date,
2473 $.timepicker.timezoneOffsetString( -date.getTimezoneOffset() ),
2474 tp_inst.timezone
2475 );
2476 tp_date = $.timepicker.timezoneAdjust(
2477 tp_date,
2478 $.timepicker.timezoneOffsetString(
2479 -tp_date.getTimezoneOffset()
2480 ),
2481 tp_inst.timezone
2482 );
2483 }
2484
2485 this._updateDatepicker( inst );
2486 this._base_setDateDatepicker.apply( this, arguments );
2487 this._setTimeDatepicker( target, tp_date, true );
2488 };
2489
2490 /*
2491 * override getDate() to allow getting time too within Date object
2492 */
2493 $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
2494 $.datepicker._getDateDatepicker = function ( target, noDefault ) {
2495 var inst = this._getInst( target );
2496 if ( ! inst ) {
2497 return;
2498 }
2499
2500 var tp_inst = this._get( inst, 'timepicker' );
2501
2502 if ( tp_inst ) {
2503 // if it hasn't yet been defined, grab from field
2504 if ( inst.lastVal === undefined ) {
2505 this._setDateFromField( inst, noDefault );
2506 }
2507
2508 var date = this._getDate( inst );
2509
2510 var currDT = null;
2511
2512 if ( tp_inst.$altInput && tp_inst._defaults.altFieldTimeOnly ) {
2513 currDT = tp_inst.$input.val() + ' ' + tp_inst.$altInput.val();
2514 } else if (
2515 tp_inst.$input.get( 0 ).tagName !== 'INPUT' &&
2516 tp_inst.$altInput
2517 ) {
2518 /**
2519 * in case the datetimepicker has been applied to a non-input tag for inline UI,
2520 * and the user has not configured the plugin to display only time in altInput,
2521 * pick current date time from the altInput (and hope for the best, for now, until "ER1" is applied)
2522 *
2523 * @todo ER1. Since altInput can have a totally difference format, convert it to standard format by reading input format from "altFormat" and "altTimeFormat" option values
2524 */
2525 currDT = tp_inst.$altInput.val();
2526 } else {
2527 currDT = tp_inst.$input.val();
2528 }
2529
2530 if (
2531 date &&
2532 tp_inst._parseTime( currDT, ! inst.settings.timeOnly )
2533 ) {
2534 date.setHours(
2535 tp_inst.hour,
2536 tp_inst.minute,
2537 tp_inst.second,
2538 tp_inst.millisec
2539 );
2540 date.setMicroseconds( tp_inst.microsec );
2541
2542 // This is important if you are using the timezone option, javascript's Date
2543 // object will only return the timezone offset for the current locale, so we
2544 // adjust it accordingly. If not using timezone option this won't matter..
2545 if ( tp_inst.timezone != null ) {
2546 // look out for DST if tz wasn't specified
2547 if (
2548 ! tp_inst.support.timezone &&
2549 tp_inst._defaults.timezone === null
2550 ) {
2551 tp_inst.timezone = date.getTimezoneOffset() * -1;
2552 }
2553 date = $.timepicker.timezoneAdjust(
2554 date,
2555 tp_inst.timezone,
2556 $.timepicker.timezoneOffsetString(
2557 -date.getTimezoneOffset()
2558 )
2559 );
2560 }
2561 }
2562 return date;
2563 }
2564 return this._base_getDateDatepicker( target, noDefault );
2565 };
2566
2567 /*
2568 * override parseDate() because UI 1.8.14 throws an error about "Extra characters"
2569 * An option in datepicker to ignore extra format characters would be nicer.
2570 */
2571 $.datepicker._base_parseDate = $.datepicker.parseDate;
2572 $.datepicker.parseDate = function ( format, value, settings ) {
2573 var date;
2574 try {
2575 date = this._base_parseDate( format, value, settings );
2576 } catch ( err ) {
2577 // Hack! The error message ends with a colon, a space, and
2578 // the "extra" characters. We rely on that instead of
2579 // attempting to perfectly reproduce the parsing algorithm.
2580 if ( err.indexOf( ':' ) >= 0 ) {
2581 date = this._base_parseDate(
2582 format,
2583 value.substring(
2584 0,
2585 value.length - ( err.length - err.indexOf( ':' ) - 2 )
2586 ),
2587 settings
2588 );
2589 $.timepicker.log(
2590 'Error parsing the date string: ' +
2591 err +
2592 '\ndate string = ' +
2593 value +
2594 '\ndate format = ' +
2595 format
2596 );
2597 } else {
2598 throw err;
2599 }
2600 }
2601 return date;
2602 };
2603
2604 /*
2605 * override formatDate to set date with time to the input
2606 */
2607 $.datepicker._base_formatDate = $.datepicker._formatDate;
2608 $.datepicker._formatDate = function ( inst, day, month, year ) {
2609 var tp_inst = this._get( inst, 'timepicker' );
2610 if ( tp_inst ) {
2611 tp_inst._updateDateTime( inst );
2612 return tp_inst.$input.val();
2613 }
2614 return this._base_formatDate( inst );
2615 };
2616
2617 /*
2618 * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
2619 */
2620 $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
2621 $.datepicker._optionDatepicker = function ( target, name, value ) {
2622 var inst = this._getInst( target ),
2623 name_clone;
2624 if ( ! inst ) {
2625 return null;
2626 }
2627
2628 var tp_inst = this._get( inst, 'timepicker' );
2629 if ( tp_inst ) {
2630 var min = null,
2631 max = null,
2632 onselect = null,
2633 overrides = tp_inst._defaults.evnts,
2634 fns = {},
2635 prop,
2636 ret,
2637 oldVal,
2638 $target;
2639 if ( typeof name === 'string' ) {
2640 // if min/max was set with the string
2641 if ( name === 'minDate' || name === 'minDateTime' ) {
2642 min = value;
2643 } else if ( name === 'maxDate' || name === 'maxDateTime' ) {
2644 max = value;
2645 } else if ( name === 'onSelect' ) {
2646 onselect = value;
2647 } else if ( overrides.hasOwnProperty( name ) ) {
2648 if ( typeof value === 'undefined' ) {
2649 return overrides[ name ];
2650 }
2651 fns[ name ] = value;
2652 name_clone = {}; //empty results in exiting function after overrides updated
2653 }
2654 } else if ( typeof name === 'object' ) {
2655 //if min/max was set with the JSON
2656 if ( name.minDate ) {
2657 min = name.minDate;
2658 } else if ( name.minDateTime ) {
2659 min = name.minDateTime;
2660 } else if ( name.maxDate ) {
2661 max = name.maxDate;
2662 } else if ( name.maxDateTime ) {
2663 max = name.maxDateTime;
2664 }
2665 for ( prop in overrides ) {
2666 if ( overrides.hasOwnProperty( prop ) && name[ prop ] ) {
2667 fns[ prop ] = name[ prop ];
2668 }
2669 }
2670 }
2671 for ( prop in fns ) {
2672 if ( fns.hasOwnProperty( prop ) ) {
2673 overrides[ prop ] = fns[ prop ];
2674 if ( ! name_clone ) {
2675 name_clone = $.extend( {}, name );
2676 }
2677 delete name_clone[ prop ];
2678 }
2679 }
2680 if ( name_clone && isEmptyObject( name_clone ) ) {
2681 return;
2682 }
2683 if ( min ) {
2684 //if min was set
2685 if ( min === 0 ) {
2686 min = new Date();
2687 } else {
2688 min = new Date( min );
2689 }
2690 tp_inst._defaults.minDate = min;
2691 tp_inst._defaults.minDateTime = min;
2692 } else if ( max ) {
2693 //if max was set
2694 if ( max === 0 ) {
2695 max = new Date();
2696 } else {
2697 max = new Date( max );
2698 }
2699 tp_inst._defaults.maxDate = max;
2700 tp_inst._defaults.maxDateTime = max;
2701 } else if ( onselect ) {
2702 tp_inst._defaults.onSelect = onselect;
2703 }
2704
2705 // Datepicker will override our date when we call _base_optionDatepicker when
2706 // calling minDate/maxDate, so we will first grab the value, call
2707 // _base_optionDatepicker, then set our value back.
2708 if ( min || max ) {
2709 $target = $( target );
2710 oldVal = $target.datetimepicker( 'getDate' );
2711 ret = this._base_optionDatepicker.call(
2712 $.datepicker,
2713 target,
2714 name_clone || name,
2715 value
2716 );
2717 $target.datetimepicker( 'setDate', oldVal );
2718 return ret;
2719 }
2720 }
2721 if ( value === undefined ) {
2722 return this._base_optionDatepicker.call(
2723 $.datepicker,
2724 target,
2725 name
2726 );
2727 }
2728 return this._base_optionDatepicker.call(
2729 $.datepicker,
2730 target,
2731 name_clone || name,
2732 value
2733 );
2734 };
2735
2736 /*
2737 * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,
2738 * it will return false for all objects
2739 */
2740 var isEmptyObject = function ( obj ) {
2741 var prop;
2742 for ( prop in obj ) {
2743 if ( obj.hasOwnProperty( prop ) ) {
2744 return false;
2745 }
2746 }
2747 return true;
2748 };
2749
2750 /*
2751 * jQuery extend now ignores nulls!
2752 */
2753 var extendRemove = function ( target, props ) {
2754 $.extend( target, props );
2755 for ( var name in props ) {
2756 if ( props[ name ] === null || props[ name ] === undefined ) {
2757 target[ name ] = props[ name ];
2758 }
2759 }
2760 return target;
2761 };
2762
2763 /*
2764 * Determine by the time format which units are supported
2765 * Returns an object of booleans for each unit
2766 */
2767 var detectSupport = function ( timeFormat ) {
2768 var tf = timeFormat.replace( /'.*?'/g, '' ).toLowerCase(), // removes literals
2769 isIn = function ( f, t ) {
2770 // does the format contain the token?
2771 return f.indexOf( t ) !== -1 ? true : false;
2772 };
2773 return {
2774 hour: isIn( tf, 'h' ),
2775 minute: isIn( tf, 'm' ),
2776 second: isIn( tf, 's' ),
2777 millisec: isIn( tf, 'l' ),
2778 microsec: isIn( tf, 'c' ),
2779 timezone: isIn( tf, 'z' ),
2780 ampm: isIn( tf, 't' ) && isIn( timeFormat, 'h' ),
2781 iso8601: isIn( timeFormat, 'Z' ),
2782 };
2783 };
2784
2785 /*
2786 * Converts 24 hour format into 12 hour
2787 * Returns 12 hour without leading 0
2788 */
2789 var convert24to12 = function ( hour ) {
2790 hour %= 12;
2791
2792 if ( hour === 0 ) {
2793 hour = 12;
2794 }
2795
2796 return String( hour );
2797 };
2798
2799 var computeEffectiveSetting = function ( settings, property ) {
2800 return settings && settings[ property ]
2801 ? settings[ property ]
2802 : $.timepicker._defaults[ property ];
2803 };
2804
2805 /*
2806 * Splits datetime string into date and time substrings.
2807 * Throws exception when date can't be parsed
2808 * Returns {dateString: dateString, timeString: timeString}
2809 */
2810 var splitDateTime = function ( dateTimeString, timeSettings ) {
2811 // The idea is to get the number separator occurrences in datetime and the time format requested (since time has
2812 // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.
2813 var separator = computeEffectiveSetting( timeSettings, 'separator' ),
2814 format = computeEffectiveSetting( timeSettings, 'timeFormat' ),
2815 timeParts = format.split( separator ), // how many occurrences of separator may be in our format?
2816 timePartsLen = timeParts.length,
2817 allParts = dateTimeString.split( separator ),
2818 allPartsLen = allParts.length;
2819
2820 if ( allPartsLen > 1 ) {
2821 return {
2822 dateString: allParts
2823 .splice( 0, allPartsLen - timePartsLen )
2824 .join( separator ),
2825 timeString: allParts
2826 .splice( 0, timePartsLen )
2827 .join( separator ),
2828 };
2829 }
2830
2831 return {
2832 dateString: dateTimeString,
2833 timeString: '',
2834 };
2835 };
2836
2837 /*
2838 * Internal function to parse datetime interval
2839 * Returns: {date: Date, timeObj: Object}, where
2840 * date - parsed date without time (type Date)
2841 * timeObj = {hour: , minute: , second: , millisec: , microsec: } - parsed time. Optional
2842 */
2843 var parseDateTimeInternal = function (
2844 dateFormat,
2845 timeFormat,
2846 dateTimeString,
2847 dateSettings,
2848 timeSettings
2849 ) {
2850 var date, parts, parsedTime;
2851
2852 parts = splitDateTime( dateTimeString, timeSettings );
2853 date = $.datepicker._base_parseDate(
2854 dateFormat,
2855 parts.dateString,
2856 dateSettings
2857 );
2858
2859 if ( parts.timeString === '' ) {
2860 return {
2861 date: date,
2862 };
2863 }
2864
2865 parsedTime = $.datepicker.parseTime(
2866 timeFormat,
2867 parts.timeString,
2868 timeSettings
2869 );
2870
2871 if ( ! parsedTime ) {
2872 throw 'Wrong time format';
2873 }
2874
2875 return {
2876 date: date,
2877 timeObj: parsedTime,
2878 };
2879 };
2880
2881 /*
2882 * Internal function to set timezone_select to the local timezone
2883 */
2884 var selectLocalTimezone = function ( tp_inst, date ) {
2885 if ( tp_inst && tp_inst.timezone_select ) {
2886 var now = date || new Date();
2887 tp_inst.timezone_select.val( -now.getTimezoneOffset() );
2888 }
2889 };
2890
2891 /*
2892 * Create a Singleton Instance
2893 */
2894 $.timepicker = new Timepicker();
2895
2896 /**
2897 * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)
2898 * @param {number} tzMinutes if not a number, less than -720 (-1200), or greater than 840 (+1400) this value is returned
2899 * @param {boolean} iso8601 if true formats in accordance to iso8601 "+12:45"
2900 * @return {string}
2901 */
2902 $.timepicker.timezoneOffsetString = function ( tzMinutes, iso8601 ) {
2903 if ( isNaN( tzMinutes ) || tzMinutes > 840 || tzMinutes < -720 ) {
2904 return tzMinutes;
2905 }
2906
2907 var off = tzMinutes,
2908 minutes = off % 60,
2909 hours = ( off - minutes ) / 60,
2910 iso = iso8601 ? ':' : '',
2911 tz =
2912 ( off >= 0 ? '+' : '-' ) +
2913 ( '0' + Math.abs( hours ) ).slice( -2 ) +
2914 iso +
2915 ( '0' + Math.abs( minutes ) ).slice( -2 );
2916
2917 if ( tz === '+00:00' ) {
2918 return 'Z';
2919 }
2920 return tz;
2921 };
2922
2923 /**
2924 * Get the number in minutes that represents a timezone string
2925 * @param {string} tzString formatted like "+0500", "-1245", "Z"
2926 * @return {number} the offset minutes or the original string if it doesn't match expectations
2927 */
2928 $.timepicker.timezoneOffsetNumber = function ( tzString ) {
2929 var normalized = tzString.toString().replace( ':', '' ); // excuse any iso8601, end up with "+1245"
2930
2931 if ( normalized.toUpperCase() === 'Z' ) {
2932 // if iso8601 with Z, its 0 minute offset
2933 return 0;
2934 }
2935
2936 if ( ! /^(\-|\+)\d{4}$/.test( normalized ) ) {
2937 // possibly a user defined tz, so just give it back
2938 return parseInt( tzString, 10 );
2939 }
2940
2941 return (
2942 ( normalized.substr( 0, 1 ) === '-' ? -1 : 1 ) * // plus or minus
2943 ( parseInt( normalized.substr( 1, 2 ), 10 ) * 60 + // hours (converted to minutes)
2944 parseInt( normalized.substr( 3, 2 ), 10 ) )
2945 ); // minutes
2946 };
2947
2948 /**
2949 * No way to set timezone in js Date, so we must adjust the minutes to compensate. (think setDate, getDate)
2950 * @param {Date} date
2951 * @param {string} fromTimezone formatted like "+0500", "-1245"
2952 * @param {string} toTimezone formatted like "+0500", "-1245"
2953 * @return {Date}
2954 */
2955 $.timepicker.timezoneAdjust = function ( date, fromTimezone, toTimezone ) {
2956 var fromTz = $.timepicker.timezoneOffsetNumber( fromTimezone );
2957 var toTz = $.timepicker.timezoneOffsetNumber( toTimezone );
2958 if ( ! isNaN( toTz ) ) {
2959 date.setMinutes( date.getMinutes() + -fromTz - -toTz );
2960 }
2961 return date;
2962 };
2963
2964 /**
2965 * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to
2966 * enforce date range limits.
2967 * n.b. The input value must be correctly formatted (reformatting is not supported)
2968 * @param {Element} startTime
2969 * @param {Element} endTime
2970 * @param {Object} options Options for the timepicker() call
2971 * @return {jQuery}
2972 */
2973 $.timepicker.timeRange = function ( startTime, endTime, options ) {
2974 return $.timepicker.handleRange(
2975 'timepicker',
2976 startTime,
2977 endTime,
2978 options
2979 );
2980 };
2981
2982 /**
2983 * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to
2984 * enforce date range limits.
2985 * @param {Element} startTime
2986 * @param {Element} endTime
2987 * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
2988 * a boolean value that can be used to reformat the input values to the `dateFormat`.
2989 * @param {string} method Can be used to specify the type of picker to be added
2990 * @return {jQuery}
2991 */
2992 $.timepicker.datetimeRange = function ( startTime, endTime, options ) {
2993 $.timepicker.handleRange(
2994 'datetimepicker',
2995 startTime,
2996 endTime,
2997 options
2998 );
2999 };
3000
3001 /**
3002 * Calls `datepicker` on the `startTime` and `endTime` elements, and configures them to
3003 * enforce date range limits.
3004 * @param {Element} startTime
3005 * @param {Element} endTime
3006 * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
3007 * a boolean value that can be used to reformat the input values to the `dateFormat`.
3008 * @return {jQuery}
3009 */
3010 $.timepicker.dateRange = function ( startTime, endTime, options ) {
3011 $.timepicker.handleRange( 'datepicker', startTime, endTime, options );
3012 };
3013
3014 /**
3015 * Calls `method` on the `startTime` and `endTime` elements, and configures them to
3016 * enforce date range limits.
3017 * @param {string} method Can be used to specify the type of picker to be added
3018 * @param {Element} startTime
3019 * @param {Element} endTime
3020 * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
3021 * a boolean value that can be used to reformat the input values to the `dateFormat`.
3022 * @return {jQuery}
3023 */
3024 $.timepicker.handleRange = function (
3025 method,
3026 startTime,
3027 endTime,
3028 options
3029 ) {
3030 options = $.extend(
3031 {},
3032 {
3033 minInterval: 0, // min allowed interval in milliseconds
3034 maxInterval: 0, // max allowed interval in milliseconds
3035 start: {}, // options for start picker
3036 end: {}, // options for end picker
3037 },
3038 options
3039 );
3040
3041 // for the mean time this fixes an issue with calling getDate with timepicker()
3042 var timeOnly = false;
3043 if ( method === 'timepicker' ) {
3044 timeOnly = true;
3045 method = 'datetimepicker';
3046 }
3047
3048 function checkDates( changed, other ) {
3049 var startdt = startTime[ method ]( 'getDate' ),
3050 enddt = endTime[ method ]( 'getDate' ),
3051 changeddt = changed[ method ]( 'getDate' );
3052
3053 if ( startdt !== null ) {
3054 var minDate = new Date( startdt.getTime() ),
3055 maxDate = new Date( startdt.getTime() );
3056
3057 minDate.setMilliseconds(
3058 minDate.getMilliseconds() + options.minInterval
3059 );
3060 maxDate.setMilliseconds(
3061 maxDate.getMilliseconds() + options.maxInterval
3062 );
3063
3064 if ( options.minInterval > 0 && minDate > enddt ) {
3065 // minInterval check
3066 endTime[ method ]( 'setDate', minDate );
3067 } else if ( options.maxInterval > 0 && maxDate < enddt ) {
3068 // max interval check
3069 endTime[ method ]( 'setDate', maxDate );
3070 } else if ( startdt > enddt ) {
3071 other[ method ]( 'setDate', changeddt );
3072 }
3073 }
3074 }
3075
3076 function selected( changed, other, option ) {
3077 if ( ! changed.val() ) {
3078 return;
3079 }
3080 var date = changed[ method ].call( changed, 'getDate' );
3081 if ( date !== null && options.minInterval > 0 ) {
3082 if ( option === 'minDate' ) {
3083 date.setMilliseconds(
3084 date.getMilliseconds() + options.minInterval
3085 );
3086 }
3087 if ( option === 'maxDate' ) {
3088 date.setMilliseconds(
3089 date.getMilliseconds() - options.minInterval
3090 );
3091 }
3092 }
3093
3094 if ( date.getTime ) {
3095 other[ method ].call( other, 'option', option, date );
3096 }
3097 }
3098
3099 $.fn[ method ].call(
3100 startTime,
3101 $.extend(
3102 {
3103 timeOnly: timeOnly,
3104 onClose: function ( dateText, inst ) {
3105 checkDates( $( this ), endTime );
3106 },
3107 onSelect: function ( selectedDateTime ) {
3108 selected( $( this ), endTime, 'minDate' );
3109 },
3110 },
3111 options,
3112 options.start
3113 )
3114 );
3115 $.fn[ method ].call(
3116 endTime,
3117 $.extend(
3118 {
3119 timeOnly: timeOnly,
3120 onClose: function ( dateText, inst ) {
3121 checkDates( $( this ), startTime );
3122 },
3123 onSelect: function ( selectedDateTime ) {
3124 selected( $( this ), startTime, 'maxDate' );
3125 },
3126 },
3127 options,
3128 options.end
3129 )
3130 );
3131
3132 checkDates( startTime, endTime );
3133
3134 selected( startTime, endTime, 'minDate' );
3135 selected( endTime, startTime, 'maxDate' );
3136
3137 return $( [ startTime.get( 0 ), endTime.get( 0 ) ] );
3138 };
3139
3140 /**
3141 * Log error or data to the console during error or debugging
3142 * @param {Object} err pass any type object to log to the console during error or debugging
3143 * @return {void}
3144 */
3145 $.timepicker.log = function () {
3146 // Older IE (9, maybe 10) throw error on accessing `window.console.log.apply`, so check first.
3147 if (
3148 window.console &&
3149 window.console.log &&
3150 window.console.log.apply
3151 ) {
3152 window.console.log.apply(
3153 window.console,
3154 Array.prototype.slice.call( arguments )
3155 );
3156 }
3157 };
3158
3159 /*
3160 * Add util object to allow access to private methods for testability.
3161 */
3162 $.timepicker._util = {
3163 _extendRemove: extendRemove,
3164 _isEmptyObject: isEmptyObject,
3165 _convert24to12: convert24to12,
3166 _detectSupport: detectSupport,
3167 _selectLocalTimezone: selectLocalTimezone,
3168 _computeEffectiveSetting: computeEffectiveSetting,
3169 _splitDateTime: splitDateTime,
3170 _parseDateTimeInternal: parseDateTimeInternal,
3171 };
3172
3173 /*
3174 * Microsecond support
3175 */
3176 if ( ! Date.prototype.getMicroseconds ) {
3177 Date.prototype.microseconds = 0;
3178 Date.prototype.getMicroseconds = function () {
3179 return this.microseconds;
3180 };
3181 Date.prototype.setMicroseconds = function ( m ) {
3182 this.setMilliseconds(
3183 this.getMilliseconds() + Math.floor( m / 1000 )
3184 );
3185 this.microseconds = m % 1000;
3186 return this;
3187 };
3188 }
3189
3190 /*
3191 * Keep up with the version
3192 */
3193 $.timepicker.version = '1.6.3';
3194 } );
3195