[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

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

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


Generated: Fri Sep 24 01:00:04 2021 Cross-referenced by PHPXref 0.7.1