datepicker.js ➔ ... ➔ $.extend._hideDatepicker   F
last analyzed

Complexity

Conditions 17
Paths 272

Size

Total Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 17
nc 272
nop 1
dl 0
loc 44
rs 3.6909
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like datepicker.js ➔ ... ➔ $.extend._hideDatepicker often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
// jscs:disable maximumLineLength
2
/* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
3
/*!
4
 * jQuery UI Datepicker 1.12.1
5
 * http://jqueryui.com
6
 *
7
 * Copyright jQuery Foundation and other contributors
8
 * Released under the MIT license.
9
 * http://jquery.org/license
10
 */
11
12
//>>label: Datepicker
13
//>>group: Widgets
14
//>>description: Displays a calendar from an input or inline for selecting dates.
15
//>>docs: http://api.jqueryui.com/datepicker/
16
//>>demos: http://jqueryui.com/datepicker/
17
//>>css.structure: ../../themes/base/core.css
18
//>>css.structure: ../../themes/base/datepicker.css
19
//>>css.theme: ../../themes/base/theme.css
20
21
( function( factory ) {
22
	if ( typeof define === "function" && define.amd ) {
23
24
		// AMD. Register as an anonymous module.
25
		define( [
26
			"jquery",
27
			"../version",
28
			"../keycode"
29
		], factory );
30
	} else {
31
32
		// Browser globals
33
		factory( jQuery );
34
	}
35
}( function( $ ) {
36
37
$.extend( $.ui, { datepicker: { version: "1.12.1" } } );
38
39
var datepicker_instActive;
40
41
function datepicker_getZindex( elem ) {
42
	var position, value;
43
	while ( elem.length && elem[ 0 ] !== document ) {
44
45
		// Ignore z-index if position is set to a value where z-index is ignored by the browser
46
		// This makes behavior of this function consistent across browsers
47
		// WebKit always returns auto if the element is positioned
48
		position = elem.css( "position" );
49
		if ( position === "absolute" || position === "relative" || position === "fixed" ) {
50
51
			// IE returns 0 when zIndex is not specified
52
			// other browsers return a string
53
			// we ignore the case of nested elements with an explicit value of 0
54
			// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
55
			value = parseInt( elem.css( "zIndex" ), 10 );
56
			if ( !isNaN( value ) && value !== 0 ) {
57
				return value;
58
			}
59
		}
60
		elem = elem.parent();
61
	}
62
63
	return 0;
64
}
65
/* Date picker manager.
66
   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
67
   Settings for (groups of) date pickers are maintained in an instance object,
68
   allowing multiple different settings on the same page. */
69
70
function Datepicker() {
71
	this._curInst = null; // The current instance in use
72
	this._keyEvent = false; // If the last event was a key event
73
	this._disabledInputs = []; // List of date picker inputs that have been disabled
74
	this._datepickerShowing = false; // True if the popup picker is showing , false if not
75
	this._inDialog = false; // True if showing within a "dialog", false if not
76
	this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
77
	this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
78
	this._appendClass = "ui-datepicker-append"; // The name of the append marker class
79
	this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
80
	this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
81
	this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
82
	this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
83
	this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
84
	this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
85
	this.regional = []; // Available regional settings, indexed by language code
86
	this.regional[ "" ] = { // Default regional settings
87
		closeText: "Done", // Display text for close link
88
		prevText: "Prev", // Display text for previous month link
89
		nextText: "Next", // Display text for next month link
90
		currentText: "Today", // Display text for current month link
91
		monthNames: [ "January","February","March","April","May","June",
92
			"July","August","September","October","November","December" ], // Names of months for drop-down and formatting
93
		monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
94
		dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
95
		dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
96
		dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday
97
		weekHeader: "Wk", // Column header for week of the year
98
		dateFormat: "mm/dd/yy", // See format options on parseDate
99
		firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
100
		isRTL: false, // True if right-to-left language, false if left-to-right
101
		showMonthAfterYear: false, // True if the year select precedes month, false for month then year
102
		yearSuffix: "" // Additional text to append to the year in the month headers
103
	};
104
	this._defaults = { // Global defaults for all the date picker instances
105
		showOn: "focus", // "focus" for popup on focus,
106
			// "button" for trigger button, or "both" for either
107
		showAnim: "fadeIn", // Name of jQuery animation for popup
108
		showOptions: {}, // Options for enhanced animations
109
		defaultDate: null, // Used when field is blank: actual date,
110
			// +/-number for offset from today, null for today
111
		appendText: "", // Display text following the input box, e.g. showing the format
112
		buttonText: "...", // Text for trigger button
113
		buttonImage: "", // URL for trigger button image
114
		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
115
		hideIfNoPrevNext: false, // True to hide next/previous month links
116
			// if not applicable, false to just disable them
117
		navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
118
		gotoCurrent: false, // True if today link goes back to current selection instead
119
		changeMonth: false, // True if month can be selected directly, false if only prev/next
120
		changeYear: false, // True if year can be selected directly, false if only prev/next
121
		yearRange: "c-10:c+10", // Range of years to display in drop-down,
122
			// either relative to today's year (-nn:+nn), relative to currently displayed year
123
			// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
124
		showOtherMonths: false, // True to show dates in other months, false to leave blank
125
		selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
126
		showWeek: false, // True to show week of the year, false to not show it
127
		calculateWeek: this.iso8601Week, // How to calculate the week of the year,
128
			// takes a Date and returns the number of the week for it
129
		shortYearCutoff: "+10", // Short year values < this are in the current century,
130
			// > this are in the previous century,
131
			// string value starting with "+" for current year + value
132
		minDate: null, // The earliest selectable date, or null for no limit
133
		maxDate: null, // The latest selectable date, or null for no limit
134
		duration: "fast", // Duration of display/closure
135
		beforeShowDay: null, // Function that takes a date and returns an array with
136
			// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
137
			// [2] = cell title (optional), e.g. $.datepicker.noWeekends
138
		beforeShow: null, // Function that takes an input field and
139
			// returns a set of custom settings for the date picker
140
		onSelect: null, // Define a callback function when a date is selected
141
		onChangeMonthYear: null, // Define a callback function when the month or year is changed
142
		onClose: null, // Define a callback function when the datepicker is closed
143
		numberOfMonths: 1, // Number of months to show at a time
144
		showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
145
		stepMonths: 1, // Number of months to step back/forward
146
		stepBigMonths: 12, // Number of months to step back/forward for the big links
147
		altField: "", // Selector for an alternate field to store selected dates into
148
		altFormat: "", // The date format to use for the alternate field
149
		constrainInput: true, // The input is constrained by the current date format
150
		showButtonPanel: false, // True to show button panel, false to not show it
151
		autoSize: false, // True to size the input for the date format, false to leave as is
152
		disabled: false // The initial disabled state
153
	};
154
	$.extend( this._defaults, this.regional[ "" ] );
155
	this.regional.en = $.extend( true, {}, this.regional[ "" ] );
156
	this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
157
	this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
158
}
159
160
$.extend( Datepicker.prototype, {
161
	/* Class name added to elements to indicate already configured with a date picker. */
162
	markerClassName: "hasDatepicker",
163
164
	//Keep track of the maximum number of rows displayed (see #7043)
165
	maxRows: 4,
166
167
	// TODO rename to "widget" when switching to widget factory
168
	_widgetDatepicker: function() {
169
		return this.dpDiv;
170
	},
171
172
	/* Override the default settings for all instances of the date picker.
173
	 * @param  settings  object - the new settings to use as defaults (anonymous object)
174
	 * @return the manager object
175
	 */
176
	setDefaults: function( settings ) {
177
		datepicker_extendRemove( this._defaults, settings || {} );
178
		return this;
179
	},
180
181
	/* Attach the date picker to a jQuery selection.
182
	 * @param  target	element - the target input field or division or span
183
	 * @param  settings  object - the new settings to use for this date picker instance (anonymous)
184
	 */
185
	_attachDatepicker: function( target, settings ) {
186
		var nodeName, inline, inst;
187
		nodeName = target.nodeName.toLowerCase();
188
		inline = ( nodeName === "div" || nodeName === "span" );
189
		if ( !target.id ) {
190
			this.uuid += 1;
191
			target.id = "dp" + this.uuid;
192
		}
193
		inst = this._newInst( $( target ), inline );
194
		inst.settings = $.extend( {}, settings || {} );
195
		if ( nodeName === "input" ) {
196
			this._connectDatepicker( target, inst );
197
		} else if ( inline ) {
198
			this._inlineDatepicker( target, inst );
199
		}
200
	},
201
202
	/* Create a new instance object. */
203
	_newInst: function( target, inline ) {
204
		var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
205
		return { id: id, input: target, // associated target
206
			selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
207
			drawMonth: 0, drawYear: 0, // month being drawn
208
			inline: inline, // is datepicker inline or not
209
			dpDiv: ( !inline ? this.dpDiv : // presentation div
210
			datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
211
	},
212
213
	/* Attach the date picker to an input field. */
214
	_connectDatepicker: function( target, inst ) {
215
		var input = $( target );
216
		inst.append = $( [] );
217
		inst.trigger = $( [] );
218
		if ( input.hasClass( this.markerClassName ) ) {
219
			return;
220
		}
221
		this._attachments( input, inst );
222
		input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
223
			on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
224
		this._autoSize( inst );
225
		$.data( target, "datepicker", inst );
226
227
		//If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
228
		if ( inst.settings.disabled ) {
229
			this._disableDatepicker( target );
230
		}
231
	},
232
233
	/* Make attachments based on settings. */
234
	_attachments: function( input, inst ) {
235
		var showOn, buttonText, buttonImage,
236
			appendText = this._get( inst, "appendText" ),
237
			isRTL = this._get( inst, "isRTL" );
238
239
		if ( inst.append ) {
240
			inst.append.remove();
241
		}
242
		if ( appendText ) {
243
			inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" );
244
			input[ isRTL ? "before" : "after" ]( inst.append );
245
		}
246
247
		input.off( "focus", this._showDatepicker );
248
249
		if ( inst.trigger ) {
250
			inst.trigger.remove();
251
		}
252
253
		showOn = this._get( inst, "showOn" );
254
		if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
255
			input.on( "focus", this._showDatepicker );
256
		}
257
		if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
258
			buttonText = this._get( inst, "buttonText" );
259
			buttonImage = this._get( inst, "buttonImage" );
260
			inst.trigger = $( this._get( inst, "buttonImageOnly" ) ?
261
				$( "<img/>" ).addClass( this._triggerClass ).
262
					attr( { src: buttonImage, alt: buttonText, title: buttonText } ) :
263
				$( "<button type='button'></button>" ).addClass( this._triggerClass ).
264
					html( !buttonImage ? buttonText : $( "<img/>" ).attr(
265
					{ src:buttonImage, alt:buttonText, title:buttonText } ) ) );
266
			input[ isRTL ? "before" : "after" ]( inst.trigger );
267
			inst.trigger.on( "click", function() {
268
				if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
269
					$.datepicker._hideDatepicker();
270
				} else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
271
					$.datepicker._hideDatepicker();
272
					$.datepicker._showDatepicker( input[ 0 ] );
273
				} else {
274
					$.datepicker._showDatepicker( input[ 0 ] );
275
				}
276
				return false;
277
			} );
278
		}
279
	},
280
281
	/* Apply the maximum length for the date format. */
282
	_autoSize: function( inst ) {
283
		if ( this._get( inst, "autoSize" ) && !inst.inline ) {
284
			var findMax, max, maxI, i,
285
				date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
286
				dateFormat = this._get( inst, "dateFormat" );
287
288
			if ( dateFormat.match( /[DM]/ ) ) {
289
				findMax = function( names ) {
290
					max = 0;
291
					maxI = 0;
292
					for ( i = 0; i < names.length; i++ ) {
0 ignored issues
show
Bug introduced by
The variable i is changed as part of the for loop for example by i++ on line 292. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
293
						if ( names[ i ].length > max ) {
0 ignored issues
show
Bug introduced by
The variable max is changed as part of the for loop for example by names.i.length on line 294. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
294
							max = names[ i ].length;
295
							maxI = i;
296
						}
297
					}
298
					return maxI;
299
				};
300
				date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
301
					"monthNames" : "monthNamesShort" ) ) ) );
302
				date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
303
					"dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
304
			}
305
			inst.input.attr( "size", this._formatDate( inst, date ).length );
306
		}
307
	},
308
309
	/* Attach an inline date picker to a div. */
310
	_inlineDatepicker: function( target, inst ) {
311
		var divSpan = $( target );
312
		if ( divSpan.hasClass( this.markerClassName ) ) {
313
			return;
314
		}
315
		divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
316
		$.data( target, "datepicker", inst );
317
		this._setDate( inst, this._getDefaultDate( inst ), true );
318
		this._updateDatepicker( inst );
319
		this._updateAlternate( inst );
320
321
		//If disabled option is true, disable the datepicker before showing it (see ticket #5665)
322
		if ( inst.settings.disabled ) {
323
			this._disableDatepicker( target );
324
		}
325
326
		// Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
327
		// http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
328
		inst.dpDiv.css( "display", "block" );
329
	},
330
331
	/* Pop-up the date picker in a "dialog" box.
332
	 * @param  input element - ignored
333
	 * @param  date	string or Date - the initial date to display
334
	 * @param  onSelect  function - the function to call when a date is selected
335
	 * @param  settings  object - update the dialog date picker instance's settings (anonymous object)
336
	 * @param  pos int[2] - coordinates for the dialog's position within the screen or
337
	 *					event - with x/y coordinates or
338
	 *					leave empty for default (screen centre)
339
	 * @return the manager object
340
	 */
341
	_dialogDatepicker: function( input, date, onSelect, settings, pos ) {
342
		var id, browserWidth, browserHeight, scrollX, scrollY,
343
			inst = this._dialogInst; // internal instance
344
345
		if ( !inst ) {
346
			this.uuid += 1;
347
			id = "dp" + this.uuid;
348
			this._dialogInput = $( "<input type='text' id='" + id +
349
				"' style='position: absolute; top: -100px; width: 0px;'/>" );
350
			this._dialogInput.on( "keydown", this._doKeyDown );
351
			$( "body" ).append( this._dialogInput );
352
			inst = this._dialogInst = this._newInst( this._dialogInput, false );
353
			inst.settings = {};
354
			$.data( this._dialogInput[ 0 ], "datepicker", inst );
355
		}
356
		datepicker_extendRemove( inst.settings, settings || {} );
357
		date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
358
		this._dialogInput.val( date );
359
360
		this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
361
		if ( !this._pos ) {
362
			browserWidth = document.documentElement.clientWidth;
363
			browserHeight = document.documentElement.clientHeight;
364
			scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
365
			scrollY = document.documentElement.scrollTop || document.body.scrollTop;
366
			this._pos = // should use actual width/height below
367
				[ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
368
		}
369
370
		// Move input on screen for focus, but hidden behind dialog
371
		this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
372
		inst.settings.onSelect = onSelect;
373
		this._inDialog = true;
374
		this.dpDiv.addClass( this._dialogClass );
375
		this._showDatepicker( this._dialogInput[ 0 ] );
376
		if ( $.blockUI ) {
377
			$.blockUI( this.dpDiv );
378
		}
379
		$.data( this._dialogInput[ 0 ], "datepicker", inst );
380
		return this;
381
	},
382
383
	/* Detach a datepicker from its control.
384
	 * @param  target	element - the target input field or division or span
385
	 */
386
	_destroyDatepicker: function( target ) {
387
		var nodeName,
388
			$target = $( target ),
389
			inst = $.data( target, "datepicker" );
390
391
		if ( !$target.hasClass( this.markerClassName ) ) {
392
			return;
393
		}
394
395
		nodeName = target.nodeName.toLowerCase();
396
		$.removeData( target, "datepicker" );
397
		if ( nodeName === "input" ) {
398
			inst.append.remove();
399
			inst.trigger.remove();
400
			$target.removeClass( this.markerClassName ).
401
				off( "focus", this._showDatepicker ).
402
				off( "keydown", this._doKeyDown ).
403
				off( "keypress", this._doKeyPress ).
404
				off( "keyup", this._doKeyUp );
405
		} else if ( nodeName === "div" || nodeName === "span" ) {
406
			$target.removeClass( this.markerClassName ).empty();
407
		}
408
409
		if ( datepicker_instActive === inst ) {
410
			datepicker_instActive = null;
411
		}
412
	},
413
414
	/* Enable the date picker to a jQuery selection.
415
	 * @param  target	element - the target input field or division or span
416
	 */
417
	_enableDatepicker: function( target ) {
418
		var nodeName, inline,
419
			$target = $( target ),
420
			inst = $.data( target, "datepicker" );
421
422
		if ( !$target.hasClass( this.markerClassName ) ) {
423
			return;
424
		}
425
426
		nodeName = target.nodeName.toLowerCase();
427
		if ( nodeName === "input" ) {
428
			target.disabled = false;
429
			inst.trigger.filter( "button" ).
430
				each( function() { this.disabled = false; } ).end().
431
				filter( "img" ).css( { opacity: "1.0", cursor: "" } );
432
		} else if ( nodeName === "div" || nodeName === "span" ) {
433
			inline = $target.children( "." + this._inlineClass );
434
			inline.children().removeClass( "ui-state-disabled" );
435
			inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
436
				prop( "disabled", false );
437
		}
438
		this._disabledInputs = $.map( this._disabledInputs,
439
			function( value ) { return ( value === target ? null : value ); } ); // delete entry
440
	},
441
442
	/* Disable the date picker to a jQuery selection.
443
	 * @param  target	element - the target input field or division or span
444
	 */
445
	_disableDatepicker: function( target ) {
446
		var nodeName, inline,
447
			$target = $( target ),
448
			inst = $.data( target, "datepicker" );
449
450
		if ( !$target.hasClass( this.markerClassName ) ) {
451
			return;
452
		}
453
454
		nodeName = target.nodeName.toLowerCase();
455
		if ( nodeName === "input" ) {
456
			target.disabled = true;
457
			inst.trigger.filter( "button" ).
458
				each( function() { this.disabled = true; } ).end().
459
				filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
460
		} else if ( nodeName === "div" || nodeName === "span" ) {
461
			inline = $target.children( "." + this._inlineClass );
462
			inline.children().addClass( "ui-state-disabled" );
463
			inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
464
				prop( "disabled", true );
465
		}
466
		this._disabledInputs = $.map( this._disabledInputs,
467
			function( value ) { return ( value === target ? null : value ); } ); // delete entry
468
		this._disabledInputs[ this._disabledInputs.length ] = target;
469
	},
470
471
	/* Is the first field in a jQuery collection disabled as a datepicker?
472
	 * @param  target	element - the target input field or division or span
473
	 * @return boolean - true if disabled, false if enabled
474
	 */
475
	_isDisabledDatepicker: function( target ) {
476
		if ( !target ) {
477
			return false;
478
		}
479
		for ( var i = 0; i < this._disabledInputs.length; i++ ) {
480
			if ( this._disabledInputs[ i ] === target ) {
481
				return true;
482
			}
483
		}
484
		return false;
485
	},
486
487
	/* Retrieve the instance data for the target control.
488
	 * @param  target  element - the target input field or division or span
489
	 * @return  object - the associated instance data
490
	 * @throws  error if a jQuery problem getting data
491
	 */
492
	_getInst: function( target ) {
493
		try {
494
			return $.data( target, "datepicker" );
495
		}
496
		catch ( err ) {
497
			throw "Missing instance data for this datepicker";
498
		}
499
	},
500
501
	/* Update or retrieve the settings for a date picker attached to an input field or division.
502
	 * @param  target  element - the target input field or division or span
503
	 * @param  name	object - the new settings to update or
504
	 *				string - the name of the setting to change or retrieve,
505
	 *				when retrieving also "all" for all instance settings or
506
	 *				"defaults" for all global defaults
507
	 * @param  value   any - the new value for the setting
508
	 *				(omit if above is an object or to retrieve a value)
509
	 */
510
	_optionDatepicker: function( target, name, value ) {
511
		var settings, date, minDate, maxDate,
512
			inst = this._getInst( target );
513
514
		if ( arguments.length === 2 && typeof name === "string" ) {
515
			return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
516
				( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
517
				this._get( inst, name ) ) : null ) );
518
		}
519
520
		settings = name || {};
521
		if ( typeof name === "string" ) {
522
			settings = {};
523
			settings[ name ] = value;
524
		}
525
526
		if ( inst ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if inst is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
527
			if ( this._curInst === inst ) {
528
				this._hideDatepicker();
529
			}
530
531
			date = this._getDateDatepicker( target, true );
532
			minDate = this._getMinMaxDate( inst, "min" );
533
			maxDate = this._getMinMaxDate( inst, "max" );
534
			datepicker_extendRemove( inst.settings, settings );
535
536
			// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
537
			if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
538
				inst.settings.minDate = this._formatDate( inst, minDate );
539
			}
540
			if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
541
				inst.settings.maxDate = this._formatDate( inst, maxDate );
542
			}
543
			if ( "disabled" in settings ) {
544
				if ( settings.disabled ) {
545
					this._disableDatepicker( target );
546
				} else {
547
					this._enableDatepicker( target );
548
				}
549
			}
550
			this._attachments( $( target ), inst );
551
			this._autoSize( inst );
552
			this._setDate( inst, date );
553
			this._updateAlternate( inst );
554
			this._updateDatepicker( inst );
555
		}
556
	},
557
558
	// Change method deprecated
559
	_changeDatepicker: function( target, name, value ) {
560
		this._optionDatepicker( target, name, value );
561
	},
562
563
	/* Redraw the date picker attached to an input field or division.
564
	 * @param  target  element - the target input field or division or span
565
	 */
566
	_refreshDatepicker: function( target ) {
567
		var inst = this._getInst( target );
568
		if ( inst ) {
569
			this._updateDatepicker( inst );
570
		}
571
	},
572
573
	/* Set the dates for a jQuery selection.
574
	 * @param  target element - the target input field or division or span
575
	 * @param  date	Date - the new date
576
	 */
577
	_setDateDatepicker: function( target, date ) {
578
		var inst = this._getInst( target );
579
		if ( inst ) {
580
			this._setDate( inst, date );
581
			this._updateDatepicker( inst );
582
			this._updateAlternate( inst );
583
		}
584
	},
585
586
	/* Get the date(s) for the first entry in a jQuery selection.
587
	 * @param  target element - the target input field or division or span
588
	 * @param  noDefault boolean - true if no default date is to be used
589
	 * @return Date - the current date
590
	 */
591
	_getDateDatepicker: function( target, noDefault ) {
592
		var inst = this._getInst( target );
593
		if ( inst && !inst.inline ) {
594
			this._setDateFromField( inst, noDefault );
595
		}
596
		return ( inst ? this._getDate( inst ) : null );
597
	},
598
599
	/* Handle keystrokes. */
600
	_doKeyDown: function( event ) {
601
		var onSelect, dateStr, sel,
602
			inst = $.datepicker._getInst( event.target ),
603
			handled = true,
604
			isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );
605
606
		inst._keyEvent = true;
607
		if ( $.datepicker._datepickerShowing ) {
608
			switch ( event.keyCode ) {
609
				case 9: $.datepicker._hideDatepicker();
610
						handled = false;
611
						break; // hide on tab out
612
				case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
613
									$.datepicker._currentClass + ")", inst.dpDiv );
614
						if ( sel[ 0 ] ) {
615
							$.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
616
						}
617
618
						onSelect = $.datepicker._get( inst, "onSelect" );
619
						if ( onSelect ) {
620
							dateStr = $.datepicker._formatDate( inst );
621
622
							// Trigger custom callback
623
							onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
624
						} else {
625
							$.datepicker._hideDatepicker();
626
						}
627
628
						return false; // don't submit the form
629
				case 27: $.datepicker._hideDatepicker();
630
						break; // hide on escape
631
				case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
632
							-$.datepicker._get( inst, "stepBigMonths" ) :
633
							-$.datepicker._get( inst, "stepMonths" ) ), "M" );
634
						break; // previous month/year on page up/+ ctrl
635
				case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
636
							+$.datepicker._get( inst, "stepBigMonths" ) :
637
							+$.datepicker._get( inst, "stepMonths" ) ), "M" );
638
						break; // next month/year on page down/+ ctrl
639
				case 35: if ( event.ctrlKey || event.metaKey ) {
640
							$.datepicker._clearDate( event.target );
641
						}
642
						handled = event.ctrlKey || event.metaKey;
643
						break; // clear on ctrl or command +end
644
				case 36: if ( event.ctrlKey || event.metaKey ) {
645
							$.datepicker._gotoToday( event.target );
646
						}
647
						handled = event.ctrlKey || event.metaKey;
648
						break; // current on ctrl or command +home
649
				case 37: if ( event.ctrlKey || event.metaKey ) {
650
							$.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
651
						}
652
						handled = event.ctrlKey || event.metaKey;
653
654
						// -1 day on ctrl or command +left
655
						if ( event.originalEvent.altKey ) {
656
							$.datepicker._adjustDate( event.target, ( event.ctrlKey ?
657
								-$.datepicker._get( inst, "stepBigMonths" ) :
658
								-$.datepicker._get( inst, "stepMonths" ) ), "M" );
659
						}
660
661
						// next month/year on alt +left on Mac
662
						break;
663
				case 38: if ( event.ctrlKey || event.metaKey ) {
664
							$.datepicker._adjustDate( event.target, -7, "D" );
665
						}
666
						handled = event.ctrlKey || event.metaKey;
667
						break; // -1 week on ctrl or command +up
668
				case 39: if ( event.ctrlKey || event.metaKey ) {
669
							$.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
670
						}
671
						handled = event.ctrlKey || event.metaKey;
672
673
						// +1 day on ctrl or command +right
674
						if ( event.originalEvent.altKey ) {
675
							$.datepicker._adjustDate( event.target, ( event.ctrlKey ?
676
								+$.datepicker._get( inst, "stepBigMonths" ) :
677
								+$.datepicker._get( inst, "stepMonths" ) ), "M" );
678
						}
679
680
						// next month/year on alt +right
681
						break;
682
				case 40: if ( event.ctrlKey || event.metaKey ) {
683
							$.datepicker._adjustDate( event.target, +7, "D" );
684
						}
685
						handled = event.ctrlKey || event.metaKey;
686
						break; // +1 week on ctrl or command +down
687
				default: handled = false;
688
			}
689
		} else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
690
			$.datepicker._showDatepicker( this );
691
		} else {
692
			handled = false;
693
		}
694
695
		if ( handled ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if handled is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
696
			event.preventDefault();
697
			event.stopPropagation();
698
		}
699
	},
700
701
	/* Filter entered characters - based on date format. */
702
	_doKeyPress: function( event ) {
703
		var chars, chr,
704
			inst = $.datepicker._getInst( event.target );
705
706
		if ( $.datepicker._get( inst, "constrainInput" ) ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if $.datepicker._get(inst, "constrainInput") is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
707
			chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
708
			chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
709
			return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
710
		}
711
	},
712
713
	/* Synchronise manual entry and field/alternate field. */
714
	_doKeyUp: function( event ) {
715
		var date,
716
			inst = $.datepicker._getInst( event.target );
717
718
		if ( inst.input.val() !== inst.lastVal ) {
719
			try {
720
				date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
721
					( inst.input ? inst.input.val() : null ),
722
					$.datepicker._getFormatConfig( inst ) );
723
724
				if ( date ) { // only if valid
725
					$.datepicker._setDateFromField( inst );
726
					$.datepicker._updateAlternate( inst );
727
					$.datepicker._updateDatepicker( inst );
728
				}
729
			}
730
			catch ( err ) {
731
			}
732
		}
733
		return true;
734
	},
735
736
	/* Pop-up the date picker for a given input field.
737
	 * If false returned from beforeShow event handler do not show.
738
	 * @param  input  element - the input field attached to the date picker or
739
	 *					event - if triggered by focus
740
	 */
741
	_showDatepicker: function( input ) {
742
		input = input.target || input;
743
		if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
744
			input = $( "input", input.parentNode )[ 0 ];
745
		}
746
747
		if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
748
			return;
749
		}
750
751
		var inst, beforeShow, beforeShowSettings, isFixed,
752
			offset, showAnim, duration;
753
754
		inst = $.datepicker._getInst( input );
755
		if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
756
			$.datepicker._curInst.dpDiv.stop( true, true );
757
			if ( inst && $.datepicker._datepickerShowing ) {
758
				$.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
759
			}
760
		}
761
762
		beforeShow = $.datepicker._get( inst, "beforeShow" );
763
		beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
764
		if ( beforeShowSettings === false ) {
765
			return;
766
		}
767
		datepicker_extendRemove( inst.settings, beforeShowSettings );
768
769
		inst.lastVal = null;
770
		$.datepicker._lastInput = input;
771
		$.datepicker._setDateFromField( inst );
772
773
		if ( $.datepicker._inDialog ) { // hide cursor
774
			input.value = "";
775
		}
776
		if ( !$.datepicker._pos ) { // position below input
777
			$.datepicker._pos = $.datepicker._findPos( input );
778
			$.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
779
		}
780
781
		isFixed = false;
782
		$( input ).parents().each( function() {
783
			isFixed |= $( this ).css( "position" ) === "fixed";
784
			return !isFixed;
785
		} );
786
787
		offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
788
		$.datepicker._pos = null;
789
790
		//to avoid flashes on Firefox
791
		inst.dpDiv.empty();
792
793
		// determine sizing offscreen
794
		inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
795
		$.datepicker._updateDatepicker( inst );
796
797
		// fix width for dynamic number of date pickers
798
		// and adjust position before showing
799
		offset = $.datepicker._checkOffset( inst, offset, isFixed );
800
		inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
801
			"static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
802
			left: offset.left + "px", top: offset.top + "px" } );
803
804
		if ( !inst.inline ) {
805
			showAnim = $.datepicker._get( inst, "showAnim" );
806
			duration = $.datepicker._get( inst, "duration" );
807
			inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
808
			$.datepicker._datepickerShowing = true;
809
810
			if ( $.effects && $.effects.effect[ showAnim ] ) {
811
				inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
812
			} else {
813
				inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
814
			}
815
816
			if ( $.datepicker._shouldFocusInput( inst ) ) {
817
				inst.input.trigger( "focus" );
818
			}
819
820
			$.datepicker._curInst = inst;
821
		}
822
	},
823
824
	/* Generate the date picker content. */
825
	_updateDatepicker: function( inst ) {
826
		this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
827
		datepicker_instActive = inst; // for delegate hover events
828
		inst.dpDiv.empty().append( this._generateHTML( inst ) );
829
		this._attachHandlers( inst );
830
831
		var origyearshtml,
832
			numMonths = this._getNumberOfMonths( inst ),
833
			cols = numMonths[ 1 ],
834
			width = 17,
835
			activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
836
837
		if ( activeCell.length > 0 ) {
838
			datepicker_handleMouseover.apply( activeCell.get( 0 ) );
839
		}
840
841
		inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
842
		if ( cols > 1 ) {
843
			inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
844
		}
845
		inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
846
			"Class" ]( "ui-datepicker-multi" );
847
		inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
848
			"Class" ]( "ui-datepicker-rtl" );
849
850
		if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
851
			inst.input.trigger( "focus" );
852
		}
853
854
		// Deffered render of the years select (to avoid flashes on Firefox)
855
		if ( inst.yearshtml ) {
856
			origyearshtml = inst.yearshtml;
857
			setTimeout( function() {
858
859
				//assure that inst.yearshtml didn't change.
860
				if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
861
					inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml );
862
				}
863
				origyearshtml = inst.yearshtml = null;
864
			}, 0 );
865
		}
866
	},
867
868
	// #6694 - don't focus the input if it's already focused
869
	// this breaks the change event in IE
870
	// Support: IE and jQuery <1.9
871
	_shouldFocusInput: function( inst ) {
872
		return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
873
	},
874
875
	/* Check positioning to remain on screen. */
876
	_checkOffset: function( inst, offset, isFixed ) {
877
		var dpWidth = inst.dpDiv.outerWidth(),
878
			dpHeight = inst.dpDiv.outerHeight(),
879
			inputWidth = inst.input ? inst.input.outerWidth() : 0,
880
			inputHeight = inst.input ? inst.input.outerHeight() : 0,
881
			viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
882
			viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );
883
884
		offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
885
		offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
886
		offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;
887
888
		// Now check if datepicker is showing outside window viewport - move to a better place if so.
889
		offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
890
			Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
891
		offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
892
			Math.abs( dpHeight + inputHeight ) : 0 );
893
894
		return offset;
895
	},
896
897
	/* Find an object's position on the screen. */
898
	_findPos: function( obj ) {
899
		var position,
900
			inst = this._getInst( obj ),
901
			isRTL = this._get( inst, "isRTL" );
902
903
		while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) {
904
			obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
905
		}
906
907
		position = $( obj ).offset();
908
		return [ position.left, position.top ];
909
	},
910
911
	/* Hide the date picker from view.
912
	 * @param  input  element - the input field attached to the date picker
913
	 */
914
	_hideDatepicker: function( input ) {
915
		var showAnim, duration, postProcess, onClose,
916
			inst = this._curInst;
917
918
		if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
919
			return;
920
		}
921
922
		if ( this._datepickerShowing ) {
923
			showAnim = this._get( inst, "showAnim" );
924
			duration = this._get( inst, "duration" );
925
			postProcess = function() {
926
				$.datepicker._tidyDialog( inst );
927
			};
928
929
			// DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
930
			if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
931
				inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
932
			} else {
933
				inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
934
					( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
935
			}
936
937
			if ( !showAnim ) {
938
				postProcess();
939
			}
940
			this._datepickerShowing = false;
941
942
			onClose = this._get( inst, "onClose" );
943
			if ( onClose ) {
944
				onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
945
			}
946
947
			this._lastInput = null;
948
			if ( this._inDialog ) {
949
				this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
950
				if ( $.blockUI ) {
951
					$.unblockUI();
952
					$( "body" ).append( this.dpDiv );
953
				}
954
			}
955
			this._inDialog = false;
956
		}
957
	},
958
959
	/* Tidy up after a dialog display. */
960
	_tidyDialog: function( inst ) {
961
		inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
962
	},
963
964
	/* Close date picker if clicked elsewhere. */
965
	_checkExternalClick: function( event ) {
966
		if ( !$.datepicker._curInst ) {
967
			return;
968
		}
969
970
		var $target = $( event.target ),
971
			inst = $.datepicker._getInst( $target[ 0 ] );
972
973
		if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
974
				$target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
975
				!$target.hasClass( $.datepicker.markerClassName ) &&
976
				!$target.closest( "." + $.datepicker._triggerClass ).length &&
977
				$.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
978
			( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
979
				$.datepicker._hideDatepicker();
980
		}
981
	},
982
983
	/* Adjust one of the date sub-fields. */
984
	_adjustDate: function( id, offset, period ) {
985
		var target = $( id ),
986
			inst = this._getInst( target[ 0 ] );
987
988
		if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
989
			return;
990
		}
991
		this._adjustInstDate( inst, offset +
992
			( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning
993
			period );
994
		this._updateDatepicker( inst );
995
	},
996
997
	/* Action for current link. */
998
	_gotoToday: function( id ) {
999
		var date,
1000
			target = $( id ),
1001
			inst = this._getInst( target[ 0 ] );
1002
1003
		if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
1004
			inst.selectedDay = inst.currentDay;
1005
			inst.drawMonth = inst.selectedMonth = inst.currentMonth;
1006
			inst.drawYear = inst.selectedYear = inst.currentYear;
1007
		} else {
1008
			date = new Date();
1009
			inst.selectedDay = date.getDate();
1010
			inst.drawMonth = inst.selectedMonth = date.getMonth();
1011
			inst.drawYear = inst.selectedYear = date.getFullYear();
1012
		}
1013
		this._notifyChange( inst );
1014
		this._adjustDate( target );
1015
	},
1016
1017
	/* Action for selecting a new month/year. */
1018
	_selectMonthYear: function( id, select, period ) {
1019
		var target = $( id ),
1020
			inst = this._getInst( target[ 0 ] );
1021
1022
		inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
1023
		inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
1024
			parseInt( select.options[ select.selectedIndex ].value, 10 );
1025
1026
		this._notifyChange( inst );
1027
		this._adjustDate( target );
1028
	},
1029
1030
	/* Action for selecting a day. */
1031
	_selectDay: function( id, month, year, td ) {
1032
		var inst,
1033
			target = $( id );
1034
1035
		if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
1036
			return;
1037
		}
1038
1039
		inst = this._getInst( target[ 0 ] );
1040
		inst.selectedDay = inst.currentDay = $( "a", td ).html();
1041
		inst.selectedMonth = inst.currentMonth = month;
1042
		inst.selectedYear = inst.currentYear = year;
1043
		this._selectDate( id, this._formatDate( inst,
1044
			inst.currentDay, inst.currentMonth, inst.currentYear ) );
1045
	},
1046
1047
	/* Erase the input field and hide the date picker. */
1048
	_clearDate: function( id ) {
1049
		var target = $( id );
1050
		this._selectDate( target, "" );
1051
	},
1052
1053
	/* Update the input field with the selected date. */
1054
	_selectDate: function( id, dateStr ) {
1055
		var onSelect,
1056
			target = $( id ),
1057
			inst = this._getInst( target[ 0 ] );
1058
1059
		dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
1060
		if ( inst.input ) {
1061
			inst.input.val( dateStr );
1062
		}
1063
		this._updateAlternate( inst );
1064
1065
		onSelect = this._get( inst, "onSelect" );
1066
		if ( onSelect ) {
1067
			onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );  // trigger custom callback
1068
		} else if ( inst.input ) {
1069
			inst.input.trigger( "change" ); // fire the change event
1070
		}
1071
1072
		if ( inst.inline ) {
1073
			this._updateDatepicker( inst );
1074
		} else {
1075
			this._hideDatepicker();
1076
			this._lastInput = inst.input[ 0 ];
1077
			if ( typeof( inst.input[ 0 ] ) !== "object" ) {
1078
				inst.input.trigger( "focus" ); // restore focus
1079
			}
1080
			this._lastInput = null;
1081
		}
1082
	},
1083
1084
	/* Update any alternate field to synchronise with the main field. */
1085
	_updateAlternate: function( inst ) {
1086
		var altFormat, date, dateStr,
1087
			altField = this._get( inst, "altField" );
1088
1089
		if ( altField ) { // update alternate field too
1090
			altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
1091
			date = this._getDate( inst );
1092
			dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
1093
			$( altField ).val( dateStr );
1094
		}
1095
	},
1096
1097
	/* Set as beforeShowDay function to prevent selection of weekends.
1098
	 * @param  date  Date - the date to customise
1099
	 * @return [boolean, string] - is this date selectable?, what is its CSS class?
1100
	 */
1101
	noWeekends: function( date ) {
1102
		var day = date.getDay();
1103
		return [ ( day > 0 && day < 6 ), "" ];
1104
	},
1105
1106
	/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
1107
	 * @param  date  Date - the date to get the week for
1108
	 * @return  number - the number of the week within the year that contains this date
1109
	 */
1110
	iso8601Week: function( date ) {
1111
		var time,
1112
			checkDate = new Date( date.getTime() );
1113
1114
		// Find Thursday of this week starting on Monday
1115
		checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
1116
1117
		time = checkDate.getTime();
1118
		checkDate.setMonth( 0 ); // Compare with Jan 1
1119
		checkDate.setDate( 1 );
1120
		return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
1121
	},
1122
1123
	/* Parse a string value into a date object.
1124
	 * See formatDate below for the possible formats.
1125
	 *
1126
	 * @param  format string - the expected format of the date
1127
	 * @param  value string - the date in the above format
1128
	 * @param  settings Object - attributes include:
1129
	 *					shortYearCutoff  number - the cutoff year for determining the century (optional)
1130
	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
1131
	 *					dayNames		string[7] - names of the days from Sunday (optional)
1132
	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
1133
	 *					monthNames		string[12] - names of the months (optional)
1134
	 * @return  Date - the extracted date value or null if value is blank
1135
	 */
1136
	parseDate: function( format, value, settings ) {
1137
		if ( format == null || value == null ) {
1138
			throw "Invalid arguments";
1139
		}
1140
1141
		value = ( typeof value === "object" ? value.toString() : value + "" );
1142
		if ( value === "" ) {
1143
			return null;
1144
		}
1145
1146
		var iFormat, dim, extra,
1147
			iValue = 0,
1148
			shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
1149
			shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
1150
				new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
1151
			dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
1152
			dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
1153
			monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
1154
			monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
1155
			year = -1,
1156
			month = -1,
1157
			day = -1,
1158
			doy = -1,
1159
			literal = false,
1160
			date,
1161
1162
			// Check whether a format character is doubled
1163
			lookAhead = function( match ) {
1164
				var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
1165
				if ( matches ) {
1166
					iFormat++;
1167
				}
1168
				return matches;
1169
			},
1170
1171
			// Extract a number from the string value
1172
			getNumber = function( match ) {
1173
				var isDoubled = lookAhead( match ),
1174
					size = ( match === "@" ? 14 : ( match === "!" ? 20 :
1175
					( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
1176
					minSize = ( match === "y" ? size : 1 ),
1177
					digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
1178
					num = value.substring( iValue ).match( digits );
1179
				if ( !num ) {
1180
					throw "Missing number at position " + iValue;
1181
				}
1182
				iValue += num[ 0 ].length;
1183
				return parseInt( num[ 0 ], 10 );
1184
			},
1185
1186
			// Extract a name from the string value and convert to an index
1187
			getName = function( match, shortNames, longNames ) {
1188
				var index = -1,
1189
					names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
1190
						return [ [ k, v ] ];
1191
					} ).sort( function( a, b ) {
1192
						return -( a[ 1 ].length - b[ 1 ].length );
1193
					} );
1194
1195
				$.each( names, function( i, pair ) {
1196
					var name = pair[ 1 ];
1197
					if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if value.substr(iValue, nam... === name.toLowerCase() is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
1198
						index = pair[ 0 ];
1199
						iValue += name.length;
1200
						return false;
1201
					}
1202
				} );
1203
				if ( index !== -1 ) {
1204
					return index + 1;
1205
				} else {
1206
					throw "Unknown name at position " + iValue;
1207
				}
1208
			},
1209
1210
			// Confirm that a literal character matches the string value
1211
			checkLiteral = function() {
1212
				if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
1213
					throw "Unexpected literal at position " + iValue;
1214
				}
1215
				iValue++;
1216
			};
1217
1218
		for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
1219
			if ( literal ) {
1220
				if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
1221
					literal = false;
1222
				} else {
1223
					checkLiteral();
1224
				}
1225
			} else {
1226
				switch ( format.charAt( iFormat ) ) {
1227
					case "d":
1228
						day = getNumber( "d" );
1229
						break;
1230
					case "D":
1231
						getName( "D", dayNamesShort, dayNames );
1232
						break;
1233
					case "o":
1234
						doy = getNumber( "o" );
1235
						break;
1236
					case "m":
1237
						month = getNumber( "m" );
1238
						break;
1239
					case "M":
1240
						month = getName( "M", monthNamesShort, monthNames );
1241
						break;
1242
					case "y":
1243
						year = getNumber( "y" );
1244
						break;
1245
					case "@":
1246
						date = new Date( getNumber( "@" ) );
1247
						year = date.getFullYear();
1248
						month = date.getMonth() + 1;
1249
						day = date.getDate();
1250
						break;
1251
					case "!":
1252
						date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
1253
						year = date.getFullYear();
1254
						month = date.getMonth() + 1;
1255
						day = date.getDate();
1256
						break;
1257
					case "'":
1258
						if ( lookAhead( "'" ) ) {
1259
							checkLiteral();
1260
						} else {
1261
							literal = true;
1262
						}
1263
						break;
1264
					default:
1265
						checkLiteral();
1266
				}
1267
			}
1268
		}
1269
1270
		if ( iValue < value.length ) {
1271
			extra = value.substr( iValue );
1272
			if ( !/^\s+/.test( extra ) ) {
1273
				throw "Extra/unparsed characters found in date: " + extra;
1274
			}
1275
		}
1276
1277
		if ( year === -1 ) {
1278
			year = new Date().getFullYear();
1279
		} else if ( year < 100 ) {
1280
			year += new Date().getFullYear() - new Date().getFullYear() % 100 +
1281
				( year <= shortYearCutoff ? 0 : -100 );
1282
		}
1283
1284
		if ( doy > -1 ) {
1285
			month = 1;
1286
			day = doy;
1287
			do {
1288
				dim = this._getDaysInMonth( year, month - 1 );
1289
				if ( day <= dim ) {
1290
					break;
1291
				}
1292
				month++;
1293
				day -= dim;
1294
			} while ( true );
1295
		}
1296
1297
		date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
1298
		if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
1299
			throw "Invalid date"; // E.g. 31/02/00
1300
		}
1301
		return date;
1302
	},
1303
1304
	/* Standard date formats. */
1305
	ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
1306
	COOKIE: "D, dd M yy",
1307
	ISO_8601: "yy-mm-dd",
1308
	RFC_822: "D, d M y",
1309
	RFC_850: "DD, dd-M-y",
1310
	RFC_1036: "D, d M y",
1311
	RFC_1123: "D, d M yy",
1312
	RFC_2822: "D, d M yy",
1313
	RSS: "D, d M y", // RFC 822
1314
	TICKS: "!",
1315
	TIMESTAMP: "@",
1316
	W3C: "yy-mm-dd", // ISO 8601
1317
1318
	_ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
1319
		Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
1320
1321
	/* Format a date object into a string value.
1322
	 * The format can be combinations of the following:
1323
	 * d  - day of month (no leading zero)
1324
	 * dd - day of month (two digit)
1325
	 * o  - day of year (no leading zeros)
1326
	 * oo - day of year (three digit)
1327
	 * D  - day name short
1328
	 * DD - day name long
1329
	 * m  - month of year (no leading zero)
1330
	 * mm - month of year (two digit)
1331
	 * M  - month name short
1332
	 * MM - month name long
1333
	 * y  - year (two digit)
1334
	 * yy - year (four digit)
1335
	 * @ - Unix timestamp (ms since 01/01/1970)
1336
	 * ! - Windows ticks (100ns since 01/01/0001)
1337
	 * "..." - literal text
1338
	 * '' - single quote
1339
	 *
1340
	 * @param  format string - the desired format of the date
1341
	 * @param  date Date - the date value to format
1342
	 * @param  settings Object - attributes include:
1343
	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
1344
	 *					dayNames		string[7] - names of the days from Sunday (optional)
1345
	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
1346
	 *					monthNames		string[12] - names of the months (optional)
1347
	 * @return  string - the date in the above format
1348
	 */
1349
	formatDate: function( format, date, settings ) {
1350
		if ( !date ) {
1351
			return "";
1352
		}
1353
1354
		var iFormat,
1355
			dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
1356
			dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
1357
			monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
1358
			monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
1359
1360
			// Check whether a format character is doubled
1361
			lookAhead = function( match ) {
1362
				var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
1363
				if ( matches ) {
1364
					iFormat++;
1365
				}
1366
				return matches;
1367
			},
1368
1369
			// Format a number, with leading zero if necessary
1370
			formatNumber = function( match, value, len ) {
1371
				var num = "" + value;
1372
				if ( lookAhead( match ) ) {
1373
					while ( num.length < len ) {
1374
						num = "0" + num;
1375
					}
1376
				}
1377
				return num;
1378
			},
1379
1380
			// Format a name, short or long as requested
1381
			formatName = function( match, value, shortNames, longNames ) {
1382
				return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
1383
			},
1384
			output = "",
1385
			literal = false;
1386
1387
		if ( date ) {
1388
			for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
1389
				if ( literal ) {
1390
					if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
1391
						literal = false;
1392
					} else {
1393
						output += format.charAt( iFormat );
1394
					}
1395
				} else {
1396
					switch ( format.charAt( iFormat ) ) {
1397
						case "d":
1398
							output += formatNumber( "d", date.getDate(), 2 );
1399
							break;
1400
						case "D":
1401
							output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
1402
							break;
1403
						case "o":
1404
							output += formatNumber( "o",
1405
								Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
1406
							break;
1407
						case "m":
1408
							output += formatNumber( "m", date.getMonth() + 1, 2 );
1409
							break;
1410
						case "M":
1411
							output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
1412
							break;
1413
						case "y":
1414
							output += ( lookAhead( "y" ) ? date.getFullYear() :
1415
								( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
1416
							break;
1417
						case "@":
1418
							output += date.getTime();
1419
							break;
1420
						case "!":
1421
							output += date.getTime() * 10000 + this._ticksTo1970;
1422
							break;
1423
						case "'":
1424
							if ( lookAhead( "'" ) ) {
1425
								output += "'";
1426
							} else {
1427
								literal = true;
1428
							}
1429
							break;
1430
						default:
1431
							output += format.charAt( iFormat );
1432
					}
1433
				}
1434
			}
1435
		}
1436
		return output;
1437
	},
1438
1439
	/* Extract all possible characters from the date format. */
1440
	_possibleChars: function( format ) {
1441
		var iFormat,
1442
			chars = "",
1443
			literal = false,
1444
1445
			// Check whether a format character is doubled
1446
			lookAhead = function( match ) {
1447
				var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
1448
				if ( matches ) {
1449
					iFormat++;
1450
				}
1451
				return matches;
1452
			};
1453
1454
		for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
1455
			if ( literal ) {
1456
				if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
1457
					literal = false;
1458
				} else {
1459
					chars += format.charAt( iFormat );
1460
				}
1461
			} else {
1462
				switch ( format.charAt( iFormat ) ) {
1463
					case "d": case "m": case "y": case "@":
1464
						chars += "0123456789";
1465
						break;
1466
					case "D": case "M":
1467
						return null; // Accept anything
1468
					case "'":
1469
						if ( lookAhead( "'" ) ) {
1470
							chars += "'";
1471
						} else {
1472
							literal = true;
1473
						}
1474
						break;
1475
					default:
1476
						chars += format.charAt( iFormat );
1477
				}
1478
			}
1479
		}
1480
		return chars;
1481
	},
1482
1483
	/* Get a setting value, defaulting if necessary. */
1484
	_get: function( inst, name ) {
1485
		return inst.settings[ name ] !== undefined ?
1486
			inst.settings[ name ] : this._defaults[ name ];
1487
	},
1488
1489
	/* Parse existing date and initialise date picker. */
1490
	_setDateFromField: function( inst, noDefault ) {
1491
		if ( inst.input.val() === inst.lastVal ) {
1492
			return;
1493
		}
1494
1495
		var dateFormat = this._get( inst, "dateFormat" ),
1496
			dates = inst.lastVal = inst.input ? inst.input.val() : null,
1497
			defaultDate = this._getDefaultDate( inst ),
1498
			date = defaultDate,
0 ignored issues
show
Unused Code introduced by
The assignment to variable date seems to be never used. Consider removing it.
Loading history...
1499
			settings = this._getFormatConfig( inst );
1500
1501
		try {
1502
			date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
1503
		} catch ( event ) {
1504
			dates = ( noDefault ? "" : dates );
1505
		}
1506
		inst.selectedDay = date.getDate();
1507
		inst.drawMonth = inst.selectedMonth = date.getMonth();
1508
		inst.drawYear = inst.selectedYear = date.getFullYear();
1509
		inst.currentDay = ( dates ? date.getDate() : 0 );
1510
		inst.currentMonth = ( dates ? date.getMonth() : 0 );
1511
		inst.currentYear = ( dates ? date.getFullYear() : 0 );
1512
		this._adjustInstDate( inst );
1513
	},
1514
1515
	/* Retrieve the default date shown on opening. */
1516
	_getDefaultDate: function( inst ) {
1517
		return this._restrictMinMax( inst,
1518
			this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
1519
	},
1520
1521
	/* A date may be specified as an exact value or a relative one. */
1522
	_determineDate: function( inst, date, defaultDate ) {
1523
		var offsetNumeric = function( offset ) {
1524
				var date = new Date();
1525
				date.setDate( date.getDate() + offset );
1526
				return date;
1527
			},
1528
			offsetString = function( offset ) {
1529
				try {
1530
					return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
1531
						offset, $.datepicker._getFormatConfig( inst ) );
1532
				}
1533
				catch ( e ) {
1534
1535
					// Ignore
1536
				}
1537
1538
				var date = ( offset.toLowerCase().match( /^c/ ) ?
1539
					$.datepicker._getDate( inst ) : null ) || new Date(),
1540
					year = date.getFullYear(),
1541
					month = date.getMonth(),
1542
					day = date.getDate(),
1543
					pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
1544
					matches = pattern.exec( offset );
1545
1546
				while ( matches ) {
1547
					switch ( matches[ 2 ] || "d" ) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
1548
						case "d" : case "D" :
1549
							day += parseInt( matches[ 1 ], 10 ); break;
1550
						case "w" : case "W" :
1551
							day += parseInt( matches[ 1 ], 10 ) * 7; break;
1552
						case "m" : case "M" :
1553
							month += parseInt( matches[ 1 ], 10 );
1554
							day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
1555
							break;
1556
						case "y": case "Y" :
1557
							year += parseInt( matches[ 1 ], 10 );
1558
							day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
1559
							break;
1560
					}
1561
					matches = pattern.exec( offset );
1562
				}
1563
				return new Date( year, month, day );
1564
			},
1565
			newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
1566
				( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );
1567
1568
		newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
1569
		if ( newDate ) {
1570
			newDate.setHours( 0 );
1571
			newDate.setMinutes( 0 );
1572
			newDate.setSeconds( 0 );
1573
			newDate.setMilliseconds( 0 );
1574
		}
1575
		return this._daylightSavingAdjust( newDate );
1576
	},
1577
1578
	/* Handle switch to/from daylight saving.
1579
	 * Hours may be non-zero on daylight saving cut-over:
1580
	 * > 12 when midnight changeover, but then cannot generate
1581
	 * midnight datetime, so jump to 1AM, otherwise reset.
1582
	 * @param  date  (Date) the date to check
1583
	 * @return  (Date) the corrected date
1584
	 */
1585
	_daylightSavingAdjust: function( date ) {
1586
		if ( !date ) {
1587
			return null;
1588
		}
1589
		date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
1590
		return date;
1591
	},
1592
1593
	/* Set the date(s) directly. */
1594
	_setDate: function( inst, date, noChange ) {
1595
		var clear = !date,
1596
			origMonth = inst.selectedMonth,
1597
			origYear = inst.selectedYear,
1598
			newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );
1599
1600
		inst.selectedDay = inst.currentDay = newDate.getDate();
1601
		inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
1602
		inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
1603
		if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
1604
			this._notifyChange( inst );
1605
		}
1606
		this._adjustInstDate( inst );
1607
		if ( inst.input ) {
1608
			inst.input.val( clear ? "" : this._formatDate( inst ) );
1609
		}
1610
	},
1611
1612
	/* Retrieve the date(s) directly. */
1613
	_getDate: function( inst ) {
1614
		var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
1615
			this._daylightSavingAdjust( new Date(
1616
			inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
1617
			return startDate;
1618
	},
1619
1620
	/* Attach the onxxx handlers.  These are declared statically so
1621
	 * they work with static code transformers like Caja.
1622
	 */
1623
	_attachHandlers: function( inst ) {
1624
		var stepMonths = this._get( inst, "stepMonths" ),
1625
			id = "#" + inst.id.replace( /\\\\/g, "\\" );
1626
		inst.dpDiv.find( "[data-handler]" ).map( function() {
1627
			var handler = {
1628
				prev: function() {
1629
					$.datepicker._adjustDate( id, -stepMonths, "M" );
1630
				},
1631
				next: function() {
1632
					$.datepicker._adjustDate( id, +stepMonths, "M" );
1633
				},
1634
				hide: function() {
1635
					$.datepicker._hideDatepicker();
1636
				},
1637
				today: function() {
1638
					$.datepicker._gotoToday( id );
1639
				},
1640
				selectDay: function() {
1641
					$.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
1642
					return false;
1643
				},
1644
				selectMonth: function() {
1645
					$.datepicker._selectMonthYear( id, this, "M" );
1646
					return false;
1647
				},
1648
				selectYear: function() {
1649
					$.datepicker._selectMonthYear( id, this, "Y" );
1650
					return false;
1651
				}
1652
			};
1653
			$( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
1654
		} );
1655
	},
1656
1657
	/* Generate the HTML for the current state of the date picker. */
1658
	_generateHTML: function( inst ) {
1659
		var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
1660
			controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
1661
			monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
1662
			selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
1663
			cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
1664
			printDate, dRow, tbody, daySettings, otherMonth, unselectable,
1665
			tempDate = new Date(),
1666
			today = this._daylightSavingAdjust(
1667
				new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
1668
			isRTL = this._get( inst, "isRTL" ),
1669
			showButtonPanel = this._get( inst, "showButtonPanel" ),
1670
			hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
1671
			navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
1672
			numMonths = this._getNumberOfMonths( inst ),
1673
			showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
1674
			stepMonths = this._get( inst, "stepMonths" ),
1675
			isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
1676
			currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
1677
				new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
1678
			minDate = this._getMinMaxDate( inst, "min" ),
1679
			maxDate = this._getMinMaxDate( inst, "max" ),
1680
			drawMonth = inst.drawMonth - showCurrentAtPos,
1681
			drawYear = inst.drawYear;
1682
1683
		if ( drawMonth < 0 ) {
1684
			drawMonth += 12;
1685
			drawYear--;
1686
		}
1687
		if ( maxDate ) {
1688
			maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
1689
				maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
1690
			maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
1691
			while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
1692
				drawMonth--;
1693
				if ( drawMonth < 0 ) {
1694
					drawMonth = 11;
1695
					drawYear--;
1696
				}
1697
			}
1698
		}
1699
		inst.drawMonth = drawMonth;
1700
		inst.drawYear = drawYear;
1701
1702
		prevText = this._get( inst, "prevText" );
1703
		prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
1704
			this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
1705
			this._getFormatConfig( inst ) ) );
1706
1707
		prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ?
1708
			"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
1709
			" title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" :
1710
			( 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>" ) );
1711
1712
		nextText = this._get( inst, "nextText" );
1713
		nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
1714
			this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
1715
			this._getFormatConfig( inst ) ) );
1716
1717
		next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ?
1718
			"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
1719
			" title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" :
1720
			( 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>" ) );
1721
1722
		currentText = this._get( inst, "currentText" );
1723
		gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
1724
		currentText = ( !navigationAsDateFormat ? currentText :
1725
			this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
1726
1727
		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'>" +
1728
			this._get( inst, "closeText" ) + "</button>" : "" );
1729
1730
		buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) +
1731
			( 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'" +
1732
			">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : "";
1733
1734
		firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
1735
		firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
1736
1737
		showWeek = this._get( inst, "showWeek" );
1738
		dayNames = this._get( inst, "dayNames" );
1739
		dayNamesMin = this._get( inst, "dayNamesMin" );
1740
		monthNames = this._get( inst, "monthNames" );
1741
		monthNamesShort = this._get( inst, "monthNamesShort" );
1742
		beforeShowDay = this._get( inst, "beforeShowDay" );
1743
		showOtherMonths = this._get( inst, "showOtherMonths" );
1744
		selectOtherMonths = this._get( inst, "selectOtherMonths" );
1745
		defaultDate = this._getDefaultDate( inst );
1746
		html = "";
1747
1748
		for ( row = 0; row < numMonths[ 0 ]; row++ ) {
1749
			group = "";
1750
			this.maxRows = 4;
1751
			for ( col = 0; col < numMonths[ 1 ]; col++ ) {
1752
				selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
1753
				cornerClass = " ui-corner-all";
1754
				calender = "";
1755
				if ( isMultiMonth ) {
1756
					calender += "<div class='ui-datepicker-group";
1757
					if ( numMonths[ 1 ] > 1 ) {
1758
						switch ( col ) {
1759
							case 0: calender += " ui-datepicker-group-first";
1760
								cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
1761
							case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
0 ignored issues
show
Bug introduced by
The variable numMonths seems to be never declared. If this is a global, consider adding a /** global: numMonths */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1762
								cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
1763
							default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
1764
						}
1765
					}
1766
					calender += "'>";
1767
				}
1768
				calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
1769
					( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
1770
					( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
1771
					this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
1772
					row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
1773
					"</div><table class='ui-datepicker-calendar'><thead>" +
1774
					"<tr>";
1775
				thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
1776
				for ( dow = 0; dow < 7; dow++ ) { // days of the week
1777
					day = ( dow + firstDay ) % 7;
1778
					thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
1779
						"<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
1780
				}
1781
				calender += thead + "</tr></thead><tbody>";
1782
				daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
1783
				if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
1784
					inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
1785
				}
1786
				leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
1787
				curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
1788
				numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
1789
				this.maxRows = numRows;
1790
				printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
1791
				for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
1792
					calender += "<tr>";
1793
					tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
1794
						this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
1795
					for ( dow = 0; dow < 7; dow++ ) { // create date picker days
1796
						daySettings = ( beforeShowDay ?
1797
							beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
1798
						otherMonth = ( printDate.getMonth() !== drawMonth );
1799
						unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
1800
							( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
1801
						tbody += "<td class='" +
1802
							( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
1803
							( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
1804
							( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
1805
							( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?
1806
1807
							// or defaultDate is current printedDate and defaultDate is selectedDate
1808
							" " + this._dayOverClass : "" ) + // highlight selected day
1809
							( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) +  // highlight unselectable days
1810
							( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
1811
							( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
1812
							( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
1813
							( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "&#39;" ) + "'" : "" ) + // cell title
1814
							( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
1815
							( otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
1816
							( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
1817
							( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
1818
							( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
1819
							( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
1820
							"' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
1821
						printDate.setDate( printDate.getDate() + 1 );
1822
						printDate = this._daylightSavingAdjust( printDate );
1823
					}
1824
					calender += tbody + "</tr>";
1825
				}
1826
				drawMonth++;
1827
				if ( drawMonth > 11 ) {
1828
					drawMonth = 0;
1829
					drawYear++;
1830
				}
1831
				calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
1832
							( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
1833
				group += calender;
1834
			}
1835
			html += group;
1836
		}
1837
		html += buttonPanel;
1838
		inst._keyEvent = false;
1839
		return html;
1840
	},
1841
1842
	/* Generate the month and year header. */
1843
	_generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
1844
			secondary, monthNames, monthNamesShort ) {
1845
1846
		var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
1847
			changeMonth = this._get( inst, "changeMonth" ),
1848
			changeYear = this._get( inst, "changeYear" ),
1849
			showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
1850
			html = "<div class='ui-datepicker-title'>",
1851
			monthHtml = "";
1852
1853
		// Month selection
1854
		if ( secondary || !changeMonth ) {
1855
			monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
1856
		} else {
1857
			inMinYear = ( minDate && minDate.getFullYear() === drawYear );
1858
			inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
1859
			monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
1860
			for ( month = 0; month < 12; month++ ) {
1861
				if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
1862
					monthHtml += "<option value='" + month + "'" +
1863
						( month === drawMonth ? " selected='selected'" : "" ) +
1864
						">" + monthNamesShort[ month ] + "</option>";
1865
				}
1866
			}
1867
			monthHtml += "</select>";
1868
		}
1869
1870
		if ( !showMonthAfterYear ) {
1871
			html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" );
1872
		}
1873
1874
		// Year selection
1875
		if ( !inst.yearshtml ) {
1876
			inst.yearshtml = "";
1877
			if ( secondary || !changeYear ) {
1878
				html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
1879
			} else {
1880
1881
				// determine range of years to display
1882
				years = this._get( inst, "yearRange" ).split( ":" );
1883
				thisYear = new Date().getFullYear();
1884
				determineYear = function( value ) {
1885
					var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
1886
						( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
1887
						parseInt( value, 10 ) ) );
1888
					return ( isNaN( year ) ? thisYear : year );
1889
				};
1890
				year = determineYear( years[ 0 ] );
1891
				endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
1892
				year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
1893
				endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
1894
				inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
1895
				for ( ; year <= endYear; year++ ) {
1896
					inst.yearshtml += "<option value='" + year + "'" +
1897
						( year === drawYear ? " selected='selected'" : "" ) +
1898
						">" + year + "</option>";
1899
				}
1900
				inst.yearshtml += "</select>";
1901
1902
				html += inst.yearshtml;
1903
				inst.yearshtml = null;
1904
			}
1905
		}
1906
1907
		html += this._get( inst, "yearSuffix" );
1908
		if ( showMonthAfterYear ) {
1909
			html += ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" ) + monthHtml;
1910
		}
1911
		html += "</div>"; // Close datepicker_header
1912
		return html;
1913
	},
1914
1915
	/* Adjust one of the date sub-fields. */
1916
	_adjustInstDate: function( inst, offset, period ) {
1917
		var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
1918
			month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
1919
			day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
1920
			date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );
1921
1922
		inst.selectedDay = date.getDate();
1923
		inst.drawMonth = inst.selectedMonth = date.getMonth();
1924
		inst.drawYear = inst.selectedYear = date.getFullYear();
1925
		if ( period === "M" || period === "Y" ) {
1926
			this._notifyChange( inst );
1927
		}
1928
	},
1929
1930
	/* Ensure a date is within any min/max bounds. */
1931
	_restrictMinMax: function( inst, date ) {
1932
		var minDate = this._getMinMaxDate( inst, "min" ),
1933
			maxDate = this._getMinMaxDate( inst, "max" ),
1934
			newDate = ( minDate && date < minDate ? minDate : date );
1935
		return ( maxDate && newDate > maxDate ? maxDate : newDate );
1936
	},
1937
1938
	/* Notify change of month/year. */
1939
	_notifyChange: function( inst ) {
1940
		var onChange = this._get( inst, "onChangeMonthYear" );
1941
		if ( onChange ) {
1942
			onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
1943
				[ inst.selectedYear, inst.selectedMonth + 1, inst ] );
1944
		}
1945
	},
1946
1947
	/* Determine the number of months to show. */
1948
	_getNumberOfMonths: function( inst ) {
1949
		var numMonths = this._get( inst, "numberOfMonths" );
1950
		return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
1951
	},
1952
1953
	/* Determine the current maximum date - ensure no time components are set. */
1954
	_getMinMaxDate: function( inst, minMax ) {
1955
		return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
1956
	},
1957
1958
	/* Find the number of days in a given month. */
1959
	_getDaysInMonth: function( year, month ) {
1960
		return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
1961
	},
1962
1963
	/* Find the day of the week of the first of a month. */
1964
	_getFirstDayOfMonth: function( year, month ) {
1965
		return new Date( year, month, 1 ).getDay();
1966
	},
1967
1968
	/* Determines if we should allow a "next/prev" month display change. */
1969
	_canAdjustMonth: function( inst, offset, curYear, curMonth ) {
1970
		var numMonths = this._getNumberOfMonths( inst ),
1971
			date = this._daylightSavingAdjust( new Date( curYear,
1972
			curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );
1973
1974
		if ( offset < 0 ) {
1975
			date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
1976
		}
1977
		return this._isInRange( inst, date );
1978
	},
1979
1980
	/* Is the given date in the accepted range? */
1981
	_isInRange: function( inst, date ) {
1982
		var yearSplit, currentYear,
1983
			minDate = this._getMinMaxDate( inst, "min" ),
1984
			maxDate = this._getMinMaxDate( inst, "max" ),
1985
			minYear = null,
1986
			maxYear = null,
1987
			years = this._get( inst, "yearRange" );
1988
			if ( years ) {
1989
				yearSplit = years.split( ":" );
1990
				currentYear = new Date().getFullYear();
1991
				minYear = parseInt( yearSplit[ 0 ], 10 );
1992
				maxYear = parseInt( yearSplit[ 1 ], 10 );
1993
				if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
1994
					minYear += currentYear;
1995
				}
1996
				if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
1997
					maxYear += currentYear;
1998
				}
1999
			}
2000
2001
		return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
2002
			( !maxDate || date.getTime() <= maxDate.getTime() ) &&
2003
			( !minYear || date.getFullYear() >= minYear ) &&
2004
			( !maxYear || date.getFullYear() <= maxYear ) );
2005
	},
2006
2007
	/* Provide the configuration settings for formatting/parsing. */
2008
	_getFormatConfig: function( inst ) {
2009
		var shortYearCutoff = this._get( inst, "shortYearCutoff" );
2010
		shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
2011
			new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
2012
		return { shortYearCutoff: shortYearCutoff,
2013
			dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
2014
			monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
2015
	},
2016
2017
	/* Format the given date for display. */
2018
	_formatDate: function( inst, day, month, year ) {
2019
		if ( !day ) {
2020
			inst.currentDay = inst.selectedDay;
2021
			inst.currentMonth = inst.selectedMonth;
2022
			inst.currentYear = inst.selectedYear;
2023
		}
2024
		var date = ( day ? ( typeof day === "object" ? day :
2025
			this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
2026
			this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
2027
		return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
2028
	}
2029
} );
2030
2031
/*
2032
 * Bind hover events for datepicker elements.
2033
 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
2034
 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
2035
 */
2036
function datepicker_bindHover( dpDiv ) {
2037
	var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
2038
	return dpDiv.on( "mouseout", selector, function() {
2039
			$( this ).removeClass( "ui-state-hover" );
2040
			if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
2041
				$( this ).removeClass( "ui-datepicker-prev-hover" );
2042
			}
2043
			if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
2044
				$( this ).removeClass( "ui-datepicker-next-hover" );
2045
			}
2046
		} )
2047
		.on( "mouseover", selector, datepicker_handleMouseover );
2048
}
2049
2050
function datepicker_handleMouseover() {
2051
	if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
2052
		$( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
2053
		$( this ).addClass( "ui-state-hover" );
2054
		if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
2055
			$( this ).addClass( "ui-datepicker-prev-hover" );
2056
		}
2057
		if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
2058
			$( this ).addClass( "ui-datepicker-next-hover" );
2059
		}
2060
	}
2061
}
2062
2063
/* jQuery extend now ignores nulls! */
2064
function datepicker_extendRemove( target, props ) {
2065
	$.extend( target, props );
2066
	for ( var name in props ) {
2067
		if ( props[ name ] == null ) {
2068
			target[ name ] = props[ name ];
2069
		}
2070
	}
2071
	return target;
2072
}
2073
2074
/* Invoke the datepicker functionality.
2075
   @param  options  string - a command, optionally followed by additional parameters or
2076
					Object - settings for attaching new datepicker functionality
2077
   @return  jQuery object */
2078
$.fn.datepicker = function( options ) {
2079
2080
	/* Verify an empty collection wasn't passed - Fixes #6976 */
2081
	if ( !this.length ) {
2082
		return this;
2083
	}
2084
2085
	/* Initialise the date picker. */
2086
	if ( !$.datepicker.initialized ) {
2087
		$( document ).on( "mousedown", $.datepicker._checkExternalClick );
2088
		$.datepicker.initialized = true;
2089
	}
2090
2091
	/* Append datepicker main container to body if not exist. */
2092
	if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
2093
		$( "body" ).append( $.datepicker.dpDiv );
2094
	}
2095
2096
	var otherArgs = Array.prototype.slice.call( arguments, 1 );
2097
	if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
2098
		return $.datepicker[ "_" + options + "Datepicker" ].
2099
			apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
2100
	}
2101
	if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
2102
		return $.datepicker[ "_" + options + "Datepicker" ].
2103
			apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
2104
	}
2105
	return this.each( function() {
2106
		typeof options === "string" ?
2107
			$.datepicker[ "_" + options + "Datepicker" ].
2108
				apply( $.datepicker, [ this ].concat( otherArgs ) ) :
2109
			$.datepicker._attachDatepicker( this, options );
2110
	} );
2111
};
2112
2113
$.datepicker = new Datepicker(); // singleton instance
2114
$.datepicker.initialized = false;
2115
$.datepicker.uuid = new Date().getTime();
2116
$.datepicker.version = "1.12.1";
2117
2118
return $.datepicker;
2119
2120
} ) );
2121