PageSourceSearch

https://www.adcmc.gov.ae/-/media/Extension-Themes/ex-core/scripts/Core/jquery-ui-datepicker.js

js adcmc.gov.ae collected 2026-10-06 20:17:34 UTC 101,069 bytes, 2,889 lines download raw bytes

1/*! jQuery UI - v1.12.1 - 2016-10-07
2* http://jqueryui.com
3* Includes: widget.js, keycode.js, widgets/datepick
vendor: 8,820 bytes, lines 3-330
3er.js
4* Copyright jQuery Foundation and other contributors; Licensed MIT */
5
6(function( factory ) {
7	if ( typeof define === "function" && define.amd ) {
8
9		// AMD. Register as an anonymous module.
10		define([ "jquery" ], factory );
11	} else {
12
13		// Browser globals
14		factory( jQuery );
15	}
16}(function( $ ) {
17
18$.ui = $.ui || {};
19
20var version = $.ui.version = "1.12.1";
21
22
23/*!
24 * jQuery UI Widget 1.12.1
25 * http://jqueryui.com
26 *
27 * Copyright jQuery Foundation and other contributors
28 * Released under the MIT license.
29 * http://jquery.org/license
30 */
31
32//>>label: Widget
33//>>group: Core
34//>>description: Provides a factory for creating stateful widgets with a common API.
35//>>docs: http://api.jqueryui.com/jQuery.widget/
36//>>demos: http://jqueryui.com/widget/
37
38
39
40var widgetUuid = 0;
41var widgetSlice = Array.prototype.slice;
42
43$.cleanData = ( function( orig ) {
44	return function( elems ) {
45		var events, elem, i;
46		for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
47			try {
48
49				// Only trigger remove when necessary to save time
50				events = $._data( elem, "events" );
51				if ( events && events.remove ) {
52					$( elem ).triggerHandler( "remove" );
53				}
54
55			// Http://bugs.jquery.com/ticket/8235
56			} catch ( e ) {}
57		}
58		orig( elems );
59	};
60} )( $.cleanData );
61
62$.widget = function( name, base, prototype ) {
63	var existingConstructor, constructor, basePrototype;
64
65	// ProxiedPrototype allows the provided prototype to remain unmodified
66	// so that it can be used as a mixin for multiple widgets (#8876)
67	var proxiedPrototype = {};
68
69	var namespace = name.split( "." )[ 0 ];
70	name = name.split( "." )[ 1 ];
71	var fullName = namespace + "-" + name;
72
73	if ( !prototype ) {
74		prototype = base;
75		base = $.Widget;
76	}
77
78	if ( $.isArray( prototype ) ) {
79		prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
80	}
81
82	// Create selector for plugin
83	$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
84		return !!$.data( elem, fullName );
85	};
86
87	$[ namespace ] = $[ namespace ] || {};
88	existingConstructor = $[ namespace ][ name ];
89	constructor = $[ namespace ][ name ] = function( options, element ) {
90
91		// Allow instantiation without "new" keyword
92		if ( !this._createWidget ) {
93			return new constructor( options, element );
94		}
95
96		// Allow instantiation without initializing for simple inheritance
97		// must use "new" keyword (the code above always passes args)
98		if ( arguments.length ) {
99			this._createWidget( options, element );
100		}
101	};
102
103	// Extend with the existing constructor to carry over any static properties
104	$.extend( constructor, existingConstructor, {
105		version: prototype.version,
106
107		// Copy the object used to create the prototype in case we need to
108		// redefine the widget later
109		_proto: $.extend( {}, prototype ),
110
111		// Track widgets that inherit from this widget in case this widget is
112		// redefined after a widget inherits from it
113		_childConstructors: []
114	} );
115
116	basePrototype = new base();
117
118	// We need to make the options hash a property directly on the new instance
119	// otherwise we'll modify the options hash on the prototype that we're
120	// inheriting from
121	basePrototype.options = $.widget.extend( {}, basePrototype.options );
122	$.each( prototype, function( prop, value ) {
123		if ( !$.isFunction( value ) ) {
124			proxiedPrototype[ prop ] = value;
125			return;
126		}
127		proxiedPrototype[ prop ] = ( function() {
128			function _super() {
129				return base.prototype[ prop ].apply( this, arguments );
130			}
131
132			function _superApply( args ) {
133				return base.prototype[ prop ].apply( this, args );
134			}
135
136			return function() {
137				var __super = this._super;
138				var __superApply = this._superApply;
139				var returnValue;
140
141				this._super = _super;
142				this._superApply = _superApply;
143
144				returnValue = value.apply( this, arguments );
145
146				this._super = __super;
147				this._superApply = __superApply;
148
149				return returnValue;
150			};
151		} )();
152	} );
153	constructor.prototype = $.widget.extend( basePrototype, {
154
155		// TODO: remove support for widgetEventPrefix
156		// always use the name + a colon as the prefix, e.g., draggable:start
157		// don't prefix for widgets that aren't DOM-based
158		widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
159	}, proxiedPrototype, {
160		constructor: constructor,
161		namespace: namespace,
162		widgetName: name,
163		widgetFullName: fullName
164	} );
165
166	// If this widget is being redefined then we need to find all widgets that
167	// are inheriting from it and redefine all of them so that they inherit from
168	// the new version of this widget. We're essentially trying to replace one
169	// level in the prototype chain.
170	if ( existingConstructor ) {
171		$.each( existingConstructor._childConstructors, function( i, child ) {
172			var childPrototype = child.prototype;
173
174			// Redefine the child widget using the same prototype that was
175			// originally used, but inherit from the new version of the base
176			$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
177				child._proto );
178		} );
179
180		// Remove the list of existing child constructors from the old constructor
181		// so the old child constructors can be garbage collected
182		delete existingConstructor._childConstructors;
183	} else {
184		base._childConstructors.push( constructor );
185	}
186
187	$.widget.bridge( name, constructor );
188
189	return constructor;
190};
191
192$.widget.extend = function( target ) {
193	var input = widgetSlice.call( arguments, 1 );
194	var inputIndex = 0;
195	var inputLength = input.length;
196	var key;
197	var value;
198
199	for ( ; inputIndex < inputLength; inputIndex++ ) {
200		for ( key in input[ inputIndex ] ) {
201			value = input[ inputIndex ][ key ];
202			if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
203
204				// Clone objects
205				if ( $.isPlainObject( value ) ) {
206					target[ key ] = $.isPlainObject( target[ key ] ) ?
207						$.widget.extend( {}, target[ key ], value ) :
208
209						// Don't extend strings, arrays, etc. with objects
210						$.widget.extend( {}, value );
211
212				// Copy everything else by reference
213				} else {
214					target[ key ] = value;
215				}
216			}
217		}
218	}
219	return target;
220};
221
222$.widget.bridge = function( name, object ) {
223	var fullName = object.prototype.widgetFullName || name;
224	$.fn[ name ] = function( options ) {
225		var isMethodCall = typeof options === "string";
226		var args = widgetSlice.call( arguments, 1 );
227		var returnValue = this;
228
229		if ( isMethodCall ) {
230
231			// If this is an empty collection, we need to have the instance method
232			// return undefined instead of the jQuery instance
233			if ( !this.length && options === "instance" ) {
234				returnValue = undefined;
235			} else {
236				this.each( function() {
237					var methodValue;
238					var instance = $.data( this, fullName );
239
240					if ( options === "instance" ) {
241						returnValue = instance;
242						return false;
243					}
244
245					if ( !instance ) {
246						return $.error( "cannot call methods on " + name +
247							" prior to initialization; " +
248							"attempted to call method '" + options + "'" );
249					}
250
251					if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
252						return $.error( "no such method '" + options + "' for " + name +
253							" widget instance" );
254					}
255
256					methodValue = instance[ options ].apply( instance, args );
257
258					if ( methodValue !== instance && methodValue !== undefined ) {
259						returnValue = methodValue && methodValue.jquery ?
260							returnValue.pushStack( methodValue.get() ) :
261							methodValue;
262						return false;
263					}
264				} );
265			}
266		} else {
267
268			// Allow multiple hashes to be passed on init
269			if ( args.length ) {
270				options = $.widget.extend.apply( null, [ options ].concat( args ) );
271			}
272
273			this.each( function() {
274				var instance = $.data( this, fullName );
275				if ( instance ) {
276					instance.option( options || {} );
277					if ( instance._init ) {
278						instance._init();
279					}
280				} else {
281					$.data( this, fullName, new object( options, this ) );
282				}
283			} );
284		}
285
286		return returnValue;
287	};
288};
289
290$.Widget = function( /* options, element */ ) {};
291$.Widget._childConstructors = [];
292
293$.Widget.prototype = {
294	widgetName: "widget",
295	widgetEventPrefix: "",
296	defaultElement: "<div>",
297
298	options: {
299		classes: {},
300		disabled: false,
301
302		// Callbacks
303		create: null
304	},
305
306	_createWidget: function( options, element ) {
307		element = $( element || this.defaultElement || this )[ 0 ];
308		this.element = $( element );
309		this.uuid = widgetUuid++;
310		this.eventNamespace = "." + this.widgetName + this.uuid;
311
312		this.bindings = $();
313		this.hoverable = $();
314		this.focusable = $();
315		this.classesElementLookup = {};
316
317		if ( element !== this ) {
318			$.data( element, this.widgetFullName, this );
319			this._on( true, this.element, {
320				remove: function( event ) {
321					if ( event.target === element ) {
322						this.destroy();
323					}
324				}
325			} );
326			this.document = $( element.style ?
327
328				// Element within the document
329				element.ownerDocument :
330
vendor: 11,069 bytes, lines 331-747
331				// Element is window or document
332				element.document || element );
333			this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
334		}
335
336		this.options = $.widget.extend( {},
337			this.options,
338			this._getCreateOptions(),
339			options );
340
341		this._create();
342
343		if ( this.options.disabled ) {
344			this._setOptionDisabled( this.options.disabled );
345		}
346
347		this._trigger( "create", null, this._getCreateEventData() );
348		this._init();
349	},
350
351	_getCreateOptions: function() {
352		return {};
353	},
354
355	_getCreateEventData: $.noop,
356
357	_create: $.noop,
358
359	_init: $.noop,
360
361	destroy: function() {
362		var that = this;
363
364		this._destroy();
365		$.each( this.classesElementLookup, function( key, value ) {
366			that._removeClass( value, key );
367		} );
368
369		// We can probably remove the unbind calls in 2.0
370		// all event bindings should go through this._on()
371		this.element
372			.off( this.eventNamespace )
373			.removeData( this.widgetFullName );
374		this.widget()
375			.off( this.eventNamespace )
376			.removeAttr( "aria-disabled" );
377
378		// Clean up events and states
379		this.bindings.off( this.eventNamespace );
380	},
381
382	_destroy: $.noop,
383
384	widget: function() {
385		return this.element;
386	},
387
388	option: function( key, value ) {
389		var options = key;
390		var parts;
391		var curOption;
392		var i;
393
394		if ( arguments.length === 0 ) {
395
396			// Don't return a reference to the internal hash
397			return $.widget.extend( {}, this.options );
398		}
399
400		if ( typeof key === "string" ) {
401
402			// Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
403			options = {};
404			parts = key.split( "." );
405			key = parts.shift();
406			if ( parts.length ) {
407				curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
408				for ( i = 0; i < parts.length - 1; i++ ) {
409					curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
410					curOption = curOption[ parts[ i ] ];
411				}
412				key = parts.pop();
413				if ( arguments.length === 1 ) {
414					return curOption[ key ] === undefined ? null : curOption[ key ];
415				}
416				curOption[ key ] = value;
417			} else {
418				if ( arguments.length === 1 ) {
419					return this.options[ key ] === undefined ? null : this.options[ key ];
420				}
421				options[ key ] = value;
422			}
423		}
424
425		this._setOptions( options );
426
427		return this;
428	},
429
430	_setOptions: function( options ) {
431		var key;
432
433		for ( key in options ) {
434			this._setOption( key, options[ key ] );
435		}
436
437		return this;
438	},
439
440	_setOption: function( key, value ) {
441		if ( key === "classes" ) {
442			this._setOptionClasses( value );
443		}
444
445		this.options[ key ] = value;
446
447		if ( key === "disabled" ) {
448			this._setOptionDisabled( value );
449		}
450
451		return this;
452	},
453
454	_setOptionClasses: function( value ) {
455		var classKey, elements, currentElements;
456
457		for ( classKey in value ) {
458			currentElements = this.classesElementLookup[ classKey ];
459			if ( value[ classKey ] === this.options.classes[ classKey ] ||
460					!currentElements ||
461					!currentElements.length ) {
462				continue;
463			}
464
465			// We are doing this to create a new jQuery object because the _removeClass() call
466			// on the next line is going to destroy the reference to the current elements being
467			// tracked. We need to save a copy of this collection so that we can add the new classes
468			// below.
469			elements = $( currentElements.get() );
470			this._removeClass( currentElements, classKey );
471
472			// We don't use _addClass() here, because that uses this.options.classes
473			// for generating the string of classes. We want to use the value passed in from
474			// _setOption(), this is the new value of the classes option which was passed to
475			// _setOption(). We pass this value directly to _classes().
476			elements.addClass( this._classes( {
477				element: elements,
478				keys: classKey,
479				classes: value,
480				add: true
481			} ) );
482		}
483	},
484
485	_setOptionDisabled: function( value ) {
486		this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );
487
488		// If the widget is becoming disabled, then nothing is interactive
489		if ( value ) {
490			this._removeClass( this.hoverable, null, "ui-state-hover" );
491			this._removeClass( this.focusable, null, "ui-state-focus" );
492		}
493	},
494
495	enable: function() {
496		return this._setOptions( { disabled: false } );
497	},
498
499	disable: function() {
500		return this._setOptions( { disabled: true } );
501	},
502
503	_classes: function( options ) {
504		var full = [];
505		var that = this;
506
507		options = $.extend( {
508			element: this.element,
509			classes: this.options.classes || {}
510		}, options );
511
512		function processClassString( classes, checkOption ) {
513			var current, i;
514			for ( i = 0; i < classes.length; i++ ) {
515				current = that.classesElementLookup[ classes[ i ] ] || $();
516				if ( options.add ) {
517					current = $( $.unique( current.get().concat( options.element.get() ) ) );
518				} else {
519					current = $( current.not( options.element ).get() );
520				}
521				that.classesElementLookup[ classes[ i ] ] = current;
522				full.push( classes[ i ] );
523				if ( checkOption && options.classes[ classes[ i ] ] ) {
524					full.push( options.classes[ classes[ i ] ] );
525				}
526			}
527		}
528
529		this._on( options.element, {
530			"remove": "_untrackClassesElement"
531		} );
532
533		if ( options.keys ) {
534			processClassString( options.keys.match( /\S+/g ) || [], true );
535		}
536		if ( options.extra ) {
537			processClassString( options.extra.match( /\S+/g ) || [] );
538		}
539
540		return full.join( " " );
541	},
542
543	_untrackClassesElement: function( event ) {
544		var that = this;
545		$.each( that.classesElementLookup, function( key, value ) {
546			if ( $.inArray( event.target, value ) !== -1 ) {
547				that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
548			}
549		} );
550	},
551
552	_removeClass: function( element, keys, extra ) {
553		return this._toggleClass( element, keys, extra, false );
554	},
555
556	_addClass: function( element, keys, extra ) {
557		return this._toggleClass( element, keys, extra, true );
558	},
559
560	_toggleClass: function( element, keys, extra, add ) {
561		add = ( typeof add === "boolean" ) ? add : extra;
562		var shift = ( typeof element === "string" || element === null ),
563			options = {
564				extra: shift ? keys : extra,
565				keys: shift ? element : keys,
566				element: shift ? this.element : element,
567				add: add
568			};
569		options.element.toggleClass( this._classes( options ), add );
570		return this;
571	},
572
573	_on: function( suppressDisabledCheck, element, handlers ) {
574		var delegateElement;
575		var instance = this;
576
577		// No suppressDisabledCheck flag, shuffle arguments
578		if ( typeof suppressDisabledCheck !== "boolean" ) {
579			handlers = element;
580			element = suppressDisabledCheck;
581			suppressDisabledCheck = false;
582		}
583
584		// No element argument, shuffle and use this.element
585		if ( !handlers ) {
586			handlers = element;
587			element = this.element;
588			delegateElement = this.widget();
589		} else {
590			element = delegateElement = $( element );
591			this.bindings = this.bindings.add( element );
592		}
593
594		$.each( handlers, function( event, handler ) {
595			function handlerProxy() {
596
597				// Allow widgets to customize the disabled handling
598				// - disabled as an array instead of boolean
599				// - disabled class as method for disabling individual parts
600				if ( !suppressDisabledCheck &&
601						( instance.options.disabled === true ||
602						$( this ).hasClass( "ui-state-disabled" ) ) ) {
603					return;
604				}
605				return ( typeof handler === "string" ? instance[ handler ] : handler )
606					.apply( instance, arguments );
607			}
608
609			// Copy the guid so direct unbinding works
610			if ( typeof handler !== "string" ) {
611				handlerProxy.guid = handler.guid =
612					handler.guid || handlerProxy.guid || $.guid++;
613			}
614
615			var match = event.match( /^([\w:-]*)\s*(.*)$/ );
616			var eventName = match[ 1 ] + instance.eventNamespace;
617			var selector = match[ 2 ];
618
619			if ( selector ) {
620				delegateElement.on( eventName, selector, handlerProxy );
621			} else {
622				element.on( eventName, handlerProxy );
623			}
624		} );
625	},
626
627	_off: function( element, eventName ) {
628		eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
629			this.eventNamespace;
630		element.off( eventName ).off( eventName );
631
632		// Clear the stack to avoid memory leaks (#10056)
633		this.bindings = $( this.bindings.not( element ).get() );
634		this.focusable = $( this.focusable.not( element ).get() );
635		this.hoverable = $( this.hoverable.not( element ).get() );
636	},
637
638	_delay: function( handler, delay ) {
639		function handlerProxy() {
640			return ( typeof handler === "string" ? instance[ handler ] : handler )
641				.apply( instance, arguments );
642		}
643		var instance = this;
644		return setTimeout( handlerProxy, delay || 0 );
645	},
646
647	_hoverable: function( element ) {
648		this.hoverable = this.hoverable.add( element );
649		this._on( element, {
650			mouseenter: function( event ) {
651				this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
652			},
653			mouseleave: function( event ) {
654				this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
655			}
656		} );
657	},
658
659	_focusable: function( element ) {
660		this.focusable = this.focusable.add( element );
661		this._on( element, {
662			focusin: function( event ) {
663				this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
664			},
665			focusout: function( event ) {
666				this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
667			}
668		} );
669	},
670
671	_trigger: function( type, event, data ) {
672		var prop, orig;
673		var callback = this.options[ type ];
674
675		data = data || {};
676		event = $.Event( event );
677		event.type = ( type === this.widgetEventPrefix ?
678			type :
679			this.widgetEventPrefix + type ).toLowerCase();
680
681		// The original event may come from any element
682		// so we need to reset the target on the new event
683		event.target = this.element[ 0 ];
684
685		// Copy original event properties over to the new event
686		orig = event.originalEvent;
687		if ( orig ) {
688			for ( prop in orig ) {
689				if ( !( prop in event ) ) {
690					event[ prop ] = orig[ prop ];
691				}
692			}
693		}
694
695		this.element.trigger( event, data );
696		return !( $.isFunction( callback ) &&
697			callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
698			event.isDefaultPrevented() );
699	}
700};
701
702$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
703	$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
704		if ( typeof options === "string" ) {
705			options = { effect: options };
706		}
707
708		var hasOptions;
709		var effectName = !options ?
710			method :
711			options === true || typeof options === "number" ?
712				defaultEffect :
713				options.effect || defaultEffect;
714
715		options = options || {};
716		if ( typeof options === "number" ) {
717			options = { duration: options };
718		}
719
720		hasOptions = !$.isEmptyObject( options );
721		options.complete = callback;
722
723		if ( options.delay ) {
724			element.delay( options.delay );
725		}
726
727		if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
728			element[ method ]( options );
729		} else if ( effectName !== method && element[ effectName ] ) {
730			element[ effectName ]( options.duration, options.easing, callback );
731		} else {
732			element.queue( function( next ) {
733				$( this )[ method ]();
734				if ( callback ) {
735					callback.call( element[ 0 ] );
736				}
737				next();
738			} );
739		}
740	};
741} );
742
743var widget = $.widget;
744
745
746/*!
747 * jQuery UI 
747Keycode 1.12.1
748 * http://jqueryui.com
749 *
750 * Copyright jQuery Foundation and other contributors
751 * Released under the MIT license.
752 * http://jquery.org/license
753 */
754
755//>>label: Keycode
756//>>group: Core
757//>>description: Provide keycodes as keynames
758//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
759
760
761var keycode = $.ui.keyCode = {
762	BACKSPACE: 8,
763	COMMA: 188,
764	DELETE: 46,
765	DOWN: 40,
766	END: 35,
767	ENTER: 13,
768	ESCAPE: 27,
769	HOME: 36,
770	LEFT: 37,
771	PAGE_DOWN: 34,
772	PAGE_UP: 33,
773	PERIOD: 190,
774	RIGHT: 39,
775	SPACE: 32,
776	TAB: 9,
777	UP: 38
778}
vendor: 80,540 bytes, lines 778-2888
778;
779
780
781// jscs:disable maximumLineLength
782/* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
783/*!
784 * jQuery UI Datepicker 1.12.1
785 * http://jqueryui.com
786 *
787 * Copyright jQuery Foundation and other contributors
788 * Released under the MIT license.
789 * http://jquery.org/license
790 */
791
792//>>label: Datepicker
793//>>group: Widgets
794//>>description: Displays a calendar from an input or inline for selecting dates.
795//>>docs: http://api.jqueryui.com/datepicker/
796//>>demos: http://jqueryui.com/datepicker/
797//>>css.structure: ../../themes/base/core.css
798//>>css.structure: ../../themes/base/datepicker.css
799//>>css.theme: ../../themes/base/theme.css
800
801
802
803$.extend( $.ui, { datepicker: { version: "1.12.1" } } );
804
805var datepicker_instActive;
806
807function datepicker_getZindex( elem ) {
808	var position, value;
809	while ( elem.length && elem[ 0 ] !== document ) {
810
811		// Ignore z-index if position is set to a value where z-index is ignored by the browser
812		// This makes behavior of this function consistent across browsers
813		// WebKit always returns auto if the element is positioned
814		position = elem.css( "position" );
815		if ( position === "absolute" || position === "relative" || position === "fixed" ) {
816
817			// IE returns 0 when zIndex is not specified
818			// other browsers return a string
819			// we ignore the case of nested elements with an explicit value of 0
820			// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
821			value = parseInt( elem.css( "zIndex" ), 10 );
822			if ( !isNaN( value ) && value !== 0 ) {
823				return value;
824			}
825		}
826		elem = elem.parent();
827	}
828
829	return 0;
830}
831/* Date picker manager.
832   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
833   Settings for (groups of) date pickers are maintained in an instance object,
834   allowing multiple different settings on the same page. */
835
836function Datepicker() {
837	this._curInst = null; // The current instance in use
838	this._keyEvent = false; // If the last event was a key event
839	this._disabledInputs = []; // List of date picker inputs that have been disabled
840	this._datepickerShowing = false; // True if the popup picker is showing , false if not
841	this._inDialog = false; // True if showing within a "dialog", false if not
842	this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
843	this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
844	this._appendClass = "ui-datepicker-append"; // The name of the append marker class
845	this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
846	this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
847	this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
848	this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
849	this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
850	this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
851	this.regional = []; // Available regional settings, indexed by language code
852	this.regional[ "" ] = { // Default regional settings
853		closeText: "Done", // Display text for close link
854		prevText: "Prev", // Display text for previous month link
855		nextText: "Next", // Display text for next month link
856		currentText: "Today", // Display text for current month link
857		monthNames: [ "January","February","March","April","May","June",
858			"July","August","September","October","November","December" ], // Names of months for drop-down and formatting
859		monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
860		dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
861		dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
862		dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday
863		weekHeader: "Wk", // Column header for week of the year
864		dateFormat: "mm/dd/yy", // See format options on parseDate
865		firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
866		isRTL: false, // True if right-to-left language, false if left-to-right
867		showMonthAfterYear: false, // True if the year select precedes month, false for month then year
868		yearSuffix: "" // Additional text to append to the year in the month headers
869	};
870	this._defaults = { // Global defaults for all the date picker instances
871		showOn: "focus", // "focus" for popup on focus,
872			// "button" for trigger button, or "both" for either
873		showAnim: "fadeIn", // Name of jQuery animation for popup
874		showOptions: {}, // Options for enhanced animations
875		defaultDate: null, // Used when field is blank: actual date,
876			// +/-number for offset from today, null for today
877		appendText: "", // Display text following the input box, e.g. showing the format
878		buttonText: "...", // Text for trigger button
879		buttonImage: "", // URL for trigger button image
880		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
881		hideIfNoPrevNext: false, // True to hide next/previous month links
882			// if not applicable, false to just disable them
883		navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
884		gotoCurrent: false, // True if today link goes back to current selection instead
885		changeMonth: false, // True if month can be selected directly, false if only prev/next
886		changeYear: false, // True if year can be selected directly, false if only prev/next
887		yearRange: "c-10:c+10", // Range of years to display in drop-down,
888			// either relative to today's year (-nn:+nn), relative to currently displayed year
889			// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
890		showOtherMonths: false, // True to show dates in other months, false to leave blank
891		selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
892		showWeek: false, // True to show week of the year, false to not show it
893		calculateWeek: this.iso8601Week, // How to calculate the week of the year,
894			// takes a Date and returns the number of the week for it
895		shortYearCutoff: "+10", // Short year values < this are in the current century,
896			// > this are in the previous century,
897			// string value starting with "+" for current year + value
898		minDate: null, // The earliest selectable date, or null for no limit
899		maxDate: null, // The latest selectable date, or null for no limit
900		duration: "fast", // Duration of display/closure
901		beforeShowDay: null, // Function that takes a date and returns an array with
902			// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
903			// [2] = cell title (optional), e.g. $.datepicker.noWeekends
904		beforeShow: null, // Function that takes an input field and
905			// returns a set of custom settings for the date picker
906		onSelect: null, // Define a callback function when a date is selected
907		onChangeMonthYear: null, // Define a callback function when the month or year is changed
908		onClose: null, // Define a callback function when the datepicker is closed
909		numberOfMonths: 1, // Number of months to show at a time
910		showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
911		stepMonths: 1, // Number of months to step back/forward
912		stepBigMonths: 12, // Number of months to step back/forward for the big links
913		altField: "", // Selector for an alternate field to store selected dates into
914		altFormat: "", // The date format to use for the alternate field
915		constrainInput: true, // The input is constrained by the current date format
916		showButtonPanel: false, // True to show button panel, false to not show it
917		autoSize: false, // True to size the input for the date format, false to leave as is
918		disabled: false // The initial disabled state
919	};
920	$.extend( this._defaults, this.regional[ "" ] );
921	this.regional.en = $.extend( true, {}, this.regional[ "" ] );
922	this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
923	this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
924}
925
926$.extend( Datepicker.prototype, {
927	/* Class name added to elements to indicate already configured with a date picker. */
928	markerClassName: "hasDatepicker",
929
930	//Keep track of the maximum number of rows displayed (see #7043)
931	maxRows: 4,
932
933	// TODO rename to "widget" when switching to widget factory
934	_widgetDatepicker: function() {
935		return this.dpDiv;
936	},
937
938	/* Override the default settings for all instances of the date picker.
939	 * @param  settings  object - the new settings to use as defaults (anonymous object)
940	 * @return the manager object
941	 */
942	setDefaults: function( settings ) {
943		datepicker_extendRemove( this._defaults, settings || {} );
944		return this;
945	},
946
947	/* Attach the date picker to a jQuery selection.
948	 * @param  target	element - the target input field or division or span
949	 * @param  settings  object - the new settings to use for this date picker instance (anonymous)
950	 */
951	_attachDatepicker: function( target, settings ) {
952		var nodeName, inline, inst;
953		nodeName = target.nodeName.toLowerCase();
954		inline = ( nodeName === "div" || nodeName === "span" );
955		if ( !target.id ) {
956			this.uuid += 1;
957			target.id = "dp" + this.uuid;
958		}
959		inst = this._newInst( $( target ), inline );
960		inst.settings = $.extend( {}, settings || {} );
961		if ( nodeName === "input" ) {
962			this._connectDatepicker( target, inst );
963		} else if ( inline ) {
964			this._inlineDatepicker( target, inst );
965		}
966	},
967
968	/* Create a new instance object. */
969	_newInst: function( target, inline ) {
970		var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
971		return { id: id, input: target, // associated target
972			selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
973			drawMonth: 0, drawYear: 0, // month being drawn
974			inline: inline, // is datepicker inline or not
975			dpDiv: ( !inline ? this.dpDiv : // presentation div
976			datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
977	},
978
979	/* Attach the date picker to an input field. */
980	_connectDatepicker: function( target, inst ) {
981		var input = $( target );
982		inst.append = $( [] );
983		inst.trigger = $( [] );
984		if ( input.hasClass( this.markerClassName ) ) {
985			return;
986		}
987		this._attachments( input, inst );
988		input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
989			on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
990		this._autoSize( inst );
991		$.data( target, "datepicker", inst );
992
993		//If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
994		if ( inst.settings.disabled ) {
995			this._disableDatepicker( target );
996		}
997	},
998
999	/* Make attachments based on settings. */
1000	_attachments: function( input, inst ) {
1001		var showOn, buttonText, buttonImage,
1002			appendText = this._get( inst, "appendText" ),
1003			isRTL = this._get( inst, "isRTL" );
1004
1005		if ( inst.append ) {
1006			inst.append.remove();
1007		}
1008		if ( appendText ) {
1009			inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" );
1010			input[ isRTL ? "before" : "after" ]( inst.append );
1011		}
1012
1013		input.off( "focus", this._showDatepicker );
1014
1015		if ( inst.trigger ) {
1016			inst.trigger.remove();
1017		}
1018
1019		showOn = this._get( inst, "showOn" );
1020		if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
1021			input.on( "focus", this._showDatepicker );
1022		}
1023		if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
1024			buttonText = this._get( inst, "buttonText" );
1025			buttonImage = this._get( inst, "buttonImage" );
1026			inst.trigger = $( this._get( inst, "buttonImageOnly" ) ?
1027				$( "<img/>" ).addClass( this._triggerClass ).
1028					attr( { src: buttonImage, alt: buttonText, title: buttonText } ) :
1029				$( "<button type='button'></button>" ).addClass( this._triggerClass ).
1030					html( !buttonImage ? buttonText : $( "<img/>" ).attr(
1031					{ src:buttonImage, alt:buttonText, title:buttonText } ) ) );
1032			input[ isRTL ? "before" : "after" ]( inst.trigger );
1033			inst.trigger.on( "click", function() {
1034				if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
1035					$.datepicker._hideDatepicker();
1036				} else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
1037					$.datepicker._hideDatepicker();
1038					$.datepicker._showDatepicker( input[ 0 ] );
1039				} else {
1040					$.datepicker._showDatepicker( input[ 0 ] );
1041				}
1042				return false;
1043			} );
1044		}
1045	},
1046
1047	/* Apply the maximum length for the date format. */
1048	_autoSize: function( inst ) {
1049		if ( this._get( inst, "autoSize" ) && !inst.inline ) {
1050			var findMax, max, maxI, i,
1051				date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
1052				dateFormat = this._get( inst, "dateFormat" );
1053
1054			if ( dateFormat.match( /[DM]/ ) ) {
1055				findMax = function( names ) {
1056					max = 0;
1057					maxI = 0;
1058					for ( i = 0; i < names.length; i++ ) {
1059						if ( names[ i ].length > max ) {
1060							max = names[ i ].length;
1061							maxI = i;
1062						}
1063					}
1064					return maxI;
1065				};
1066				date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
1067					"monthNames" : "monthNamesShort" ) ) ) );
1068				date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
1069					"dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
1070			}
1071			inst.input.attr( "size", this._formatDate( inst, date ).length );
1072		}
1073	},
1074
1075	/* Attach an inline date picker to a div. */
1076	_inlineDatepicker: function( target, inst ) {
1077		var divSpan = $( target );
1078		if ( divSpan.hasClass( this.markerClassName ) ) {
1079			return;
1080		}
1081		divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
1082		$.data( target, "datepicker", inst );
1083		this._setDate( inst, this._getDefaultDate( inst ), true );
1084		this._updateDatepicker( inst );
1085		this._updateAlternate( inst );
1086
1087		//If disabled option is true, disable the datepicker before showing it (see ticket #5665)
1088		if ( inst.settings.disabled ) {
1089			this._disableDatepicker( target );
1090		}
1091
1092		// Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
1093		// http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
1094		inst.dpDiv.css( "display", "block" );
1095	},
1096
1097	/* Pop-up the date picker in a "dialog" box.
1098	 * @param  input element - ignored
1099	 * @param  date	string or Date - the initial date to display
1100	 * @param  onSelect  function - the function to call when a date is selected
1101	 * @param  settings  object - update the dialog date picker instance's settings (anonymous object)
1102	 * @param  pos int[2] - coordinates for the dialog's position within the screen or
1103	 *					event - with x/y coordinates or
1104	 *					leave empty for default (screen centre)
1105	 * @return the manager object
1106	 */
1107	_dialogDatepicker: function( input, date, onSelect, settings, pos ) {
1108		var id, browserWidth, browserHeight, scrollX, scrollY,
1109			inst = this._dialogInst; // internal instance
1110
1111		if ( !inst ) {
1112			this.uuid += 1;
1113			id = "dp" + this.uuid;
1114			this._dialogInput = $( "<input type='text' id='" + id +
1115				"' style='position: absolute; top: -100px; width: 0px;'/>" );
1116			this._dialogInput.on( "keydown", this._doKeyDown );
1117			$( "body" ).append( this._dialogInput );
1118			inst = this._dialogInst = this._newInst( this._dialogInput, false );
1119			inst.settings = {};
1120			$.data( this._dialogInput[ 0 ], "datepicker", inst );
1121		}
1122		datepicker_extendRemove( inst.settings, settings || {} );
1123		date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
1124		this._dialogInput.val( date );
1125
1126		this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
1127		if ( !this._pos ) {
1128			browserWidth = document.documentElement.clientWidth;
1129			browserHeight = document.documentElement.clientHeight;
1130			scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
1131			scrollY = document.documentElement.scrollTop || document.body.scrollTop;
1132			this._pos = // should use actual width/height below
1133				[ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
1134		}
1135
1136		// Move input on screen for focus, but hidden behind dialog
1137		this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
1138		inst.settings.onSelect = onSelect;
1139		this._inDialog = true;
1140		this.dpDiv.addClass( this._dialogClass );
1141		this._showDatepicker( this._dialogInput[ 0 ] );
1142		if ( $.blockUI ) {
1143			$.blockUI( this.dpDiv );
1144		}
1145		$.data( this._dialogInput[ 0 ], "datepicker", inst );
1146		return this;
1147	},
1148
1149	/* Detach a datepicker from its control.
1150	 * @param  target	element - the target input field or division or span
1151	 */
1152	_destroyDatepicker: function( target ) {
1153		var nodeName,
1154			$target = $( target ),
1155			inst = $.data( target, "datepicker" );
1156
1157		if ( !$target.hasClass( this.markerClassName ) ) {
1158			return;
1159		}
1160
1161		nodeName = target.nodeName.toLowerCase();
1162		$.removeData( target, "datepicker" );
1163		if ( nodeName === "input" ) {
1164			inst.append.remove();
1165			inst.trigger.remove();
1166			$target.removeClass( this.markerClassName ).
1167				off( "focus", this._showDatepicker ).
1168				off( "keydown", this._doKeyDown ).
1169				off( "keypress", this._doKeyPress ).
1170				off( "keyup", this._doKeyUp );
1171		} else if ( nodeName === "div" || nodeName === "span" ) {
1172			$target.removeClass( this.markerClassName ).empty();
1173		}
1174
1175		if ( datepicker_instActive === inst ) {
1176			datepicker_instActive = null;
1177		}
1178	},
1179
1180	/* Enable the date picker to a jQuery selection.
1181	 * @param  target	element - the target input field or division or span
1182	 */
1183	_enableDatepicker: function( target ) {
1184		var nodeName, inline,
1185			$target = $( target ),
1186			inst = $.data( target, "datepicker" );
1187
1188		if ( !$target.hasClass( this.markerClassName ) ) {
1189			return;
1190		}
1191
1192		nodeName = target.nodeName.toLowerCase();
1193		if ( nodeName === "input" ) {
1194			target.disabled = false;
1195			inst.trigger.filter( "button" ).
1196				each( function() { this.disabled = false; } ).end().
1197				filter( "img" ).css( { opacity: "1.0", cursor: "" } );
1198		} else if ( nodeName === "div" || nodeName === "span" ) {
1199			inline = $target.children( "." + this._inlineClass );
1200			inline.children().removeClass( "ui-state-disabled" );
1201			inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
1202				prop( "disabled", false );
1203		}
1204		this._disabledInputs = $.map( this._disabledInputs,
1205			function( value ) { return ( value === target ? null : value ); } ); // delete entry
1206	},
1207
1208	/* Disable the date picker to a jQuery selection.
1209	 * @param  target	element - the target input field or division or span
1210	 */
1211	_disableDatepicker: function( target ) {
1212		var nodeName, inline,
1213			$target = $( target ),
1214			inst = $.data( target, "datepicker" );
1215
1216		if ( !$target.hasClass( this.markerClassName ) ) {
1217			return;
1218		}
1219
1220		nodeName = target.nodeName.toLowerCase();
1221		if ( nodeName === "input" ) {
1222			target.disabled = true;
1223			inst.trigger.filter( "button" ).
1224				each( function() { this.disabled = true; } ).end().
1225				filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
1226		} else if ( nodeName === "div" || nodeName === "span" ) {
1227			inline = $target.children( "." + this._inlineClass );
1228			inline.children().addClass( "ui-state-disabled" );
1229			inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
1230				prop( "disabled", true );
1231		}
1232		this._disabledInputs = $.map( this._disabledInputs,
1233			function( value ) { return ( value === target ? null : value ); } ); // delete entry
1234		this._disabledInputs[ this._disabledInputs.length ] = target;
1235	},
1236
1237	/* Is the first field in a jQuery collection disabled as a datepicker?
1238	 * @param  target	element - the target input field or division or span
1239	 * @return boolean - true if disabled, false if enabled
1240	 */
1241	_isDisabledDatepicker: function( target ) {
1242		if ( !target ) {
1243			return false;
1244		}
1245		for ( var i = 0; i < this._disabledInputs.length; i++ ) {
1246			if ( this._disabledInputs[ i ] === target ) {
1247				return true;
1248			}
1249		}
1250		return false;
1251	},
1252
1253	/* Retrieve the instance data for the target control.
1254	 * @param  target  element - the target input field or division or span
1255	 * @return  object - the associated instance data
1256	 * @throws  error if a jQuery problem getting data
1257	 */
1258	_getInst: function( target ) {
1259		try {
1260			return $.data( target, "datepicker" );
1261		}
1262		catch ( err ) {
1263			throw "Missing instance data for this datepicker";
1264		}
1265	},
1266
1267	/* Update or retrieve the settings for a date picker attached to an input field or division.
1268	 * @param  target  element - the target input field or division or span
1269	 * @param  name	object - the new settings to update or
1270	 *				string - the name of the setting to change or retrieve,
1271	 *				when retrieving also "all" for all instance settings or
1272	 *				"defaults" for all global defaults
1273	 * @param  value   any - the new value for the setting
1274	 *				(omit if above is an object or to retrieve a value)
1275	 */
1276	_optionDatepicker: function( target, name, value ) {
1277		var settings, date, minDate, maxDate,
1278			inst = this._getInst( target );
1279
1280		if ( arguments.length === 2 && typeof name === "string" ) {
1281			return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
1282				( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
1283				this._get( inst, name ) ) : null ) );
1284		}
1285
1286		settings = name || {};
1287		if ( typeof name === "string" ) {
1288			settings = {};
1289			settings[ name ] = value;
1290		}
1291
1292		if ( inst ) {
1293			if ( this._curInst === inst ) {
1294				this._hideDatepicker();
1295			}
1296
1297			date = this._getDateDatepicker( target, true );
1298			minDate = this._getMinMaxDate( inst, "min" );
1299			maxDate = this._getMinMaxDate( inst, "max" );
1300			datepicker_extendRemove( inst.settings, settings );
1301
1302			// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
1303			if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
1304				inst.settings.minDate = this._formatDate( inst, minDate );
1305			}
1306			if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
1307				inst.settings.maxDate = this._formatDate( inst, maxDate );
1308			}
1309			if ( "disabled" in settings ) {
1310				if ( settings.disabled ) {
1311					this._disableDatepicker( target );
1312				} else {
1313					this._enableDatepicker( target );
1314				}
1315			}
1316			this._attachments( $( target ), inst );
1317			this._autoSize( inst );
1318			this._setDate( inst, date );
1319			this._updateAlternate( inst );
1320			this._updateDatepicker( inst );
1321		}
1322	},
1323
1324	// Change method deprecated
1325	_changeDatepicker: function( target, name, value ) {
1326		this._optionDatepicker( target, name, value );
1327	},
1328
1329	/* Redraw the date picker attached to an input field or division.
1330	 * @param  target  element - the target input field or division or span
1331	 */
1332	_refreshDatepicker: function( target ) {
1333		var inst = this._getInst( target );
1334		if ( inst ) {
1335			this._updateDatepicker( inst );
1336		}
1337	},
1338
1339	/* Set the dates for a jQuery selection.
1340	 * @param  target element - the target input field or division or span
1341	 * @param  date	Date - the new date
1342	 */
1343	_setDateDatepicker: function( target, date ) {
1344		var inst = this._getInst( target );
1345		if ( inst ) {
1346			this._setDate( inst, date );
1347			this._updateDatepicker( inst );
1348			this._updateAlternate( inst );
1349		}
1350	},
1351
1352	/* Get the date(s) for the first entry in a jQuery selection.
1353	 * @param  target element - the target input field or division or span
1354	 * @param  noDefault boolean - true if no default date is to be used
1355	 * @return Date - the current date
1356	 */
1357	_getDateDatepicker: function( target, noDefault ) {
1358		var inst = this._getInst( target );
1359		if ( inst && !inst.inline ) {
1360			this._setDateFromField( inst, noDefault );
1361		}
1362		return ( inst ? this._getDate( inst ) : null );
1363	},
1364
1365	/* Handle keystrokes. */
1366	_doKeyDown: function( event ) {
1367		var onSelect, dateStr, sel,
1368			inst = $.datepicker._getInst( event.target ),
1369			handled = true,
1370			isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );
1371
1372		inst._keyEvent = true;
1373		if ( $.datepicker._datepickerShowing ) {
1374			switch ( event.keyCode ) {
1375				case 9: $.datepicker._hideDatepicker();
1376						handled = false;
1377						break; // hide on tab out
1378				case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
1379									$.datepicker._currentClass + ")", inst.dpDiv );
1380						if ( sel[ 0 ] ) {
1381							$.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
1382						}
1383
1384						onSelect = $.datepicker._get( inst, "onSelect" );
1385						if ( onSelect ) {
1386							dateStr = $.datepicker._formatDate( inst );
1387
1388							// Trigger custom callback
1389							onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
1390						} else {
1391							$.datepicker._hideDatepicker();
1392						}
1393
1394						return false; // don't submit the form
1395				case 27: $.datepicker._hideDatepicker();
1396						break; // hide on escape
1397				case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
1398							-$.datepicker._get( inst, "stepBigMonths" ) :
1399							-$.datepicker._get( inst, "stepMonths" ) ), "M" );
1400						break; // previous month/year on page up/+ ctrl
1401				case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
1402							+$.datepicker._get( inst, "stepBigMonths" ) :
1403							+$.datepicker._get( inst, "stepMonths" ) ), "M" );
1404						break; // next month/year on page down/+ ctrl
1405				case 35: if ( event.ctrlKey || event.metaKey ) {
1406							$.datepicker._clearDate( event.target );
1407						}
1408						handled = event.ctrlKey || event.metaKey;
1409						break; // clear on ctrl or command +end
1410				case 36: if ( event.ctrlKey || event.metaKey ) {
1411							$.datepicker._gotoToday( event.target );
1412						}
1413						handled = event.ctrlKey || event.metaKey;
1414						break; // current on ctrl or command +home
1415				case 37: if ( event.ctrlKey || event.metaKey ) {
1416							$.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
1417						}
1418						handled = event.ctrlKey || event.metaKey;
1419
1420						// -1 day on ctrl or command +left
1421						if ( event.originalEvent.altKey ) {
1422							$.datepicker._adjustDate( event.target, ( event.ctrlKey ?
1423								-$.datepicker._get( inst, "stepBigMonths" ) :
1424								-$.datepicker._get( inst, "stepMonths" ) ), "M" );
1425						}
1426
1427						// next month/year on alt +left on Mac
1428						break;
1429				case 38: if ( event.ctrlKey || event.metaKey ) {
1430							$.datepicker._adjustDate( event.target, -7, "D" );
1431						}
1432						handled = event.ctrlKey || event.metaKey;
1433						break; // -1 week on ctrl or command +up
1434				case 39: if ( event.ctrlKey || event.metaKey ) {
1435							$.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
1436						}
1437						handled = event.ctrlKey || event.metaKey;
1438
1439						// +1 day on ctrl or command +right
1440						if ( event.originalEvent.altKey ) {
1441							$.datepicker._adjustDate( event.target, ( event.ctrlKey ?
1442								+$.datepicker._get( inst, "stepBigMonths" ) :
1443								+$.datepicker._get( inst, "stepMonths" ) ), "M" );
1444						}
1445
1446						// next month/year on alt +right
1447						break;
1448				case 40: if ( event.ctrlKey || event.metaKey ) {
1449							$.datepicker._adjustDate( event.target, +7, "D" );
1450						}
1451						handled = event.ctrlKey || event.metaKey;
1452						break; // +1 week on ctrl or command +down
1453				default: handled = false;
1454			}
1455		} else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
1456			$.datepicker._showDatepicker( this );
1457		} else {
1458			handled = false;
1459		}
1460
1461		if ( handled ) {
1462			event.preventDefault();
1463			event.stopPropagation();
1464		}
1465	},
1466
1467	/* Filter entered characters - based on date format. */
1468	_doKeyPress: function( event ) {
1469		var chars, chr,
1470			inst = $.datepicker._getInst( event.target );
1471
1472		if ( $.datepicker._get( inst, "constrainInput" ) ) {
1473			chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
1474			chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
1475			return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
1476		}
1477	},
1478
1479	/* Synchronise manual entry and field/alternate field. */
1480	_doKeyUp: function( event ) {
1481		var date,
1482			inst = $.datepicker._getInst( event.target );
1483
1484		if ( inst.input.val() !== inst.lastVal ) {
1485			try {
1486				date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
1487					( inst.input ? inst.input.val() : null ),
1488					$.datepicker._getFormatConfig( inst ) );
1489
1490				if ( date ) { // only if valid
1491					$.datepicker._setDateFromField( inst );
1492					$.datepicker._updateAlternate( inst );
1493					$.datepicker._updateDatepicker( inst );
1494				}
1495			}
1496			catch ( err ) {
1497			}
1498		}
1499		return true;
1500	},
1501
1502	/* Pop-up the date picker for a given input field.
1503	 * If false returned from beforeShow event handler do not show.
1504	 * @param  input  element - the input field attached to the date picker or
1505	 *					event - if triggered by focus
1506	 */
1507	_showDatepicker: function( input ) {
1508		input = input.target || input;
1509		if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
1510			input = $( "input", input.parentNode )[ 0 ];
1511		}
1512
1513		if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
1514			return;
1515		}
1516
1517		var inst, beforeShow, beforeShowSettings, isFixed,
1518			offset, showAnim, duration;
1519
1520		inst = $.datepicker._getInst( input );
1521		if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
1522			$.datepicker._curInst.dpDiv.stop( true, true );
1523			if ( inst && $.datepicker._datepickerShowing ) {
1524				$.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
1525			}
1526		}
1527
1528		beforeShow = $.datepicker._get( inst, "beforeShow" );
1529		beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
1530		if ( beforeShowSettings === false ) {
1531			return;
1532		}
1533		datepicker_extendRemove( inst.settings, beforeShowSettings );
1534
1535		inst.lastVal = null;
1536		$.datepicker._lastInput = input;
1537		$.datepicker._setDateFromField( inst );
1538
1539		if ( $.datepicker._inDialog ) { // hide cursor
1540			input.value = "";
1541		}
1542		if ( !$.datepicker._pos ) { // position below input
1543			$.datepicker._pos = $.datepicker._findPos( input );
1544			$.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
1545		}
1546
1547		isFixed = false;
1548		$( input ).parents().each( function() {
1549			isFixed |= $( this ).css( "position" ) === "fixed";
1550			return !isFixed;
1551		} );
1552
1553		offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
1554		$.datepicker._pos = null;
1555
1556		//to avoid flashes on Firefox
1557		inst.dpDiv.empty();
1558
1559		// determine sizing offscreen
1560		inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
1561		$.datepicker._updateDatepicker( inst );
1562
1563		// fix width for dynamic number of date pickers
1564		// and adjust position before showing
1565		offset = $.datepicker._checkOffset( inst, offset, isFixed );
1566		inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
1567			"static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
1568			left: offset.left + "px", top: offset.top + "px" } );
1569
1570		if ( !inst.inline ) {
1571			showAnim = $.datepicker._get( inst, "showAnim" );
1572			duration = $.datepicker._get( inst, "duration" );
1573			inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
1574			$.datepicker._datepickerShowing = true;
1575
1576			if ( $.effects && $.effects.effect[ showAnim ] ) {
1577				inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
1578			} else {
1579				inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
1580			}
1581
1582			if ( $.datepicker._shouldFocusInput( inst ) ) {
1583				inst.input.trigger( "focus" );
1584			}
1585
1586			$.datepicker._curInst = inst;
1587		}
1588	},
1589
1590	/* Generate the date picker content. */
1591	_updateDatepicker: function( inst ) {
1592		this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
1593		datepicker_instActive = inst; // for delegate hover events
1594		inst.dpDiv.empty().append( this._generateHTML( inst ) );
1595		this._attachHandlers( inst );
1596
1597		var origyearshtml,
1598			numMonths = this._getNumberOfMonths( inst ),
1599			cols = numMonths[ 1 ],
1600			width = 17,
1601			activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
1602
1603		if ( activeCell.length > 0 ) {
1604			datepicker_handleMouseover.apply( activeCell.get( 0 ) );
1605		}
1606
1607		inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
1608		if ( cols > 1 ) {
1609			inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
1610		}
1611		inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
1612			"Class" ]( "ui-datepicker-multi" );
1613		inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
1614			"Class" ]( "ui-datepicker-rtl" );
1615
1616		if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
1617			inst.input.trigger( "focus" );
1618		}
1619
1620		// Deffered render of the years select (to avoid flashes on Firefox)
1621		if ( inst.yearshtml ) {
1622			origyearshtml = inst.yearshtml;
1623			setTimeout( function() {
1624
1625				//assure that inst.yearshtml didn't change.
1626				if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
1627					inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml );
1628				}
1629				origyearshtml = inst.yearshtml = null;
1630			}, 0 );
1631		}
1632	},
1633
1634	// #6694 - don't focus the input if it's already focused
1635	// this breaks the change event in IE
1636	// Support: IE and jQuery <1.9
1637	_shouldFocusInput: function( inst ) {
1638		return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
1639	},
1640
1641	/* Check positioning to remain on screen. */
1642	_checkOffset: function( inst, offset, isFixed ) {
1643		var dpWidth = inst.dpDiv.outerWidth(),
1644			dpHeight = inst.dpDiv.outerHeight(),
1645			inputWidth = inst.input ? inst.input.outerWidth() : 0,
1646			inputHeight = inst.input ? inst.input.outerHeight() : 0,
1647			viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
1648			viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );
1649
1650		offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
1651		offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
1652		offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;
1653
1654		// Now check if datepicker is showing outside window viewport - move to a better place if so.
1655		offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
1656			Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
1657		offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
1658			Math.abs( dpHeight + inputHeight ) : 0 );
1659
1660		return offset;
1661	},
1662
1663	/* Find an object's position on the screen. */
1664	_findPos: function( obj ) {
1665		var position,
1666			inst = this._getInst( obj ),
1667			isRTL = this._get( inst, "isRTL" );
1668
1669		while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) {
1670			obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
1671		}
1672
1673		position = $( obj ).offset();
1674		return [ position.left, position.top ];
1675	},
1676
1677	/* Hide the date picker from view.
1678	 * @param  input  element - the input field attached to the date picker
1679	 */
1680	_hideDatepicker: function( input ) {
1681		var showAnim, duration, postProcess, onClose,
1682			inst = this._curInst;
1683
1684		if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
1685			return;
1686		}
1687
1688		if ( this._datepickerShowing ) {
1689			showAnim = this._get( inst, "showAnim" );
1690			duration = this._get( inst, "duration" );
1691			postProcess = function() {
1692				$.datepicker._tidyDialog( inst );
1693			};
1694
1695			// DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
1696			if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
1697				inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
1698			} else {
1699				inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
1700					( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
1701			}
1702
1703			if ( !showAnim ) {
1704				postProcess();
1705			}
1706			this._datepickerShowing = false;
1707
1708			onClose = this._get( inst, "onClose" );
1709			if ( onClose ) {
1710				onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
1711			}
1712
1713			this._lastInput = null;
1714			if ( this._inDialog ) {
1715				this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
1716				if ( $.blockUI ) {
1717					$.unblockUI();
1718					$( "body" ).append( this.dpDiv );
1719				}
1720			}
1721			this._inDialog = false;
1722		}
1723	},
1724
1725	/* Tidy up after a dialog display. */
1726	_tidyDialog: function( inst ) {
1727		inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
1728	},
1729
1730	/* Close date picker if clicked elsewhere. */
1731	_checkExternalClick: function( event ) {
1732		if ( !$.datepicker._curInst ) {
1733			return;
1734		}
1735
1736		var $target = $( event.target ),
1737			inst = $.datepicker._getInst( $target[ 0 ] );
1738
1739		if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
1740				$target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
1741				!$target.hasClass( $.datepicker.markerClassName ) &&
1742				!$target.closest( "." + $.datepicker._triggerClass ).length &&
1743				$.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
1744			( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
1745				$.datepicker._hideDatepicker();
1746		}
1747	},
1748
1749	/* Adjust one of the date sub-fields. */
1750	_adjustDate: function( id, offset, period ) {
1751		var target = $( id ),
1752			inst = this._getInst( target[ 0 ] );
1753
1754		if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
1755			return;
1756		}
1757		this._adjustInstDate( inst, offset +
1758			( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning
1759			period );
1760		this._updateDatepicker( inst );
1761	},
1762
1763	/* Action for current link. */
1764	_gotoToday: function( id ) {
1765		var date,
1766			target = $( id ),
1767			inst = this._getInst( target[ 0 ] );
1768
1769		if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
1770			inst.selectedDay = inst.currentDay;
1771			inst.drawMonth = inst.selectedMonth = inst.currentMonth;
1772			inst.drawYear = inst.selectedYear = inst.currentYear;
1773		} else {
1774			date = new Date();
1775			inst.selectedDay = date.getDate();
1776			inst.drawMonth = inst.selectedMonth = date.getMonth();
1777			inst.drawYear = inst.selectedYear = date.getFullYear();
1778		}
1779		this._notifyChange( inst );
1780		this._adjustDate( target );
1781	},
1782
1783	/* Action for selecting a new month/year. */
1784	_selectMonthYear: function( id, select, period ) {
1785		var target = $( id ),
1786			inst = this._getInst( target[ 0 ] );
1787
1788		inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
1789		inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
1790			parseInt( select.options[ select.selectedIndex ].value, 10 );
1791
1792		this._notifyChange( inst );
1793		this._adjustDate( target );
1794	},
1795
1796	/* Action for selecting a day. */
1797	_selectDay: function( id, month, year, td ) {
1798		var inst,
1799			target = $( id );
1800
1801		if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
1802			return;
1803		}
1804
1805		inst = this._getInst( target[ 0 ] );
1806		inst.selectedDay = inst.currentDay = $( "a", td ).html();
1807		inst.selectedMonth = inst.currentMonth = month;
1808		inst.selectedYear = inst.currentYear = year;
1809		this._selectDate( id, this._formatDate( inst,
1810			inst.currentDay, inst.currentMonth, inst.currentYear ) );
1811	},
1812
1813	/* Erase the input field and hide the date picker. */
1814	_clearDate: function( id ) {
1815		var target = $( id );
1816		this._selectDate( target, "" );
1817	},
1818
1819	/* Update the input field with the selected date. */
1820	_selectDate: function( id, dateStr ) {
1821		var onSelect,
1822			target = $( id ),
1823			inst = this._getInst( target[ 0 ] );
1824
1825		dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
1826		if ( inst.input ) {
1827			inst.input.val( dateStr );
1828		}
1829		this._updateAlternate( inst );
1830
1831		onSelect = this._get( inst, "onSelect" );
1832		if ( onSelect ) {
1833			onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );  // trigger custom callback
1834		} else if ( inst.input ) {
1835			inst.input.trigger( "change" ); // fire the change event
1836		}
1837
1838		if ( inst.inline ) {
1839			this._updateDatepicker( inst );
1840		} else {
1841			this._hideDatepicker();
1842			this._lastInput = inst.input[ 0 ];
1843			if ( typeof( inst.input[ 0 ] ) !== "object" ) {
1844				inst.input.trigger( "focus" ); // restore focus
1845			}
1846			this._lastInput = null;
1847		}
1848	},
1849
1850	/* Update any alternate field to synchronise with the main field. */
1851	_updateAlternate: function( inst ) {
1852		var altFormat, date, dateStr,
1853			altField = this._get( inst, "altField" );
1854
1855		if ( altField ) { // update alternate field too
1856			altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
1857			date = this._getDate( inst );
1858			dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
1859			$( altField ).val( dateStr );
1860		}
1861	},
1862
1863	/* Set as beforeShowDay function to prevent selection of weekends.
1864	 * @param  date  Date - the date to customise
1865	 * @return [boolean, string] - is this date selectable?, what is its CSS class?
1866	 */
1867	noWeekends: function( date ) {
1868		var day = date.getDay();
1869		return [ ( day > 0 && day < 6 ), "" ];
1870	},
1871
1872	/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
1873	 * @param  date  Date - the date to get the week for
1874	 * @return  number - the number of the week within the year that contains this date
1875	 */
1876	iso8601Week: function( date ) {
1877		var time,
1878			checkDate = new Date( date.getTime() );
1879
1880		// Find Thursday of this week starting on Monday
1881		checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
1882
1883		time = checkDate.getTime();
1884		checkDate.setMonth( 0 ); // Compare with Jan 1
1885		checkDate.setDate( 1 );
1886		return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
1887	},
1888
1889	/* Parse a string value into a date object.
1890	 * See formatDate below for the possible formats.
1891	 *
1892	 * @param  format string - the expected format of the date
1893	 * @param  value string - the date in the above format
1894	 * @param  settings Object - attributes include:
1895	 *					shortYearCutoff  number - the cutoff year for determining the century (optional)
1896	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
1897	 *					dayNames		string[7] - names of the days from Sunday (optional)
1898	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
1899	 *					monthNames		string[12] - names of the months (optional)
1900	 * @return  Date - the extracted date value or null if value is blank
1901	 */
1902	parseDate: function( format, value, settings ) {
1903		if ( format == null || value == null ) {
1904			throw "Invalid arguments";
1905		}
1906
1907		value = ( typeof value === "object" ? value.toString() : value + "" );
1908		if ( value === "" ) {
1909			return null;
1910		}
1911
1912		var iFormat, dim, extra,
1913			iValue = 0,
1914			shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
1915			shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
1916				new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
1917			dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
1918			dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
1919			monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
1920			monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
1921			year = -1,
1922			month = -1,
1923			day = -1,
1924			doy = -1,
1925			literal = false,
1926			date,
1927
1928			// Check whether a format character is doubled
1929			lookAhead = function( match ) {
1930				var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
1931				if ( matches ) {
1932					iFormat++;
1933				}
1934				return matches;
1935			},
1936
1937			// Extract a number from the string value
1938			getNumber = function( match ) {
1939				var isDoubled = lookAhead( match ),
1940					size = ( match === "@" ? 14 : ( match === "!" ? 20 :
1941					( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
1942					minSize = ( match === "y" ? size : 1 ),
1943					digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
1944					num = value.substring( iValue ).match( digits );
1945				if ( !num ) {
1946					throw "Missing number at position " + iValue;
1947				}
1948				iValue += num[ 0 ].length;
1949				return parseInt( num[ 0 ], 10 );
1950			},
1951
1952			// Extract a name from the string value and convert to an index
1953			getName = function( match, shortNames, longNames ) {
1954				var index = -1,
1955					names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
1956						return [ [ k, v ] ];
1957					} ).sort( function( a, b ) {
1958						return -( a[ 1 ].length - b[ 1 ].length );
1959					} );
1960
1961				$.each( names, function( i, pair ) {
1962					var name = pair[ 1 ];
1963					if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
1964						index = pair[ 0 ];
1965						iValue += name.length;
1966						return false;
1967					}
1968				} );
1969				if ( index !== -1 ) {
1970					return index + 1;
1971				} else {
1972					throw "Unknown name at position " + iValue;
1973				}
1974			},
1975
1976			// Confirm that a literal character matches the string value
1977			checkLiteral = function() {
1978				if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
1979					throw "Unexpected literal at position " + iValue;
1980				}
1981				iValue++;
1982			};
1983
1984		for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
1985			if ( literal ) {
1986				if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
1987					literal = false;
1988				} else {
1989					checkLiteral();
1990				}
1991			} else {
1992				switch ( format.charAt( iFormat ) ) {
1993					case "d":
1994						day = getNumber( "d" );
1995						break;
1996					case "D":
1997						getName( "D", dayNamesShort, dayNames );
1998						break;
1999					case "o":
2000						doy = getNumber( "o" );
2001						break;
2002					case "m":
2003						month = getNumber( "m" );
2004						break;
2005					case "M":
2006						month = getName( "M", monthNamesShort, monthNames );
2007						break;
2008					case "y":
2009						year = getNumber( "y" );
2010						break;
2011					case "@":
2012						date = new Date( getNumber( "@" ) );
2013						year = date.getFullYear();
2014						month = date.getMonth() + 1;
2015						day = date.getDate();
2016						break;
2017					case "!":
2018						date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
2019						year = date.getFullYear();
2020						month = date.getMonth() + 1;
2021						day = date.getDate();
2022						break;
2023					case "'":
2024						if ( lookAhead( "'" ) ) {
2025							checkLiteral();
2026						} else {
2027							literal = true;
2028						}
2029						break;
2030					default:
2031						checkLiteral();
2032				}
2033			}
2034		}
2035
2036		if ( iValue < value.length ) {
2037			extra = value.substr( iValue );
2038			if ( !/^\s+/.test( extra ) ) {
2039				throw "Extra/unparsed characters found in date: " + extra;
2040			}
2041		}
2042
2043		if ( year === -1 ) {
2044			year = new Date().getFullYear();
2045		} else if ( year < 100 ) {
2046			year += new Date().getFullYear() - new Date().getFullYear() % 100 +
2047				( year <= shortYearCutoff ? 0 : -100 );
2048		}
2049
2050		if ( doy > -1 ) {
2051			month = 1;
2052			day = doy;
2053			do {
2054				dim = this._getDaysInMonth( year, month - 1 );
2055				if ( day <= dim ) {
2056					break;
2057				}
2058				month++;
2059				day -= dim;
2060			} while ( true );
2061		}
2062
2063		date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
2064		if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
2065			throw "Invalid date"; // E.g. 31/02/00
2066		}
2067		return date;
2068	},
2069
2070	/* Standard date formats. */
2071	ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
2072	COOKIE: "D, dd M yy",
2073	ISO_8601: "yy-mm-dd",
2074	RFC_822: "D, d M y",
2075	RFC_850: "DD, dd-M-y",
2076	RFC_1036: "D, d M y",
2077	RFC_1123: "D, d M yy",
2078	RFC_2822: "D, d M yy",
2079	RSS: "D, d M y", // RFC 822
2080	TICKS: "!",
2081	TIMESTAMP: "@",
2082	W3C: "yy-mm-dd", // ISO 8601
2083
2084	_ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
2085		Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
2086
2087	/* Format a date object into a string value.
2088	 * The format can be combinations of the following:
2089	 * d  - day of month (no leading zero)
2090	 * dd - day of month (two digit)
2091	 * o  - day of year (no leading zeros)
2092	 * oo - day of year (three digit)
2093	 * D  - day name short
2094	 * DD - day name long
2095	 * m  - month of year (no leading zero)
2096	 * mm - month of year (two digit)
2097	 * M  - month name short
2098	 * MM - month name long
2099	 * y  - year (two digit)
2100	 * yy - year (four digit)
2101	 * @ - Unix timestamp (ms since 01/01/1970)
2102	 * ! - Windows ticks (100ns since 01/01/0001)
2103	 * "..." - literal text
2104	 * '' - single quote
2105	 *
2106	 * @param  format string - the desired format of the date
2107	 * @param  date Date - the date value to format
2108	 * @param  settings Object - attributes include:
2109	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
2110	 *					dayNames		string[7] - names of the days from Sunday (optional)
2111	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
2112	 *					monthNames		string[12] - names of the months (optional)
2113	 * @return  string - the date in the above format
2114	 */
2115	formatDate: function( format, date, settings ) {
2116		if ( !date ) {
2117			return "";
2118		}
2119
2120		var iFormat,
2121			dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
2122			dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
2123			monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
2124			monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
2125
2126			// Check whether a format character is doubled
2127			lookAhead = function( match ) {
2128				var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
2129				if ( matches ) {
2130					iFormat++;
2131				}
2132				return matches;
2133			},
2134
2135			// Format a number, with leading zero if necessary
2136			formatNumber = function( match, value, len ) {
2137				var num = "" + value;
2138				if ( lookAhead( match ) ) {
2139					while ( num.length < len ) {
2140						num = "0" + num;
2141					}
2142				}
2143				return num;
2144			},
2145
2146			// Format a name, short or long as requested
2147			formatName = function( match, value, shortNames, longNames ) {
2148				return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
2149			},
2150			output = "",
2151			literal = false;
2152
2153		if ( date ) {
2154			for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
2155				if ( literal ) {
2156					if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
2157						literal = false;
2158					} else {
2159						output += format.charAt( iFormat );
2160					}
2161				} else {
2162					switch ( format.charAt( iFormat ) ) {
2163						case "d":
2164							output += formatNumber( "d", date.getDate(), 2 );
2165							break;
2166						case "D":
2167							output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
2168							break;
2169						case "o":
2170							output += formatNumber( "o",
2171								Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
2172							break;
2173						case "m":
2174							output += formatNumber( "m", date.getMonth() + 1, 2 );
2175							break;
2176						case "M":
2177							output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
2178							break;
2179						case "y":
2180							output += ( lookAhead( "y" ) ? date.getFullYear() :
2181								( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
2182							break;
2183						case "@":
2184							output += date.getTime();
2185							break;
2186						case "!":
2187							output += date.getTime() * 10000 + this._ticksTo1970;
2188							break;
2189						case "'":
2190							if ( lookAhead( "'" ) ) {
2191								output += "'";
2192							} else {
2193								literal = true;
2194							}
2195							break;
2196						default:
2197							output += format.charAt( iFormat );
2198					}
2199				}
2200			}
2201		}
2202		return output;
2203	},
2204
2205	/* Extract all possible characters from the date format. */
2206	_possibleChars: function( format ) {
2207		var iFormat,
2208			chars = "",
2209			literal = false,
2210
2211			// Check whether a format character is doubled
2212			lookAhead = function( match ) {
2213				var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
2214				if ( matches ) {
2215					iFormat++;
2216				}
2217				return matches;
2218			};
2219
2220		for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
2221			if ( literal ) {
2222				if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
2223					literal = false;
2224				} else {
2225					chars += format.charAt( iFormat );
2226				}
2227			} else {
2228				switch ( format.charAt( iFormat ) ) {
2229					case "d": case "m": case "y": case "@":
2230						chars += "0123456789";
2231						break;
2232					case "D": case "M":
2233						return null; // Accept anything
2234					case "'":
2235						if ( lookAhead( "'" ) ) {
2236							chars += "'";
2237						} else {
2238							literal = true;
2239						}
2240						break;
2241					default:
2242						chars += format.charAt( iFormat );
2243				}
2244			}
2245		}
2246		return chars;
2247	},
2248
2249	/* Get a setting value, defaulting if necessary. */
2250	_get: function( inst, name ) {
2251		return inst.settings[ name ] !== undefined ?
2252			inst.settings[ name ] : this._defaults[ name ];
2253	},
2254
2255	/* Parse existing date and initialise date picker. */
2256	_setDateFromField: function( inst, noDefault ) {
2257		if ( inst.input.val() === inst.lastVal ) {
2258			return;
2259		}
2260
2261		var dateFormat = this._get( inst, "dateFormat" ),
2262			dates = inst.lastVal = inst.input ? inst.input.val() : null,
2263			defaultDate = this._getDefaultDate( inst ),
2264			date = defaultDate,
2265			settings = this._getFormatConfig( inst );
2266
2267		try {
2268			date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
2269		} catch ( event ) {
2270			dates = ( noDefault ? "" : dates );
2271		}
2272		inst.selectedDay = date.getDate();
2273		inst.drawMonth = inst.selectedMonth = date.getMonth();
2274		inst.drawYear = inst.selectedYear = date.getFullYear();
2275		inst.currentDay = ( dates ? date.getDate() : 0 );
2276		inst.currentMonth = ( dates ? date.getMonth() : 0 );
2277		inst.currentYear = ( dates ? date.getFullYear() : 0 );
2278		this._adjustInstDate( inst );
2279	},
2280
2281	/* Retrieve the default date shown on opening. */
2282	_getDefaultDate: function( inst ) {
2283		return this._restrictMinMax( inst,
2284			this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
2285	},
2286
2287	/* A date may be specified as an exact value or a relative one. */
2288	_determineDate: function( inst, date, defaultDate ) {
2289		var offsetNumeric = function( offset ) {
2290				var date = new Date();
2291				date.setDate( date.getDate() + offset );
2292				return date;
2293			},
2294			offsetString = function( offset ) {
2295				try {
2296					return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
2297						offset, $.datepicker._getFormatConfig( inst ) );
2298				}
2299				catch ( e ) {
2300
2301					// Ignore
2302				}
2303
2304				var date = ( offset.toLowerCase().match( /^c/ ) ?
2305					$.datepicker._getDate( inst ) : null ) || new Date(),
2306					year = date.getFullYear(),
2307					month = date.getMonth(),
2308					day = date.getDate(),
2309					pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
2310					matches = pattern.exec( offset );
2311
2312				while ( matches ) {
2313					switch ( matches[ 2 ] || "d" ) {
2314						case "d" : case "D" :
2315							day += parseInt( matches[ 1 ], 10 ); break;
2316						case "w" : case "W" :
2317							day += parseInt( matches[ 1 ], 10 ) * 7; break;
2318						case "m" : case "M" :
2319							month += parseInt( matches[ 1 ], 10 );
2320							day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
2321							break;
2322						case "y": case "Y" :
2323							year += parseInt( matches[ 1 ], 10 );
2324							day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
2325							break;
2326					}
2327					matches = pattern.exec( offset );
2328				}
2329				return new Date( year, month, day );
2330			},
2331			newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
2332				( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );
2333
2334		newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
2335		if ( newDate ) {
2336			newDate.setHours( 0 );
2337			newDate.setMinutes( 0 );
2338			newDate.setSeconds( 0 );
2339			newDate.setMilliseconds( 0 );
2340		}
2341		return this._daylightSavingAdjust( newDate );
2342	},
2343
2344	/* Handle switch to/from daylight saving.
2345	 * Hours may be non-zero on daylight saving cut-over:
2346	 * > 12 when midnight changeover, but then cannot generate
2347	 * midnight datetime, so jump to 1AM, otherwise reset.
2348	 * @param  date  (Date) the date to check
2349	 * @return  (Date) the corrected date
2350	 */
2351	_daylightSavingAdjust: function( date ) {
2352		if ( !date ) {
2353			return null;
2354		}
2355		date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
2356		return date;
2357	},
2358
2359	/* Set the date(s) directly. */
2360	_setDate: function( inst, date, noChange ) {
2361		var clear = !date,
2362			origMonth = inst.selectedMonth,
2363			origYear = inst.selectedYear,
2364			newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );
2365
2366		inst.selectedDay = inst.currentDay = newDate.getDate();
2367		inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
2368		inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
2369		if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
2370			this._notifyChange( inst );
2371		}
2372		this._adjustInstDate( inst );
2373		if ( inst.input ) {
2374			inst.input.val( clear ? "" : this._formatDate( inst ) );
2375		}
2376	},
2377
2378	/* Retrieve the date(s) directly. */
2379	_getDate: function( inst ) {
2380		var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
2381			this._daylightSavingAdjust( new Date(
2382			inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
2383			return startDate;
2384	},
2385
2386	/* Attach the onxxx handlers.  These are declared statically so
2387	 * they work with static code transformers like Caja.
2388	 */
2389	_attachHandlers: function( inst ) {
2390		var stepMonths = this._get( inst, "stepMonths" ),
2391			id = "#" + inst.id.replace( /\\\\/g, "\\" );
2392		inst.dpDiv.find( "[data-handler]" ).map( function() {
2393			var handler = {
2394				prev: function() {
2395					$.datepicker._adjustDate( id, -stepMonths, "M" );
2396				},
2397				next: function() {
2398					$.datepicker._adjustDate( id, +stepMonths, "M" );
2399				},
2400				hide: function() {
2401					$.datepicker._hideDatepicker();
2402				},
2403				today: function() {
2404					$.datepicker._gotoToday( id );
2405				},
2406				selectDay: function() {
2407					$.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
2408					return false;
2409				},
2410				selectMonth: function() {
2411					$.datepicker._selectMonthYear( id, this, "M" );
2412					return false;
2413				},
2414				selectYear: function() {
2415					$.datepicker._selectMonthYear( id, this, "Y" );
2416					return false;
2417				}
2418			};
2419			$( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
2420		} );
2421	},
2422
2423	/* Generate the HTML for the current state of the date picker. */
2424	_generateHTML: function( inst ) {
2425		var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
2426			controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
2427			monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
2428			selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
2429			cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
2430			printDate, dRow, tbody, daySettings, otherMonth, unselectable,
2431			tempDate = new Date(),
2432			today = this._daylightSavingAdjust(
2433				new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
2434			isRTL = this._get( inst, "isRTL" ),
2435			showButtonPanel = this._get( inst, "showButtonPanel" ),
2436			hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
2437			navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
2438			numMonths = this._getNumberOfMonths( inst ),
2439			showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
2440			stepMonths = this._get( inst, "stepMonths" ),
2441			isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
2442			currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
2443				new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
2444			minDate = this._getMinMaxDate( inst, "min" ),
2445			maxDate = this._getMinMaxDate( inst, "max" ),
2446			drawMonth = inst.drawMonth - showCurrentAtPos,
2447			drawYear = inst.drawYear;
2448
2449		if ( drawMonth < 0 ) {
2450			drawMonth += 12;
2451			drawYear--;
2452		}
2453		if ( maxDate ) {
2454			maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
2455				maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
2456			maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
2457			while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
2458				drawMonth--;
2459				if ( drawMonth < 0 ) {
2460					drawMonth = 11;
2461					drawYear--;
2462				}
2463			}
2464		}
2465		inst.drawMonth = drawMonth;
2466		inst.drawYear = drawYear;
2467
2468		prevText = this._get( inst, "prevText" );
2469		prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
2470			this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
2471			this._getFormatConfig( inst ) ) );
2472
2473		prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ?
2474			"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
2475			" title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" :
2476			( 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>" ) );
2477
2478		nextText = this._get( inst, "nextText" );
2479		nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
2480			this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
2481			this._getFormatConfig( inst ) ) );
2482
2483		next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ?
2484			"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
2485			" title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" :
2486			( 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>" ) );
2487
2488		currentText = this._get( inst, "currentText" );
2489		gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
2490		currentText = ( !navigationAsDateFormat ? currentText :
2491			this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
2492
2493		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'>" +
2494			this._get( inst, "closeText" ) + "</button>" : "" );
2495
2496		buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) +
2497			( 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'" +
2498			">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : "";
2499
2500		firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
2501		firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
2502
2503		showWeek = this._get( inst, "showWeek" );
2504		dayNames = this._get( inst, "dayNames" );
2505		dayNamesMin = this._get( inst, "dayNamesMin" );
2506		monthNames = this._get( inst, "monthNames" );
2507		monthNamesShort = this._get( inst, "monthNamesShort" );
2508		beforeShowDay = this._get( inst, "beforeShowDay" );
2509		showOtherMonths = this._get( inst, "showOtherMonths" );
2510		selectOtherMonths = this._get( inst, "selectOtherMonths" );
2511		defaultDate = this._getDefaultDate( inst );
2512		html = "";
2513
2514		for ( row = 0; row < numMonths[ 0 ]; row++ ) {
2515			group = "";
2516			this.maxRows = 4;
2517			for ( col = 0; col < numMonths[ 1 ]; col++ ) {
2518				selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
2519				cornerClass = " ui-corner-all";
2520				calender = "";
2521				if ( isMultiMonth ) {
2522					calender += "<div class='ui-datepicker-group";
2523					if ( numMonths[ 1 ] > 1 ) {
2524						switch ( col ) {
2525							case 0: calender += " ui-datepicker-group-first";
2526								cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
2527							case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
2528								cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
2529							default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
2530						}
2531					}
2532					calender += "'>";
2533				}
2534				calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
2535					( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
2536					( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
2537					this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
2538					row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
2539					"</div><table class='ui-datepicker-calendar'><thead>" +
2540					"<tr>";
2541				thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
2542				for ( dow = 0; dow < 7; dow++ ) { // days of the week
2543					day = ( dow + firstDay ) % 7;
2544					thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
2545						"<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
2546				}
2547				calender += thead + "</tr></thead><tbody>";
2548				daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
2549				if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
2550					inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
2551				}
2552				leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
2553				curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
2554				numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
2555				this.maxRows = numRows;
2556				printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
2557				for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
2558					calender += "<tr>";
2559					tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
2560						this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
2561					for ( dow = 0; dow < 7; dow++ ) { // create date picker days
2562						daySettings = ( beforeShowDay ?
2563							beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
2564						otherMonth = ( printDate.getMonth() !== drawMonth );
2565						unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
2566							( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
2567						tbody += "<td class='" +
2568							( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
2569							( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
2570							( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
2571							( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?
2572
2573							// or defaultDate is current printedDate and defaultDate is selectedDate
2574							" " + this._dayOverClass : "" ) + // highlight selected day
2575							( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) +  // highlight unselectable days
2576							( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
2577							( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
2578							( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
2579							( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "&#39;" ) + "'" : "" ) + // cell title
2580							( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
2581							( otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
2582							( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
2583							( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
2584							( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
2585							( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
2586							"' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
2587						printDate.setDate( printDate.getDate() + 1 );
2588						printDate = this._daylightSavingAdjust( printDate );
2589					}
2590					calender += tbody + "</tr>";
2591				}
2592				drawMonth++;
2593				if ( drawMonth > 11 ) {
2594					drawMonth = 0;
2595					drawYear++;
2596				}
2597				calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
2598							( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
2599				group += calender;
2600			}
2601			html += group;
2602		}
2603		html += buttonPanel;
2604		inst._keyEvent = false;
2605		return html;
2606	},
2607
2608	/* Generate the month and year header. */
2609	_generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
2610			secondary, monthNames, monthNamesShort ) {
2611
2612		var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
2613			changeMonth = this._get( inst, "changeMonth" ),
2614			changeYear = this._get( inst, "changeYear" ),
2615			showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
2616			html = "<div class='ui-datepicker-title'>",
2617			monthHtml = "";
2618
2619		// Month selection
2620		if ( secondary || !changeMonth ) {
2621			monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
2622		} else {
2623			inMinYear = ( minDate && minDate.getFullYear() === drawYear );
2624			inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
2625			monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
2626			for ( month = 0; month < 12; month++ ) {
2627				if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
2628					monthHtml += "<option value='" + month + "'" +
2629						( month === drawMonth ? " selected='selected'" : "" ) +
2630						">" + monthNamesShort[ month ] + "</option>";
2631				}
2632			}
2633			monthHtml += "</select>";
2634		}
2635
2636		if ( !showMonthAfterYear ) {
2637			html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" );
2638		}
2639
2640		// Year selection
2641		if ( !inst.yearshtml ) {
2642			inst.yearshtml = "";
2643			if ( secondary || !changeYear ) {
2644				html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
2645			} else {
2646
2647				// determine range of years to display
2648				years = this._get( inst, "yearRange" ).split( ":" );
2649				thisYear = new Date().getFullYear();
2650				determineYear = function( value ) {
2651					var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
2652						( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
2653						parseInt( value, 10 ) ) );
2654					return ( isNaN( year ) ? thisYear : year );
2655				};
2656				year = determineYear( years[ 0 ] );
2657				endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
2658				year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
2659				endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
2660				inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
2661				for ( ; year <= endYear; year++ ) {
2662					inst.yearshtml += "<option value='" + year + "'" +
2663						( year === drawYear ? " selected='selected'" : "" ) +
2664						">" + year + "</option>";
2665				}
2666				inst.yearshtml += "</select>";
2667
2668				html += inst.yearshtml;
2669				inst.yearshtml = null;
2670			}
2671		}
2672
2673		html += this._get( inst, "yearSuffix" );
2674		if ( showMonthAfterYear ) {
2675			html += ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" ) + monthHtml;
2676		}
2677		html += "</div>"; // Close datepicker_header
2678		return html;
2679	},
2680
2681	/* Adjust one of the date sub-fields. */
2682	_adjustInstDate: function( inst, offset, period ) {
2683		var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
2684			month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
2685			day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
2686			date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );
2687
2688		inst.selectedDay = date.getDate();
2689		inst.drawMonth = inst.selectedMonth = date.getMonth();
2690		inst.drawYear = inst.selectedYear = date.getFullYear();
2691		if ( period === "M" || period === "Y" ) {
2692			this._notifyChange( inst );
2693		}
2694	},
2695
2696	/* Ensure a date is within any min/max bounds. */
2697	_restrictMinMax: function( inst, date ) {
2698		var minDate = this._getMinMaxDate( inst, "min" ),
2699			maxDate = this._getMinMaxDate( inst, "max" ),
2700			newDate = ( minDate && date < minDate ? minDate : date );
2701		return ( maxDate && newDate > maxDate ? maxDate : newDate );
2702	},
2703
2704	/* Notify change of month/year. */
2705	_notifyChange: function( inst ) {
2706		var onChange = this._get( inst, "onChangeMonthYear" );
2707		if ( onChange ) {
2708			onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
2709				[ inst.selectedYear, inst.selectedMonth + 1, inst ] );
2710		}
2711	},
2712
2713	/* Determine the number of months to show. */
2714	_getNumberOfMonths: function( inst ) {
2715		var numMonths = this._get( inst, "numberOfMonths" );
2716		return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
2717	},
2718
2719	/* Determine the current maximum date - ensure no time components are set. */
2720	_getMinMaxDate: function( inst, minMax ) {
2721		return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
2722	},
2723
2724	/* Find the number of days in a given month. */
2725	_getDaysInMonth: function( year, month ) {
2726		return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
2727	},
2728
2729	/* Find the day of the week of the first of a month. */
2730	_getFirstDayOfMonth: function( year, month ) {
2731		return new Date( year, month, 1 ).getDay();
2732	},
2733
2734	/* Determines if we should allow a "next/prev" month display change. */
2735	_canAdjustMonth: function( inst, offset, curYear, curMonth ) {
2736		var numMonths = this._getNumberOfMonths( inst ),
2737			date = this._daylightSavingAdjust( new Date( curYear,
2738			curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );
2739
2740		if ( offset < 0 ) {
2741			date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
2742		}
2743		return this._isInRange( inst, date );
2744	},
2745
2746	/* Is the given date in the accepted range? */
2747	_isInRange: function( inst, date ) {
2748		var yearSplit, currentYear,
2749			minDate = this._getMinMaxDate( inst, "min" ),
2750			maxDate = this._getMinMaxDate( inst, "max" ),
2751			minYear = null,
2752			maxYear = null,
2753			years = this._get( inst, "yearRange" );
2754			if ( years ) {
2755				yearSplit = years.split( ":" );
2756				currentYear = new Date().getFullYear();
2757				minYear = parseInt( yearSplit[ 0 ], 10 );
2758				maxYear = parseInt( yearSplit[ 1 ], 10 );
2759				if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
2760					minYear += currentYear;
2761				}
2762				if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
2763					maxYear += currentYear;
2764				}
2765			}
2766
2767		return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
2768			( !maxDate || date.getTime() <= maxDate.getTime() ) &&
2769			( !minYear || date.getFullYear() >= minYear ) &&
2770			( !maxYear || date.getFullYear() <= maxYear ) );
2771	},
2772
2773	/* Provide the configuration settings for formatting/parsing. */
2774	_getFormatConfig: function( inst ) {
2775		var shortYearCutoff = this._get( inst, "shortYearCutoff" );
2776		shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
2777			new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
2778		return { shortYearCutoff: shortYearCutoff,
2779			dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
2780			monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
2781	},
2782
2783	/* Format the given date for display. */
2784	_formatDate: function( inst, day, month, year ) {
2785		if ( !day ) {
2786			inst.currentDay = inst.selectedDay;
2787			inst.currentMonth = inst.selectedMonth;
2788			inst.currentYear = inst.selectedYear;
2789		}
2790		var date = ( day ? ( typeof day === "object" ? day :
2791			this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
2792			this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
2793		return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
2794	}
2795} );
2796
2797/*
2798 * Bind hover events for datepicker elements.
2799 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
2800 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
2801 */
2802function datepicker_bindHover( dpDiv ) {
2803	var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
2804	return dpDiv.on( "mouseout", selector, function() {
2805			$( this ).removeClass( "ui-state-hover" );
2806			if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
2807				$( this ).removeClass( "ui-datepicker-prev-hover" );
2808			}
2809			if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
2810				$( this ).removeClass( "ui-datepicker-next-hover" );
2811			}
2812		} )
2813		.on( "mouseover", selector, datepicker_handleMouseover );
2814}
2815
2816function datepicker_handleMouseover() {
2817	if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
2818		$( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
2819		$( this ).addClass( "ui-state-hover" );
2820		if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
2821			$( this ).addClass( "ui-datepicker-prev-hover" );
2822		}
2823		if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
2824			$( this ).addClass( "ui-datepicker-next-hover" );
2825		}
2826	}
2827}
2828
2829/* jQuery extend now ignores nulls! */
2830function datepicker_extendRemove( target, props ) {
2831	$.extend( target, props );
2832	for ( var name in props ) {
2833		if ( props[ name ] == null ) {
2834			target[ name ] = props[ name ];
2835		}
2836	}
2837	return target;
2838}
2839
2840/* Invoke the datepicker functionality.
2841   @param  options  string - a command, optionally followed by additional parameters or
2842					Object - settings for attaching new datepicker functionality
2843   @return  jQuery object */
2844$.fn.datepicker = function( options ) {
2845
2846	/* Verify an empty collection wasn't passed - Fixes #6976 */
2847	if ( !this.length ) {
2848		return this;
2849	}
2850
2851	/* Initialise the date picker. */
2852	if ( !$.datepicker.initialized ) {
2853		$( document ).on( "mousedown", $.datepicker._checkExternalClick );
2854		$.datepicker.initialized = true;
2855	}
2856
2857	/* Append datepicker main container to body if not exist. */
2858	if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
2859		$( "body" ).append( $.datepicker.dpDiv );
2860	}
2861
2862	var otherArgs = Array.prototype.slice.call( arguments, 1 );
2863	if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
2864		return $.datepicker[ "_" + options + "Datepicker" ].
2865			apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
2866	}
2867	if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
2868		return $.datepicker[ "_" + options + "Datepicker" ].
2869			apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
2870	}
2871	return this.each( function() {
2872		typeof options === "string" ?
2873			$.datepicker[ "_" + options + "Datepicker" ].
2874				apply( $.datepicker, [ this ].concat( otherArgs ) ) :
2875			$.datepicker._attachDatepicker( this, options );
2876	} );
2877};
2878
2879$.datepicker = new Datepicker(); // singleton instance
2880$.datepicker.initialized = false;
2881$.datepicker.uuid = new Date().getTime();
2882$.datepicker.version = "1.12.1";
2883
2884var widgetsDatepicker = $.datepicker;
2885
2886
2887
2888
2889}));

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.