aboutsummaryrefslogtreecommitdiffstats
path: root/ui/widgets/calendar.js
diff options
context:
space:
mode:
Diffstat (limited to 'ui/widgets/calendar.js')
-rw-r--r--ui/widgets/calendar.js812
1 files changed, 812 insertions, 0 deletions
diff --git a/ui/widgets/calendar.js b/ui/widgets/calendar.js
new file mode 100644
index 000000000..d9ed4dee3
--- /dev/null
+++ b/ui/widgets/calendar.js
@@ -0,0 +1,812 @@
+/*!
+ * jQuery UI Calendar @VERSION
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Calendar
+//>>group: Widgets
+//>>description: Displays a calendar for inline date selection.
+//>>docs: http://api.jqueryui.com/calendar/
+//>>demos: http://jqueryui.com/calendar/
+//>>css.structure: ../../themes/base/core.css
+//>>css.structure: ../../themes/base/calendar.css
+//>>css.theme: ../../themes/base/theme.css
+
+( function( factory ) {
+ if ( typeof define === "function" && define.amd ) {
+
+ // AMD. Register as an anonymous module.
+ define( [
+ "jquery",
+ "globalize",
+ "globalize/date",
+ "globalize-locales",
+ "../date",
+ "./button",
+ "../widget",
+ "../version",
+ "../keycode",
+ "../unique-id",
+ "../tabbable",
+ "../escape-selector"
+ ], factory );
+ } else {
+
+ // Browser globals
+ factory( jQuery, Globalize );
+ }
+}( function( $, Globalize ) {
+
+return $.widget( "ui.calendar", {
+ version: "@VERSION",
+ options: {
+ buttons: [],
+ classes: {
+ "ui-calendar": "ui-corner-all",
+ "ui-calendar-header-first": "ui-corner-left",
+ "ui-calendar-header-last": "ui-corner-right",
+ "ui-calendar-prev": "ui-corner-all",
+ "ui-calendar-next": "ui-corner-all"
+ },
+ dateFormat: { date: "short" },
+ eachDay: $.noop,
+ icons: {
+ prevButton: "ui-icon-circle-triangle-w",
+ nextButton: "ui-icon-circle-triangle-e"
+ },
+ labels: {
+ "datePickerRole": "date picker",
+ "nextText": "Next",
+ "prevText": "Prev",
+ "weekHeader": "Wk"
+ },
+ locale: "en",
+ max: null,
+ min: null,
+ numberOfMonths: 1,
+ showWeek: false,
+ value: null,
+
+ // callbacks
+ change: null,
+ refresh: null,
+ select: null
+ },
+
+ refreshRelatedOptions: {
+ dateFormat: true,
+ eachDay: true,
+ locale: true,
+ max: true,
+ min: true,
+ showWeek: true,
+ value: true
+ },
+
+ _create: function() {
+ this.id = this.element.uniqueId().attr( "id" );
+ this._setGridId( this.id );
+ this.labels = this.options.labels;
+ this.buttonClickContext = this.element[ 0 ];
+
+ this._setLocale( this.options.locale, this.options.dateFormat );
+
+ this._setDate( new $.ui.date( this.options.value, this._calendarDateOptions ) );
+ this._setViewDate( this._getDate().clone() );
+ this._getViewDate().eachDay = this.options.eachDay;
+
+ this._on( this.element, {
+ "click .ui-calendar-prev": function( event ) {
+ event.preventDefault();
+ this._getDate().adjust( "M", -this.options.numberOfMonths );
+ this._updateView();
+ },
+ "click .ui-calendar-next": function( event ) {
+ event.preventDefault();
+ this._getDate().adjust( "M", this.options.numberOfMonths );
+ this._updateView();
+ },
+ "mousedown .ui-calendar-calendar button": "_select",
+ "mouseenter .ui-calendar-header-buttons button": "_hover",
+ "mouseleave .ui-calendar-header-buttons button": "_hover",
+ "mouseenter .ui-calendar-calendar button": "_hover",
+ "mouseleave .ui-calendar-calendar button": "_hover",
+ "keydown .ui-calendar-calendar": "_handleKeydown"
+ } );
+
+ this._createCalendar();
+ this._setActiveDescendant();
+ },
+
+ _hover: function( event ) {
+ this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
+ },
+
+ _select: function( event ) {
+ var oldValue = this.options.value ? this.options.value.getTime() : "";
+
+ this._setOption(
+ "value", new Date( $( event.currentTarget ).data( "ui-calendar-timestamp" ) )
+ );
+ this._updateDayElement( "ui-state-active" );
+
+ // Allow datepicker to handle focus
+ if ( this._trigger( "select", event, { value: this.options.value } ) !== false ) {
+ this.activeDescendant.closest( this.grid ).focus();
+ event.preventDefault();
+ }
+
+ if ( oldValue !== this.options.value.getTime() ) {
+ this._trigger( "change", event, { value: this.options.value } );
+ }
+ },
+
+ _handleKeydown: function( event ) {
+ var pageAltKey = ( event.altKey || event.ctrlKey && event.shiftKey );
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.ENTER:
+ this._select(
+ $.Event( event, { currentTarget: this.activeDescendant[ 0 ] } )
+ );
+ return;
+ case $.ui.keyCode.PAGE_UP:
+ this._getDate().adjust( pageAltKey ? "Y" : "M", -1 );
+ break;
+ case $.ui.keyCode.PAGE_DOWN:
+ this._getDate().adjust( pageAltKey ? "Y" : "M", 1 );
+ break;
+ case $.ui.keyCode.END:
+ this._getDate().setDay( this._getDate().daysInMonth() );
+ break;
+ case $.ui.keyCode.HOME:
+ this._getDate().setDay( 1 );
+ break;
+ case $.ui.keyCode.LEFT:
+ this._getDate().adjust( "D", -1 );
+ break;
+ case $.ui.keyCode.UP:
+ this._getDate().adjust( "D", -7 );
+ break;
+ case $.ui.keyCode.RIGHT:
+ this._getDate().adjust( "D", 1 );
+ break;
+ case $.ui.keyCode.DOWN:
+ this._getDate().adjust( "D", 7 );
+ break;
+ default:
+ return;
+ }
+
+ if ( this._needsRefresh() ) {
+ this._updateView();
+ this.activeDescendant.closest( this.grid ).focus();
+ } else {
+ this._setActiveDescendant();
+ }
+ },
+
+ _updateView: function() {
+ if ( this.options.numberOfMonths > 1 &&
+ this._getDate().year() === this._getViewDate().year()
+ ) {
+ this._getViewDate().adjust( "M", this.options.numberOfMonths *
+ ( this._getDate().month() > this._getViewDate().month() ? 1 : -1 )
+ );
+ } else {
+ this._getViewDate().setTimestamp( this._getDate().timestamp() );
+ }
+
+ this.refresh();
+ },
+
+ _needsRefresh: function() {
+ if ( this._getDate().month() !== this._getViewDate().month() ||
+ this._getDate().year() !== this._getViewDate().year()
+ ) {
+
+ // Check if the needed day is already present in our grid due
+ // to eachDay option changes (eg. other-months demo)
+ return !this._getDateElement( this._getDayId( this._getDate() ) ).length;
+ }
+
+ return false;
+ },
+
+ _setActiveDescendant: function() {
+ this.activeDescendant = this._updateDayElement( "ui-state-focus" );
+ },
+
+ _updateDayElement: function( state ) {
+ var id = this._getDayId( this._getDate() ),
+ button = this._getDateElement( id ).children( "button" );
+
+ this.grid.attr( "aria-activedescendant", id );
+
+ this._removeClass( this.grid.find( "button." + state ), null, state );
+ this._addClass( button, null, state );
+
+ return button;
+ },
+
+ _getDateElement: function( id ) {
+ return this.grid.find( "#" + $.ui.escapeSelector( id ) );
+ },
+
+ _setLocale: function( locale, dateFormat ) {
+ var globalize = new Globalize( locale ),
+ weekdayShortFormatter = globalize.dateFormatter( { raw: "EEEEEE" } ),
+ weekdayNarrowFormatter = globalize.dateFormatter( { raw: "EEEEE" } ),
+ firstDayRaw = globalize.dateFormatter( { raw: "c" } )( new Date( 1970, 0, 3 ) );
+
+ this._format = globalize.dateFormatter( dateFormat );
+ this._parse = globalize.dateParser( dateFormat );
+ this._calendarDateOptions = {
+ firstDay: ( 7 - globalize.parseNumber( firstDayRaw ) ),
+ formatWeekdayShort: function( date ) {
+
+ // Return the short weekday if its length is < 3. Otherwise, its narrow form.
+ var shortWeekday = weekdayShortFormatter( date );
+
+ return shortWeekday.length > 3 ? weekdayNarrowFormatter( date ) : shortWeekday;
+ },
+ formatWeekdayFull: globalize.dateFormatter( { raw: "EEEE" } ),
+ formatMonth: globalize.dateFormatter( { raw: "MMMM" } ),
+ formatWeekOfYear: globalize.dateFormatter( { raw: "w" } ),
+ parse: this._parse
+ };
+ },
+
+ _createCalendar: function() {
+ this.element
+ .attr( "role", "region" )
+ .append( this._buildHeaderButtons() );
+
+ if ( this.options.numberOfMonths === 1 ) {
+ this._buildSinglePicker();
+ } else {
+ this._buildMultiplePicker();
+ }
+
+ this._addClass(
+ this.element, "ui-calendar", "ui-widget ui-widget-content ui-helper-clearfix"
+ );
+
+ this._refreshHeaderButtons();
+ this._createButtonPane();
+
+ this.grid = this.element.find( ".ui-calendar-calendar" );
+ },
+
+ _buildSinglePicker: function() {
+ var header = this._buildHeader();
+
+ this._addClass( header, "ui-calendar-header-first ui-calendar-header-last" );
+ this.element
+ .attr( "aria-labelledby", this._getGridId() + "-title" )
+ .append( header )
+ .append( this._buildGrid() );
+ },
+
+ _buildMultiplePicker: function() {
+ var element, header,
+ rowBreak = $( "<div>" ),
+ currentDate = this._getViewDate(),
+ months = this._getViewDate().months( this.options.numberOfMonths - 1 ),
+ labelledBy = [],
+ i = 0;
+
+ for ( ; i < months.length; i++ ) {
+
+ // TODO: Shouldn't we pass date as a parameter to build* fns
+ // instead of setting this.viewDate?
+ this._setViewDate( months[ i ] );
+ this._setGridId( this.id + "-" + i );
+ labelledBy.push( this._getGridId() + "-title" );
+
+ element = $( "<div>" );
+ this._addClass( element, "ui-calendar-group" );
+
+ header = this._buildHeader();
+ this._addClass( header, "ui-calendar-header-" +
+ ( ( months[ i ].first ) ? "first" : ( months[ i ].last ) ? "last" : "middle" )
+ );
+
+ element.appendTo( this.element )
+ .append( header )
+ .append( this._buildGrid() );
+ }
+
+ this._addClass( this.element, "ui-calendar-multi" )
+ ._addClass( rowBreak, "ui-calendar-row-break" );
+
+ this.element
+ .attr( "aria-labelledby", labelledBy.join( " " ) )
+ .append( rowBreak );
+
+ this._setViewDate( currentDate );
+ },
+
+ _buildHeaderButtons: function() {
+ var buttons = $( "<div>" );
+
+ this._addClass( buttons, "ui-calendar-header-buttons" );
+
+ return buttons
+ .append( this.prevButton = this._buildIconButton( "prev" ) )
+ .append( this.nextButton = this._buildIconButton( "next" ) );
+ },
+
+ _buildIconButton: function( key ) {
+ var button = $( "<button>" ),
+ icon = $( "<span>" );
+
+ this._addClass( button, "ui-calendar-" + key )
+ ._addClass( icon, null, "ui-icon " + this.options.icons[ key + "Button" ] );
+
+ return button.append( icon );
+ },
+
+ _buildHeader: function() {
+ var header = $( "<div>" ),
+ title = $( "<div>", { role: "header", id: this._getGridId() + "-title" } ),
+ notice = $( "<span>" ).text( ", " + this._getTranslation( "datePickerRole" ) );
+
+ this._addClass( header, "ui-calendar-header", "ui-widget-header ui-helper-clearfix" )
+ ._addClass( notice, null, "ui-helper-hidden-accessible" );
+
+ return header.append(
+ title
+ .append( this._buildTitle() )
+ .append( notice )
+ );
+ },
+
+ _buildTitle: function() {
+ var title = $( "<div>", { role: "alert", id: this._getGridId() + "-month-label" } ),
+ month = this._buildTitleMonth(),
+ year = this._buildTitleYear();
+
+ this._addClass( title, "ui-calendar-title" )
+ ._addClass( month, "ui-calendar-month" )
+ ._addClass( year, "ui-calendar-year" );
+
+ return title
+ .append( month )
+ .append( " " )
+ .append( year );
+ },
+
+ _buildTitleMonth: function() {
+ return $( "<span>" ).text( this._getViewDate().monthName() );
+ },
+
+ _buildTitleYear: function() {
+ return $( "<span>" ).text( this._getViewDate().year() );
+ },
+
+ _buildGrid: function() {
+ var table = $( "<table>", {
+ role: "grid",
+ tabindex: 0,
+ "aria-readonly": true,
+ "aria-labelledby": this._getGridId() + "-month-label",
+ "aria-activedescendant": this._getDayId( this._getDate() )
+ } );
+
+ this._addClass( table, "ui-calendar-calendar" );
+
+ return table
+ .append( this._buildGridHeading() )
+ .append( this._buildGridBody() );
+ },
+
+ _buildGridHeading: function() {
+ var head = $( "<thead role='presentation'>" ),
+ week = $( "<th>" ),
+ row = $( "<tr role='row'>" ),
+ i = 0,
+ weekDayLength = this._getViewDate().weekdays().length,
+ weekdays = this._getViewDate().weekdays();
+
+ if ( this.options.showWeek ) {
+ this._addClass( week, "ui-calendar-week-col" );
+ row.append( week.text( this._getTranslation( "weekHeader" ) ) );
+ }
+
+ for ( ; i < weekDayLength; i++ ) {
+ row.append( this._buildGridHeaderCell( weekdays[ i ] ) );
+ }
+
+ return head.append( row );
+ },
+
+ _buildGridHeaderCell: function( day ) {
+ return $( "<th role='columnheader' abbr='" + day.fullname +
+ "' aria-label='" + day.fullname + "'>" +
+ "<span title='" + day.fullname + "'>" + day.shortname + "</span>" +
+ "</th>" );
+ },
+
+ _buildGridBody: function() {
+ var days = this._getViewDate().days(),
+ i = 0,
+ rows = "";
+
+ for ( ; i < days.length; i++ ) {
+ rows += this._buildWeekRow( days[ i ] );
+ }
+
+ return "<tbody role='presentation'>" + rows + "</tbody>";
+ },
+
+ _buildWeekRow: function( week ) {
+ var cells = "",
+ i = 0;
+
+ if ( this.options.showWeek ) {
+ cells += "<td class='ui-calendar-week-col'>" + week.number + "</td>";
+ }
+ for ( ; i < week.days.length; i++ ) {
+ cells += this._buildDayCell( week.days[ i ] );
+ }
+
+ return "<tr role='row'>" + cells + "</tr>";
+ },
+
+ _buildDayCell: function( day ) {
+ var content = "",
+ dateObject = new Date( day.timestamp ),
+ dayName = this._calendarDateOptions.formatWeekdayFull( dateObject ),
+ attributes = [
+ "role='gridcell'",
+ "aria-selected='" + ( this._isCurrent( day ) ? true : false ) + "'",
+ "aria-label='" + dayName + ", " + this._format( dateObject ) + "'",
+ "aria-describedby='" + this._getGridId() + "-month-label'"
+ ],
+ selectable = ( day.selectable && this._isValid( dateObject ) );
+
+ if ( day.render ) {
+ attributes.push(
+ "id='" + this.id + "-" + day.year + "-" + day.month + "-" + day.date + "'"
+ );
+
+ if ( !selectable ) {
+ attributes.push( "aria-disabled='true'" );
+ attributes.push( "class='ui-state-disabled'" );
+ }
+
+ content = this._buildDayElement( day, selectable );
+ }
+
+ return "<td " + attributes.join( " " ) + ">" + content + "</td>";
+ },
+
+ _getDayId: function( date ) {
+ return this.id + "-" + date.year() + "-" + date.month() + "-" + date.day();
+ },
+
+ _buildDayElement: function( day, selectable ) {
+ var attributes, content,
+ classes = [ "ui-state-default" ];
+
+ if ( day === this._getDate() && selectable ) {
+ classes.push( "ui-state-focus" );
+ }
+ if ( this._isCurrent( day ) ) {
+ classes.push( "ui-state-active" );
+ }
+ if ( day.today ) {
+ classes.push( "ui-state-highlight" );
+ }
+ if ( day.extraClasses ) {
+ classes.push( day.extraClasses.split( " " ) );
+ }
+
+ attributes = " class='" + classes.join( " " ) + "'";
+ if ( selectable ) {
+ attributes += " tabindex='-1' data-ui-calendar-timestamp='" + day.timestamp + "'";
+ } else {
+ attributes += " disabled='disabled'";
+ }
+ content = "<button" + attributes + ">" + day.date + "</button>";
+
+ if ( day.today ) {
+ content += "<span class='ui-helper-hidden-accessible'>, " +
+ this._getTranslation( "currentText" ) + "</span>";
+ }
+
+ return content;
+ },
+
+ _isCurrent: function( day ) {
+ return this.options.value && day.timestamp === this.options.value.getTime();
+ },
+
+ _createButtonPane: function() {
+ this.buttonPane = $( "<div>" );
+ this.buttonSet = $( "<div>" ).appendTo( this.buttonPane );
+
+ this._addClass(
+ this.buttonPane, "ui-calendar-buttonpane", "ui-widget-content ui-helper-clearfix"
+ )
+ ._addClass( this.buttonSet, "ui-calendar-buttonset" );
+
+ this._createButtons();
+ },
+
+ _createButtons: function() {
+ var that = this,
+ buttons = this.options.buttons;
+
+ this.buttonPane.remove();
+ this.buttonSet.empty();
+
+ if ( $.isEmptyObject( buttons ) || ( $.isArray( buttons ) && !buttons.length ) ) {
+ this._removeClass( this.element, "ui-calendar-buttons" );
+ return;
+ }
+
+ $.each( buttons, function( name, props ) {
+ var click, buttonOptions;
+ props = $.isFunction( props ) ?
+ { click: props, text: name } :
+ props;
+
+ // Default to a non-submitting button
+ props = $.extend( { type: "button" }, props );
+
+ // Change the context for the click callback to be the main element
+ click = props.click;
+ buttonOptions = {
+ icon: props.icon,
+ iconPosition: props.iconPosition,
+ showLabel: props.showLabel
+ };
+
+ delete props.click;
+ delete props.icon;
+ delete props.iconPosition;
+ delete props.showLabel;
+
+ $( "<button></button>", props )
+ .button( buttonOptions )
+ .appendTo( that.buttonSet )
+ .on( "click", function() {
+ click.apply( that.buttonClickContext, arguments );
+ } );
+ } );
+
+ this._addClass( this.element, "ui-calendar-buttons" );
+ this.buttonPane.appendTo( this.element );
+ },
+
+ // Refreshing the entire calendar during interaction confuses screen readers, specifically
+ // because the grid heading is marked up as a live region and will often not update if it's
+ // destroyed and recreated instead of just having its text change.
+ refresh: function() {
+ this.labels = this.options.labels;
+
+ // Determine which day grid cell to focus after refresh
+ if ( this.options.numberOfMonths === 1 ) {
+ this.element.find( ".ui-calendar-title" ).replaceWith( this._buildTitle() );
+ this.element.find( ".ui-calendar-calendar" ).replaceWith( this._buildGrid() );
+ } else {
+ this._refreshMultiplePicker();
+ }
+
+ this.grid = this.element.find( ".ui-calendar-calendar" );
+
+ this._setActiveDescendant();
+ this._refreshHeaderButtons();
+ this._createButtons();
+
+ this._trigger( "refresh" );
+ },
+
+ _refreshHeaderButtons: function() {
+ var prevText = this._getTranslation( "prevText" ),
+ nextText = this._getTranslation( "nextText" );
+
+ this.prevButton.attr( "title", prevText ).children().html( prevText );
+ this.nextButton.attr( "title", nextText ).children().html( nextText );
+ this._headerButtonsState();
+ },
+
+ _headerButtonsState: function() {
+ var months = this._getViewDate().months( this.options.numberOfMonths - 1 ),
+ i = 0;
+
+ for ( ; i < months.length; i++ ) {
+ if ( this.options.min !== null && months[ i ].first ) {
+ this._disableElement( this.prevButton,
+ ( this.options.min.getMonth() >= months[ i ].month() &&
+ this.options.min.getFullYear() === months[ i ].year() ) ||
+ this.options.min.getFullYear() > months[ i ].year()
+ );
+ }
+ if ( this.options.max !== null && months[ i ].last ) {
+ this._disableElement( this.nextButton,
+ ( this.options.max.getMonth() <= months[ i ].month() &&
+ this.options.max.getFullYear() === months[ i ].year() ) ||
+ this.options.max.getFullYear() < months[ i ].year()
+ );
+ }
+ }
+ },
+
+ _disableElement: function( element, state ) {
+ element.attr( "aria-disabled", state );
+ this._toggleClass( element, null, "ui-state-disabled", state );
+ },
+
+ _refreshMultiplePicker: function() {
+ var i = 0;
+
+ for ( ; i < this.options.numberOfMonths; i++ ) {
+ this.element.find( ".ui-calendar-title" ).eq( i ).replaceWith( this._buildTitle() );
+ this.element.find( ".ui-calendar-calendar" ).eq( i ).replaceWith( this._buildGrid() );
+ this._getViewDate().adjust( "M", 1 );
+ }
+ this._getViewDate().adjust( "M", -this.options.numberOfMonths );
+ },
+
+ _getTranslation: function( key ) {
+ return $( "<a>" ).text( this.labels[ key ] ).html();
+ },
+
+ _setHiddenPicker: function() {
+ this.element.attr( {
+ "aria-hidden": "true",
+ "aria-expanded": "false"
+ } );
+ },
+
+ _getGridId: function() {
+ return this.gridId;
+ },
+
+ _setGridId: function( id ) {
+ this.gridId = id;
+ },
+
+ _getDate: function() {
+ return this.date;
+ },
+
+ _setDate: function( date ) {
+ this.date = date;
+ },
+
+ _getViewDate: function() {
+ return this.viewDate;
+ },
+
+ _setViewDate: function( date ) {
+ this.viewDate = date;
+ },
+
+ value: function( value ) {
+ if ( arguments.length ) {
+ this.valueAsDate( this._parse( value ) );
+ } else {
+ return this.option( "value" ) === null ?
+ null : this._format( this.option( "value" ) );
+ }
+ },
+
+ valueAsDate: function( value ) {
+ if ( arguments.length ) {
+ this.option( "value", value );
+ } else {
+ return this.options.value;
+ }
+ },
+
+ _isValid: function( value ) {
+ if ( $.type( value ) !== "date" ) {
+ return false;
+ }
+
+ if ( $.type( this.options.max ) === "date" ) {
+ if ( value > this.options.max ) {
+ return false;
+ }
+ }
+
+ if ( $.type( this.options.min ) === "date" ) {
+ if ( value < this.options.min ) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ _destroy: function() {
+ this.element
+ .removeAttr( "role aria-labelledby" )
+ .removeUniqueId()
+ .empty();
+ },
+
+ _setOptions: function( options ) {
+ var that = this,
+ create = false,
+ refresh = false,
+ dateAttributes = false;
+
+ $.each( options, function( key, value ) {
+ that._setOption( key, value );
+
+ if ( key === "numberOfMonths" ) {
+ create = true;
+ }
+ if ( key in that.refreshRelatedOptions ) {
+ refresh = true;
+ }
+ if ( key === "dateFormat" || key === "locale" ) {
+ dateAttributes = true;
+ }
+ } );
+
+ if ( dateAttributes ) {
+ this._setLocale( this.options.locale, this.options.dateFormat );
+ this._getDate().setAttributes( this._calendarDateOptions );
+ this._getViewDate().setAttributes( this._calendarDateOptions );
+ }
+ if ( create || refresh ) {
+ this._getViewDate().setTimestamp( this._getDate().timestamp() );
+ }
+ if ( create ) {
+ this.element.empty();
+ this._removeClass( this.element, "ui-calendar-multi" );
+ this._createCalendar();
+ refresh = false;
+ }
+ if ( refresh ) {
+ this.refresh();
+ }
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "value" ) {
+ if ( this._isValid( value ) ) {
+ this._getDate().setTimestamp( value.getTime() );
+ } else {
+ value = null;
+ }
+ }
+
+ if ( key === "max" || key === "min" ) {
+ if ( $.type( value ) !== "date" || value === null ) {
+ this._super( key, null );
+ } else {
+ this._super( key, value );
+ }
+ return;
+ }
+
+ this._super( key, value );
+
+ if ( key === "buttons" ) {
+ this._createButtons();
+ }
+
+ if ( key === "disabled" ) {
+ this.element
+ .toggleClass( "ui-state-disabled", value )
+ .attr( "aria-disabled", value );
+ }
+
+ if ( key === "eachDay" ) {
+ this._getViewDate().eachDay = value;
+ }
+ }
+} );
+
+} ) );