PageSourceSearch

https://k-startupcenter.org/resources/_Js/jquery-ui-timepicker-addon.js

js k-startupcenter.org collected 2026-09-30 05:10:17 UTC 58,386 bytes, 1,764 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.