source: extensions/manage_properties_photos/js/jquery-ui-timepicker-addon.js @ 32135

Last change on this file since 32135 was 32135, checked in by ddtddt, 4 years ago

[manage_properties_photos]

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