source: trunk/prototype/app/plugins/timepicker/jquery-ui-timepicker-addon.js @ 5341

Revision 5341, 48.8 KB checked in by wmerlotto, 12 years ago (diff)

Ticket #2434 - Commit inicial do novo módulo de agenda do Expresso - expressoCalendar

Line 
1/*
2* jQuery timepicker addon
3* By: Trent Richardson [http://trentrichardson.com]
4* Version 0.9.8
5* Last Modified: 12/03/2011
6*
7* Copyright 2011 Trent Richardson
8* Dual licensed under the MIT and GPL licenses.
9* http://trentrichardson.com/Impromptu/GPL-LICENSE.txt
10* http://trentrichardson.com/Impromptu/MIT-LICENSE.txt
11*
12* HERES THE CSS:
13* .ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }
14* .ui-timepicker-div dl { text-align: left; }
15* .ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; }
16* .ui-timepicker-div dl dd { margin: 0 10px 10px 65px; }
17* .ui-timepicker-div td { font-size: 90%; }
18* .ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; }
19*/
20
21(function($) {
22
23$.extend($.ui, { timepicker: { version: "0.9.8" } });
24
25/* Time picker manager.
26   Use the singleton instance of this class, $.timepicker, to interact with the time picker.
27   Settings for (groups of) time pickers are maintained in an instance object,
28   allowing multiple different settings on the same page. */
29
30function Timepicker() {
31        this.regional = []; // Available regional settings, indexed by language code
32        this.regional[''] = { // Default regional settings
33                currentText: 'Now',
34                closeText: 'Done',
35                ampm: false,
36                amNames: ['AM', 'A'],
37                pmNames: ['PM', 'P'],
38                timeFormat: 'hh:mm tt',
39                timeSuffix: '',
40                timeOnlyTitle: 'Choose Time',
41                timeText: 'Time',
42                hourText: 'Hour',
43                minuteText: 'Minute',
44                secondText: 'Second',
45                millisecText: 'Millisecond',
46                timezoneText: 'Time Zone'
47        };
48        this._defaults = { // Global defaults for all the datetime picker instances
49                showButtonPanel: true,
50                timeOnly: false,
51                showHour: true,
52                showMinute: true,
53                showSecond: false,
54                showMillisec: false,
55                showTimezone: false,
56                showTime: true,
57                stepHour: 1,
58                stepMinute: 1,
59                stepSecond: 1,
60                stepMillisec: 1,
61                hour: 0,
62                minute: 0,
63                second: 0,
64                millisec: 0,
65                timezone: '+0000',
66                hourMin: 0,
67                minuteMin: 0,
68                secondMin: 0,
69                millisecMin: 0,
70                hourMax: 23,
71                minuteMax: 59,
72                secondMax: 59,
73                millisecMax: 999,
74                minDateTime: null,
75                maxDateTime: null,
76                onSelect: null,
77                hourGrid: 0,
78                minuteGrid: 0,
79                secondGrid: 0,
80                millisecGrid: 0,
81                alwaysSetTime: true,
82                separator: ' ',
83                altFieldTimeOnly: true,
84                showTimepicker: true,
85                timezoneIso8609: false,
86                timezoneList: null,
87                addSliderAccess: false,
88                sliderAccessArgs: null
89        };
90        $.extend(this._defaults, this.regional['']);
91}
92
93$.extend(Timepicker.prototype, {
94        $input: null,
95        $altInput: null,
96        $timeObj: null,
97        inst: null,
98        hour_slider: null,
99        minute_slider: null,
100        second_slider: null,
101        millisec_slider: null,
102        timezone_select: null,
103        hour: 0,
104        minute: 0,
105        second: 0,
106        millisec: 0,
107        timezone: '+0000',
108        hourMinOriginal: null,
109        minuteMinOriginal: null,
110        secondMinOriginal: null,
111        millisecMinOriginal: null,
112        hourMaxOriginal: null,
113        minuteMaxOriginal: null,
114        secondMaxOriginal: null,
115        millisecMaxOriginal: null,
116        ampm: '',
117        formattedDate: '',
118        formattedTime: '',
119        formattedDateTime: '',
120        timezoneList: null,
121
122        /* Override the default settings for all instances of the time picker.
123           @param  settings  object - the new settings to use as defaults (anonymous object)
124           @return the manager object */
125        setDefaults: function(settings) {
126                extendRemove(this._defaults, settings || {});
127                return this;
128        },
129
130        //########################################################################
131        // Create a new Timepicker instance
132        //########################################################################
133        _newInst: function($input, o) {
134                var tp_inst = new Timepicker(),
135                        inlineSettings = {};
136                       
137                for (var attrName in this._defaults) {
138                        var attrValue = $input.attr('time:' + attrName);
139                        if (attrValue) {
140                                try {
141                                        inlineSettings[attrName] = eval(attrValue);
142                                } catch (err) {
143                                        inlineSettings[attrName] = attrValue;
144                                }
145                        }
146                }
147                tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, {
148                        beforeShow: function(input, dp_inst) {
149                                if ($.isFunction(o.beforeShow))
150                                        o.beforeShow(input, dp_inst, tp_inst);
151                        },
152                        onChangeMonthYear: function(year, month, dp_inst) {
153                                // Update the time as well : this prevents the time from disappearing from the $input field.
154                                tp_inst._updateDateTime(dp_inst);
155                                if ($.isFunction(o.onChangeMonthYear))
156                                        o.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
157                        },
158                        onClose: function(dateText, dp_inst) {
159                                if (tp_inst.timeDefined === true && $input.val() != '')
160                                        tp_inst._updateDateTime(dp_inst);
161                                if ($.isFunction(o.onClose))
162                                        o.onClose.call($input[0], dateText, dp_inst, tp_inst);
163                        },
164                        timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
165                });
166                tp_inst.amNames = $.map(tp_inst._defaults.amNames, function(val) { return val.toUpperCase() });
167                tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function(val) { return val.toUpperCase() });
168
169                if (tp_inst._defaults.timezoneList === null) {
170                        var timezoneList = [];
171                        for (var i = -11; i <= 12; i++)
172                                timezoneList.push((i >= 0 ? '+' : '-') + ('0' + Math.abs(i).toString()).slice(-2) + '00');
173                        if (tp_inst._defaults.timezoneIso8609)
174                                timezoneList = $.map(timezoneList, function(val) {
175                                        return val == '+0000' ? 'Z' : (val.substring(0, 3) + ':' + val.substring(3));
176                                });
177                        tp_inst._defaults.timezoneList = timezoneList;
178                }
179
180                tp_inst.hour = tp_inst._defaults.hour;
181                tp_inst.minute = tp_inst._defaults.minute;
182                tp_inst.second = tp_inst._defaults.second;
183                tp_inst.millisec = tp_inst._defaults.millisec;
184                tp_inst.ampm = '';
185                tp_inst.$input = $input;
186
187                if (o.altField)
188                        tp_inst.$altInput = $(o.altField)
189                                .css({ cursor: 'pointer' })
190                                .focus(function(){ $input.trigger("focus"); });
191               
192                if(tp_inst._defaults.minDate==0 || tp_inst._defaults.minDateTime==0)
193                {
194                        tp_inst._defaults.minDate=new Date();
195                }
196                if(tp_inst._defaults.maxDate==0 || tp_inst._defaults.maxDateTime==0)
197                {
198                        tp_inst._defaults.maxDate=new Date();
199                }
200               
201                // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
202                if(tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date)
203                        tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
204                if(tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date)
205                        tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
206                if(tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date)
207                        tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
208                if(tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date)
209                        tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
210                return tp_inst;
211        },
212
213        //########################################################################
214        // add our sliders to the calendar
215        //########################################################################
216        _addTimePicker: function(dp_inst) {
217                var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ?
218                                this.$input.val() + ' ' + this.$altInput.val() :
219                                this.$input.val();
220
221                this.timeDefined = this._parseTime(currDT);
222                this._limitMinMaxDateTime(dp_inst, false);
223                this._injectTimePicker();
224        },
225
226        //########################################################################
227        // parse the time string from input value or _setTime
228        //########################################################################
229        _parseTime: function(timeString, withDate) {
230                var regstr = this._defaults.timeFormat.toString()
231                                .replace(/h{1,2}/ig, '(\\d?\\d)')
232                                .replace(/m{1,2}/ig, '(\\d?\\d)')
233                                .replace(/s{1,2}/ig, '(\\d?\\d)')
234                                .replace(/l{1}/ig, '(\\d?\\d?\\d)')
235                                .replace(/t{1,2}/ig, this._getPatternAmpm())
236                                .replace(/z{1}/ig, '(z|[-+]\\d\\d:?\\d\\d)?')
237                                .replace(/\s/g, '\\s?') + this._defaults.timeSuffix + '$',
238                        order = this._getFormatPositions(),
239                        ampm = '',
240                        treg;
241
242                if (!this.inst) this.inst = $.datepicker._getInst(this.$input[0]);
243
244                if (withDate || !this._defaults.timeOnly) {
245                        // the time should come after x number of characters and a space.
246                        // x = at least the length of text specified by the date format
247                        var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
248                        // escape special regex characters in the seperator
249                        var specials = new RegExp("[.*+?|()\\[\\]{}\\\\]", "g");
250                        regstr = '.{' + dp_dateFormat.length + ',}' + this._defaults.separator.replace(specials, "\\$&") + regstr;
251                }
252               
253                treg = timeString.match(new RegExp(regstr, 'i'));
254
255                if (treg) {
256                        if (order.t !== -1) {
257                                if (treg[order.t] === undefined || treg[order.t].length === 0) {
258                                        ampm = '';
259                                        this.ampm = '';
260                                } else {
261                                        ampm = $.inArray(treg[order.t].toUpperCase(), this.amNames) !== -1 ? 'AM' : 'PM';
262                                        this.ampm = this._defaults[ampm == 'AM' ? 'amNames' : 'pmNames'][0];
263                                }
264                        }
265
266                        if (order.h !== -1) {
267                                if (ampm == 'AM' && treg[order.h] == '12')
268                                        this.hour = 0; // 12am = 0 hour
269                                else if (ampm == 'PM' && treg[order.h] != '12')
270                                        this.hour = (parseFloat(treg[order.h]) + 12).toFixed(0); // 12pm = 12 hour, any other pm = hour + 12
271                                else this.hour = Number(treg[order.h]);
272                        }
273
274                        if (order.m !== -1) this.minute = Number(treg[order.m]);
275                        if (order.s !== -1) this.second = Number(treg[order.s]);
276                        if (order.l !== -1) this.millisec = Number(treg[order.l]);
277                        if (order.z !== -1 && treg[order.z] !== undefined) {
278                                var tz = treg[order.z].toUpperCase();
279                                switch (tz.length) {
280                                case 1: // Z
281                                        tz = this._defaults.timezoneIso8609 ? 'Z' : '+0000';
282                                        break;
283                                case 5: // +hhmm
284                                        if (this._defaults.timezoneIso8609)
285                                                tz = tz.substring(1) == '0000'
286                                                   ? 'Z'
287                                                   : tz.substring(0, 3) + ':' + tz.substring(3);
288                                        break;
289                                case 6: // +hh:mm
290                                        if (!this._defaults.timezoneIso8609)
291                                                tz = tz == 'Z' || tz.substring(1) == '00:00'
292                                                   ? '+0000'
293                                                   : tz.replace(/:/, '');
294                                        else if (tz.substring(1) == '00:00')
295                                                tz = 'Z';
296                                        break;
297                                }
298                                this.timezone = tz;
299                        }
300                       
301                        return true;
302
303                }
304                return false;
305        },
306
307        //########################################################################
308        // pattern for standard and localized AM/PM markers
309        //########################################################################
310        _getPatternAmpm: function() {
311                var markers = [];
312                        o = this._defaults;
313                if (o.amNames)
314                        $.merge(markers, o.amNames);
315                if (o.pmNames)
316                        $.merge(markers, o.pmNames);
317                markers = $.map(markers, function(val) { return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&') });
318                return '(' + markers.join('|') + ')?';
319        },
320
321        //########################################################################
322        // figure out position of time elements.. cause js cant do named captures
323        //########################################################################
324        _getFormatPositions: function() {
325                var finds = this._defaults.timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|t{1,2}|z)/g),
326                        orders = { h: -1, m: -1, s: -1, l: -1, t: -1, z: -1 };
327
328                if (finds)
329                        for (var i = 0; i < finds.length; i++)
330                                if (orders[finds[i].toString().charAt(0)] == -1)
331                                        orders[finds[i].toString().charAt(0)] = i + 1;
332
333                return orders;
334        },
335
336        //########################################################################
337        // generate and inject html for timepicker into ui datepicker
338        //########################################################################
339        _injectTimePicker: function() {
340                var $dp = this.inst.dpDiv,
341                        o = this._defaults,
342                        tp_inst = this,
343                        // Added by Peter Medeiros:
344                        // - Figure out what the hour/minute/second max should be based on the step values.
345                        // - Example: if stepMinute is 15, then minMax is 45.
346                        hourMax = parseInt((o.hourMax - ((o.hourMax - o.hourMin) % o.stepHour)) ,10),
347                        minMax  = parseInt((o.minuteMax - ((o.minuteMax - o.minuteMin) % o.stepMinute)) ,10),
348                        secMax  = parseInt((o.secondMax - ((o.secondMax - o.secondMin) % o.stepSecond)) ,10),
349                        millisecMax  = parseInt((o.millisecMax - ((o.millisecMax - o.millisecMin) % o.stepMillisec)) ,10),
350                        dp_id = this.inst.id.toString().replace(/([^A-Za-z0-9_])/g, '');
351
352                // Prevent displaying twice
353                //if ($dp.find("div#ui-timepicker-div-"+ dp_id).length === 0) {
354                if ($dp.find("div#ui-timepicker-div-"+ dp_id).length === 0 && o.showTimepicker) {
355                        var noDisplay = ' style="display:none;"',
356                                html =  '<div class="ui-timepicker-div" id="ui-timepicker-div-' + dp_id + '"><dl>' +
357                                                '<dt class="ui_tpicker_time_label" id="ui_tpicker_time_label_' + dp_id + '"' +
358                                                ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' +
359                                                '<dd class="ui_tpicker_time" id="ui_tpicker_time_' + dp_id + '"' +
360                                                ((o.showTime) ? '' : noDisplay) + '></dd>' +
361                                                '<dt class="ui_tpicker_hour_label" id="ui_tpicker_hour_label_' + dp_id + '"' +
362                                                ((o.showHour) ? '' : noDisplay) + '>' + o.hourText + '</dt>',
363                                hourGridSize = 0,
364                                minuteGridSize = 0,
365                                secondGridSize = 0,
366                                millisecGridSize = 0,
367                                size;
368
369                        // Hours
370                        html += '<dd class="ui_tpicker_hour"><div id="ui_tpicker_hour_' + dp_id + '"' +
371                                                ((o.showHour) ? '' : noDisplay) + '></div>';
372                        if (o.showHour && o.hourGrid > 0) {
373                                html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
374
375                                for (var h = o.hourMin; h <= hourMax; h += parseInt(o.hourGrid,10)) {
376                                        hourGridSize++;
377                                        var tmph = (o.ampm && h > 12) ? h-12 : h;
378                                        if (tmph < 10) tmph = '0' + tmph;
379                                        if (o.ampm) {
380                                                if (h == 0) tmph = 12 +'a';
381                                                else if (h < 12) tmph += 'a';
382                                                else tmph += 'p';
383                                        }
384                                        html += '<td>' + tmph + '</td>';
385                                }
386
387                                html += '</tr></table></div>';
388                        }
389                        html += '</dd>';
390
391                        // Minutes
392                        html += '<dt class="ui_tpicker_minute_label" id="ui_tpicker_minute_label_' + dp_id + '"' +
393                                        ((o.showMinute) ? '' : noDisplay) + '>' + o.minuteText + '</dt>'+
394                                        '<dd class="ui_tpicker_minute"><div id="ui_tpicker_minute_' + dp_id + '"' +
395                                                        ((o.showMinute) ? '' : noDisplay) + '></div>';
396
397                        if (o.showMinute && o.minuteGrid > 0) {
398                                html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
399
400                                for (var m = o.minuteMin; m <= minMax; m += parseInt(o.minuteGrid,10)) {
401                                        minuteGridSize++;
402                                        html += '<td>' + ((m < 10) ? '0' : '') + m + '</td>';
403                                }
404
405                                html += '</tr></table></div>';
406                        }
407                        html += '</dd>';
408
409                        // Seconds
410                        html += '<dt class="ui_tpicker_second_label" id="ui_tpicker_second_label_' + dp_id + '"' +
411                                        ((o.showSecond) ? '' : noDisplay) + '>' + o.secondText + '</dt>'+
412                                        '<dd class="ui_tpicker_second"><div id="ui_tpicker_second_' + dp_id + '"'+
413                                                        ((o.showSecond) ? '' : noDisplay) + '></div>';
414
415                        if (o.showSecond && o.secondGrid > 0) {
416                                html += '<div style="padding-left: 1px"><table><tr>';
417
418                                for (var s = o.secondMin; s <= secMax; s += parseInt(o.secondGrid,10)) {
419                                        secondGridSize++;
420                                        html += '<td>' + ((s < 10) ? '0' : '') + s + '</td>';
421                                }
422
423                                html += '</tr></table></div>';
424                        }
425                        html += '</dd>';
426
427                        // Milliseconds
428                        html += '<dt class="ui_tpicker_millisec_label" id="ui_tpicker_millisec_label_' + dp_id + '"' +
429                                        ((o.showMillisec) ? '' : noDisplay) + '>' + o.millisecText + '</dt>'+
430                                        '<dd class="ui_tpicker_millisec"><div id="ui_tpicker_millisec_' + dp_id + '"'+
431                                                        ((o.showMillisec) ? '' : noDisplay) + '></div>';
432
433                        if (o.showMillisec && o.millisecGrid > 0) {
434                                html += '<div style="padding-left: 1px"><table><tr>';
435
436                                for (var l = o.millisecMin; l <= millisecMax; l += parseInt(o.millisecGrid,10)) {
437                                        millisecGridSize++;
438                                        html += '<td>' + ((l < 10) ? '0' : '') + l + '</td>';
439                                }
440
441                                html += '</tr></table></div>';
442                        }
443                        html += '</dd>';
444
445                        // Timezone
446                        html += '<dt class="ui_tpicker_timezone_label" id="ui_tpicker_timezone_label_' + dp_id + '"' +
447                                        ((o.showTimezone) ? '' : noDisplay) + '>' + o.timezoneText + '</dt>';
448                        html += '<dd class="ui_tpicker_timezone" id="ui_tpicker_timezone_' + dp_id + '"'        +
449                                                        ((o.showTimezone) ? '' : noDisplay) + '></dd>';
450
451                        html += '</dl></div>';
452                        $tp = $(html);
453
454                                // if we only want time picker...
455                        if (o.timeOnly === true) {
456                                $tp.prepend(
457                                        '<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' +
458                                                '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' +
459                                        '</div>');
460                                $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
461                        }
462
463                        this.hour_slider = $tp.find('#ui_tpicker_hour_'+ dp_id).slider({
464                                orientation: "horizontal",
465                                value: this.hour,
466                                min: o.hourMin,
467                                max: hourMax,
468                                step: o.stepHour,
469                                slide: function(event, ui) {
470                                        tp_inst.hour_slider.slider( "option", "value", ui.value);
471                                        tp_inst._onTimeChange();
472                                }
473                        });
474
475                       
476                        // Updated by Peter Medeiros:
477                        // - Pass in Event and UI instance into slide function
478                        this.minute_slider = $tp.find('#ui_tpicker_minute_'+ dp_id).slider({
479                                orientation: "horizontal",
480                                value: this.minute,
481                                min: o.minuteMin,
482                                max: minMax,
483                                step: o.stepMinute,
484                                slide: function(event, ui) {
485                                        tp_inst.minute_slider.slider( "option", "value", ui.value);
486                                        tp_inst._onTimeChange();
487                                }
488                        });
489
490                        this.second_slider = $tp.find('#ui_tpicker_second_'+ dp_id).slider({
491                                orientation: "horizontal",
492                                value: this.second,
493                                min: o.secondMin,
494                                max: secMax,
495                                step: o.stepSecond,
496                                slide: function(event, ui) {
497                                        tp_inst.second_slider.slider( "option", "value", ui.value);
498                                        tp_inst._onTimeChange();
499                                }
500                        });
501
502                        this.millisec_slider = $tp.find('#ui_tpicker_millisec_'+ dp_id).slider({
503                                orientation: "horizontal",
504                                value: this.millisec,
505                                min: o.millisecMin,
506                                max: millisecMax,
507                                step: o.stepMillisec,
508                                slide: function(event, ui) {
509                                        tp_inst.millisec_slider.slider( "option", "value", ui.value);
510                                        tp_inst._onTimeChange();
511                                }
512                        });
513
514                        this.timezone_select = $tp.find('#ui_tpicker_timezone_'+ dp_id).append('<select></select>').find("select");
515                        $.fn.append.apply(this.timezone_select,
516                                $.map(o.timezoneList, function(val, idx) {
517                                        return $("<option />")
518                                                .val(typeof val == "object" ? val.value : val)
519                                                .text(typeof val == "object" ? val.label : val);
520                                })
521                        );
522                        this.timezone_select.val((typeof this.timezone != "undefined" && this.timezone != null && this.timezone != "") ? this.timezone : o.timezone);
523                        this.timezone_select.change(function() {
524                                tp_inst._onTimeChange();
525                        });
526
527                        // Add grid functionality
528                        if (o.showHour && o.hourGrid > 0) {
529                                size = 100 * hourGridSize * o.hourGrid / (hourMax - o.hourMin);
530
531                                $tp.find(".ui_tpicker_hour table").css({
532                                        width: size + "%",
533                                        marginLeft: (size / (-2 * hourGridSize)) + "%",
534                                        borderCollapse: 'collapse'
535                                }).find("td").each( function(index) {
536                                        $(this).click(function() {
537                                                var h = $(this).html();
538                                                if(o.ampm)      {
539                                                        var ap = h.substring(2).toLowerCase(),
540                                                                aph = parseInt(h.substring(0,2), 10);
541                                                        if (ap == 'a') {
542                                                                if (aph == 12) h = 0;
543                                                                else h = aph;
544                                                        } else if (aph == 12) h = 12;
545                                                        else h = aph + 12;
546                                                }
547                                                tp_inst.hour_slider.slider("option", "value", h);
548                                                tp_inst._onTimeChange();
549                                                tp_inst._onSelectHandler();
550                                        }).css({
551                                                cursor: 'pointer',
552                                                width: (100 / hourGridSize) + '%',
553                                                textAlign: 'center',
554                                                overflow: 'hidden'
555                                        });
556                                });
557                        }
558
559                        if (o.showMinute && o.minuteGrid > 0) {
560                                size = 100 * minuteGridSize * o.minuteGrid / (minMax - o.minuteMin);
561                                $tp.find(".ui_tpicker_minute table").css({
562                                        width: size + "%",
563                                        marginLeft: (size / (-2 * minuteGridSize)) + "%",
564                                        borderCollapse: 'collapse'
565                                }).find("td").each(function(index) {
566                                        $(this).click(function() {
567                                                tp_inst.minute_slider.slider("option", "value", $(this).html());
568                                                tp_inst._onTimeChange();
569                                                tp_inst._onSelectHandler();
570                                        }).css({
571                                                cursor: 'pointer',
572                                                width: (100 / minuteGridSize) + '%',
573                                                textAlign: 'center',
574                                                overflow: 'hidden'
575                                        });
576                                });
577                        }
578
579                        if (o.showSecond && o.secondGrid > 0) {
580                                $tp.find(".ui_tpicker_second table").css({
581                                        width: size + "%",
582                                        marginLeft: (size / (-2 * secondGridSize)) + "%",
583                                        borderCollapse: 'collapse'
584                                }).find("td").each(function(index) {
585                                        $(this).click(function() {
586                                                tp_inst.second_slider.slider("option", "value", $(this).html());
587                                                tp_inst._onTimeChange();
588                                                tp_inst._onSelectHandler();
589                                        }).css({
590                                                cursor: 'pointer',
591                                                width: (100 / secondGridSize) + '%',
592                                                textAlign: 'center',
593                                                overflow: 'hidden'
594                                        });
595                                });
596                        }
597
598                        if (o.showMillisec && o.millisecGrid > 0) {
599                                $tp.find(".ui_tpicker_millisec table").css({
600                                        width: size + "%",
601                                        marginLeft: (size / (-2 * millisecGridSize)) + "%",
602                                        borderCollapse: 'collapse'
603                                }).find("td").each(function(index) {
604                                        $(this).click(function() {
605                                                tp_inst.millisec_slider.slider("option", "value", $(this).html());
606                                                tp_inst._onTimeChange();
607                                                tp_inst._onSelectHandler();
608                                        }).css({
609                                                cursor: 'pointer',
610                                                width: (100 / millisecGridSize) + '%',
611                                                textAlign: 'center',
612                                                overflow: 'hidden'
613                                        });
614                                });
615                        }
616
617                        var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
618                        if ($buttonPanel.length) $buttonPanel.before($tp);
619                        else $dp.append($tp);
620
621                        this.$timeObj = $tp.find('#ui_tpicker_time_'+ dp_id);
622
623                        if (this.inst !== null) {
624                                var timeDefined = this.timeDefined;
625                                this._onTimeChange();
626                                this.timeDefined = timeDefined;
627                        }
628
629                        //Emulate datepicker onSelect behavior. Call on slidestop.
630                        var onSelectDelegate = function() {
631                                tp_inst._onSelectHandler();
632                        };
633                        this.hour_slider.bind('slidestop',onSelectDelegate);
634                        this.minute_slider.bind('slidestop',onSelectDelegate);
635                        this.second_slider.bind('slidestop',onSelectDelegate);
636                        this.millisec_slider.bind('slidestop',onSelectDelegate);
637                       
638                        // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
639                        if (this._defaults.addSliderAccess){
640                                var sliderAccessArgs = this._defaults.sliderAccessArgs;
641                                setTimeout(function(){ // fix for inline mode
642                                        if($tp.find('.ui-slider-access').length == 0){
643                                                $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);
644
645                                                // fix any grids since sliders are shorter
646                                                var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);
647                                                if(sliderAccessWidth){
648                                                        $tp.find('table:visible').each(function(){
649                                                                var $g = $(this),
650                                                                        oldWidth = $g.outerWidth(),
651                                                                        oldMarginLeft = $g.css('marginLeft').toString().replace('%',''),
652                                                                        newWidth = oldWidth - sliderAccessWidth,
653                                                                        newMarginLeft = ((oldMarginLeft * newWidth)/oldWidth) + '%';
654                                               
655                                                                $g.css({ width: newWidth, marginLeft: newMarginLeft });
656                                                        });
657                                                }
658                                        }
659                                },0);
660                        }
661                        // end slideAccess integration
662                       
663                }
664        },
665
666        //########################################################################
667        // This function tries to limit the ability to go outside the
668        // min/max date range
669        //########################################################################
670        _limitMinMaxDateTime: function(dp_inst, adjustSliders){
671                var o = this._defaults,
672                        dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
673
674                if(!this._defaults.showTimepicker) return; // No time so nothing to check here
675
676                if($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date){
677                        var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),
678                                minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
679
680                        if(this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null){
681                                this.hourMinOriginal = o.hourMin;
682                                this.minuteMinOriginal = o.minuteMin;
683                                this.secondMinOriginal = o.secondMin;
684                                this.millisecMinOriginal = o.millisecMin;
685                        }
686
687                        if(dp_inst.settings.timeOnly || minDateTimeDate.getTime() == dp_date.getTime()) {
688                                this._defaults.hourMin = minDateTime.getHours();
689                                if (this.hour <= this._defaults.hourMin) {
690                                        this.hour = this._defaults.hourMin;
691                                        this._defaults.minuteMin = minDateTime.getMinutes();
692                                        if (this.minute <= this._defaults.minuteMin) {
693                                                this.minute = this._defaults.minuteMin;
694                                                this._defaults.secondMin = minDateTime.getSeconds();
695                                        } else if (this.second <= this._defaults.secondMin){
696                                                this.second = this._defaults.secondMin;
697                                                this._defaults.millisecMin = minDateTime.getMilliseconds();
698                                        } else {
699                                                if(this.millisec < this._defaults.millisecMin)
700                                                        this.millisec = this._defaults.millisecMin;
701                                                this._defaults.millisecMin = this.millisecMinOriginal;
702                                        }
703                                } else {
704                                        this._defaults.minuteMin = this.minuteMinOriginal;
705                                        this._defaults.secondMin = this.secondMinOriginal;
706                                        this._defaults.millisecMin = this.millisecMinOriginal;
707                                }
708                        }else{
709                                this._defaults.hourMin = this.hourMinOriginal;
710                                this._defaults.minuteMin = this.minuteMinOriginal;
711                                this._defaults.secondMin = this.secondMinOriginal;
712                                this._defaults.millisecMin = this.millisecMinOriginal;
713                        }
714                }
715
716                if($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date){
717                        var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),
718                                maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
719
720                        if(this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null){
721                                this.hourMaxOriginal = o.hourMax;
722                                this.minuteMaxOriginal = o.minuteMax;
723                                this.secondMaxOriginal = o.secondMax;
724                                this.millisecMaxOriginal = o.millisecMax;
725                        }
726
727                        if(dp_inst.settings.timeOnly || maxDateTimeDate.getTime() == dp_date.getTime()){
728                                this._defaults.hourMax = maxDateTime.getHours();
729                                if (this.hour >= this._defaults.hourMax) {
730                                        this.hour = this._defaults.hourMax;
731                                        this._defaults.minuteMax = maxDateTime.getMinutes();
732                                        if (this.minute >= this._defaults.minuteMax) {
733                                                this.minute = this._defaults.minuteMax;
734                                                this._defaults.secondMax = maxDateTime.getSeconds();
735                                        } else if (this.second >= this._defaults.secondMax) {
736                                                this.second = this._defaults.secondMax;
737                                                this._defaults.millisecMax = maxDateTime.getMilliseconds();
738                                        } else {
739                                                if(this.millisec > this._defaults.millisecMax) this.millisec = this._defaults.millisecMax;
740                                                this._defaults.millisecMax = this.millisecMaxOriginal;
741                                        }
742                                } else {
743                                        this._defaults.minuteMax = this.minuteMaxOriginal;
744                                        this._defaults.secondMax = this.secondMaxOriginal;
745                                        this._defaults.millisecMax = this.millisecMaxOriginal;
746                                }
747                        }else{
748                                this._defaults.hourMax = this.hourMaxOriginal;
749                                this._defaults.minuteMax = this.minuteMaxOriginal;
750                                this._defaults.secondMax = this.secondMaxOriginal;
751                                this._defaults.millisecMax = this.millisecMaxOriginal;
752                        }
753                }
754
755                if(adjustSliders !== undefined && adjustSliders === true){
756                        var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)) ,10),
757                minMax  = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)) ,10),
758                secMax  = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)) ,10),
759                                millisecMax  = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)) ,10);
760
761                        if(this.hour_slider)
762                                this.hour_slider.slider("option", { min: this._defaults.hourMin, max: hourMax }).slider('value', this.hour);
763                        if(this.minute_slider)
764                                this.minute_slider.slider("option", { min: this._defaults.minuteMin, max: minMax }).slider('value', this.minute);
765                        if(this.second_slider)
766                                this.second_slider.slider("option", { min: this._defaults.secondMin, max: secMax }).slider('value', this.second);
767                        if(this.millisec_slider)
768                                this.millisec_slider.slider("option", { min: this._defaults.millisecMin, max: millisecMax }).slider('value', this.millisec);
769                }
770
771        },
772
773       
774        //########################################################################
775        // when a slider moves, set the internal time...
776        // on time change is also called when the time is updated in the text field
777        //########################################################################
778        _onTimeChange: function() {
779                var hour   = (this.hour_slider) ? this.hour_slider.slider('value') : false,
780                        minute = (this.minute_slider) ? this.minute_slider.slider('value') : false,
781                        second = (this.second_slider) ? this.second_slider.slider('value') : false,
782                        millisec = (this.millisec_slider) ? this.millisec_slider.slider('value') : false,
783                        timezone = (this.timezone_select) ? this.timezone_select.val() : false,
784                        o = this._defaults;
785
786                if (typeof(hour) == 'object') hour = false;
787                if (typeof(minute) == 'object') minute = false;
788                if (typeof(second) == 'object') second = false;
789                if (typeof(millisec) == 'object') millisec = false;
790                if (typeof(timezone) == 'object') timezone = false;
791
792                if (hour !== false) hour = parseInt(hour,10);
793                if (minute !== false) minute = parseInt(minute,10);
794                if (second !== false) second = parseInt(second,10);
795                if (millisec !== false) millisec = parseInt(millisec,10);
796
797                var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];
798
799                // If the update was done in the input field, the input field should not be updated.
800                // If the update was done using the sliders, update the input field.
801                var hasChanged = (hour != this.hour || minute != this.minute
802                                || second != this.second || millisec != this.millisec
803                                || (this.ampm.length > 0
804                                    && (hour < 12) != ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1))
805                                || timezone != this.timezone);
806               
807                if (hasChanged) {
808
809                        if (hour !== false)this.hour = hour;
810                        if (minute !== false) this.minute = minute;
811                        if (second !== false) this.second = second;
812                        if (millisec !== false) this.millisec = millisec;
813                        if (timezone !== false) this.timezone = timezone;
814                       
815                        if (!this.inst) this.inst = $.datepicker._getInst(this.$input[0]);
816                       
817                        this._limitMinMaxDateTime(this.inst, true);
818                }
819                if (o.ampm) this.ampm = ampm;
820               
821                this._formatTime();
822                if (this.$timeObj) this.$timeObj.text(this.formattedTime + o.timeSuffix);
823                this.timeDefined = true;
824                if (hasChanged) this._updateDateTime();
825        },
826   
827        //########################################################################
828        // call custom onSelect.
829        // bind to sliders slidestop, and grid click.
830        //########################################################################
831        _onSelectHandler: function() {
832                var onSelect = this._defaults.onSelect;
833                var inputEl = this.$input ? this.$input[0] : null;
834                if (onSelect && inputEl) {
835                        onSelect.apply(inputEl, [this.formattedDateTime, this]);
836                }
837        },
838
839        //########################################################################
840        // format the time all pretty...
841        //########################################################################
842        _formatTime: function(time, format, ampm) {
843                if (ampm == undefined) ampm = this._defaults.ampm;
844                time = time || { hour: this.hour, minute: this.minute, second: this.second, millisec: this.millisec, ampm: this.ampm, timezone: this.timezone };
845                var tmptime = (format || this._defaults.timeFormat).toString();
846
847                var hour = parseInt(time.hour, 10);
848                if (ampm) {
849                        if (!$.inArray(time.ampm.toUpperCase(), this.amNames) !== -1)
850                                hour = hour % 12;
851                        if (hour === 0)
852                                hour = 12;
853                }
854                tmptime = tmptime.replace(/(?:hh?|mm?|ss?|[tT]{1,2}|[lz])/g, function(match) {
855                        switch (match.toLowerCase()) {
856                                case 'hh': return ('0' + hour).slice(-2);
857                                case 'h':  return hour;
858                                case 'mm': return ('0' + time.minute).slice(-2);
859                                case 'm':  return time.minute;
860                                case 'ss': return ('0' + time.second).slice(-2);
861                                case 's':  return time.second;
862                                case 'l':  return ('00' + time.millisec).slice(-3);
863                                case 'z':  return time.timezone;
864                                case 't': case 'tt':
865                                        if (ampm) {
866                                                var _ampm = time.ampm;
867                                                if (match.length == 1)
868                                                        _ampm = _ampm.charAt(0);
869                                                return match.charAt(0) == 'T' ? _ampm.toUpperCase() : _ampm.toLowerCase();
870                                        }
871                                        return '';
872                        }
873                });
874
875                if (arguments.length) return tmptime;
876                else this.formattedTime = tmptime;
877        },
878
879        //########################################################################
880        // update our input with the new date time..
881        //########################################################################
882        _updateDateTime: function(dp_inst) {
883                dp_inst = this.inst || dp_inst;
884                var dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
885                        dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
886                        formatCfg = $.datepicker._getFormatConfig(dp_inst),
887                        timeAvailable = dt !== null && this.timeDefined;
888                this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
889                var formattedDateTime = this.formattedDate;
890                if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0))
891                        return;
892
893                if (this._defaults.timeOnly === true) {
894                        formattedDateTime = this.formattedTime;
895                } else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) {
896                        formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;
897                }
898
899                this.formattedDateTime = formattedDateTime;
900
901                if(!this._defaults.showTimepicker) {
902                        this.$input.val(this.formattedDate);
903                } else if (this.$altInput && this._defaults.altFieldTimeOnly === true) {
904                        this.$altInput.val(this.formattedTime);
905                        this.$input.val(this.formattedDate);
906                } else if(this.$altInput) {
907                        this.$altInput.val(formattedDateTime);
908                        this.$input.val(formattedDateTime);
909                } else {
910                        this.$input.val(formattedDateTime);
911                }
912               
913                this.$input.trigger("change");
914        }
915
916});
917
918$.fn.extend({
919        //########################################################################
920        // shorthand just to use timepicker..
921        //########################################################################
922        timepicker: function(o) {
923                o = o || {};
924                var tmp_args = arguments;
925
926                if (typeof o == 'object') tmp_args[0] = $.extend(o, { timeOnly: true });
927
928                return $(this).each(function() {
929                        $.fn.datetimepicker.apply($(this), tmp_args);
930                });
931        },
932
933        //########################################################################
934        // extend timepicker to datepicker
935        //########################################################################
936        datetimepicker: function(o) {
937                o = o || {};
938                var $input = this,
939                tmp_args = arguments;
940
941                if (typeof(o) == 'string'){
942                        if(o == 'getDate')
943                                return $.fn.datepicker.apply($(this[0]), tmp_args);
944                        else
945                                return this.each(function() {
946                                        var $t = $(this);
947                                        $t.datepicker.apply($t, tmp_args);
948                                });
949                }
950                else
951                        return this.each(function() {
952                                var $t = $(this);
953                                $t.datepicker($.timepicker._newInst($t, o)._defaults);
954                        });
955        }
956});
957
958//########################################################################
959// the bad hack :/ override datepicker so it doesnt close on select
960// inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
961//########################################################################
962$.datepicker._base_selectDate = $.datepicker._selectDate;
963$.datepicker._selectDate = function (id, dateStr) {
964        var inst = this._getInst($(id)[0]),
965                tp_inst = this._get(inst, 'timepicker');
966
967        if (tp_inst) {
968                tp_inst._limitMinMaxDateTime(inst, true);
969                inst.inline = inst.stay_open = true;
970                //This way the onSelect handler called from calendarpicker get the full dateTime
971                this._base_selectDate(id, dateStr);
972                inst.inline = inst.stay_open = false;
973                this._notifyChange(inst);
974                this._updateDatepicker(inst);
975        }
976        else this._base_selectDate(id, dateStr);
977};
978
979//#############################################################################################
980// second bad hack :/ override datepicker so it triggers an event when changing the input field
981// and does not redraw the datepicker on every selectDate event
982//#############################################################################################
983$.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
984$.datepicker._updateDatepicker = function(inst) {
985
986        // don't popup the datepicker if there is another instance already opened
987        var input = inst.input[0];
988        if($.datepicker._curInst &&
989           $.datepicker._curInst != inst &&
990           $.datepicker._datepickerShowing &&
991           $.datepicker._lastInput != input) {
992                return;
993        }
994
995        if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
996                               
997                this._base_updateDatepicker(inst);
998               
999                // Reload the time control when changing something in the input text field.
1000                var tp_inst = this._get(inst, 'timepicker');
1001                if(tp_inst) tp_inst._addTimePicker(inst);
1002        }
1003};
1004
1005//#######################################################################################
1006// third bad hack :/ override datepicker so it allows spaces and colon in the input field
1007//#######################################################################################
1008$.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
1009$.datepicker._doKeyPress = function(event) {
1010        var inst = $.datepicker._getInst(event.target),
1011                tp_inst = $.datepicker._get(inst, 'timepicker');
1012
1013        if (tp_inst) {
1014                if ($.datepicker._get(inst, 'constrainInput')) {
1015                        var ampm = tp_inst._defaults.ampm,
1016                                dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
1017                                datetimeChars = tp_inst._defaults.timeFormat.toString()
1018                                                                .replace(/[hms]/g, '')
1019                                                                .replace(/TT/g, ampm ? 'APM' : '')
1020                                                                .replace(/Tt/g, ampm ? 'AaPpMm' : '')
1021                                                                .replace(/tT/g, ampm ? 'AaPpMm' : '')
1022                                                                .replace(/T/g, ampm ? 'AP' : '')
1023                                                                .replace(/tt/g, ampm ? 'apm' : '')
1024                                                                .replace(/t/g, ampm ? 'ap' : '') +
1025                                                                " " +
1026                                                                tp_inst._defaults.separator +
1027                                                                tp_inst._defaults.timeSuffix +
1028                                                                (tp_inst._defaults.showTimezone ? tp_inst._defaults.timezoneList.join('') : '') +
1029                                                                (tp_inst._defaults.amNames.join('')) +
1030                                                                (tp_inst._defaults.pmNames.join('')) +
1031                                                                dateChars,
1032                                chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
1033                        return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);
1034                }
1035        }
1036       
1037        return $.datepicker._base_doKeyPress(event);
1038};
1039
1040//#######################################################################################
1041// Override key up event to sync manual input changes.
1042//#######################################################################################
1043$.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
1044$.datepicker._doKeyUp = function (event) {
1045        var inst = $.datepicker._getInst(event.target),
1046                tp_inst = $.datepicker._get(inst, 'timepicker');
1047
1048        if (tp_inst) {
1049                if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) {
1050                        try {
1051                                $.datepicker._updateDatepicker(inst);
1052                        }
1053                        catch (err) {
1054                                $.datepicker.log(err);
1055                        }
1056                }
1057        }
1058
1059        return $.datepicker._base_doKeyUp(event);
1060};
1061
1062//#######################################################################################
1063// override "Today" button to also grab the time.
1064//#######################################################################################
1065$.datepicker._base_gotoToday = $.datepicker._gotoToday;
1066$.datepicker._gotoToday = function(id) {
1067        var inst = this._getInst($(id)[0]),
1068                $dp = inst.dpDiv;
1069        this._base_gotoToday(id);
1070        var now = new Date();
1071        var tp_inst = this._get(inst, 'timepicker');
1072        if (tp_inst._defaults.showTimezone && tp_inst.timezone_select) {
1073                var tzoffset = now.getTimezoneOffset(); // If +0100, returns -60
1074                var tzsign = tzoffset > 0 ? '-' : '+';
1075                tzoffset = Math.abs(tzoffset);
1076                var tzmin = tzoffset % 60
1077                tzoffset = tzsign + ('0' + (tzoffset - tzmin) / 60).slice(-2) + ('0' + tzmin).slice(-2);
1078                if (tp_inst._defaults.timezoneIso8609)
1079                        tzoffset = tzoffset.substring(0, 3) + ':' + tzoffset.substring(3);
1080                tp_inst.timezone_select.val(tzoffset);
1081        }
1082        this._setTime(inst, now);
1083        $( '.ui-datepicker-today', $dp).click();
1084};
1085
1086//#######################################################################################
1087// Disable & enable the Time in the datetimepicker
1088//#######################################################################################
1089$.datepicker._disableTimepickerDatepicker = function(target, date, withDate) {
1090        var inst = this._getInst(target),
1091        tp_inst = this._get(inst, 'timepicker');
1092        $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
1093        if (tp_inst) {
1094                tp_inst._defaults.showTimepicker = false;
1095                tp_inst._updateDateTime(inst);
1096        }
1097};
1098
1099$.datepicker._enableTimepickerDatepicker = function(target, date, withDate) {
1100        var inst = this._getInst(target),
1101        tp_inst = this._get(inst, 'timepicker');
1102        $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
1103        if (tp_inst) {
1104                tp_inst._defaults.showTimepicker = true;
1105                tp_inst._addTimePicker(inst); // Could be disabled on page load
1106                tp_inst._updateDateTime(inst);
1107        }
1108};
1109
1110//#######################################################################################
1111// Create our own set time function
1112//#######################################################################################
1113$.datepicker._setTime = function(inst, date) {
1114        var tp_inst = this._get(inst, 'timepicker');
1115        if (tp_inst) {
1116                var defaults = tp_inst._defaults,
1117                        // calling _setTime with no date sets time to defaults
1118                        hour = date ? date.getHours() : defaults.hour,
1119                        minute = date ? date.getMinutes() : defaults.minute,
1120                        second = date ? date.getSeconds() : defaults.second,
1121                        millisec = date ? date.getMilliseconds() : defaults.millisec;
1122
1123                //check if within min/max times..
1124                if ((hour < defaults.hourMin || hour > defaults.hourMax) || (minute < defaults.minuteMin || minute > defaults.minuteMax) || (second < defaults.secondMin || second > defaults.secondMax) || (millisec < defaults.millisecMin || millisec > defaults.millisecMax)) {
1125                        hour = defaults.hourMin;
1126                        minute = defaults.minuteMin;
1127                        second = defaults.secondMin;
1128                        millisec = defaults.millisecMin;
1129                }
1130
1131                tp_inst.hour = hour;
1132                tp_inst.minute = minute;
1133                tp_inst.second = second;
1134                tp_inst.millisec = millisec;
1135
1136                if (tp_inst.hour_slider) tp_inst.hour_slider.slider('value', hour);
1137                if (tp_inst.minute_slider) tp_inst.minute_slider.slider('value', minute);
1138                if (tp_inst.second_slider) tp_inst.second_slider.slider('value', second);
1139                if (tp_inst.millisec_slider) tp_inst.millisec_slider.slider('value', millisec);
1140
1141                tp_inst._onTimeChange();
1142                tp_inst._updateDateTime(inst);
1143        }
1144};
1145
1146//#######################################################################################
1147// Create new public method to set only time, callable as $().datepicker('setTime', date)
1148//#######################################################################################
1149$.datepicker._setTimeDatepicker = function(target, date, withDate) {
1150        var inst = this._getInst(target),
1151                tp_inst = this._get(inst, 'timepicker');
1152
1153        if (tp_inst) {
1154                this._setDateFromField(inst);
1155                var tp_date;
1156                if (date) {
1157                        if (typeof date == "string") {
1158                                tp_inst._parseTime(date, withDate);
1159                                tp_date = new Date();
1160                                tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
1161                        }
1162                        else tp_date = new Date(date.getTime());
1163                        if (tp_date.toString() == 'Invalid Date') tp_date = undefined;
1164                        this._setTime(inst, tp_date);
1165                }
1166        }
1167
1168};
1169
1170//#######################################################################################
1171// override setDate() to allow setting time too within Date object
1172//#######################################################################################
1173$.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
1174$.datepicker._setDateDatepicker = function(target, date) {
1175        var inst = this._getInst(target),
1176        tp_date = (date instanceof Date) ? new Date(date.getTime()) : date;
1177
1178        this._updateDatepicker(inst);
1179        this._base_setDateDatepicker.apply(this, arguments);
1180        this._setTimeDatepicker(target, tp_date, true);
1181};
1182
1183//#######################################################################################
1184// override getDate() to allow getting time too within Date object
1185//#######################################################################################
1186$.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
1187$.datepicker._getDateDatepicker = function(target, noDefault) {
1188        var inst = this._getInst(target),
1189                tp_inst = this._get(inst, 'timepicker');
1190
1191        if (tp_inst) {
1192                this._setDateFromField(inst, noDefault);
1193                var date = this._getDate(inst);
1194                if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
1195                return date;
1196        }
1197        return this._base_getDateDatepicker(target, noDefault);
1198};
1199
1200//#######################################################################################
1201// override parseDate() because UI 1.8.14 throws an error about "Extra characters"
1202// An option in datapicker to ignore extra format characters would be nicer.
1203//#######################################################################################
1204$.datepicker._base_parseDate = $.datepicker.parseDate;
1205$.datepicker.parseDate = function(format, value, settings) {
1206        var date;
1207        try {
1208                date = this._base_parseDate(format, value, settings);
1209        } catch (err) {
1210                // Hack!  The error message ends with a colon, a space, and
1211                // the "extra" characters.  We rely on that instead of
1212                // attempting to perfectly reproduce the parsing algorithm.
1213                date = this._base_parseDate(format, value.substring(0,value.length-(err.length-err.indexOf(':')-2)), settings);
1214        }
1215        return date;
1216};
1217
1218//#######################################################################################
1219// override formatDate to set date with time to the input
1220//#######################################################################################
1221$.datepicker._base_formatDate=$.datepicker._formatDate;
1222$.datepicker._formatDate = function(inst, day, month, year){
1223        var tp_inst = this._get(inst, 'timepicker');
1224        if(tp_inst)
1225        {
1226                if(day)
1227                        var b = this._base_formatDate(inst, day, month, year);
1228                tp_inst._updateDateTime(inst); 
1229                return tp_inst.$input.val();
1230        }
1231        return this._base_formatDate(inst);
1232}
1233
1234//#######################################################################################
1235// override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
1236//#######################################################################################
1237$.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
1238$.datepicker._optionDatepicker = function(target, name, value) {
1239        var inst = this._getInst(target),
1240                tp_inst = this._get(inst, 'timepicker');
1241        if (tp_inst) {
1242                var min,max,onselect;
1243                if (typeof name == 'string') { // if min/max was set with the string
1244                        if (name==='minDate' || name==='minDateTime' )
1245                                min = value;
1246                        else if (name==='maxDate' || name==='maxDateTime')
1247                                max = value;
1248                        else if (name==='onSelect')
1249                                onselect=value;
1250                } else if (typeof name == 'object') { //if min/max was set with the JSON
1251                        if(name.minDate)
1252                                min = name.minDate;
1253                        else if (name.minDateTime)
1254                                min = name.minDateTime;
1255                        else if (name.maxDate)
1256                                max = name.maxDate;
1257                        else if (name.maxDateTime)
1258                                max = name.maxDateTime;
1259                }
1260                if(min){ //if min was set
1261                        if(min==0)
1262                                min=new Date();
1263                        else
1264                                min= new Date(min);
1265                       
1266                        tp_inst._defaults.minDate = min;
1267                        tp_inst._defaults.minDateTime = min;
1268                } else if (max){ //if max was set
1269                        if(max==0)
1270                                max=new Date();
1271                        else
1272                                max= new Date(max);
1273                        tp_inst._defaults.maxDate = max;
1274                        tp_inst._defaults.maxDateTime = max;
1275                }
1276                else if (onselect)
1277                        tp_inst._defaults.onSelect=onselect;
1278        }
1279        if (value === undefined)
1280                return this._base_optionDatepicker(target, name);
1281        return this._base_optionDatepicker(target, name, value);
1282};
1283
1284//#######################################################################################
1285// jQuery extend now ignores nulls!
1286//#######################################################################################
1287function extendRemove(target, props) {
1288        $.extend(target, props);
1289        for (var name in props)
1290                if (props[name] === null || props[name] === undefined)
1291                        target[name] = props[name];
1292        return target;
1293}
1294
1295$.timepicker = new Timepicker(); // singleton instance
1296$.timepicker.version = "0.9.8";
1297
1298})(jQuery);
1299
Note: See TracBrowser for help on using the repository browser.