[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/jquery/ui/ -> datepicker.js (source)

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


Generated : Sat Jul 18 08:20:16 2026 Cross-referenced by PHPXref