PluginProbe
weForms – Easy Drag & Drop Contact Form Builder For WordPress / 1.5.4
weForms – Easy Drag & Drop Contact Form Builder For WordPress v1.5.4
1.6.7 1.6.8 1.6.9 1.6.12 1.6.13 1.6.14 1.6.15 1.6.16 1.6.17 1.6.18 1.6.19 1.6.2 1.6.20 1.6.21 1.6.22 1.6.23 1.6.24 1.6.25 1.6.26 1.6.27 1.6.28 1.6.3 1.6.4 1.6.5 1.6.6 All 74 releases
weforms / assets / wpuf / js / jquery-ui-timepicker-addon.js

jquery-ui-timepicker-addon.js in weForms – Easy Drag & Drop Contact Form Builder For WordPress 1.5.4, at assets/wpuf/js/jquery-ui-timepicker-addon.js

1,920 lines 65.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*
2 * jQuery timepicker addon
3 * By: Trent Richardson [http://trentrichardson.com]
4 * Version 1.2
5 * Last Modified: 02/02/2013
6 *
7 * Copyright 2013 Trent Richardson
8 * You may use this project under MIT or GPL licenses.
9 * http://trentrichardson.com/Impromptu/GPL-LICENSE.txt
10 * http://trentrichardson.com/Impromptu/MIT-LICENSE.txt
11 */
12
13 /*jslint evil: true, white: false, undef: false, nomen: false */
14
15 (function($) {
16
17 /*
18 * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
19 */
20 $.ui.timepicker = $.ui.timepicker || {};
21 if ($.ui.timepicker.version) {
22 return;
23 }
24
25 /*
26 * Extend jQueryUI, get it started with our version number
27 */
28 $.extend($.ui, {
29 timepicker: {
30 version: "1.2"
31 }
32 });
33
34 /*
35 * Timepicker manager.
36 * Use the singleton instance of this class, $.timepicker, to interact with the time picker.
37 * Settings for (groups of) time pickers are maintained in an instance object,
38 * allowing multiple different settings on the same page.
39 */
40 var Timepicker = function() {
41 this.regional = []; // Available regional settings, indexed by language code
42 this.regional[''] = { // Default regional settings
43 currentText: 'Now',
44 closeText: 'Done',
45 amNames: ['AM', 'A'],
46 pmNames: ['PM', 'P'],
47 timeFormat: 'HH:mm',
48 timeSuffix: '',
49 timeOnlyTitle: 'Choose Time',
50 timeText: 'Time',
51 hourText: 'Hour',
52 minuteText: 'Minute',
53 secondText: 'Second',
54 millisecText: 'Millisecond',
55 timezoneText: 'Time Zone',
56 isRTL: false
57 };
58 this._defaults = { // Global defaults for all the datetime picker instances
59 showButtonPanel: true,
60 timeOnly: false,
61 showHour: true,
62 showMinute: true,
63 showSecond: false,
64 showMillisec: false,
65 showTimezone: false,
66 showTime: true,
67 stepHour: 1,
68 stepMinute: 1,
69 stepSecond: 1,
70 stepMillisec: 1,
71 hour: 0,
72 minute: 0,
73 second: 0,
74 millisec: 0,
75 timezone: null,
76 useLocalTimezone: false,
77 defaultTimezone: "+0000",
78 hourMin: 0,
79 minuteMin: 0,
80 secondMin: 0,
81 millisecMin: 0,
82 hourMax: 23,
83 minuteMax: 59,
84 secondMax: 59,
85 millisecMax: 999,
86 minDateTime: null,
87 maxDateTime: null,
88 onSelect: null,
89 hourGrid: 0,
90 minuteGrid: 0,
91 secondGrid: 0,
92 millisecGrid: 0,
93 alwaysSetTime: true,
94 separator: ' ',
95 altFieldTimeOnly: true,
96 altTimeFormat: null,
97 altSeparator: null,
98 altTimeSuffix: null,
99 pickerTimeFormat: null,
100 pickerTimeSuffix: null,
101 showTimepicker: true,
102 timezoneIso8601: false,
103 timezoneList: null,
104 addSliderAccess: false,
105 sliderAccessArgs: null,
106 controlType: 'slider',
107 defaultValue: null,
108 parse: 'strict'
109 };
110 $.extend(this._defaults, this.regional['']);
111 };
112
113 $.extend(Timepicker.prototype, {
114 $input: null,
115 $altInput: null,
116 $timeObj: null,
117 inst: null,
118 hour_slider: null,
119 minute_slider: null,
120 second_slider: null,
121 millisec_slider: null,
122 timezone_select: null,
123 hour: 0,
124 minute: 0,
125 second: 0,
126 millisec: 0,
127 timezone: null,
128 defaultTimezone: "+0000",
129 hourMinOriginal: null,
130 minuteMinOriginal: null,
131 secondMinOriginal: null,
132 millisecMinOriginal: null,
133 hourMaxOriginal: null,
134 minuteMaxOriginal: null,
135 secondMaxOriginal: null,
136 millisecMaxOriginal: null,
137 ampm: '',
138 formattedDate: '',
139 formattedTime: '',
140 formattedDateTime: '',
141 timezoneList: null,
142 units: ['hour','minute','second','millisec'],
143 control: null,
144
145 /*
146 * Override the default settings for all instances of the time picker.
147 * @param settings object - the new settings to use as defaults (anonymous object)
148 * @return the manager object
149 */
150 setDefaults: function(settings) {
151 extendRemove(this._defaults, settings || {});
152 return this;
153 },
154
155 /*
156 * Create a new Timepicker instance
157 */
158 _newInst: function($input, o) {
159 var tp_inst = new Timepicker(),
160 inlineSettings = {},
161 fns = {},
162 overrides, i;
163
164 for (var attrName in this._defaults) {
165 if(this._defaults.hasOwnProperty(attrName)){
166 var attrValue = $input.attr('time:' + attrName);
167 if (attrValue) {
168 try {
169 inlineSettings[attrName] = eval(attrValue);
170 } catch (err) {
171 inlineSettings[attrName] = attrValue;
172 }
173 }
174 }
175 }
176 overrides = {
177 beforeShow: function (input, dp_inst) {
178 if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) {
179 return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);
180 }
181 },
182 onChangeMonthYear: function (year, month, dp_inst) {
183 // Update the time as well : this prevents the time from disappearing from the $input field.
184 tp_inst._updateDateTime(dp_inst);
185 if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) {
186 tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
187 }
188 },
189 onClose: function (dateText, dp_inst) {
190 if (tp_inst.timeDefined === true && $input.val() !== '') {
191 tp_inst._updateDateTime(dp_inst);
192 }
193 if ($.isFunction(tp_inst._defaults.evnts.onClose)) {
194 tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);
195 }
196 }
197 };
198 for (i in overrides) {
199 if (overrides.hasOwnProperty(i)) {
200 fns[i] = o[i] || null;
201 }
202 }
203 tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, overrides, {
204 evnts:fns,
205 timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
206 });
207 tp_inst.amNames = $.map(tp_inst._defaults.amNames, function(val) {
208 return val.toUpperCase();
209 });
210 tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function(val) {
211 return val.toUpperCase();
212 });
213
214 // controlType is string - key to our this._controls
215 if(typeof(tp_inst._defaults.controlType) === 'string'){
216 if($.fn[tp_inst._defaults.controlType] === undefined){
217 tp_inst._defaults.controlType = 'select';
218 }
219 tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];
220 }
221 // controlType is an object and must implement create, options, value methods
222 else{
223 tp_inst.control = tp_inst._defaults.controlType;
224 }
225
226 if (tp_inst._defaults.timezoneList === null) {
227 var timezoneList = ['-1200', '-1100', '-1000', '-0930', '-0900', '-0800', '-0700', '-0600', '-0500', '-0430', '-0400', '-0330', '-0300', '-0200', '-0100', '+0000',
228 '+0100', '+0200', '+0300', '+0330', '+0400', '+0430', '+0500', '+0530', '+0545', '+0600', '+0630', '+0700', '+0800', '+0845', '+0900', '+0930',
229 '+1000', '+1030', '+1100', '+1130', '+1200', '+1245', '+1300', '+1400'];
230
231 if (tp_inst._defaults.timezoneIso8601) {
232 timezoneList = $.map(timezoneList, function(val) {
233 return val == '+0000' ? 'Z' : (val.substring(0, 3) + ':' + val.substring(3));
234 });
235 }
236 tp_inst._defaults.timezoneList = timezoneList;
237 }
238
239 tp_inst.timezone = tp_inst._defaults.timezone;
240 tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin? tp_inst._defaults.hourMin :
241 tp_inst._defaults.hour > tp_inst._defaults.hourMax? tp_inst._defaults.hourMax : tp_inst._defaults.hour;
242 tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin? tp_inst._defaults.minuteMin :
243 tp_inst._defaults.minute > tp_inst._defaults.minuteMax? tp_inst._defaults.minuteMax : tp_inst._defaults.minute;
244 tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin? tp_inst._defaults.secondMin :
245 tp_inst._defaults.second > tp_inst._defaults.secondMax? tp_inst._defaults.secondMax : tp_inst._defaults.second;
246 tp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin? tp_inst._defaults.millisecMin :
247 tp_inst._defaults.millisec > tp_inst._defaults.millisecMax? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec;
248 tp_inst.ampm = '';
249 tp_inst.$input = $input;
250
251 if (o.altField) {
252 tp_inst.$altInput = $(o.altField).css({
253 cursor: 'pointer'
254 }).focus(function() {
255 $input.trigger("focus");
256 });
257 }
258
259 if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {
260 tp_inst._defaults.minDate = new Date();
261 }
262 if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {
263 tp_inst._defaults.maxDate = new Date();
264 }
265
266 // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
267 if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {
268 tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
269 }
270 if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {
271 tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
272 }
273 if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {
274 tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
275 }
276 if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {
277 tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
278 }
279 tp_inst.$input.bind('focus', function() {
280 tp_inst._onFocus();
281 });
282
283 return tp_inst;
284 },
285
286 /*
287 * add our sliders to the calendar
288 */
289 _addTimePicker: function(dp_inst) {
290 var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val();
291
292 this.timeDefined = this._parseTime(currDT);
293 this._limitMinMaxDateTime(dp_inst, false);
294 this._injectTimePicker();
295 },
296
297 /*
298 * parse the time string from input value or _setTime
299 */
300 _parseTime: function(timeString, withDate) {
301 if (!this.inst) {
302 this.inst = $.datepicker._getInst(this.$input[0]);
303 }
304
305 if (withDate || !this._defaults.timeOnly) {
306 var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
307 try {
308 var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);
309 if (!parseRes.timeObj) {
310 return false;
311 }
312 $.extend(this, parseRes.timeObj);
313 } catch (err) {
314 $.timepicker.log("Error parsing the date/time string: " + err +
315 "\ndate/time string = " + timeString +
316 "\ntimeFormat = " + this._defaults.timeFormat +
317 "\ndateFormat = " + dp_dateFormat);
318 return false;
319 }
320 return true;
321 } else {
322 var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);
323 if (!timeObj) {
324 return false;
325 }
326 $.extend(this, timeObj);
327 return true;
328 }
329 },
330
331 /*
332 * generate and inject html for timepicker into ui datepicker
333 */
334 _injectTimePicker: function() {
335 var $dp = this.inst.dpDiv,
336 o = this.inst.settings,
337 tp_inst = this,
338 litem = '',
339 uitem = '',
340 max = {},
341 gridSize = {},
342 size = null;
343
344 // Prevent displaying twice
345 if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) {
346 var noDisplay = ' style="display:none;"',
347 html = '<div class="ui-timepicker-div'+ (o.isRTL? ' ui-timepicker-rtl' : '') +'"><dl>' + '<dt class="ui_tpicker_time_label"' + ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' +
348 '<dd class="ui_tpicker_time"' + ((o.showTime) ? '' : noDisplay) + '></dd>';
349
350 // Create the markup
351 for(var i=0,l=this.units.length; i<l; i++){
352 litem = this.units[i];
353 uitem = litem.substr(0,1).toUpperCase() + litem.substr(1);
354 // Added by Peter Medeiros:
355 // - Figure out what the hour/minute/second max should be based on the step values.
356 // - Example: if stepMinute is 15, then minMax is 45.
357 max[litem] = parseInt((o[litem+'Max'] - ((o[litem+'Max'] - o[litem+'Min']) % o['step'+uitem])), 10);
358 gridSize[litem] = 0;
359
360 html += '<dt class="ui_tpicker_'+ litem +'_label"' + ((o['show'+uitem]) ? '' : noDisplay) + '>' + o[litem +'Text'] + '</dt>' +
361 '<dd class="ui_tpicker_'+ litem +'"><div class="ui_tpicker_'+ litem +'_slider"' + ((o['show'+uitem]) ? '' : noDisplay) + '></div>';
362
363 if (o['show'+uitem] && o[litem+'Grid'] > 0) {
364 html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
365
366 if(litem == 'hour'){
367 for (var h = o[litem+'Min']; h <= max[litem]; h += parseInt(o[litem+'Grid'], 10)) {
368 gridSize[litem]++;
369 var tmph = $.datepicker.formatTime(useAmpm(o.pickerTimeFormat || o.timeFormat)? 'hht':'HH', {hour:h}, o);
370 html += '<td data-for="'+litem+'">' + tmph + '</td>';
371 }
372 }
373 else{
374 for (var m = o[litem+'Min']; m <= max[litem]; m += parseInt(o[litem+'Grid'], 10)) {
375 gridSize[litem]++;
376 html += '<td data-for="'+litem+'">' + ((m < 10) ? '0' : '') + m + '</td>';
377 }
378 }
379
380 html += '</tr></table></div>';
381 }
382 html += '</dd>';
383 }
384
385 // Timezone
386 html += '<dt class="ui_tpicker_timezone_label"' + ((o.showTimezone) ? '' : noDisplay) + '>' + o.timezoneText + '</dt>';
387 html += '<dd class="ui_tpicker_timezone" ' + ((o.showTimezone) ? '' : noDisplay) + '></dd>';
388
389 // Create the elements from string
390 html += '</dl></div>';
391 var $tp = $(html);
392
393 // if we only want time picker...
394 if (o.timeOnly === true) {
395 $tp.prepend('<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + '</div>');
396 $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
397 }
398
399 // add sliders, adjust grids, add events
400 for(var i=0,l=tp_inst.units.length; i<l; i++){
401 litem = tp_inst.units[i];
402 uitem = litem.substr(0,1).toUpperCase() + litem.substr(1);
403
404 // add the slider
405 tp_inst[litem+'_slider'] = tp_inst.control.create(tp_inst, $tp.find('.ui_tpicker_'+litem+'_slider'), litem, tp_inst[litem], o[litem+'Min'], max[litem], o['step'+uitem]);
406
407 // adjust the grid and add click event
408 if (o['show'+uitem] && o[litem+'Grid'] > 0) {
409 size = 100 * gridSize[litem] * o[litem+'Grid'] / (max[litem] - o[litem+'Min']);
410 $tp.find('.ui_tpicker_'+litem+' table').css({
411 width: size + "%",
412 marginLeft: o.isRTL? '0' : ((size / (-2 * gridSize[litem])) + "%"),
413 marginRight: o.isRTL? ((size / (-2 * gridSize[litem])) + "%") : '0',
414 borderCollapse: 'collapse'
415 }).find("td").click(function(e){
416 var $t = $(this),
417 h = $t.html(),
418 n = parseInt(h.replace(/[^0-9]/g),10),
419 ap = h.replace(/[^apm]/ig),
420 f = $t.data('for'); // loses scope, so we use data-for
421
422 if(f == 'hour'){
423 if(ap.indexOf('p') !== -1 && n < 12){
424 n += 12;
425 }
426 else{
427 if(ap.indexOf('a') !== -1 && n === 12){
428 n = 0;
429 }
430 }
431 }
432
433 tp_inst.control.value(tp_inst, tp_inst[f+'_slider'], litem, n);
434
435 tp_inst._onTimeChange();
436 tp_inst._onSelectHandler();
437 })
438 .css({
439 cursor: 'pointer',
440 width: (100 / gridSize[litem]) + '%',
441 textAlign: 'center',
442 overflow: 'hidden'
443 });
444 } // end if grid > 0
445 } // end for loop
446
447 // Add timezone options
448 this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find("select");
449 $.fn.append.apply(this.timezone_select,
450 $.map(o.timezoneList, function(val, idx) {
451 return $("<option />").val(typeof val == "object" ? val.value : val).text(typeof val == "object" ? val.label : val);
452 }));
453 if (typeof(this.timezone) != "undefined" && this.timezone !== null && this.timezone !== "") {
454 var local_date = new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12);
455 var local_timezone = $.timepicker.timeZoneOffsetString(local_date);
456 if (local_timezone == this.timezone) {
457 selectLocalTimeZone(tp_inst);
458 } else {
459 this.timezone_select.val(this.timezone);
460 }
461 } else {
462 if (typeof(this.hour) != "undefined" && this.hour !== null && this.hour !== "") {
463 this.timezone_select.val(o.defaultTimezone);
464 } else {
465 selectLocalTimeZone(tp_inst);
466 }
467 }
468 this.timezone_select.change(function() {
469 tp_inst._defaults.useLocalTimezone = false;
470 tp_inst._onTimeChange();
471 tp_inst._onSelectHandler();
472 });
473 // End timezone options
474
475 // inject timepicker into datepicker
476 var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
477 if ($buttonPanel.length) {
478 $buttonPanel.before($tp);
479 } else {
480 $dp.append($tp);
481 }
482
483 this.$timeObj = $tp.find('.ui_tpicker_time');
484
485 if (this.inst !== null) {
486 var timeDefined = this.timeDefined;
487 this._onTimeChange();
488 this.timeDefined = timeDefined;
489 }
490
491 // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
492 if (this._defaults.addSliderAccess) {
493 var sliderAccessArgs = this._defaults.sliderAccessArgs,
494 rtl = this._defaults.isRTL;
495 sliderAccessArgs.isRTL = rtl;
496
497 setTimeout(function() { // fix for inline mode
498 if ($tp.find('.ui-slider-access').length === 0) {
499 $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);
500
501 // fix any grids since sliders are shorter
502 var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);
503 if (sliderAccessWidth) {
504 $tp.find('table:visible').each(function() {
505 var $g = $(this),
506 oldWidth = $g.outerWidth(),
507 oldMarginLeft = $g.css(rtl? 'marginRight':'marginLeft').toString().replace('%', ''),
508 newWidth = oldWidth - sliderAccessWidth,
509 newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%',
510 css = { width: newWidth, marginRight: 0, marginLeft: 0 };
511 css[rtl? 'marginRight':'marginLeft'] = newMarginLeft;
512 $g.css(css);
513 });
514 }
515 }
516 }, 10);
517 }
518 // end slideAccess integration
519
520 }
521 },
522
523 /*
524 * This function tries to limit the ability to go outside the
525 * min/max date range
526 */
527 _limitMinMaxDateTime: function(dp_inst, adjustSliders) {
528 var o = this._defaults,
529 dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
530
531 if (!this._defaults.showTimepicker) {
532 return;
533 } // No time so nothing to check here
534
535 if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) {
536 var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),
537 minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
538
539 if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null) {
540 this.hourMinOriginal = o.hourMin;
541 this.minuteMinOriginal = o.minuteMin;
542 this.secondMinOriginal = o.secondMin;
543 this.millisecMinOriginal = o.millisecMin;
544 }
545
546 if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() == dp_date.getTime()) {
547 this._defaults.hourMin = minDateTime.getHours();
548 if (this.hour <= this._defaults.hourMin) {
549 this.hour = this._defaults.hourMin;
550 this._defaults.minuteMin = minDateTime.getMinutes();
551 if (this.minute <= this._defaults.minuteMin) {
552 this.minute = this._defaults.minuteMin;
553 this._defaults.secondMin = minDateTime.getSeconds();
554 if (this.second <= this._defaults.secondMin) {
555 this.second = this._defaults.secondMin;
556 this._defaults.millisecMin = minDateTime.getMilliseconds();
557 } else {
558 if (this.millisec < this._defaults.millisecMin) {
559 this.millisec = this._defaults.millisecMin;
560 }
561 this._defaults.millisecMin = this.millisecMinOriginal;
562 }
563 } else {
564 this._defaults.secondMin = this.secondMinOriginal;
565 this._defaults.millisecMin = this.millisecMinOriginal;
566 }
567 } else {
568 this._defaults.minuteMin = this.minuteMinOriginal;
569 this._defaults.secondMin = this.secondMinOriginal;
570 this._defaults.millisecMin = this.millisecMinOriginal;
571 }
572 } else {
573 this._defaults.hourMin = this.hourMinOriginal;
574 this._defaults.minuteMin = this.minuteMinOriginal;
575 this._defaults.secondMin = this.secondMinOriginal;
576 this._defaults.millisecMin = this.millisecMinOriginal;
577 }
578 }
579
580 if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) {
581 var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),
582 maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
583
584 if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null) {
585 this.hourMaxOriginal = o.hourMax;
586 this.minuteMaxOriginal = o.minuteMax;
587 this.secondMaxOriginal = o.secondMax;
588 this.millisecMaxOriginal = o.millisecMax;
589 }
590
591 if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() == dp_date.getTime()) {
592 this._defaults.hourMax = maxDateTime.getHours();
593 if (this.hour >= this._defaults.hourMax) {
594 this.hour = this._defaults.hourMax;
595 this._defaults.minuteMax = maxDateTime.getMinutes();
596 if (this.minute >= this._defaults.minuteMax) {
597 this.minute = this._defaults.minuteMax;
598 this._defaults.secondMax = maxDateTime.getSeconds();
599 if (this.second >= this._defaults.secondMax) {
600 this.second = this._defaults.secondMax;
601 this._defaults.millisecMax = maxDateTime.getMilliseconds();
602 } else {
603 if (this.millisec > this._defaults.millisecMax) {
604 this.millisec = this._defaults.millisecMax;
605 }
606 this._defaults.millisecMax = this.millisecMaxOriginal;
607 }
608 } else {
609 this._defaults.secondMax = this.secondMaxOriginal;
610 this._defaults.millisecMax = this.millisecMaxOriginal;
611 }
612 } else {
613 this._defaults.minuteMax = this.minuteMaxOriginal;
614 this._defaults.secondMax = this.secondMaxOriginal;
615 this._defaults.millisecMax = this.millisecMaxOriginal;
616 }
617 } else {
618 this._defaults.hourMax = this.hourMaxOriginal;
619 this._defaults.minuteMax = this.minuteMaxOriginal;
620 this._defaults.secondMax = this.secondMaxOriginal;
621 this._defaults.millisecMax = this.millisecMaxOriginal;
622 }
623 }
624
625 if (adjustSliders !== undefined && adjustSliders === true) {
626 var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10),
627 minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10),
628 secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10),
629 millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10);
630
631 if (this.hour_slider) {
632 this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax });
633 this.control.value(this, this.hour_slider, 'hour', this.hour - (this.hour % this._defaults.stepHour));
634 }
635 if (this.minute_slider) {
636 this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax });
637 this.control.value(this, this.minute_slider, 'minute', this.minute - (this.minute % this._defaults.stepMinute));
638 }
639 if (this.second_slider) {
640 this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax });
641 this.control.value(this, this.second_slider, 'second', this.second - (this.second % this._defaults.stepSecond));
642 }
643 if (this.millisec_slider) {
644 this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax });
645 this.control.value(this, this.millisec_slider, 'millisec', this.millisec - (this.millisec % this._defaults.stepMillisec));
646 }
647 }
648
649 },
650
651 /*
652 * when a slider moves, set the internal time...
653 * on time change is also called when the time is updated in the text field
654 */
655 _onTimeChange: function() {
656 var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false,
657 minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false,
658 second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false,
659 millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false,
660 timezone = (this.timezone_select) ? this.timezone_select.val() : false,
661 o = this._defaults,
662 pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,
663 pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;
664
665 if (typeof(hour) == 'object') {
666 hour = false;
667 }
668 if (typeof(minute) == 'object') {
669 minute = false;
670 }
671 if (typeof(second) == 'object') {
672 second = false;
673 }
674 if (typeof(millisec) == 'object') {
675 millisec = false;
676 }
677 if (typeof(timezone) == 'object') {
678 timezone = false;
679 }
680
681 if (hour !== false) {
682 hour = parseInt(hour, 10);
683 }
684 if (minute !== false) {
685 minute = parseInt(minute, 10);
686 }
687 if (second !== false) {
688 second = parseInt(second, 10);
689 }
690 if (millisec !== false) {
691 millisec = parseInt(millisec, 10);
692 }
693
694 var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];
695
696 // If the update was done in the input field, the input field should not be updated.
697 // If the update was done using the sliders, update the input field.
698 var hasChanged = (hour != this.hour || minute != this.minute || second != this.second || millisec != this.millisec
699 || (this.ampm.length > 0 && (hour < 12) != ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1))
700 || ((this.timezone === null && timezone != this.defaultTimezone) || (this.timezone !== null && timezone != this.timezone)));
701
702 if (hasChanged) {
703
704 if (hour !== false) {
705 this.hour = hour;
706 }
707 if (minute !== false) {
708 this.minute = minute;
709 }
710 if (second !== false) {
711 this.second = second;
712 }
713 if (millisec !== false) {
714 this.millisec = millisec;
715 }
716 if (timezone !== false) {
717 this.timezone = timezone;
718 }
719
720 if (!this.inst) {
721 this.inst = $.datepicker._getInst(this.$input[0]);
722 }
723
724 this._limitMinMaxDateTime(this.inst, true);
725 }
726 if (useAmpm(o.timeFormat)) {
727 this.ampm = ampm;
728 }
729
730 // Updates the time within the timepicker
731 this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o);
732 if (this.$timeObj) {
733 if(pickerTimeFormat === o.timeFormat){
734 this.$timeObj.text(this.formattedTime + pickerTimeSuffix);
735 }
736 else{
737 this.$timeObj.text($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix);
738 }
739 }
740
741 this.timeDefined = true;
742 if (hasChanged) {
743 this._updateDateTime();
744 }
745 },
746
747 /*
748 * call custom onSelect.
749 * bind to sliders slidestop, and grid click.
750 */
751 _onSelectHandler: function() {
752 var onSelect = this._defaults.onSelect || this.inst.settings.onSelect;
753 var inputEl = this.$input ? this.$input[0] : null;
754 if (onSelect && inputEl) {
755 onSelect.apply(inputEl, [this.formattedDateTime, this]);
756 }
757 },
758
759 /*
760 * update our input with the new date time..
761 */
762 _updateDateTime: function(dp_inst) {
763 dp_inst = this.inst || dp_inst;
764 var dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
765 dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
766 formatCfg = $.datepicker._getFormatConfig(dp_inst),
767 timeAvailable = dt !== null && this.timeDefined;
768 this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
769 var formattedDateTime = this.formattedDate;
770
771 // if a slider was changed but datepicker doesn't have a value yet, set it
772 if(dp_inst.lastVal==""){
773 dp_inst.currentYear=dp_inst.selectedYear;
774 dp_inst.currentMonth=dp_inst.selectedMonth;
775 dp_inst.currentDay=dp_inst.selectedDay;
776 }
777
778 /*
779 * remove following lines to force every changes in date picker to change the input value
780 * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.
781 * If the user manually empty the value in the input field, the date picker will never change selected value.
782 */
783 //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {
784 // return;
785 //}
786
787 if (this._defaults.timeOnly === true) {
788 formattedDateTime = this.formattedTime;
789 } else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) {
790 formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;
791 }
792
793 this.formattedDateTime = formattedDateTime;
794
795 if (!this._defaults.showTimepicker) {
796 this.$input.val(this.formattedDate);
797 } else if (this.$altInput && this._defaults.altFieldTimeOnly === true) {
798 this.$altInput.val(this.formattedTime);
799 this.$input.val(this.formattedDate);
800 } else if (this.$altInput) {
801 this.$input.val(formattedDateTime);
802 var altFormattedDateTime = '',
803 altSeparator = this._defaults.altSeparator ? this._defaults.altSeparator : this._defaults.separator,
804 altTimeSuffix = this._defaults.altTimeSuffix ? this._defaults.altTimeSuffix : this._defaults.timeSuffix;
805
806 if (this._defaults.altFormat) altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg);
807 else altFormattedDateTime = this.formattedDate;
808 if (altFormattedDateTime) altFormattedDateTime += altSeparator;
809 if (this._defaults.altTimeFormat) altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix;
810 else altFormattedDateTime += this.formattedTime + altTimeSuffix;
811 this.$altInput.val(altFormattedDateTime);
812 } else {
813 this.$input.val(formattedDateTime);
814 }
815
816 this.$input.trigger("change");
817 },
818
819 _onFocus: function() {
820 if (!this.$input.val() && this._defaults.defaultValue) {
821 this.$input.val(this._defaults.defaultValue);
822 var inst = $.datepicker._getInst(this.$input.get(0)),
823 tp_inst = $.datepicker._get(inst, 'timepicker');
824 if (tp_inst) {
825 if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) {
826 try {
827 $.datepicker._updateDatepicker(inst);
828 } catch (err) {
829 $.timepicker.log(err);
830 }
831 }
832 }
833 }
834 },
835
836 /*
837 * Small abstraction to control types
838 * We can add more, just be sure to follow the pattern: create, options, value
839 */
840 _controls: {
841 // slider methods
842 slider: {
843 create: function(tp_inst, obj, unit, val, min, max, step){
844 var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60
845 return obj.prop('slide', null).slider({
846 orientation: "horizontal",
847 value: rtl? val*-1 : val,
848 min: rtl? max*-1 : min,
849 max: rtl? min*-1 : max,
850 step: step,
851 slide: function(event, ui) {
852 tp_inst.control.value(tp_inst, $(this), unit, rtl? ui.value*-1:ui.value);
853 tp_inst._onTimeChange();
854 },
855 stop: function(event, ui) {
856 tp_inst._onSelectHandler();
857 }
858 });
859 },
860 options: function(tp_inst, obj, unit, opts, val){
861 if(tp_inst._defaults.isRTL){
862 if(typeof(opts) == 'string'){
863 if(opts == 'min' || opts == 'max'){
864 if(val !== undefined)
865 return obj.slider(opts, val*-1);
866 return Math.abs(obj.slider(opts));
867 }
868 return obj.slider(opts);
869 }
870 var min = opts.min,
871 max = opts.max;
872 opts.min = opts.max = null;
873 if(min !== undefined)
874 opts.max = min * -1;
875 if(max !== undefined)
876 opts.min = max * -1;
877 return obj.slider(opts);
878 }
879 if(typeof(opts) == 'string' && val !== undefined)
880 return obj.slider(opts, val);
881 return obj.slider(opts);
882 },
883 value: function(tp_inst, obj, unit, val){
884 if(tp_inst._defaults.isRTL){
885 if(val !== undefined)
886 return obj.slider('value', val*-1);
887 return Math.abs(obj.slider('value'));
888 }
889 if(val !== undefined)
890 return obj.slider('value', val);
891 return obj.slider('value');
892 }
893 },
894 // select methods
895 select: {
896 create: function(tp_inst, obj, unit, val, min, max, step){
897 var sel = '<select class="ui-timepicker-select" data-unit="'+ unit +'" data-min="'+ min +'" data-max="'+ max +'" data-step="'+ step +'">',
898 ul = tp_inst._defaults.timeFormat.indexOf('t') !== -1? 'toLowerCase':'toUpperCase',
899 m = 0;
900
901 for(var i=min; i<=max; i+=step){
902 sel += '<option value="'+ i +'"'+ (i==val? ' selected':'') +'>';
903 if(unit == 'hour' && useAmpm(tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat))
904 sel += $.datepicker.formatTime("hh TT", {hour:i}, tp_inst._defaults);
905 else if(unit == 'millisec' || i >= 10) sel += i;
906 else sel += '0'+ i.toString();
907 sel += '</option>';
908 }
909 sel += '</select>';
910
911 obj.children('select').remove();
912
913 $(sel).appendTo(obj).change(function(e){
914 tp_inst._onTimeChange();
915 tp_inst._onSelectHandler();
916 });
917
918 return obj;
919 },
920 options: function(tp_inst, obj, unit, opts, val){
921 var o = {},
922 $t = obj.children('select');
923 if(typeof(opts) == 'string'){
924 if(val === undefined)
925 return $t.data(opts);
926 o[opts] = val;
927 }
928 else o = opts;
929 return tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min || $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step'));
930 },
931 value: function(tp_inst, obj, unit, val){
932 var $t = obj.children('select');
933 if(val !== undefined)
934 return $t.val(val);
935 return $t.val();
936 }
937 }
938 } // end _controls
939
940 });
941
942 $.fn.extend({
943 /*
944 * shorthand just to use timepicker..
945 */
946 timepicker: function(o) {
947 o = o || {};
948 var tmp_args = Array.prototype.slice.call(arguments);
949
950 if (typeof o == 'object') {
951 tmp_args[0] = $.extend(o, {
952 timeOnly: true
953 });
954 }
955
956 return $(this).each(function() {
957 $.fn.datetimepicker.apply($(this), tmp_args);
958 });
959 },
960
961 /*
962 * extend timepicker to datepicker
963 */
964 datetimepicker: function(o) {
965 o = o || {};
966 var tmp_args = arguments;
967
968 if (typeof(o) == 'string') {
969 if (o == 'getDate') {
970 return $.fn.datepicker.apply($(this[0]), tmp_args);
971 } else {
972 return this.each(function() {
973 var $t = $(this);
974 $t.datepicker.apply($t, tmp_args);
975 });
976 }
977 } else {
978 return this.each(function() {
979 var $t = $(this);
980 $t.datepicker($.timepicker._newInst($t, o)._defaults);
981 });
982 }
983 }
984 });
985
986 /*
987 * Public Utility to parse date and time
988 */
989 $.datepicker.parseDateTime = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
990 var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);
991 if (parseRes.timeObj) {
992 var t = parseRes.timeObj;
993 parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);
994 }
995
996 return parseRes.date;
997 };
998
999 /*
1000 * Public utility to parse time
1001 */
1002 $.datepicker.parseTime = function(timeFormat, timeString, options) {
1003 var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {});
1004
1005 // Strict parse requires the timeString to match the timeFormat exactly
1006 var strictParse = function(f, s, o){
1007
1008 // pattern for standard and localized AM/PM markers
1009 var getPatternAmpm = function(amNames, pmNames) {
1010 var markers = [];
1011 if (amNames) {
1012 $.merge(markers, amNames);
1013 }
1014 if (pmNames) {
1015 $.merge(markers, pmNames);
1016 }
1017 markers = $.map(markers, function(val) {
1018 return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&');
1019 });
1020 return '(' + markers.join('|') + ')?';
1021 };
1022
1023 // figure out position of time elements.. cause js cant do named captures
1024 var getFormatPositions = function(timeFormat) {
1025 var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|t{1,2}|z|'.*?')/g),
1026 orders = {
1027 h: -1,
1028 m: -1,
1029 s: -1,
1030 l: -1,
1031 t: -1,
1032 z: -1
1033 };
1034
1035 if (finds) {
1036 for (var i = 0; i < finds.length; i++) {
1037 if (orders[finds[i].toString().charAt(0)] == -1) {
1038 orders[finds[i].toString().charAt(0)] = i + 1;
1039 }
1040 }
1041 }
1042 return orders;
1043 };
1044
1045 var regstr = '^' + f.toString()
1046 .replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[lz]|'.*?')/g, function (match) {
1047 var ml = match.length;
1048 switch (match.charAt(0).toLowerCase()) {
1049 case 'h': return ml === 1? '(\\d?\\d)':'(\\d{'+ml+'})';
1050 case 'm': return ml === 1? '(\\d?\\d)':'(\\d{'+ml+'})';
1051 case 's': return ml === 1? '(\\d?\\d)':'(\\d{'+ml+'})';
1052 case 'l': return '(\\d?\\d?\\d)';
1053 case 'z': return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?';
1054 case 't': return getPatternAmpm(o.amNames, o.pmNames);
1055 default: // literal escaped in quotes
1056 return '(' + match.replace(/\'/g, "").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function (m) { return "\\" + m; }) + ')?';
1057 }
1058 })
1059 .replace(/\s/g, '\\s?') +
1060 o.timeSuffix + '$',
1061 order = getFormatPositions(f),
1062 ampm = '',
1063 treg;
1064
1065 treg = s.match(new RegExp(regstr, 'i'));
1066
1067 var resTime = {
1068 hour: 0,
1069 minute: 0,
1070 second: 0,
1071 millisec: 0
1072 };
1073
1074 if (treg) {
1075 if (order.t !== -1) {
1076 if (treg[order.t] === undefined || treg[order.t].length === 0) {
1077 ampm = '';
1078 resTime.ampm = '';
1079 } else {
1080 ampm = $.inArray(treg[order.t].toUpperCase(), o.amNames) !== -1 ? 'AM' : 'PM';
1081 resTime.ampm = o[ampm == 'AM' ? 'amNames' : 'pmNames'][0];
1082 }
1083 }
1084
1085 if (order.h !== -1) {
1086 if (ampm == 'AM' && treg[order.h] == '12') {
1087 resTime.hour = 0; // 12am = 0 hour
1088 } else {
1089 if (ampm == 'PM' && treg[order.h] != '12') {
1090 resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12
1091 } else {
1092 resTime.hour = Number(treg[order.h]);
1093 }
1094 }
1095 }
1096
1097 if (order.m !== -1) {
1098 resTime.minute = Number(treg[order.m]);
1099 }
1100 if (order.s !== -1) {
1101 resTime.second = Number(treg[order.s]);
1102 }
1103 if (order.l !== -1) {
1104 resTime.millisec = Number(treg[order.l]);
1105 }
1106 if (order.z !== -1 && treg[order.z] !== undefined) {
1107 var tz = treg[order.z].toUpperCase();
1108 switch (tz.length) {
1109 case 1:
1110 // Z
1111 tz = o.timezoneIso8601 ? 'Z' : '+0000';
1112 break;
1113 case 5:
1114 // +hhmm
1115 if (o.timezoneIso8601) {
1116 tz = tz.substring(1) == '0000' ? 'Z' : tz.substring(0, 3) + ':' + tz.substring(3);
1117 }
1118 break;
1119 case 6:
1120 // +hh:mm
1121 if (!o.timezoneIso8601) {
1122 tz = tz == 'Z' || tz.substring(1) == '00:00' ? '+0000' : tz.replace(/:/, '');
1123 } else {
1124 if (tz.substring(1) == '00:00') {
1125 tz = 'Z';
1126 }
1127 }
1128 break;
1129 }
1130 resTime.timezone = tz;
1131 }
1132
1133
1134 return resTime;
1135 }
1136 return false;
1137 };// end strictParse
1138
1139 // First try JS Date, if that fails, use strictParse
1140 var looseParse = function(f,s,o){
1141 try{
1142 var d = new Date('2012-01-01 '+ s);
1143 if(isNaN(d.getTime())){
1144 d = new Date('2012-01-01T'+ s);
1145 if(isNaN(d.getTime())){
1146 d = new Date('01/01/2012 '+ s);
1147 if(isNaN(d.getTime())){
1148 throw "Unable to parse time with native Date: "+ s;
1149 }
1150 }
1151 }
1152
1153 return {
1154 hour: d.getHours(),
1155 minute: d.getMinutes(),
1156 second: d.getSeconds(),
1157 millisec: d.getMilliseconds(),
1158 timezone: $.timepicker.timeZoneOffsetString(d)
1159 };
1160 }
1161 catch(err){
1162 try{
1163 return strictParse(f,s,o);
1164 }
1165 catch(err2){
1166 $.timepicker.log("Unable to parse \ntimeString: "+ s +"\ntimeFormat: "+ f);
1167 }
1168 }
1169 return false;
1170 }; // end looseParse
1171
1172 if(typeof o.parse === "function"){
1173 return o.parse(timeFormat, timeString, o)
1174 }
1175 if(o.parse === 'loose'){
1176 return looseParse(timeFormat, timeString, o);
1177 }
1178 return strictParse(timeFormat, timeString, o);
1179 };
1180
1181 /*
1182 * Public utility to format the time
1183 * format = string format of the time
1184 * time = a {}, not a Date() for timezones
1185 * options = essentially the regional[].. amNames, pmNames, ampm
1186 */
1187 $.datepicker.formatTime = function(format, time, options) {
1188 options = options || {};
1189 options = $.extend({}, $.timepicker._defaults, options);
1190 time = $.extend({
1191 hour: 0,
1192 minute: 0,
1193 second: 0,
1194 millisec: 0,
1195 timezone: '+0000'
1196 }, time);
1197
1198 var tmptime = format,
1199 ampmName = options.amNames[0],
1200 hour = parseInt(time.hour, 10);
1201
1202 if (hour > 11) {
1203 ampmName = options.pmNames[0];
1204 }
1205
1206 tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[lz]|('.*?'|".*?"))/g, function(match) {
1207 switch (match) {
1208 case 'HH':
1209 return ('0' + hour).slice(-2);
1210 case 'H':
1211 return hour;
1212 case 'hh':
1213 return ('0' + convert24to12(hour)).slice(-2);
1214 case 'h':
1215 return convert24to12(hour);
1216 case 'mm':
1217 return ('0' + time.minute).slice(-2);
1218 case 'm':
1219 return time.minute;
1220 case 'ss':
1221 return ('0' + time.second).slice(-2);
1222 case 's':
1223 return time.second;
1224 case 'l':
1225 return ('00' + time.millisec).slice(-3);
1226 case 'z':
1227 return time.timezone === null? options.defaultTimezone : time.timezone;
1228 case 'T':
1229 return ampmName.charAt(0).toUpperCase();
1230 case 'TT':
1231 return ampmName.toUpperCase();
1232 case 't':
1233 return ampmName.charAt(0).toLowerCase();
1234 case 'tt':
1235 return ampmName.toLowerCase();
1236 default:
1237 return match.replace(/\'/g, "") || "'";
1238 }
1239 });
1240
1241 tmptime = $.trim(tmptime);
1242 return tmptime;
1243 };
1244
1245 /*
1246 * the bad hack :/ override datepicker so it doesnt close on select
1247 // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
1248 */
1249 $.datepicker._base_selectDate = $.datepicker._selectDate;
1250 $.datepicker._selectDate = function(id, dateStr) {
1251 var inst = this._getInst($(id)[0]),
1252 tp_inst = this._get(inst, 'timepicker');
1253
1254 if (tp_inst) {
1255 tp_inst._limitMinMaxDateTime(inst, true);
1256 inst.inline = inst.stay_open = true;
1257 //This way the onSelect handler called from calendarpicker get the full dateTime
1258 this._base_selectDate(id, dateStr);
1259 inst.inline = inst.stay_open = false;
1260 this._notifyChange(inst);
1261 this._updateDatepicker(inst);
1262 } else {
1263 this._base_selectDate(id, dateStr);
1264 }
1265 };
1266
1267 /*
1268 * second bad hack :/ override datepicker so it triggers an event when changing the input field
1269 * and does not redraw the datepicker on every selectDate event
1270 */
1271 $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
1272 $.datepicker._updateDatepicker = function(inst) {
1273
1274 // don't popup the datepicker if there is another instance already opened
1275 var input = inst.input[0];
1276 if ($.datepicker._curInst && $.datepicker._curInst != inst && $.datepicker._datepickerShowing && $.datepicker._lastInput != input) {
1277 return;
1278 }
1279
1280 if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
1281
1282 this._base_updateDatepicker(inst);
1283
1284 // Reload the time control when changing something in the input text field.
1285 var tp_inst = this._get(inst, 'timepicker');
1286 if (tp_inst) {
1287 tp_inst._addTimePicker(inst);
1288
1289 // if (tp_inst._defaults.useLocalTimezone) { //checks daylight saving with the new date.
1290 // var date = new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay, 12);
1291 // selectLocalTimeZone(tp_inst, date);
1292 // tp_inst._onTimeChange();
1293 // }
1294 }
1295 }
1296 };
1297
1298 /*
1299 * third bad hack :/ override datepicker so it allows spaces and colon in the input field
1300 */
1301 $.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
1302 $.datepicker._doKeyPress = function(event) {
1303 var inst = $.datepicker._getInst(event.target),
1304 tp_inst = $.datepicker._get(inst, 'timepicker');
1305
1306 if (tp_inst) {
1307 if ($.datepicker._get(inst, 'constrainInput')) {
1308 var ampm = useAmpm(tp_inst._defaults.timeFormat),
1309 dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
1310 datetimeChars = tp_inst._defaults.timeFormat.toString()
1311 .replace(/[hms]/g, '')
1312 .replace(/TT/g, ampm ? 'APM' : '')
1313 .replace(/Tt/g, ampm ? 'AaPpMm' : '')
1314 .replace(/tT/g, ampm ? 'AaPpMm' : '')
1315 .replace(/T/g, ampm ? 'AP' : '')
1316 .replace(/tt/g, ampm ? 'apm' : '')
1317 .replace(/t/g, ampm ? 'ap' : '') +
1318 " " + tp_inst._defaults.separator +
1319 tp_inst._defaults.timeSuffix +
1320 (tp_inst._defaults.showTimezone ? tp_inst._defaults.timezoneList.join('') : '') +
1321 (tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) +
1322 dateChars,
1323 chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
1324 return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);
1325 }
1326 }
1327
1328 return $.datepicker._base_doKeyPress(event);
1329 };
1330
1331 /*
1332 * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField
1333 */
1334 $.datepicker._base_updateAlternate = $.datepicker._updateAlternate;
1335 /* Update any alternate field to synchronise with the main field. */
1336 $.datepicker._updateAlternate = function(inst) {
1337 var tp_inst = this._get(inst, 'timepicker');
1338 if(tp_inst){
1339 var altField = tp_inst._defaults.altField;
1340 if (altField) { // update alternate field too
1341 var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat,
1342 date = this._getDate(inst),
1343 formatCfg = $.datepicker._getFormatConfig(inst),
1344 altFormattedDateTime = '',
1345 altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator,
1346 altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix,
1347 altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat;
1348
1349 altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix;
1350 if(!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly && date !== null){
1351 if(tp_inst._defaults.altFormat)
1352 altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, date, formatCfg) + altSeparator + altFormattedDateTime;
1353 else altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime;
1354 }
1355 $(altField).val(altFormattedDateTime);
1356 }
1357 }
1358 else{
1359 $.datepicker._base_updateAlternate(inst);
1360 }
1361 };
1362
1363 /*
1364 * Override key up event to sync manual input changes.
1365 */
1366 $.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
1367 $.datepicker._doKeyUp = function(event) {
1368 var inst = $.datepicker._getInst(event.target),
1369 tp_inst = $.datepicker._get(inst, 'timepicker');
1370
1371 if (tp_inst) {
1372 if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) {
1373 try {
1374 $.datepicker._updateDatepicker(inst);
1375 } catch (err) {
1376 $.timepicker.log(err);
1377 }
1378 }
1379 }
1380
1381 return $.datepicker._base_doKeyUp(event);
1382 };
1383
1384 /*
1385 * override "Today" button to also grab the time.
1386 */
1387 $.datepicker._base_gotoToday = $.datepicker._gotoToday;
1388 $.datepicker._gotoToday = function(id) {
1389 var inst = this._getInst($(id)[0]),
1390 $dp = inst.dpDiv;
1391 this._base_gotoToday(id);
1392 var tp_inst = this._get(inst, 'timepicker');
1393 selectLocalTimeZone(tp_inst);
1394 var now = new Date();
1395 this._setTime(inst, now);
1396 $('.ui-datepicker-today', $dp).click();
1397 };
1398
1399 /*
1400 * Disable & enable the Time in the datetimepicker
1401 */
1402 $.datepicker._disableTimepickerDatepicker = function(target) {
1403 var inst = this._getInst(target);
1404 if (!inst) {
1405 return;
1406 }
1407
1408 var tp_inst = this._get(inst, 'timepicker');
1409 $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
1410 if (tp_inst) {
1411 tp_inst._defaults.showTimepicker = false;
1412 tp_inst._updateDateTime(inst);
1413 }
1414 };
1415
1416 $.datepicker._enableTimepickerDatepicker = function(target) {
1417 var inst = this._getInst(target);
1418 if (!inst) {
1419 return;
1420 }
1421
1422 var tp_inst = this._get(inst, 'timepicker');
1423 $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
1424 if (tp_inst) {
1425 tp_inst._defaults.showTimepicker = true;
1426 tp_inst._addTimePicker(inst); // Could be disabled on page load
1427 tp_inst._updateDateTime(inst);
1428 }
1429 };
1430
1431 /*
1432 * Create our own set time function
1433 */
1434 $.datepicker._setTime = function(inst, date) {
1435 var tp_inst = this._get(inst, 'timepicker');
1436 if (tp_inst) {
1437 var defaults = tp_inst._defaults;
1438
1439 // calling _setTime with no date sets time to defaults
1440 tp_inst.hour = date ? date.getHours() : defaults.hour;
1441 tp_inst.minute = date ? date.getMinutes() : defaults.minute;
1442 tp_inst.second = date ? date.getSeconds() : defaults.second;
1443 tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec;
1444
1445 //check if within min/max times..
1446 tp_inst._limitMinMaxDateTime(inst, true);
1447
1448 tp_inst._onTimeChange();
1449 tp_inst._updateDateTime(inst);
1450 }
1451 };
1452
1453 /*
1454 * Create new public method to set only time, callable as $().datepicker('setTime', date)
1455 */
1456 $.datepicker._setTimeDatepicker = function(target, date, withDate) {
1457 var inst = this._getInst(target);
1458 if (!inst) {
1459 return;
1460 }
1461
1462 var tp_inst = this._get(inst, 'timepicker');
1463
1464 if (tp_inst) {
1465 this._setDateFromField(inst);
1466 var tp_date;
1467 if (date) {
1468 if (typeof date == "string") {
1469 tp_inst._parseTime(date, withDate);
1470 tp_date = new Date();
1471 tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
1472 } else {
1473 tp_date = new Date(date.getTime());
1474 }
1475 if (tp_date.toString() == 'Invalid Date') {
1476 tp_date = undefined;
1477 }
1478 this._setTime(inst, tp_date);
1479 }
1480 }
1481
1482 };
1483
1484 /*
1485 * override setDate() to allow setting time too within Date object
1486 */
1487 $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
1488 $.datepicker._setDateDatepicker = function(target, date) {
1489 var inst = this._getInst(target);
1490 if (!inst) {
1491 return;
1492 }
1493
1494 var tp_date = (date instanceof Date) ? new Date(date.getTime()) : date;
1495
1496 this._updateDatepicker(inst);
1497 this._base_setDateDatepicker.apply(this, arguments);
1498 this._setTimeDatepicker(target, tp_date, true);
1499 };
1500
1501 /*
1502 * override getDate() to allow getting time too within Date object
1503 */
1504 $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
1505 $.datepicker._getDateDatepicker = function(target, noDefault) {
1506 var inst = this._getInst(target);
1507 if (!inst) {
1508 return;
1509 }
1510
1511 var tp_inst = this._get(inst, 'timepicker');
1512
1513 if (tp_inst) {
1514 // if it hasn't yet been defined, grab from field
1515 if(inst.lastVal === undefined){
1516 this._setDateFromField(inst, noDefault);
1517 }
1518
1519 var date = this._getDate(inst);
1520 if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) {
1521 date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
1522 }
1523 return date;
1524 }
1525 return this._base_getDateDatepicker(target, noDefault);
1526 };
1527
1528 /*
1529 * override parseDate() because UI 1.8.14 throws an error about "Extra characters"
1530 * An option in datapicker to ignore extra format characters would be nicer.
1531 */
1532 $.datepicker._base_parseDate = $.datepicker.parseDate;
1533 $.datepicker.parseDate = function(format, value, settings) {
1534 var date;
1535 try {
1536 date = this._base_parseDate(format, value, settings);
1537 } catch (err) {
1538 // Hack! The error message ends with a colon, a space, and
1539 // the "extra" characters. We rely on that instead of
1540 // attempting to perfectly reproduce the parsing algorithm.
1541 date = this._base_parseDate(format, value.substring(0,value.length-(err.length-err.indexOf(':')-2)), settings);
1542 $.timepicker.log("Error parsing the date string: " + err + "\ndate string = " + value + "\ndate format = " + format);
1543 }
1544 return date;
1545 };
1546
1547 /*
1548 * override formatDate to set date with time to the input
1549 */
1550 $.datepicker._base_formatDate = $.datepicker._formatDate;
1551 $.datepicker._formatDate = function(inst, day, month, year) {
1552 var tp_inst = this._get(inst, 'timepicker');
1553 if (tp_inst) {
1554 tp_inst._updateDateTime(inst);
1555 return tp_inst.$input.val();
1556 }
1557 return this._base_formatDate(inst);
1558 };
1559
1560 /*
1561 * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
1562 */
1563 $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
1564 $.datepicker._optionDatepicker = function(target, name, value) {
1565 var inst = this._getInst(target),
1566 name_clone;
1567 if (!inst) {
1568 return null;
1569 }
1570
1571 var tp_inst = this._get(inst, 'timepicker');
1572 if (tp_inst) {
1573 var min = null,
1574 max = null,
1575 onselect = null,
1576 overrides = tp_inst._defaults.evnts,
1577 fns = {},
1578 prop;
1579 if (typeof name == 'string') { // if min/max was set with the string
1580 if (name === 'minDate' || name === 'minDateTime') {
1581 min = value;
1582 } else if (name === 'maxDate' || name === 'maxDateTime') {
1583 max = value;
1584 } else if (name === 'onSelect') {
1585 onselect = value;
1586 } else if (overrides.hasOwnProperty(name)) {
1587 if (typeof (value) === 'undefined') {
1588 return overrides[name];
1589 }
1590 fns[name] = value;
1591 name_clone = {}; //empty results in exiting function after overrides updated
1592 }
1593 } else if (typeof name == 'object') { //if min/max was set with the JSON
1594 if (name.minDate) {
1595 min = name.minDate;
1596 } else if (name.minDateTime) {
1597 min = name.minDateTime;
1598 } else if (name.maxDate) {
1599 max = name.maxDate;
1600 } else if (name.maxDateTime) {
1601 max = name.maxDateTime;
1602 }
1603 for (prop in overrides) {
1604 if (overrides.hasOwnProperty(prop) && name[prop]) {
1605 fns[prop] = name[prop];
1606 }
1607 }
1608 }
1609 for (prop in fns) {
1610 if (fns.hasOwnProperty(prop)) {
1611 overrides[prop] = fns[prop];
1612 if (!name_clone) { name_clone = $.extend({}, name);}
1613 delete name_clone[prop];
1614 }
1615 }
1616 if (name_clone && isEmptyObject(name_clone)) { return; }
1617 if (min) { //if min was set
1618 if (min === 0) {
1619 min = new Date();
1620 } else {
1621 min = new Date(min);
1622 }
1623 tp_inst._defaults.minDate = min;
1624 tp_inst._defaults.minDateTime = min;
1625 } else if (max) { //if max was set
1626 if (max === 0) {
1627 max = new Date();
1628 } else {
1629 max = new Date(max);
1630 }
1631 tp_inst._defaults.maxDate = max;
1632 tp_inst._defaults.maxDateTime = max;
1633 } else if (onselect) {
1634 tp_inst._defaults.onSelect = onselect;
1635 }
1636 }
1637 if (value === undefined) {
1638 return this._base_optionDatepicker.call($.datepicker, target, name);
1639 }
1640 return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
1641 };
1642 /*
1643 * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,
1644 * it will return false for all objects
1645 */
1646 var isEmptyObject = function(obj) {
1647 var prop;
1648 for (prop in obj) {
1649 if (obj.hasOwnProperty(obj)) {
1650 return false;
1651 }
1652 }
1653 return true;
1654 };
1655
1656 /*
1657 * jQuery extend now ignores nulls!
1658 */
1659 var extendRemove = function(target, props) {
1660 $.extend(target, props);
1661 for (var name in props) {
1662 if (props[name] === null || props[name] === undefined) {
1663 target[name] = props[name];
1664 }
1665 }
1666 return target;
1667 };
1668
1669 /*
1670 * Determine by the time format if should use ampm
1671 * Returns true if should use ampm, false if not
1672 */
1673 var useAmpm = function(timeFormat){
1674 return (timeFormat.indexOf('t') !== -1 && timeFormat.indexOf('h') !== -1);
1675 };
1676
1677 /*
1678 * Converts 24 hour format into 12 hour
1679 * Returns 12 hour without leading 0
1680 */
1681 var convert24to12 = function(hour) {
1682 if (hour > 12) {
1683 hour = hour - 12;
1684 }
1685
1686 if (hour == 0) {
1687 hour = 12;
1688 }
1689
1690 return String(hour);
1691 };
1692
1693 /*
1694 * Splits datetime string into date ans time substrings.
1695 * Throws exception when date can't be parsed
1696 * Returns [dateString, timeString]
1697 */
1698 var splitDateTime = function(dateFormat, dateTimeString, dateSettings, timeSettings) {
1699 try {
1700 // The idea is to get the number separator occurances in datetime and the time format requested (since time has
1701 // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.
1702 var separator = timeSettings && timeSettings.separator ? timeSettings.separator : $.timepicker._defaults.separator,
1703 format = timeSettings && timeSettings.timeFormat ? timeSettings.timeFormat : $.timepicker._defaults.timeFormat,
1704 timeParts = format.split(separator), // how many occurances of separator may be in our format?
1705 timePartsLen = timeParts.length,
1706 allParts = dateTimeString.split(separator),
1707 allPartsLen = allParts.length;
1708
1709 if (allPartsLen > 1) {
1710 return [
1711 allParts.splice(0,allPartsLen-timePartsLen).join(separator),
1712 allParts.splice(0,timePartsLen).join(separator)
1713 ];
1714 }
1715
1716 } catch (err) {
1717 $.timepicker.log('Could not split the date from the time. Please check the following datetimepicker options' +
1718 "\nthrown error: " + err +
1719 "\ndateTimeString" + dateTimeString +
1720 "\ndateFormat = " + dateFormat +
1721 "\nseparator = " + timeSettings.separator +
1722 "\ntimeFormat = " + timeSettings.timeFormat);
1723
1724 if (err.indexOf(":") >= 0) {
1725 // Hack! The error message ends with a colon, a space, and
1726 // the "extra" characters. We rely on that instead of
1727 // attempting to perfectly reproduce the parsing algorithm.
1728 var dateStringLength = dateTimeString.length - (err.length - err.indexOf(':') - 2),
1729 timeString = dateTimeString.substring(dateStringLength);
1730
1731 return [$.trim(dateTimeString.substring(0, dateStringLength)), $.trim(dateTimeString.substring(dateStringLength))];
1732
1733 } else {
1734 throw err;
1735 }
1736 }
1737 return [dateTimeString, ''];
1738 };
1739
1740 /*
1741 * Internal function to parse datetime interval
1742 * Returns: {date: Date, timeObj: Object}, where
1743 * date - parsed date without time (type Date)
1744 * timeObj = {hour: , minute: , second: , millisec: } - parsed time. Optional
1745 */
1746 var parseDateTimeInternal = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
1747 var date;
1748 var splitRes = splitDateTime(dateFormat, dateTimeString, dateSettings, timeSettings);
1749 date = $.datepicker._base_parseDate(dateFormat, splitRes[0], dateSettings);
1750 if (splitRes[1] !== '') {
1751 var timeString = splitRes[1],
1752 parsedTime = $.datepicker.parseTime(timeFormat, timeString, timeSettings);
1753
1754 if (parsedTime === null) {
1755 throw 'Wrong time format';
1756 }
1757 return {
1758 date: date,
1759 timeObj: parsedTime
1760 };
1761 } else {
1762 return {
1763 date: date
1764 };
1765 }
1766 };
1767
1768 /*
1769 * Internal function to set timezone_select to the local timezone
1770 */
1771 var selectLocalTimeZone = function(tp_inst, date) {
1772 if (tp_inst && tp_inst.timezone_select) {
1773 tp_inst._defaults.useLocalTimezone = true;
1774 var now = typeof date !== 'undefined' ? date : new Date();
1775 var tzoffset = $.timepicker.timeZoneOffsetString(now);
1776 if (tp_inst._defaults.timezoneIso8601) {
1777 tzoffset = tzoffset.substring(0, 3) + ':' + tzoffset.substring(3);
1778 }
1779 tp_inst.timezone_select.val(tzoffset);
1780 }
1781 };
1782
1783 /*
1784 * Create a Singleton Insance
1785 */
1786 $.timepicker = new Timepicker();
1787
1788 /**
1789 * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)
1790 * @param date
1791 * @return string
1792 */
1793 $.timepicker.timeZoneOffsetString = function(date) {
1794 var off = date.getTimezoneOffset() * -1,
1795 minutes = off % 60,
1796 hours = (off - minutes) / 60;
1797 return (off >= 0 ? '+' : '-') + ('0' + (hours * 101).toString()).slice(-2) + ('0' + (minutes * 101).toString()).slice(-2);
1798 };
1799
1800 /**
1801 * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to
1802 * enforce date range limits.
1803 * n.b. The input value must be correctly formatted (reformatting is not supported)
1804 * @param Element startTime
1805 * @param Element endTime
1806 * @param obj options Options for the timepicker() call
1807 * @return jQuery
1808 */
1809 $.timepicker.timeRange = function(startTime, endTime, options) {
1810 return $.timepicker.handleRange('timepicker', startTime, endTime, options);
1811 };
1812
1813 /**
1814 * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to
1815 * enforce date range limits.
1816 * @param Element startTime
1817 * @param Element endTime
1818 * @param obj options Options for the `timepicker()` call. Also supports `reformat`,
1819 * a boolean value that can be used to reformat the input values to the `dateFormat`.
1820 * @param string method Can be used to specify the type of picker to be added
1821 * @return jQuery
1822 */
1823 $.timepicker.dateTimeRange = function(startTime, endTime, options) {
1824 $.timepicker.dateRange(startTime, endTime, options, 'datetimepicker');
1825 };
1826
1827 /**
1828 * Calls `method` on the `startTime` and `endTime` elements, and configures them to
1829 * enforce date range limits.
1830 * @param Element startTime
1831 * @param Element endTime
1832 * @param obj options Options for the `timepicker()` call. Also supports `reformat`,
1833 * a boolean value that can be used to reformat the input values to the `dateFormat`.
1834 * @param string method Can be used to specify the type of picker to be added
1835 * @return jQuery
1836 */
1837 $.timepicker.dateRange = function(startTime, endTime, options, method) {
1838 method = method || 'datepicker';
1839 $.timepicker.handleRange(method, startTime, endTime, options);
1840 };
1841
1842 /**
1843 * Calls `method` on the `startTime` and `endTime` elements, and configures them to
1844 * enforce date range limits.
1845 * @param string method Can be used to specify the type of picker to be added
1846 * @param Element startTime
1847 * @param Element endTime
1848 * @param obj options Options for the `timepicker()` call. Also supports `reformat`,
1849 * a boolean value that can be used to reformat the input values to the `dateFormat`.
1850 * @return jQuery
1851 */
1852 $.timepicker.handleRange = function(method, startTime, endTime, options) {
1853 $.fn[method].call(startTime, $.extend({
1854 onClose: function(dateText, inst) {
1855 checkDates(this, endTime, dateText);
1856 },
1857 onSelect: function(selectedDateTime) {
1858 selected(this, endTime, 'minDate');
1859 }
1860 }, options, options.start));
1861 $.fn[method].call(endTime, $.extend({
1862 onClose: function(dateText, inst) {
1863 checkDates(this, startTime, dateText);
1864 },
1865 onSelect: function(selectedDateTime) {
1866 selected(this, startTime, 'maxDate');
1867 }
1868 }, options, options.end));
1869 // timepicker doesn't provide access to its 'timeFormat' option,
1870 // nor could I get datepicker.formatTime() to behave with times, so I
1871 // have disabled reformatting for timepicker
1872 if (method != 'timepicker' && options.reformat) {
1873 $([startTime, endTime]).each(function() {
1874 var format = $(this)[method].call($(this), 'option', 'dateFormat'),
1875 date = new Date($(this).val());
1876 if ($(this).val() && date) {
1877 $(this).val($.datepicker.formatDate(format, date));
1878 }
1879 });
1880 }
1881 checkDates(startTime, endTime, startTime.val());
1882
1883 function checkDates(changed, other, dateText) {
1884 if (other.val() && (new Date(startTime.val()) > new Date(endTime.val()))) {
1885 other.val(dateText);
1886 }
1887 }
1888 selected(startTime, endTime, 'minDate');
1889 selected(endTime, startTime, 'maxDate');
1890
1891 function selected(changed, other, option) {
1892 if (!$(changed).val()) {
1893 return;
1894 }
1895 var date = $(changed)[method].call($(changed), 'getDate');
1896 // timepicker doesn't implement 'getDate' and returns a jQuery
1897 if (date.getTime) {
1898 $(other)[method].call($(other), 'option', option, date);
1899 }
1900 }
1901 return $([startTime.get(0), endTime.get(0)]);
1902 };
1903
1904 /**
1905 * Log error or data to the console during error or debugging
1906 * @param Object err pass any type object to log to the console during error or debugging
1907 * @return void
1908 */
1909 $.timepicker.log = function(err){
1910 if(window.console)
1911 console.log(err);
1912 };
1913
1914 /*
1915 * Keep up with the version
1916 */
1917 $.timepicker.version = "1.2";
1918
1919 })(jQuery);
1920