PageSourceSearch

https://fsaa.com.au/assets/js/jquery.ui.datepicker.js

js fsaa.com.au collected 2026-10-04 22:46:26 UTC 76,324 bytes, 2,038 lines download raw bytes

1/*!
2 * jQuery UI Datepicker 1.10.3
3 * http://jqueryui.com
4 *
5 * Copyright 2013 jQuery Foundation and other contributors
6 * Released under the MIT license.
7 * http://jquery.org/license
8 *
9 * http://api.jqueryui.com/datepicker/
10 *
11 * Depends:
12 *	jquery.ui.core.js
13 */
vendor: 76,059 bytes, lines 13-2038
13
14(function( $, undefined ) {
15
16$.extend($.ui, { datepicker: { version: "1.10.3" } });
17
18var PROP_NAME = "datepicker",
19	instActive;
20
21/* Date picker manager.
22   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
23   Settings for (groups of) date pickers are maintained in an instance object,
24   allowing multiple different settings on the same page. */
25
26function Datepicker() {
27	this._curInst = null; // The current instance in use
28	this._keyEvent = false; // If the last event was a key event
29	this._disabledInputs = []; // List of date picker inputs that have been disabled
30	this._datepickerShowing = false; // True if the popup picker is showing , false if not
31	this._inDialog = false; // True if showing within a "dialog", false if not
32	this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
33	this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
34	this._appendClass = "ui-datepicker-append"; // The name of the append marker class
35	this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
36	this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
37	this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
38	this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
39	this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
40	this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
41	this.regional = []; // Available regional settings, indexed by language code
42	this.regional[""] = { // Default regional settings
43		closeText: "Done", // Display text for close link
44		prevText: "Prev", // Display text for previous month link
45		nextText: "Next", // Display text for next month link
46		currentText: "Today", // Display text for current month link
47		monthNames: ["January","February","March","April","May","June",
48			"July","August","September","October","November","December"], // Names of months for drop-down and formatting
49		monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
50		dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
51		dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
52		dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
53		weekHeader: "Wk", // Column header for week of the year
54		dateFormat: "mm/dd/yy", // See format options on parseDate
55		firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
56		isRTL: false, // True if right-to-left language, false if left-to-right
57		showMonthAfterYear: false, // True if the year select precedes month, false for month then year
58		yearSuffix: "" // Additional text to append to the year in the month headers
59	};
60	this._defaults = { // Global defaults for all the date picker instances
61		showOn: "focus", // "focus" for popup on focus,
62			// "button" for trigger button, or "both" for either
63		showAnim: "fadeIn", // Name of jQuery animation for popup
64		showOptions: {}, // Options for enhanced animations
65		defaultDate: null, // Used when field is blank: actual date,
66			// +/-number for offset from today, null for today
67		appendText: "", // Display text following the input box, e.g. showing the format
68		buttonText: "...", // Text for trigger button
69		buttonImage: "", // URL for trigger button image
70		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
71		hideIfNoPrevNext: false, // True to hide next/previous month links
72			// if not applicable, false to just disable them
73		navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
74		gotoCurrent: false, // True if today link goes back to current selection instead
75		changeMonth: false, // True if month can be selected directly, false if only prev/next
76		changeYear: false, // True if year can be selected directly, false if only prev/next
77		yearRange: "c-10:c+10", // Range of years to display in drop-down,
78			// either relative to today's year (-nn:+nn), relative to currently displayed year
79			// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
80		showOtherMonths: false, // True to show dates in other months, false to leave blank
81		selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
82		showWeek: false, // True to show week of the year, false to not show it
83		calculateWeek: this.iso8601Week, // How to calculate the week of the year,
84			// takes a Date and returns the number of the week for it
85		shortYearCutoff: "+10", // Short year values < this are in the current century,
86			// > this are in the previous century,
87			// string value starting with "+" for current year + value
88		minDate: null, // The earliest selectable date, or null for no limit
89		maxDate: null, // The latest selectable date, or null for no limit
90		duration: "fast", // Duration of display/closure
91		beforeShowDay: null, // Function that takes a date and returns an array with
92			// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
93			// [2] = cell title (optional), e.g. $.datepicker.noWeekends
94		beforeShow: null, // Function that takes an input field and
95			// returns a set of custom settings for the date picker
96		onSelect: null, // Define a callback function when a date is selected
97		onChangeMonthYear: null, // Define a callback function when the month or year is changed
98		onClose: null, // Define a callback function when the datepicker is closed
99		numberOfMonths: 1, // Number of months to show at a time
100		showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
101		stepMonths: 1, // Number of months to step back/forward
102		stepBigMonths: 12, // Number of months to step back/forward for the big links
103		altField: "", // Selector for an alternate field to store selected dates into
104		altFormat: "", // The date format to use for the alternate field
105		constrainInput: true, // The input is constrained by the current date format
106		showButtonPanel: false, // True to show button panel, false to not show it
107		autoSize: false, // True to size the input for the date format, false to leave as is
108		disabled: false // The initial disabled state
109	};
110	$.extend(this._defaults, this.regional[""]);
111	this.dpDiv = bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
112}
113
114$.extend(Datepicker.prototype, {
115	/* Class name added to elements to indicate already configured with a date picker. */
116	markerClassName: "hasDatepicker",
117
118	//Keep track of the maximum number of rows displayed (see #7043)
119	maxRows: 4,
120
121	// TODO rename to "widget" when switching to widget factory
122	_widgetDatepicker: function() {
123		return this.dpDiv;
124	},
125
126	/* Override the default settings for all instances of the date picker.
127	 * @param  settings  object - the new settings to use as defaults (anonymous object)
128	 * @return the manager object
129	 */
130	setDefaults: function(settings) {
131		extendRemove(this._defaults, settings || {});
132		return this;
133	},
134
135	/* Attach the date picker to a jQuery selection.
136	 * @param  target	element - the target input field or division or span
137	 * @param  settings  object - the new settings to use for this date picker instance (anonymous)
138	 */
139	_attachDatepicker: function(target, settings) {
140		var nodeName, inline, inst;
141		nodeName = target.nodeName.toLowerCase();
142		inline = (nodeName === "div" || nodeName === "span");
143		if (!target.id) {
144			this.uuid += 1;
145			target.id = "dp" + this.uuid;
146		}
147		inst = this._newInst($(target), inline);
148		inst.settings = $.extend({}, settings || {});
149		if (nodeName === "input") {
150			this._connectDatepicker(target, inst);
151		} else if (inline) {
152			this._inlineDatepicker(target, inst);
153		}
154	},
155
156	/* Create a new instance object. */
157	_newInst: function(target, inline) {
158		var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
159		return {id: id, input: target, // associated target
160			selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
161			drawMonth: 0, drawYear: 0, // month being drawn
162			inline: inline, // is datepicker inline or not
163			dpDiv: (!inline ? this.dpDiv : // presentation div
164			bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
165	},
166
167	/* Attach the date picker to an input field. */
168	_connectDatepicker: function(target, inst) {
169		var input = $(target);
170		inst.append = $([]);
171		inst.trigger = $([]);
172		if (input.hasClass(this.markerClassName)) {
173			return;
174		}
175		this._attachments(input, inst);
176		input.addClass(this.markerClassName).keydown(this._doKeyDown).
177			keypress(this._doKeyPress).keyup(this._doKeyUp);
178		this._autoSize(inst);
179		$.data(target, PROP_NAME, inst);
180		//If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
181		if( inst.settings.disabled ) {
182			this._disableDatepicker( target );
183		}
184	},
185
186	/* Make attachments based on settings. */
187	_attachments: function(input, inst) {
188		var showOn, buttonText, buttonImage,
189			appendText = this._get(inst, "appendText"),
190			isRTL = this._get(inst, "isRTL");
191
192		if (inst.append) {
193			inst.append.remove();
194		}
195		if (appendText) {
196			inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
197			input[isRTL ? "before" : "after"](inst.append);
198		}
199
200		input.unbind("focus", this._showDatepicker);
201
202		if (inst.trigger) {
203			inst.trigger.remove();
204		}
205
206		showOn = this._get(inst, "showOn");
207		if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
208			input.focus(this._showDatepicker);
209		}
210		if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
211			buttonText = this._get(inst, "buttonText");
212			buttonImage = this._get(inst, "buttonImage");
213			inst.trigger = $(this._get(inst, "buttonImageOnly") ?
214				$("<img/>").addClass(this._triggerClass).
215					attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
216				$("<button type='button'></button>").addClass(this._triggerClass).
217					html(!buttonImage ? buttonText : $("<img/>").attr(
218					{ src:buttonImage, alt:buttonText, title:buttonText })));
219			input[isRTL ? "before" : "after"](inst.trigger);
220			inst.trigger.click(function() {
221				if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
222					$.datepicker._hideDatepicker();
223				} else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
224					$.datepicker._hideDatepicker();
225					$.datepicker._showDatepicker(input[0]);
226				} else {
227					$.datepicker._showDatepicker(input[0]);
228				}
229				return false;
230			});
231		}
232	},
233
234	/* Apply the maximum length for the date format. */
235	_autoSize: function(inst) {
236		if (this._get(inst, "autoSize") && !inst.inline) {
237			var findMax, max, maxI, i,
238				date = new Date(2009, 12 - 1, 20), // Ensure double digits
239				dateFormat = this._get(inst, "dateFormat");
240
241			if (dateFormat.match(/[DM]/)) {
242				findMax = function(names) {
243					max = 0;
244					maxI = 0;
245					for (i = 0; i < names.length; i++) {
246						if (names[i].length > max) {
247							max = names[i].length;
248							maxI = i;
249						}
250					}
251					return maxI;
252				};
253				date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
254					"monthNames" : "monthNamesShort"))));
255				date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
256					"dayNames" : "dayNamesShort"))) + 20 - date.getDay());
257			}
258			inst.input.attr("size", this._formatDate(inst, date).length);
259		}
260	},
261
262	/* Attach an inline date picker to a div. */
263	_inlineDatepicker: function(target, inst) {
264		var divSpan = $(target);
265		if (divSpan.hasClass(this.markerClassName)) {
266			return;
267		}
268		divSpan.addClass(this.markerClassName).append(inst.dpDiv);
269		$.data(target, PROP_NAME, inst);
270		this._setDate(inst, this._getDefaultDate(inst), true);
271		this._updateDatepicker(inst);
272		this._updateAlternate(inst);
273		//If disabled option is true, disable the datepicker before showing it (see ticket #5665)
274		if( inst.settings.disabled ) {
275			this._disableDatepicker( target );
276		}
277		// Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
278		// http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
279		inst.dpDiv.css( "display", "block" );
280	},
281
282	/* Pop-up the date picker in a "dialog" box.
283	 * @param  input element - ignored
284	 * @param  date	string or Date - the initial date to display
285	 * @param  onSelect  function - the function to call when a date is selected
286	 * @param  settings  object - update the dialog date picker instance's settings (anonymous object)
287	 * @param  pos int[2] - coordinates for the dialog's position within the screen or
288	 *					event - with x/y coordinates or
289	 *					leave empty for default (screen centre)
290	 * @return the manager object
291	 */
292	_dialogDatepicker: function(input, date, onSelect, settings, pos) {
293		var id, browserWidth, browserHeight, scrollX, scrollY,
294			inst = this._dialogInst; // internal instance
295
296		if (!inst) {
297			this.uuid += 1;
298			id = "dp" + this.uuid;
299			this._dialogInput = $("<input type='text' id='" + id +
300				"' style='position: absolute; top: -100px; width: 0px;'/>");
301			this._dialogInput.keydown(this._doKeyDown);
302			$("body").append(this._dialogInput);
303			inst = this._dialogInst = this._newInst(this._dialogInput, false);
304			inst.settings = {};
305			$.data(this._dialogInput[0], PROP_NAME, inst);
306		}
307		extendRemove(inst.settings, settings || {});
308		date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
309		this._dialogInput.val(date);
310
311		this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
312		if (!this._pos) {
313			browserWidth = document.documentElement.clientWidth;
314			browserHeight = document.documentElement.clientHeight;
315			scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
316			scrollY = document.documentElement.scrollTop || document.body.scrollTop;
317			this._pos = // should use actual width/height below
318				[(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
319		}
320
321		// move input on screen for focus, but hidden behind dialog
322		this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
323		inst.settings.onSelect = onSelect;
324		this._inDialog = true;
325		this.dpDiv.addClass(this._dialogClass);
326		this._showDatepicker(this._dialogInput[0]);
327		if ($.blockUI) {
328			$.blockUI(this.dpDiv);
329		}
330		$.data(this._dialogInput[0], PROP_NAME, inst);
331		return this;
332	},
333
334	/* Detach a datepicker from its control.
335	 * @param  target	element - the target input field or division or span
336	 */
337	_destroyDatepicker: function(target) {
338		var nodeName,
339			$target = $(target),
340			inst = $.data(target, PROP_NAME);
341
342		if (!$target.hasClass(this.markerClassName)) {
343			return;
344		}
345
346		nodeName = target.nodeName.toLowerCase();
347		$.removeData(target, PROP_NAME);
348		if (nodeName === "input") {
349			inst.append.remove();
350			inst.trigger.remove();
351			$target.removeClass(this.markerClassName).
352				unbind("focus", this._showDatepicker).
353				unbind("keydown", this._doKeyDown).
354				unbind("keypress", this._doKeyPress).
355				unbind("keyup", this._doKeyUp);
356		} else if (nodeName === "div" || nodeName === "span") {
357			$target.removeClass(this.markerClassName).empty();
358		}
359	},
360
361	/* Enable the date picker to a jQuery selection.
362	 * @param  target	element - the target input field or division or span
363	 */
364	_enableDatepicker: function(target) {
365		var nodeName, inline,
366			$target = $(target),
367			inst = $.data(target, PROP_NAME);
368
369		if (!$target.hasClass(this.markerClassName)) {
370			return;
371		}
372
373		nodeName = target.nodeName.toLowerCase();
374		if (nodeName === "input") {
375			target.disabled = false;
376			inst.trigger.filter("button").
377				each(function() { this.disabled = false; }).end().
378				filter("img").css({opacity: "1.0", cursor: ""});
379		} else if (nodeName === "div" || nodeName === "span") {
380			inline = $target.children("." + this._inlineClass);
381			inline.children().removeClass("ui-state-disabled");
382			inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
383				prop("disabled", false);
384		}
385		this._disabledInputs = $.map(this._disabledInputs,
386			function(value) { return (value === target ? null : value); }); // delete entry
387	},
388
389	/* Disable the date picker to a jQuery selection.
390	 * @param  target	element - the target input field or division or span
391	 */
392	_disableDatepicker: function(target) {
393		var nodeName, inline,
394			$target = $(target),
395			inst = $.data(target, PROP_NAME);
396
397		if (!$target.hasClass(this.markerClassName)) {
398			return;
399		}
400
401		nodeName = target.nodeName.toLowerCase();
402		if (nodeName === "input") {
403			target.disabled = true;
404			inst.trigger.filter("button").
405				each(function() { this.disabled = true; }).end().
406				filter("img").css({opacity: "0.5", cursor: "default"});
407		} else if (nodeName === "div" || nodeName === "span") {
408			inline = $target.children("." + this._inlineClass);
409			inline.children().addClass("ui-state-disabled");
410			inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
411				prop("disabled", true);
412		}
413		this._disabledInputs = $.map(this._disabledInputs,
414			function(value) { return (value === target ? null : value); }); // delete entry
415		this._disabledInputs[this._disabledInputs.length] = target;
416	},
417
418	/* Is the first field in a jQuery collection disabled as a datepicker?
419	 * @param  target	element - the target input field or division or span
420	 * @return boolean - true if disabled, false if enabled
421	 */
422	_isDisabledDatepicker: function(target) {
423		if (!target) {
424			return false;
425		}
426		for (var i = 0; i < this._disabledInputs.length; i++) {
427			if (this._disabledInputs[i] === target) {
428				return true;
429			}
430		}
431		return false;
432	},
433
434	/* Retrieve the instance data for the target control.
435	 * @param  target  element - the target input field or division or span
436	 * @return  object - the associated instance data
437	 * @throws  error if a jQuery problem getting data
438	 */
439	_getInst: function(target) {
440		try {
441			return $.data(target, PROP_NAME);
442		}
443		catch (err) {
444			throw "Missing instance data for this datepicker";
445		}
446	},
447
448	/* Update or retrieve the settings for a date picker attached to an input field or division.
449	 * @param  target  element - the target input field or division or span
450	 * @param  name	object - the new settings to update or
451	 *				string - the name of the setting to change or retrieve,
452	 *				when retrieving also "all" for all instance settings or
453	 *				"defaults" for all global defaults
454	 * @param  value   any - the new value for the setting
455	 *				(omit if above is an object or to retrieve a value)
456	 */
457	_optionDatepicker: function(target, name, value) {
458		var settings, date, minDate, maxDate,
459			inst = this._getInst(target);
460
461		if (arguments.length === 2 && typeof name === "string") {
462			return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
463				(inst ? (name === "all" ? $.extend({}, inst.settings) :
464				this._get(inst, name)) : null));
465		}
466
467		settings = name || {};
468		if (typeof name === "string") {
469			settings = {};
470			settings[name] = value;
471		}
472
473		if (inst) {
474			if (this._curInst === inst) {
475				this._hideDatepicker();
476			}
477
478			date = this._getDateDatepicker(target, true);
479			minDate = this._getMinMaxDate(inst, "min");
480			maxDate = this._getMinMaxDate(inst, "max");
481			extendRemove(inst.settings, settings);
482			// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
483			if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
484				inst.settings.minDate = this._formatDate(inst, minDate);
485			}
486			if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
487				inst.settings.maxDate = this._formatDate(inst, maxDate);
488			}
489			if ( "disabled" in settings ) {
490				if ( settings.disabled ) {
491					this._disableDatepicker(target);
492				} else {
493					this._enableDatepicker(target);
494				}
495			}
496			this._attachments($(target), inst);
497			this._autoSize(inst);
498			this._setDate(inst, date);
499			this._updateAlternate(inst);
500			this._updateDatepicker(inst);
501		}
502	},
503
504	// change method deprecated
505	_changeDatepicker: function(target, name, value) {
506		this._optionDatepicker(target, name, value);
507	},
508
509	/* Redraw the date picker attached to an input field or division.
510	 * @param  target  element - the target input field or division or span
511	 */
512	_refreshDatepicker: function(target) {
513		var inst = this._getInst(target);
514		if (inst) {
515			this._updateDatepicker(inst);
516		}
517	},
518
519	/* Set the dates for a jQuery selection.
520	 * @param  target element - the target input field or division or span
521	 * @param  date	Date - the new date
522	 */
523	_setDateDatepicker: function(target, date) {
524		var inst = this._getInst(target);
525		if (inst) {
526			this._setDate(inst, date);
527			this._updateDatepicker(inst);
528			this._updateAlternate(inst);
529		}
530	},
531
532	/* Get the date(s) for the first entry in a jQuery selection.
533	 * @param  target element - the target input field or division or span
534	 * @param  noDefault boolean - true if no default date is to be used
535	 * @return Date - the current date
536	 */
537	_getDateDatepicker: function(target, noDefault) {
538		var inst = this._getInst(target);
539		if (inst && !inst.inline) {
540			this._setDateFromField(inst, noDefault);
541		}
542		return (inst ? this._getDate(inst) : null);
543	},
544
545	/* Handle keystrokes. */
546	_doKeyDown: function(event) {
547		var onSelect, dateStr, sel,
548			inst = $.datepicker._getInst(event.target),
549			handled = true,
550			isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
551
552		inst._keyEvent = true;
553		if ($.datepicker._datepickerShowing) {
554			switch (event.keyCode) {
555				case 9: $.datepicker._hideDatepicker();
556						handled = false;
557						break; // hide on tab out
558				case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
559									$.datepicker._currentClass + ")", inst.dpDiv);
560						if (sel[0]) {
561							$.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
562						}
563
564						onSelect = $.datepicker._get(inst, "onSelect");
565						if (onSelect) {
566							dateStr = $.datepicker._formatDate(inst);
567
568							// trigger custom callback
569							onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
570						} else {
571							$.datepicker._hideDatepicker();
572						}
573
574						return false; // don't submit the form
575				case 27: $.datepicker._hideDatepicker();
576						break; // hide on escape
577				case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
578							-$.datepicker._get(inst, "stepBigMonths") :
579							-$.datepicker._get(inst, "stepMonths")), "M");
580						break; // previous month/year on page up/+ ctrl
581				case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
582							+$.datepicker._get(inst, "stepBigMonths") :
583							+$.datepicker._get(inst, "stepMonths")), "M");
584						break; // next month/year on page down/+ ctrl
585				case 35: if (event.ctrlKey || event.metaKey) {
586							$.datepicker._clearDate(event.target);
587						}
588						handled = event.ctrlKey || event.metaKey;
589						break; // clear on ctrl or command +end
590				case 36: if (event.ctrlKey || event.metaKey) {
591							$.datepicker._gotoToday(event.target);
592						}
593						handled = event.ctrlKey || event.metaKey;
594						break; // current on ctrl or command +home
595				case 37: if (event.ctrlKey || event.metaKey) {
596							$.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
597						}
598						handled = event.ctrlKey || event.metaKey;
599						// -1 day on ctrl or command +left
600						if (event.originalEvent.altKey) {
601							$.datepicker._adjustDate(event.target, (event.ctrlKey ?
602								-$.datepicker._get(inst, "stepBigMonths") :
603								-$.datepicker._get(inst, "stepMonths")), "M");
604						}
605						// next month/year on alt +left on Mac
606						break;
607				case 38: if (event.ctrlKey || event.metaKey) {
608							$.datepicker._adjustDate(event.target, -7, "D");
609						}
610						handled = event.ctrlKey || event.metaKey;
611						break; // -1 week on ctrl or command +up
612				case 39: if (event.ctrlKey || event.metaKey) {
613							$.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
614						}
615						handled = event.ctrlKey || event.metaKey;
616						// +1 day on ctrl or command +right
617						if (event.originalEvent.altKey) {
618							$.datepicker._adjustDate(event.target, (event.ctrlKey ?
619								+$.datepicker._get(inst, "stepBigMonths") :
620								+$.datepicker._get(inst, "stepMonths")), "M");
621						}
622						// next month/year on alt +right
623						break;
624				case 40: if (event.ctrlKey || event.metaKey) {
625							$.datepicker._adjustDate(event.target, +7, "D");
626						}
627						handled = event.ctrlKey || event.metaKey;
628						break; // +1 week on ctrl or command +down
629				default: handled = false;
630			}
631		} else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
632			$.datepicker._showDatepicker(this);
633		} else {
634			handled = false;
635		}
636
637		if (handled) {
638			event.preventDefault();
639			event.stopPropagation();
640		}
641	},
642
643	/* Filter entered characters - based on date format. */
644	_doKeyPress: function(event) {
645		var chars, chr,
646			inst = $.datepicker._getInst(event.target);
647
648		if ($.datepicker._get(inst, "constrainInput")) {
649			chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
650			chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
651			return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
652		}
653	},
654
655	/* Synchronise manual entry and field/alternate field. */
656	_doKeyUp: function(event) {
657		var date,
658			inst = $.datepicker._getInst(event.target);
659
660		if (inst.input.val() !== inst.lastVal) {
661			try {
662				date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
663					(inst.input ? inst.input.val() : null),
664					$.datepicker._getFormatConfig(inst));
665
666				if (date) { // only if valid
667					$.datepicker._setDateFromField(inst);
668					$.datepicker._updateAlternate(inst);
669					$.datepicker._updateDatepicker(inst);
670				}
671			}
672			catch (err) {
673			}
674		}
675		return true;
676	},
677
678	/* Pop-up the date picker for a given input field.
679	 * If false returned from beforeShow event handler do not show.
680	 * @param  input  element - the input field attached to the date picker or
681	 *					event - if triggered by focus
682	 */
683	_showDatepicker: function(input) {
684		input = input.target || input;
685		if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
686			input = $("input", input.parentNode)[0];
687		}
688
689		if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
690			return;
691		}
692
693		var inst, beforeShow, beforeShowSettings, isFixed,
694			offset, showAnim, duration;
695
696		inst = $.datepicker._getInst(input);
697		if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
698			$.datepicker._curInst.dpDiv.stop(true, true);
699			if ( inst && $.datepicker._datepickerShowing ) {
700				$.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
701			}
702		}
703
704		beforeShow = $.datepicker._get(inst, "beforeShow");
705		beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
706		if(beforeShowSettings === false){
707			return;
708		}
709		extendRemove(inst.settings, beforeShowSettings);
710
711		inst.lastVal = null;
712		$.datepicker._lastInput = input;
713		$.datepicker._setDateFromField(inst);
714
715		if ($.datepicker._inDialog) { // hide cursor
716			input.value = "";
717		}
718		if (!$.datepicker._pos) { // position below input
719			$.datepicker._pos = $.datepicker._findPos(input);
720			$.datepicker._pos[1] += input.offsetHeight; // add the height
721		}
722
723		isFixed = false;
724		$(input).parents().each(function() {
725			isFixed |= $(this).css("position") === "fixed";
726			return !isFixed;
727		});
728
729		offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
730		$.datepicker._pos = null;
731		//to avoid flashes on Firefox
732		inst.dpDiv.empty();
733		// determine sizing offscreen
734		inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
735		$.datepicker._updateDatepicker(inst);
736		// fix width for dynamic number of date pickers
737		// and adjust position before showing
738		offset = $.datepicker._checkOffset(inst, offset, isFixed);
739		inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
740			"static" : (isFixed ? "fixed" : "absolute")), display: "none",
741			left: offset.left + "px", top: offset.top + "px"});
742
743		if (!inst.inline) {
744			showAnim = $.datepicker._get(inst, "showAnim");
745			duration = $.datepicker._get(inst, "duration");
746			inst.dpDiv.zIndex($(input).zIndex()+1);
747			$.datepicker._datepickerShowing = true;
748
749			if ( $.effects && $.effects.effect[ showAnim ] ) {
750				inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
751			} else {
752				inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
753			}
754
755			if ( $.datepicker._shouldFocusInput( inst ) ) {
756				inst.input.focus();
757			}
758
759			$.datepicker._curInst = inst;
760		}
761	},
762
763	/* Generate the date picker content. */
764	_updateDatepicker: function(inst) {
765		this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
766		instActive = inst; // for delegate hover events
767		inst.dpDiv.empty().append(this._generateHTML(inst));
768		this._attachHandlers(inst);
769		inst.dpDiv.find("." + this._dayOverClass + " a").mouseover();
770
771		var origyearshtml,
772			numMonths = this._getNumberOfMonths(inst),
773			cols = numMonths[1],
774			width = 17;
775
776		inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
777		if (cols > 1) {
778			inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
779		}
780		inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
781			"Class"]("ui-datepicker-multi");
782		inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
783			"Class"]("ui-datepicker-rtl");
784
785		if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
786			inst.input.focus();
787		}
788
789		// deffered render of the years select (to avoid flashes on Firefox)
790		if( inst.yearshtml ){
791			origyearshtml = inst.yearshtml;
792			setTimeout(function(){
793				//assure that inst.yearshtml didn't change.
794				if( origyearshtml === inst.yearshtml && inst.yearshtml ){
795					inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
796				}
797				origyearshtml = inst.yearshtml = null;
798			}, 0);
799		}
800	},
801
802	// #6694 - don't focus the input if it's already focused
803	// this breaks the change event in IE
804	// Support: IE and jQuery <1.9
805	_shouldFocusInput: function( inst ) {
806		return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
807	},
808
809	/* Check positioning to remain on screen. */
810	_checkOffset: function(inst, offset, isFixed) {
811		var dpWidth = inst.dpDiv.outerWidth(),
812			dpHeight = inst.dpDiv.outerHeight(),
813			inputWidth = inst.input ? inst.input.outerWidth() : 0,
814			inputHeight = inst.input ? inst.input.outerHeight() : 0,
815			viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
816			viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
817
818		offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
819		offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
820		offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
821
822		// now check if datepicker is showing outside window viewport - move to a better place if so.
823		offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
824			Math.abs(offset.left + dpWidth - viewWidth) : 0);
825		offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
826			Math.abs(dpHeight + inputHeight) : 0);
827
828		return offset;
829	},
830
831	/* Find an object's position on the screen. */
832	_findPos: function(obj) {
833		var position,
834			inst = this._getInst(obj),
835			isRTL = this._get(inst, "isRTL");
836
837		while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
838			obj = obj[isRTL ? "previousSibling" : "nextSibling"];
839		}
840
841		position = $(obj).offset();
842		return [position.left, position.top];
843	},
844
845	/* Hide the date picker from view.
846	 * @param  input  element - the input field attached to the date picker
847	 */
848	_hideDatepicker: function(input) {
849		var showAnim, duration, postProcess, onClose,
850			inst = this._curInst;
851
852		if (!inst || (input && inst !== $.data(input, PROP_NAME))) {
853			return;
854		}
855
856		if (this._datepickerShowing) {
857			showAnim = this._get(inst, "showAnim");
858			duration = this._get(inst, "duration");
859			postProcess = function() {
860				$.datepicker._tidyDialog(inst);
861			};
862
863			// DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
864			if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
865				inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
866			} else {
867				inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
868					(showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
869			}
870
871			if (!showAnim) {
872				postProcess();
873			}
874			this._datepickerShowing = false;
875
876			onClose = this._get(inst, "onClose");
877			if (onClose) {
878				onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
879			}
880
881			this._lastInput = null;
882			if (this._inDialog) {
883				this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
884				if ($.blockUI) {
885					$.unblockUI();
886					$("body").append(this.dpDiv);
887				}
888			}
889			this._inDialog = false;
890		}
891	},
892
893	/* Tidy up after a dialog display. */
894	_tidyDialog: function(inst) {
895		inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
896	},
897
898	/* Close date picker if clicked elsewhere. */
899	_checkExternalClick: function(event) {
900		if (!$.datepicker._curInst) {
901			return;
902		}
903
904		var $target = $(event.target),
905			inst = $.datepicker._getInst($target[0]);
906
907		if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
908				$target.parents("#" + $.datepicker._mainDivId).length === 0 &&
909				!$target.hasClass($.datepicker.markerClassName) &&
910				!$target.closest("." + $.datepicker._triggerClass).length &&
911				$.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
912			( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
913				$.datepicker._hideDatepicker();
914		}
915	},
916
917	/* Adjust one of the date sub-fields. */
918	_adjustDate: function(id, offset, period) {
919		var target = $(id),
920			inst = this._getInst(target[0]);
921
922		if (this._isDisabledDatepicker(target[0])) {
923			return;
924		}
925		this._adjustInstDate(inst, offset +
926			(period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
927			period);
928		this._updateDatepicker(inst);
929	},
930
931	/* Action for current link. */
932	_gotoToday: function(id) {
933		var date,
934			target = $(id),
935			inst = this._getInst(target[0]);
936
937		if (this._get(inst, "gotoCurrent") && inst.currentDay) {
938			inst.selectedDay = inst.currentDay;
939			inst.drawMonth = inst.selectedMonth = inst.currentMonth;
940			inst.drawYear = inst.selectedYear = inst.currentYear;
941		} else {
942			date = new Date();
943			inst.selectedDay = date.getDate();
944			inst.drawMonth = inst.selectedMonth = date.getMonth();
945			inst.drawYear = inst.selectedYear = date.getFullYear();
946		}
947		this._notifyChange(inst);
948		this._adjustDate(target);
949	},
950
951	/* Action for selecting a new month/year. */
952	_selectMonthYear: function(id, select, period) {
953		var target = $(id),
954			inst = this._getInst(target[0]);
955
956		inst["selected" + (period === "M" ? "Month" : "Year")] =
957		inst["draw" + (period === "M" ? "Month" : "Year")] =
958			parseInt(select.options[select.selectedIndex].value,10);
959
960		this._notifyChange(inst);
961		this._adjustDate(target);
962	},
963
964	/* Action for selecting a day. */
965	_selectDay: function(id, month, year, td) {
966		var inst,
967			target = $(id);
968
969		if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
970			return;
971		}
972
973		inst = this._getInst(target[0]);
974		inst.selectedDay = inst.currentDay = $("a", td).html();
975		inst.selectedMonth = inst.currentMonth = month;
976		inst.selectedYear = inst.currentYear = year;
977		this._selectDate(id, this._formatDate(inst,
978			inst.currentDay, inst.currentMonth, inst.currentYear));
979	},
980
981	/* Erase the input field and hide the date picker. */
982	_clearDate: function(id) {
983		var target = $(id);
984		this._selectDate(target, "");
985	},
986
987	/* Update the input field with the selected date. */
988	_selectDate: function(id, dateStr) {
989		var onSelect,
990			target = $(id),
991			inst = this._getInst(target[0]);
992
993		dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
994		if (inst.input) {
995			inst.input.val(dateStr);
996		}
997		this._updateAlternate(inst);
998
999		onSelect = this._get(inst, "onSelect");
1000		if (onSelect) {
1001			onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);  // trigger custom callback
1002		} else if (inst.input) {
1003			inst.input.trigger("change"); // fire the change event
1004		}
1005
1006		if (inst.inline){
1007			this._updateDatepicker(inst);
1008		} else {
1009			this._hideDatepicker();
1010			this._lastInput = inst.input[0];
1011			if (typeof(inst.input[0]) !== "object") {
1012				inst.input.focus(); // restore focus
1013			}
1014			this._lastInput = null;
1015		}
1016	},
1017
1018	/* Update any alternate field to synchronise with the main field. */
1019	_updateAlternate: function(inst) {
1020		var altFormat, date, dateStr,
1021			altField = this._get(inst, "altField");
1022
1023		if (altField) { // update alternate field too
1024			altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
1025			date = this._getDate(inst);
1026			dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
1027			$(altField).each(function() { $(this).val(dateStr); });
1028		}
1029	},
1030
1031	/* Set as beforeShowDay function to prevent selection of weekends.
1032	 * @param  date  Date - the date to customise
1033	 * @return [boolean, string] - is this date selectable?, what is its CSS class?
1034	 */
1035	noWeekends: function(date) {
1036		var day = date.getDay();
1037		return [(day > 0 && day < 6), ""];
1038	},
1039
1040	/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
1041	 * @param  date  Date - the date to get the week for
1042	 * @return  number - the number of the week within the year that contains this date
1043	 */
1044	iso8601Week: function(date) {
1045		var time,
1046			checkDate = new Date(date.getTime());
1047
1048		// Find Thursday of this week starting on Monday
1049		checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
1050
1051		time = checkDate.getTime();
1052		checkDate.setMonth(0); // Compare with Jan 1
1053		checkDate.setDate(1);
1054		return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
1055	},
1056
1057	/* Parse a string value into a date object.
1058	 * See formatDate below for the possible formats.
1059	 *
1060	 * @param  format string - the expected format of the date
1061	 * @param  value string - the date in the above format
1062	 * @param  settings Object - attributes include:
1063	 *					shortYearCutoff  number - the cutoff year for determining the century (optional)
1064	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
1065	 *					dayNames		string[7] - names of the days from Sunday (optional)
1066	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
1067	 *					monthNames		string[12] - names of the months (optional)
1068	 * @return  Date - the extracted date value or null if value is blank
1069	 */
1070	parseDate: function (format, value, settings) {
1071		if (format == null || value == null) {
1072			throw "Invalid arguments";
1073		}
1074
1075		value = (typeof value === "object" ? value.toString() : value + "");
1076		if (value === "") {
1077			return null;
1078		}
1079
1080		var iFormat, dim, extra,
1081			iValue = 0,
1082			shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
1083			shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
1084				new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
1085			dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
1086			dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
1087			monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
1088			monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
1089			year = -1,
1090			month = -1,
1091			day = -1,
1092			doy = -1,
1093			literal = false,
1094			date,
1095			// Check whether a format character is doubled
1096			lookAhead = function(match) {
1097				var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
1098				if (matches) {
1099					iFormat++;
1100				}
1101				return matches;
1102			},
1103			// Extract a number from the string value
1104			getNumber = function(match) {
1105				var isDoubled = lookAhead(match),
1106					size = (match === "@" ? 14 : (match === "!" ? 20 :
1107					(match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
1108					digits = new RegExp("^\\d{1," + size + "}"),
1109					num = value.substring(iValue).match(digits);
1110				if (!num) {
1111					throw "Missing number at position " + iValue;
1112				}
1113				iValue += num[0].length;
1114				return parseInt(num[0], 10);
1115			},
1116			// Extract a name from the string value and convert to an index
1117			getName = function(match, shortNames, longNames) {
1118				var index = -1,
1119					names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
1120						return [ [k, v] ];
1121					}).sort(function (a, b) {
1122						return -(a[1].length - b[1].length);
1123					});
1124
1125				$.each(names, function (i, pair) {
1126					var name = pair[1];
1127					if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
1128						index = pair[0];
1129						iValue += name.length;
1130						return false;
1131					}
1132				});
1133				if (index !== -1) {
1134					return index + 1;
1135				} else {
1136					throw "Unknown name at position " + iValue;
1137				}
1138			},
1139			// Confirm that a literal character matches the string value
1140			checkLiteral = function() {
1141				if (value.charAt(iValue) !== format.charAt(iFormat)) {
1142					throw "Unexpected literal at position " + iValue;
1143				}
1144				iValue++;
1145			};
1146
1147		for (iFormat = 0; iFormat < format.length; iFormat++) {
1148			if (literal) {
1149				if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
1150					literal = false;
1151				} else {
1152					checkLiteral();
1153				}
1154			} else {
1155				switch (format.charAt(iFormat)) {
1156					case "d":
1157						day = getNumber("d");
1158						break;
1159					case "D":
1160						getName("D", dayNamesShort, dayNames);
1161						break;
1162					case "o":
1163						doy = getNumber("o");
1164						break;
1165					case "m":
1166						month = getNumber("m");
1167						break;
1168					case "M":
1169						month = getName("M", monthNamesShort, monthNames);
1170						break;
1171					case "y":
1172						year = getNumber("y");
1173						break;
1174					case "@":
1175						date = new Date(getNumber("@"));
1176						year = date.getFullYear();
1177						month = date.getMonth() + 1;
1178						day = date.getDate();
1179						break;
1180					case "!":
1181						date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
1182						year = date.getFullYear();
1183						month = date.getMonth() + 1;
1184						day = date.getDate();
1185						break;
1186					case "'":
1187						if (lookAhead("'")){
1188							checkLiteral();
1189						} else {
1190							literal = true;
1191						}
1192						break;
1193					default:
1194						checkLiteral();
1195				}
1196			}
1197		}
1198
1199		if (iValue < value.length){
1200			extra = value.substr(iValue);
1201			if (!/^\s+/.test(extra)) {
1202				throw "Extra/unparsed characters found in date: " + extra;
1203			}
1204		}
1205
1206		if (year === -1) {
1207			year = new Date().getFullYear();
1208		} else if (year < 100) {
1209			year += new Date().getFullYear() - new Date().getFullYear() % 100 +
1210				(year <= shortYearCutoff ? 0 : -100);
1211		}
1212
1213		if (doy > -1) {
1214			month = 1;
1215			day = doy;
1216			do {
1217				dim = this._getDaysInMonth(year, month - 1);
1218				if (day <= dim) {
1219					break;
1220				}
1221				month++;
1222				day -= dim;
1223			} while (true);
1224		}
1225
1226		date = this._daylightSavingAdjust(new Date(year, month - 1, day));
1227		if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
1228			throw "Invalid date"; // E.g. 31/02/00
1229		}
1230		return date;
1231	},
1232
1233	/* Standard date formats. */
1234	ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
1235	COOKIE: "D, dd M yy",
1236	ISO_8601: "yy-mm-dd",
1237	RFC_822: "D, d M y",
1238	RFC_850: "DD, dd-M-y",
1239	RFC_1036: "D, d M y",
1240	RFC_1123: "D, d M yy",
1241	RFC_2822: "D, d M yy",
1242	RSS: "D, d M y", // RFC 822
1243	TICKS: "!",
1244	TIMESTAMP: "@",
1245	W3C: "yy-mm-dd", // ISO 8601
1246
1247	_ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
1248		Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
1249
1250	/* Format a date object into a string value.
1251	 * The format can be combinations of the following:
1252	 * d  - day of month (no leading zero)
1253	 * dd - day of month (two digit)
1254	 * o  - day of year (no leading zeros)
1255	 * oo - day of year (three digit)
1256	 * D  - day name short
1257	 * DD - day name long
1258	 * m  - month of year (no leading zero)
1259	 * mm - month of year (two digit)
1260	 * M  - month name short
1261	 * MM - month name long
1262	 * y  - year (two digit)
1263	 * yy - year (four digit)
1264	 * @ - Unix timestamp (ms since 01/01/1970)
1265	 * ! - Windows ticks (100ns since 01/01/0001)
1266	 * "..." - literal text
1267	 * '' - single quote
1268	 *
1269	 * @param  format string - the desired format of the date
1270	 * @param  date Date - the date value to format
1271	 * @param  settings Object - attributes include:
1272	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
1273	 *					dayNames		string[7] - names of the days from Sunday (optional)
1274	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
1275	 *					monthNames		string[12] - names of the months (optional)
1276	 * @return  string - the date in the above format
1277	 */
1278	formatDate: function (format, date, settings) {
1279		if (!date) {
1280			return "";
1281		}
1282
1283		var iFormat,
1284			dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
1285			dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
1286			monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
1287			monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
1288			// Check whether a format character is doubled
1289			lookAhead = function(match) {
1290				var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
1291				if (matches) {
1292					iFormat++;
1293				}
1294				return matches;
1295			},
1296			// Format a number, with leading zero if necessary
1297			formatNumber = function(match, value, len) {
1298				var num = "" + value;
1299				if (lookAhead(match)) {
1300					while (num.length < len) {
1301						num = "0" + num;
1302					}
1303				}
1304				return num;
1305			},
1306			// Format a name, short or long as requested
1307			formatName = function(match, value, shortNames, longNames) {
1308				return (lookAhead(match) ? longNames[value] : shortNames[value]);
1309			},
1310			output = "",
1311			literal = false;
1312
1313		if (date) {
1314			for (iFormat = 0; iFormat < format.length; iFormat++) {
1315				if (literal) {
1316					if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
1317						literal = false;
1318					} else {
1319						output += format.charAt(iFormat);
1320					}
1321				} else {
1322					switch (format.charAt(iFormat)) {
1323						case "d":
1324							output += formatNumber("d", date.getDate(), 2);
1325							break;
1326						case "D":
1327							output += formatName("D", date.getDay(), dayNamesShort, dayNames);
1328							break;
1329						case "o":
1330							output += formatNumber("o",
1331								Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
1332							break;
1333						case "m":
1334							output += formatNumber("m", date.getMonth() + 1, 2);
1335							break;
1336						case "M":
1337							output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
1338							break;
1339						case "y":
1340							output += (lookAhead("y") ? date.getFullYear() :
1341								(date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
1342							break;
1343						case "@":
1344							output += date.getTime();
1345							break;
1346						case "!":
1347							output += date.getTime() * 10000 + this._ticksTo1970;
1348							break;
1349						case "'":
1350							if (lookAhead("'")) {
1351								output += "'";
1352							} else {
1353								literal = true;
1354							}
1355							break;
1356						default:
1357							output += format.charAt(iFormat);
1358					}
1359				}
1360			}
1361		}
1362		return output;
1363	},
1364
1365	/* Extract all possible characters from the date format. */
1366	_possibleChars: function (format) {
1367		var iFormat,
1368			chars = "",
1369			literal = false,
1370			// Check whether a format character is doubled
1371			lookAhead = function(match) {
1372				var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
1373				if (matches) {
1374					iFormat++;
1375				}
1376				return matches;
1377			};
1378
1379		for (iFormat = 0; iFormat < format.length; iFormat++) {
1380			if (literal) {
1381				if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
1382					literal = false;
1383				} else {
1384					chars += format.charAt(iFormat);
1385				}
1386			} else {
1387				switch (format.charAt(iFormat)) {
1388					case "d": case "m": case "y": case "@":
1389						chars += "0123456789";
1390						break;
1391					case "D": case "M":
1392						return null; // Accept anything
1393					case "'":
1394						if (lookAhead("'")) {
1395							chars += "'";
1396						} else {
1397							literal = true;
1398						}
1399						break;
1400					default:
1401						chars += format.charAt(iFormat);
1402				}
1403			}
1404		}
1405		return chars;
1406	},
1407
1408	/* Get a setting value, defaulting if necessary. */
1409	_get: function(inst, name) {
1410		return inst.settings[name] !== undefined ?
1411			inst.settings[name] : this._defaults[name];
1412	},
1413
1414	/* Parse existing date and initialise date picker. */
1415	_setDateFromField: function(inst, noDefault) {
1416		if (inst.input.val() === inst.lastVal) {
1417			return;
1418		}
1419
1420		var dateFormat = this._get(inst, "dateFormat"),
1421			dates = inst.lastVal = inst.input ? inst.input.val() : null,
1422			defaultDate = this._getDefaultDate(inst),
1423			date = defaultDate,
1424			settings = this._getFormatConfig(inst);
1425
1426		try {
1427			date = this.parseDate(dateFormat, dates, settings) || defaultDate;
1428		} catch (event) {
1429			dates = (noDefault ? "" : dates);
1430		}
1431		inst.selectedDay = date.getDate();
1432		inst.drawMonth = inst.selectedMonth = date.getMonth();
1433		inst.drawYear = inst.selectedYear = date.getFullYear();
1434		inst.currentDay = (dates ? date.getDate() : 0);
1435		inst.currentMonth = (dates ? date.getMonth() : 0);
1436		inst.currentYear = (dates ? date.getFullYear() : 0);
1437		this._adjustInstDate(inst);
1438	},
1439
1440	/* Retrieve the default date shown on opening. */
1441	_getDefaultDate: function(inst) {
1442		return this._restrictMinMax(inst,
1443			this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
1444	},
1445
1446	/* A date may be specified as an exact value or a relative one. */
1447	_determineDate: function(inst, date, defaultDate) {
1448		var offsetNumeric = function(offset) {
1449				var date = new Date();
1450				date.setDate(date.getDate() + offset);
1451				return date;
1452			},
1453			offsetString = function(offset) {
1454				try {
1455					return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
1456						offset, $.datepicker._getFormatConfig(inst));
1457				}
1458				catch (e) {
1459					// Ignore
1460				}
1461
1462				var date = (offset.toLowerCase().match(/^c/) ?
1463					$.datepicker._getDate(inst) : null) || new Date(),
1464					year = date.getFullYear(),
1465					month = date.getMonth(),
1466					day = date.getDate(),
1467					pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
1468					matches = pattern.exec(offset);
1469
1470				while (matches) {
1471					switch (matches[2] || "d") {
1472						case "d" : case "D" :
1473							day += parseInt(matches[1],10); break;
1474						case "w" : case "W" :
1475							day += parseInt(matches[1],10) * 7; break;
1476						case "m" : case "M" :
1477							month += parseInt(matches[1],10);
1478							day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
1479							break;
1480						case "y": case "Y" :
1481							year += parseInt(matches[1],10);
1482							day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
1483							break;
1484					}
1485					matches = pattern.exec(offset);
1486				}
1487				return new Date(year, month, day);
1488			},
1489			newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
1490				(typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
1491
1492		newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
1493		if (newDate) {
1494			newDate.setHours(0);
1495			newDate.setMinutes(0);
1496			newDate.setSeconds(0);
1497			newDate.setMilliseconds(0);
1498		}
1499		return this._daylightSavingAdjust(newDate);
1500	},
1501
1502	/* Handle switch to/from daylight saving.
1503	 * Hours may be non-zero on daylight saving cut-over:
1504	 * > 12 when midnight changeover, but then cannot generate
1505	 * midnight datetime, so jump to 1AM, otherwise reset.
1506	 * @param  date  (Date) the date to check
1507	 * @return  (Date) the corrected date
1508	 */
1509	_daylightSavingAdjust: function(date) {
1510		if (!date) {
1511			return null;
1512		}
1513		date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
1514		return date;
1515	},
1516
1517	/* Set the date(s) directly. */
1518	_setDate: function(inst, date, noChange) {
1519		var clear = !date,
1520			origMonth = inst.selectedMonth,
1521			origYear = inst.selectedYear,
1522			newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
1523
1524		inst.selectedDay = inst.currentDay = newDate.getDate();
1525		inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
1526		inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
1527		if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
1528			this._notifyChange(inst);
1529		}
1530		this._adjustInstDate(inst);
1531		if (inst.input) {
1532			inst.input.val(clear ? "" : this._formatDate(inst));
1533		}
1534	},
1535
1536	/* Retrieve the date(s) directly. */
1537	_getDate: function(inst) {
1538		var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
1539			this._daylightSavingAdjust(new Date(
1540			inst.currentYear, inst.currentMonth, inst.currentDay)));
1541			return startDate;
1542	},
1543
1544	/* Attach the onxxx handlers.  These are declared statically so
1545	 * they work with static code transformers like Caja.
1546	 */
1547	_attachHandlers: function(inst) {
1548		var stepMonths = this._get(inst, "stepMonths"),
1549			id = "#" + inst.id.replace( /\\\\/g, "\\" );
1550		inst.dpDiv.find("[data-handler]").map(function () {
1551			var handler = {
1552				prev: function () {
1553					$.datepicker._adjustDate(id, -stepMonths, "M");
1554				},
1555				next: function () {
1556					$.datepicker._adjustDate(id, +stepMonths, "M");
1557				},
1558				hide: function () {
1559					$.datepicker._hideDatepicker();
1560				},
1561				today: function () {
1562					$.datepicker._gotoToday(id);
1563				},
1564				selectDay: function () {
1565					$.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
1566					return false;
1567				},
1568				selectMonth: function () {
1569					$.datepicker._selectMonthYear(id, this, "M");
1570					return false;
1571				},
1572				selectYear: function () {
1573					$.datepicker._selectMonthYear(id, this, "Y");
1574					return false;
1575				}
1576			};
1577			$(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
1578		});
1579	},
1580
1581	/* Generate the HTML for the current state of the date picker. */
1582	_generateHTML: function(inst) {
1583		var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
1584			controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
1585			monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
1586			selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
1587			cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
1588			printDate, dRow, tbody, daySettings, otherMonth, unselectable,
1589			tempDate = new Date(),
1590			today = this._daylightSavingAdjust(
1591				new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
1592			isRTL = this._get(inst, "isRTL"),
1593			showButtonPanel = this._get(inst, "showButtonPanel"),
1594			hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
1595			navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
1596			numMonths = this._getNumberOfMonths(inst),
1597			showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
1598			stepMonths = this._get(inst, "stepMonths"),
1599			isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
1600			currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
1601				new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
1602			minDate = this._getMinMaxDate(inst, "min"),
1603			maxDate = this._getMinMaxDate(inst, "max"),
1604			drawMonth = inst.drawMonth - showCurrentAtPos,
1605			drawYear = inst.drawYear;
1606
1607		if (drawMonth < 0) {
1608			drawMonth += 12;
1609			drawYear--;
1610		}
1611		if (maxDate) {
1612			maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
1613				maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
1614			maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
1615			while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
1616				drawMonth--;
1617				if (drawMonth < 0) {
1618					drawMonth = 11;
1619					drawYear--;
1620				}
1621			}
1622		}
1623		inst.drawMonth = drawMonth;
1624		inst.drawYear = drawYear;
1625
1626		prevText = this._get(inst, "prevText");
1627		prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
1628			this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
1629			this._getFormatConfig(inst)));
1630
1631		prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
1632			"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
1633			" title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
1634			(hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>"));
1635
1636		nextText = this._get(inst, "nextText");
1637		nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
1638			this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
1639			this._getFormatConfig(inst)));
1640
1641		next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
1642			"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
1643			" title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
1644			(hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>"));
1645
1646		currentText = this._get(inst, "currentText");
1647		gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
1648		currentText = (!navigationAsDateFormat ? currentText :
1649			this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
1650
1651		controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
1652			this._get(inst, "closeText") + "</button>" : "");
1653
1654		buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
1655			(this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
1656			">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
1657
1658		firstDay = parseInt(this._get(inst, "firstDay"),10);
1659		firstDay = (isNaN(firstDay) ? 0 : firstDay);
1660
1661		showWeek = this._get(inst, "showWeek");
1662		dayNames = this._get(inst, "dayNames");
1663		dayNamesMin = this._get(inst, "dayNamesMin");
1664		monthNames = this._get(inst, "monthNames");
1665		monthNamesShort = this._get(inst, "monthNamesShort");
1666		beforeShowDay = this._get(inst, "beforeShowDay");
1667		showOtherMonths = this._get(inst, "showOtherMonths");
1668		selectOtherMonths = this._get(inst, "selectOtherMonths");
1669		defaultDate = this._getDefaultDate(inst);
1670		html = "";
1671		dow;
1672		for (row = 0; row < numMonths[0]; row++) {
1673			group = "";
1674			this.maxRows = 4;
1675			for (col = 0; col < numMonths[1]; col++) {
1676				selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
1677				cornerClass = " ui-corner-all";
1678				calender = "";
1679				if (isMultiMonth) {
1680					calender += "<div class='ui-datepicker-group";
1681					if (numMonths[1] > 1) {
1682						switch (col) {
1683							case 0: calender += " ui-datepicker-group-first";
1684								cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
1685							case numMonths[1]-1: calender += " ui-datepicker-group-last";
1686								cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
1687							default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
1688						}
1689					}
1690					calender += "'>";
1691				}
1692				calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
1693					(/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
1694					(/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
1695					this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
1696					row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
1697					"</div><table class='ui-datepicker-calendar'><thead>" +
1698					"<tr>";
1699				thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
1700				for (dow = 0; dow < 7; dow++) { // days of the week
1701					day = (dow + firstDay) % 7;
1702					thead += "<th" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
1703						"<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
1704				}
1705				calender += thead + "</tr></thead><tbody>";
1706				daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
1707				if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
1708					inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
1709				}
1710				leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
1711				curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
1712				numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
1713				this.maxRows = numRows;
1714				printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
1715				for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
1716					calender += "<tr>";
1717					tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
1718						this._get(inst, "calculateWeek")(printDate) + "</td>");
1719					for (dow = 0; dow < 7; dow++) { // create date picker days
1720						daySettings = (beforeShowDay ?
1721							beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
1722						otherMonth = (printDate.getMonth() !== drawMonth);
1723						unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
1724							(minDate && printDate < minDate) || (maxDate && printDate > maxDate);
1725						tbody += "<td class='" +
1726							((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
1727							(otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
1728							((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
1729							(defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
1730							// or defaultDate is current printedDate and defaultDate is selectedDate
1731							" " + this._dayOverClass : "") + // highlight selected day
1732							(unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") +  // highlight unselectable days
1733							(otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
1734							(printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
1735							(printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
1736							((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
1737							(unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
1738							(otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
1739							(unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
1740							(printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
1741							(printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
1742							(otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
1743							"' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
1744						printDate.setDate(printDate.getDate() + 1);
1745						printDate = this._daylightSavingAdjust(printDate);
1746					}
1747					calender += tbody + "</tr>";
1748				}
1749				drawMonth++;
1750				if (drawMonth > 11) {
1751					drawMonth = 0;
1752					drawYear++;
1753				}
1754				calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
1755							((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
1756				group += calender;
1757			}
1758			html += group;
1759		}
1760		html += buttonPanel;
1761		inst._keyEvent = false;
1762		return html;
1763	},
1764
1765	/* Generate the month and year header. */
1766	_generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
1767			secondary, monthNames, monthNamesShort) {
1768
1769		var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
1770			changeMonth = this._get(inst, "changeMonth"),
1771			changeYear = this._get(inst, "changeYear"),
1772			showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
1773			html = "<div class='ui-datepicker-title'>",
1774			monthHtml = "";
1775
1776		// month selection
1777		if (secondary || !changeMonth) {
1778			monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
1779		} else {
1780			inMinYear = (minDate && minDate.getFullYear() === drawYear);
1781			inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
1782			monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
1783			for ( month = 0; month < 12; month++) {
1784				if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
1785					monthHtml += "<option value='" + month + "'" +
1786						(month === drawMonth ? " selected='selected'" : "") +
1787						">" + monthNamesShort[month] + "</option>";
1788				}
1789			}
1790			monthHtml += "</select>";
1791		}
1792
1793		if (!showMonthAfterYear) {
1794			html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
1795		}
1796
1797		// year selection
1798		if ( !inst.yearshtml ) {
1799			inst.yearshtml = "";
1800			if (secondary || !changeYear) {
1801				html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
1802			} else {
1803				// determine range of years to display
1804				years = this._get(inst, "yearRange").split(":");
1805				thisYear = new Date().getFullYear();
1806				determineYear = function(value) {
1807					var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
1808						(value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
1809						parseInt(value, 10)));
1810					return (isNaN(year) ? thisYear : year);
1811				};
1812				year = determineYear(years[0]);
1813				endYear = Math.max(year, determineYear(years[1] || ""));
1814				year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
1815				endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
1816				inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
1817				for (; year <= endYear; year++) {
1818					inst.yearshtml += "<option value='" + year + "'" +
1819						(year === drawYear ? " selected='selected'" : "") +
1820						">" + year + "</option>";
1821				}
1822				inst.yearshtml += "</select>";
1823
1824				html += inst.yearshtml;
1825				inst.yearshtml = null;
1826			}
1827		}
1828
1829		html += this._get(inst, "yearSuffix");
1830		if (showMonthAfterYear) {
1831			html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
1832		}
1833		html += "</div>"; // Close datepicker_header
1834		return html;
1835	},
1836
1837	/* Adjust one of the date sub-fields. */
1838	_adjustInstDate: function(inst, offset, period) {
1839		var year = inst.drawYear + (period === "Y" ? offset : 0),
1840			month = inst.drawMonth + (period === "M" ? offset : 0),
1841			day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
1842			date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
1843
1844		inst.selectedDay = date.getDate();
1845		inst.drawMonth = inst.selectedMonth = date.getMonth();
1846		inst.drawYear = inst.selectedYear = date.getFullYear();
1847		if (period === "M" || period === "Y") {
1848			this._notifyChange(inst);
1849		}
1850	},
1851
1852	/* Ensure a date is within any min/max bounds. */
1853	_restrictMinMax: function(inst, date) {
1854		var minDate = this._getMinMaxDate(inst, "min"),
1855			maxDate = this._getMinMaxDate(inst, "max"),
1856			newDate = (minDate && date < minDate ? minDate : date);
1857		return (maxDate && newDate > maxDate ? maxDate : newDate);
1858	},
1859
1860	/* Notify change of month/year. */
1861	_notifyChange: function(inst) {
1862		var onChange = this._get(inst, "onChangeMonthYear");
1863		if (onChange) {
1864			onChange.apply((inst.input ? inst.input[0] : null),
1865				[inst.selectedYear, inst.selectedMonth + 1, inst]);
1866		}
1867	},
1868
1869	/* Determine the number of months to show. */
1870	_getNumberOfMonths: function(inst) {
1871		var numMonths = this._get(inst, "numberOfMonths");
1872		return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
1873	},
1874
1875	/* Determine the current maximum date - ensure no time components are set. */
1876	_getMinMaxDate: function(inst, minMax) {
1877		return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
1878	},
1879
1880	/* Find the number of days in a given month. */
1881	_getDaysInMonth: function(year, month) {
1882		return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
1883	},
1884
1885	/* Find the day of the week of the first of a month. */
1886	_getFirstDayOfMonth: function(year, month) {
1887		return new Date(year, month, 1).getDay();
1888	},
1889
1890	/* Determines if we should allow a "next/prev" month display change. */
1891	_canAdjustMonth: function(inst, offset, curYear, curMonth) {
1892		var numMonths = this._getNumberOfMonths(inst),
1893			date = this._daylightSavingAdjust(new Date(curYear,
1894			curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
1895
1896		if (offset < 0) {
1897			date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
1898		}
1899		return this._isInRange(inst, date);
1900	},
1901
1902	/* Is the given date in the accepted range? */
1903	_isInRange: function(inst, date) {
1904		var yearSplit, currentYear,
1905			minDate = this._getMinMaxDate(inst, "min"),
1906			maxDate = this._getMinMaxDate(inst, "max"),
1907			minYear = null,
1908			maxYear = null,
1909			years = this._get(inst, "yearRange");
1910			if (years){
1911				yearSplit = years.split(":");
1912				currentYear = new Date().getFullYear();
1913				minYear = parseInt(yearSplit[0], 10);
1914				maxYear = parseInt(yearSplit[1], 10);
1915				if ( yearSplit[0].match(/[+\-].*/) ) {
1916					minYear += currentYear;
1917				}
1918				if ( yearSplit[1].match(/[+\-].*/) ) {
1919					maxYear += currentYear;
1920				}
1921			}
1922
1923		return ((!minDate || date.getTime() >= minDate.getTime()) &&
1924			(!maxDate || date.getTime() <= maxDate.getTime()) &&
1925			(!minYear || date.getFullYear() >= minYear) &&
1926			(!maxYear || date.getFullYear() <= maxYear));
1927	},
1928
1929	/* Provide the configuration settings for formatting/parsing. */
1930	_getFormatConfig: function(inst) {
1931		var shortYearCutoff = this._get(inst, "shortYearCutoff");
1932		shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
1933			new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
1934		return {shortYearCutoff: shortYearCutoff,
1935			dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
1936			monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
1937	},
1938
1939	/* Format the given date for display. */
1940	_formatDate: function(inst, day, month, year) {
1941		if (!day) {
1942			inst.currentDay = inst.selectedDay;
1943			inst.currentMonth = inst.selectedMonth;
1944			inst.currentYear = inst.selectedYear;
1945		}
1946		var date = (day ? (typeof day === "object" ? day :
1947			this._daylightSavingAdjust(new Date(year, month, day))) :
1948			this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
1949		return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
1950	}
1951});
1952
1953/*
1954 * Bind hover events for datepicker elements.
1955 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
1956 * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
1957 */
1958function bindHover(dpDiv) {
1959	var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
1960	return dpDiv.delegate(selector, "mouseout", function() {
1961			$(this).removeClass("ui-state-hover");
1962			if (this.className.indexOf("ui-datepicker-prev") !== -1) {
1963				$(this).removeClass("ui-datepicker-prev-hover");
1964			}
1965			if (this.className.indexOf("ui-datepicker-next") !== -1) {
1966				$(this).removeClass("ui-datepicker-next-hover");
1967			}
1968		})
1969		.delegate(selector, "mouseover", function(){
1970			if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
1971				$(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
1972				$(this).addClass("ui-state-hover");
1973				if (this.className.indexOf("ui-datepicker-prev") !== -1) {
1974					$(this).addClass("ui-datepicker-prev-hover");
1975				}
1976				if (this.className.indexOf("ui-datepicker-next") !== -1) {
1977					$(this).addClass("ui-datepicker-next-hover");
1978				}
1979			}
1980		});
1981}
1982
1983/* jQuery extend now ignores nulls! */
1984function extendRemove(target, props) {
1985	$.extend(target, props);
1986	for (var name in props) {
1987		if (props[name] == null) {
1988			target[name] = props[name];
1989		}
1990	}
1991	return target;
1992}
1993
1994/* Invoke the datepicker functionality.
1995   @param  options  string - a command, optionally followed by additional parameters or
1996					Object - settings for attaching new datepicker functionality
1997   @return  jQuery object */
1998$.fn.datepicker = function(options){
1999
2000	/* Verify an empty collection wasn't passed - Fixes #6976 */
2001	if ( !this.length ) {
2002		return this;
2003	}
2004
2005	/* Initialise the date picker. */
2006	if (!$.datepicker.initialized) {
2007		$(document).mousedown($.datepicker._checkExternalClick);
2008		$.datepicker.initialized = true;
2009	}
2010
2011	/* Append datepicker main container to body if not exist. */
2012	if ($("#"+$.datepicker._mainDivId).length === 0) {
2013		$("body").append($.datepicker.dpDiv);
2014	}
2015
2016	var otherArgs = Array.prototype.slice.call(arguments, 1);
2017	if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
2018		return $.datepicker["_" + options + "Datepicker"].
2019			apply($.datepicker, [this[0]].concat(otherArgs));
2020	}
2021	if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
2022		return $.datepicker["_" + options + "Datepicker"].
2023			apply($.datepicker, [this[0]].concat(otherArgs));
2024	}
2025	return this.each(function() {
2026		typeof options === "string" ?
2027			$.datepicker["_" + options + "Datepicker"].
2028				apply($.datepicker, [this].concat(otherArgs)) :
2029			$.datepicker._attachDatepicker(this, options);
2030	});
2031};
2032
2033$.datepicker = new Datepicker(); // singleton instance
2034$.datepicker.initialized = false;
2035$.datepicker.uuid = new Date().getTime();
2036$.datepicker.version = "1.10.3";
2037
2038})(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.