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