standard header in about page (#676)
[openemr.git] / public / assets / jquery-ui-1-12-1 / ui / widgets / datepicker.js
blob8b6a4f4ecdfa77ff6b077e882e175cf25ad0a79f
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  */
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
21 ( function( factory ) {
22         if ( typeof define === "function" && define.amd ) {
24                 // AMD. Register as an anonymous module.
25                 define( [
26                         "jquery",
27                         "../version",
28                         "../keycode"
29                 ], factory );
30         } else {
32                 // Browser globals
33                 factory( jQuery );
34         }
35 }( function( $ ) {
37 $.extend( $.ui, { datepicker: { version: "1.12.1" } } );
39 var datepicker_instActive;
41 function datepicker_getZindex( elem ) {
42         var position, value;
43         while ( elem.length && elem[ 0 ] !== document ) {
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" ) {
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         }
63         return 0;
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. */
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>" ) );
160 $.extend( Datepicker.prototype, {
161         /* Class name added to elements to indicate already configured with a date picker. */
162         markerClassName: "hasDatepicker",
164         //Keep track of the maximum number of rows displayed (see #7043)
165         maxRows: 4,
167         // TODO rename to "widget" when switching to widget factory
168         _widgetDatepicker: function() {
169                 return this.dpDiv;
170         },
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         },
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         },
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         },
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 );
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         },
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" );
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                 }
247                 input.off( "focus", this._showDatepicker );
249                 if ( inst.trigger ) {
250                         inst.trigger.remove();
251                 }
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         },
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" );
288                         if ( dateFormat.match( /[DM]/ ) ) {
289                                 findMax = function( names ) {
290                                         max = 0;
291                                         maxI = 0;
292                                         for ( i = 0; i < names.length; i++ ) {
293                                                 if ( names[ i ].length > max ) {
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         },
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 );
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                 }
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         },
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
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 );
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                 }
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         },
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" );
391                 if ( !$target.hasClass( this.markerClassName ) ) {
392                         return;
393                 }
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                 }
409                 if ( datepicker_instActive === inst ) {
410                         datepicker_instActive = null;
411                 }
412         },
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" );
422                 if ( !$target.hasClass( this.markerClassName ) ) {
423                         return;
424                 }
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         },
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" );
450                 if ( !$target.hasClass( this.markerClassName ) ) {
451                         return;
452                 }
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         },
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         },
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         },
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 );
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                 }
520                 settings = name || {};
521                 if ( typeof name === "string" ) {
522                         settings = {};
523                         settings[ name ] = value;
524                 }
526                 if ( inst ) {
527                         if ( this._curInst === inst ) {
528                                 this._hideDatepicker();
529                         }
531                         date = this._getDateDatepicker( target, true );
532                         minDate = this._getMinMaxDate( inst, "min" );
533                         maxDate = this._getMinMaxDate( inst, "max" );
534                         datepicker_extendRemove( inst.settings, settings );
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         },
558         // Change method deprecated
559         _changeDatepicker: function( target, name, value ) {
560                 this._optionDatepicker( target, name, value );
561         },
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         },
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         },
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         },
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" );
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                                                 }
618                                                 onSelect = $.datepicker._get( inst, "onSelect" );
619                                                 if ( onSelect ) {
620                                                         dateStr = $.datepicker._formatDate( inst );
622                                                         // Trigger custom callback
623                                                         onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
624                                                 } else {
625                                                         $.datepicker._hideDatepicker();
626                                                 }
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;
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                                                 }
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;
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                                                 }
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                 }
695                 if ( handled ) {
696                         event.preventDefault();
697                         event.stopPropagation();
698                 }
699         },
701         /* Filter entered characters - based on date format. */
702         _doKeyPress: function( event ) {
703                 var chars, chr,
704                         inst = $.datepicker._getInst( event.target );
706                 if ( $.datepicker._get( inst, "constrainInput" ) ) {
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         },
713         /* Synchronise manual entry and field/alternate field. */
714         _doKeyUp: function( event ) {
715                 var date,
716                         inst = $.datepicker._getInst( event.target );
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 ) );
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         },
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                 }
747                 if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
748                         return;
749                 }
751                 var inst, beforeShow, beforeShowSettings, isFixed,
752                         offset, showAnim, duration;
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                 }
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 );
769                 inst.lastVal = null;
770                 $.datepicker._lastInput = input;
771                 $.datepicker._setDateFromField( inst );
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                 }
781                 isFixed = false;
782                 $( input ).parents().each( function() {
783                         isFixed |= $( this ).css( "position" ) === "fixed";
784                         return !isFixed;
785                 } );
787                 offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
788                 $.datepicker._pos = null;
790                 //to avoid flashes on Firefox
791                 inst.dpDiv.empty();
793                 // determine sizing offscreen
794                 inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
795                 $.datepicker._updateDatepicker( inst );
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" } );
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;
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                         }
816                         if ( $.datepicker._shouldFocusInput( inst ) ) {
817                                 inst.input.trigger( "focus" );
818                         }
820                         $.datepicker._curInst = inst;
821                 }
822         },
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 );
831                 var origyearshtml,
832                         numMonths = this._getNumberOfMonths( inst ),
833                         cols = numMonths[ 1 ],
834                         width = 17,
835                         activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
837                 if ( activeCell.length > 0 ) {
838                         datepicker_handleMouseover.apply( activeCell.get( 0 ) );
839                 }
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" );
850                 if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
851                         inst.input.trigger( "focus" );
852                 }
854                 // Deffered render of the years select (to avoid flashes on Firefox)
855                 if ( inst.yearshtml ) {
856                         origyearshtml = inst.yearshtml;
857                         setTimeout( function() {
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         },
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         },
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() );
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;
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 );
894                 return offset;
895         },
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" );
903                 while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) {
904                         obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
905                 }
907                 position = $( obj ).offset();
908                 return [ position.left, position.top ];
909         },
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;
918                 if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
919                         return;
920                 }
922                 if ( this._datepickerShowing ) {
923                         showAnim = this._get( inst, "showAnim" );
924                         duration = this._get( inst, "duration" );
925                         postProcess = function() {
926                                 $.datepicker._tidyDialog( inst );
927                         };
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                         }
937                         if ( !showAnim ) {
938                                 postProcess();
939                         }
940                         this._datepickerShowing = false;
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                         }
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         },
959         /* Tidy up after a dialog display. */
960         _tidyDialog: function( inst ) {
961                 inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
962         },
964         /* Close date picker if clicked elsewhere. */
965         _checkExternalClick: function( event ) {
966                 if ( !$.datepicker._curInst ) {
967                         return;
968                 }
970                 var $target = $( event.target ),
971                         inst = $.datepicker._getInst( $target[ 0 ] );
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         },
983         /* Adjust one of the date sub-fields. */
984         _adjustDate: function( id, offset, period ) {
985                 var target = $( id ),
986                         inst = this._getInst( target[ 0 ] );
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         },
997         /* Action for current link. */
998         _gotoToday: function( id ) {
999                 var date,
1000                         target = $( id ),
1001                         inst = this._getInst( target[ 0 ] );
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         },
1017         /* Action for selecting a new month/year. */
1018         _selectMonthYear: function( id, select, period ) {
1019                 var target = $( id ),
1020                         inst = this._getInst( target[ 0 ] );
1022                 inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
1023                 inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
1024                         parseInt( select.options[ select.selectedIndex ].value, 10 );
1026                 this._notifyChange( inst );
1027                 this._adjustDate( target );
1028         },
1030         /* Action for selecting a day. */
1031         _selectDay: function( id, month, year, td ) {
1032                 var inst,
1033                         target = $( id );
1035                 if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
1036                         return;
1037                 }
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         },
1047         /* Erase the input field and hide the date picker. */
1048         _clearDate: function( id ) {
1049                 var target = $( id );
1050                 this._selectDate( target, "" );
1051         },
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 ] );
1059                 dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
1060                 if ( inst.input ) {
1061                         inst.input.val( dateStr );
1062                 }
1063                 this._updateAlternate( inst );
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                 }
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         },
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" );
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         },
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         },
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() );
1114                 // Find Thursday of this week starting on Monday
1115                 checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
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         },
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                 }
1141                 value = ( typeof value === "object" ? value.toString() : value + "" );
1142                 if ( value === "" ) {
1143                         return null;
1144                 }
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,
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                         },
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                         },
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                                         } );
1195                                 $.each( names, function( i, pair ) {
1196                                         var name = pair[ 1 ];
1197                                         if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
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                         },
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                         };
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                 }
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                 }
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                 }
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                 }
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         },
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
1318         _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
1319                 Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
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                 }
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,
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                         },
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                         },
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;
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         },
1439         /* Extract all possible characters from the date format. */
1440         _possibleChars: function( format ) {
1441                 var iFormat,
1442                         chars = "",
1443                         literal = false,
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                         };
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         },
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         },
1489         /* Parse existing date and initialise date picker. */
1490         _setDateFromField: function( inst, noDefault ) {
1491                 if ( inst.input.val() === inst.lastVal ) {
1492                         return;
1493                 }
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,
1499                         settings = this._getFormatConfig( inst );
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         },
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         },
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 ) {
1535                                         // Ignore
1536                                 }
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 );
1546                                 while ( matches ) {
1547                                         switch ( matches[ 2 ] || "d" ) {
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() ) ) ) );
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         },
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         },
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() ) );
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         },
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         },
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         },
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;
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;
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 ) ) );
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>" ) );
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 ) ) );
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>" ) );
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 ) ) );
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>" : "" );
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>" : "";
1734                 firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
1735                 firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
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 = "";
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";
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() ) ?
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         },
1842         /* Generate the month and year header. */
1843         _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
1844                         secondary, monthNames, monthNamesShort ) {
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 = "";
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                 }
1870                 if ( !showMonthAfterYear ) {
1871                         html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" );
1872                 }
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 {
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>";
1902                                 html += inst.yearshtml;
1903                                 inst.yearshtml = null;
1904                         }
1905                 }
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         },
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 ) ) );
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         },
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         },
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         },
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         },
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         },
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         },
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         },
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 ) );
1974                 if ( offset < 0 ) {
1975                         date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
1976                 }
1977                 return this._isInRange( inst, date );
1978         },
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                         }
2001                 return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
2002                         ( !maxDate || date.getTime() <= maxDate.getTime() ) &&
2003                         ( !minYear || date.getFullYear() >= minYear ) &&
2004                         ( !maxYear || date.getFullYear() <= maxYear ) );
2005         },
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         },
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 } );
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 );
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         }
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;
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 ) {
2080         /* Verify an empty collection wasn't passed - Fixes #6976 */
2081         if ( !this.length ) {
2082                 return this;
2083         }
2085         /* Initialise the date picker. */
2086         if ( !$.datepicker.initialized ) {
2087                 $( document ).on( "mousedown", $.datepicker._checkExternalClick );
2088                 $.datepicker.initialized = true;
2089         }
2091         /* Append datepicker main container to body if not exist. */
2092         if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
2093                 $( "body" ).append( $.datepicker.dpDiv );
2094         }
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         } );
2113 $.datepicker = new Datepicker(); // singleton instance
2114 $.datepicker.initialized = false;
2115 $.datepicker.uuid = new Date().getTime();
2116 $.datepicker.version = "1.12.1";
2118 return $.datepicker;
2120 } ) );