2014-06-03 21:18:51 +00:00
|
|
|
/*!
|
|
|
|
* jQuery UI Calendar @VERSION
|
|
|
|
* http://jqueryui.com
|
|
|
|
*
|
2015-12-02 17:50:13 +00:00
|
|
|
* Copyright jQuery Foundation and other contributors
|
2014-06-03 21:18:51 +00:00
|
|
|
* Released under the MIT license.
|
|
|
|
* http://jquery.org/license
|
|
|
|
*/
|
2015-01-29 18:41:50 +00:00
|
|
|
|
2015-12-02 17:50:13 +00:00
|
|
|
//>>label: Calendar
|
2015-01-29 18:41:50 +00:00
|
|
|
//>>group: Widgets
|
|
|
|
//>>description: Displays a calendar for inline date selection.
|
|
|
|
//>>docs: http://api.jqueryui.com/calendar/
|
|
|
|
//>>demos: http://jqueryui.com/calendar/
|
2015-12-02 17:53:26 +00:00
|
|
|
//>>css.structure: ../../themes/base/core.css
|
|
|
|
//>>css.structure: ../../themes/base/calendar.css
|
|
|
|
//>>css.theme: ../../themes/base/theme.css
|
2015-01-29 18:41:50 +00:00
|
|
|
|
2015-04-30 15:38:01 +00:00
|
|
|
( function( factory ) {
|
2014-06-03 21:18:51 +00:00
|
|
|
if ( typeof define === "function" && define.amd ) {
|
|
|
|
|
|
|
|
// AMD. Register as an anonymous module.
|
2015-04-30 15:38:01 +00:00
|
|
|
define( [
|
2014-06-03 21:18:51 +00:00
|
|
|
"jquery",
|
2015-07-15 13:40:38 +00:00
|
|
|
"globalize",
|
2014-09-04 18:47:48 +00:00
|
|
|
"globalize/date",
|
2015-04-30 15:38:01 +00:00
|
|
|
"globalize-locales",
|
2015-09-27 16:35:35 +00:00
|
|
|
"../date",
|
2015-07-15 13:40:38 +00:00
|
|
|
"./button",
|
2015-08-20 13:48:11 +00:00
|
|
|
"../widget",
|
|
|
|
"../version",
|
|
|
|
"../keycode",
|
|
|
|
"../unique-id",
|
2015-08-25 21:11:21 +00:00
|
|
|
"../tabbable",
|
|
|
|
"../escape-selector"
|
2015-07-27 18:53:16 +00:00
|
|
|
], factory );
|
2014-06-03 21:18:51 +00:00
|
|
|
} else {
|
|
|
|
|
|
|
|
// Browser globals
|
2015-07-15 13:40:38 +00:00
|
|
|
factory( jQuery, Globalize );
|
2014-06-03 21:18:51 +00:00
|
|
|
}
|
2015-04-30 15:38:01 +00:00
|
|
|
}( function( $, Globalize ) {
|
2014-06-03 21:18:51 +00:00
|
|
|
|
|
|
|
return $.widget( "ui.calendar", {
|
|
|
|
version: "@VERSION",
|
|
|
|
options: {
|
2014-06-19 22:13:20 +00:00
|
|
|
buttons: [],
|
2016-04-16 14:49:40 +00:00
|
|
|
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"
|
|
|
|
},
|
2015-07-27 22:42:32 +00:00
|
|
|
dateFormat: { date: "short" },
|
2014-06-03 21:18:51 +00:00
|
|
|
eachDay: $.noop,
|
2016-04-16 15:20:58 +00:00
|
|
|
icons: {
|
|
|
|
prevButton: "ui-icon-circle-triangle-w",
|
|
|
|
nextButton: "ui-icon-circle-triangle-e"
|
|
|
|
},
|
2014-09-04 18:47:48 +00:00
|
|
|
labels: {
|
|
|
|
"datePickerRole": "date picker",
|
|
|
|
"nextText": "Next",
|
|
|
|
"prevText": "Prev",
|
|
|
|
"weekHeader": "Wk"
|
|
|
|
},
|
2014-09-04 18:47:48 +00:00
|
|
|
locale: "en",
|
2014-06-04 17:07:23 +00:00
|
|
|
max: null,
|
|
|
|
min: null,
|
2014-06-03 21:18:51 +00:00
|
|
|
numberOfMonths: 1,
|
|
|
|
showWeek: false,
|
|
|
|
value: null,
|
|
|
|
|
|
|
|
// callbacks
|
2016-05-29 08:57:35 +00:00
|
|
|
change: null,
|
2014-06-03 21:18:51 +00:00
|
|
|
select: null
|
|
|
|
},
|
|
|
|
|
2014-12-18 16:39:27 +00:00
|
|
|
refreshRelatedOptions: {
|
2015-07-27 22:42:32 +00:00
|
|
|
dateFormat: true,
|
2014-12-18 16:39:27 +00:00
|
|
|
eachDay: true,
|
2015-07-27 22:42:32 +00:00
|
|
|
locale: true,
|
2014-12-18 16:39:27 +00:00
|
|
|
max: true,
|
|
|
|
min: true,
|
|
|
|
showWeek: true,
|
|
|
|
value: true
|
|
|
|
},
|
|
|
|
|
2014-06-03 21:18:51 +00:00
|
|
|
_create: function() {
|
|
|
|
this.id = this.element.uniqueId().attr( "id" );
|
2015-12-02 21:02:24 +00:00
|
|
|
this.gridId = this.id;
|
2014-09-04 18:47:48 +00:00
|
|
|
this.labels = this.options.labels;
|
2014-06-19 22:13:20 +00:00
|
|
|
this.buttonClickContext = this.element[ 0 ];
|
2014-06-03 21:18:51 +00:00
|
|
|
|
2015-07-27 22:42:32 +00:00
|
|
|
this._setLocale( this.options.locale, this.options.dateFormat );
|
2014-09-04 18:47:48 +00:00
|
|
|
|
2015-09-27 16:35:35 +00:00
|
|
|
this.date = new $.ui.date( this.options.value, this._calendarDateOptions );
|
2015-01-24 01:23:24 +00:00
|
|
|
this.viewDate = this.date.clone();
|
|
|
|
this.viewDate.eachDay = this.options.eachDay;
|
2014-06-03 21:18:51 +00:00
|
|
|
|
|
|
|
this._on( this.element, {
|
|
|
|
"click .ui-calendar-prev": function( event ) {
|
|
|
|
event.preventDefault();
|
|
|
|
this.date.adjust( "M", -this.options.numberOfMonths );
|
2015-12-02 20:47:25 +00:00
|
|
|
this._updateView();
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
|
|
|
"click .ui-calendar-next": function( event ) {
|
|
|
|
event.preventDefault();
|
|
|
|
this.date.adjust( "M", this.options.numberOfMonths );
|
2015-12-02 20:47:25 +00:00
|
|
|
this._updateView();
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
2016-05-22 15:19:09 +00:00
|
|
|
"mousedown .ui-calendar-calendar button": "_select",
|
2015-12-02 20:47:25 +00:00
|
|
|
"mouseenter .ui-calendar-header-buttons button": "_hover",
|
|
|
|
"mouseleave .ui-calendar-header-buttons button": "_hover",
|
2015-01-20 17:23:49 +00:00
|
|
|
"mouseenter .ui-calendar-calendar button": "_hover",
|
|
|
|
"mouseleave .ui-calendar-calendar button": "_hover",
|
2014-06-03 21:18:51 +00:00
|
|
|
"keydown .ui-calendar-calendar": "_handleKeydown"
|
2015-04-30 15:38:01 +00:00
|
|
|
} );
|
2014-06-03 21:18:51 +00:00
|
|
|
|
|
|
|
this._createCalendar();
|
2015-12-02 20:47:25 +00:00
|
|
|
this._setActiveDescendant();
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
|
|
|
|
2014-08-30 00:06:52 +00:00
|
|
|
_hover: function( event ) {
|
2016-04-16 14:49:40 +00:00
|
|
|
this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
|
2014-08-30 00:06:52 +00:00
|
|
|
},
|
|
|
|
|
2016-05-22 15:19:09 +00:00
|
|
|
_select: function( event ) {
|
2016-05-29 08:57:35 +00:00
|
|
|
var oldValue = this.options.value ? this.options.value.getTime() : "";
|
|
|
|
|
2016-12-11 16:54:16 +00:00
|
|
|
this._setOption(
|
|
|
|
"value", new Date( $( event.currentTarget ).data( "ui-calendar-timestamp" ) )
|
|
|
|
);
|
2016-05-22 15:19:09 +00:00
|
|
|
this._updateDayElement( "ui-state-active" );
|
|
|
|
|
|
|
|
// Allow datepicker to handle focus
|
|
|
|
if ( this._trigger( "select", event ) !== false ) {
|
|
|
|
this.activeDescendant.closest( this.grid ).focus();
|
|
|
|
event.preventDefault();
|
|
|
|
}
|
2016-05-29 08:57:35 +00:00
|
|
|
|
|
|
|
if ( oldValue !== this.options.value.getTime() ) {
|
|
|
|
this._trigger( "change", event );
|
|
|
|
}
|
2016-05-22 15:19:09 +00:00
|
|
|
},
|
|
|
|
|
2014-06-03 21:18:51 +00:00
|
|
|
_handleKeydown: function( event ) {
|
2016-04-13 20:19:01 +00:00
|
|
|
var pageAltKey = ( event.altKey || event.ctrlKey && event.shiftKey );
|
|
|
|
|
2014-06-03 21:18:51 +00:00
|
|
|
switch ( event.keyCode ) {
|
|
|
|
case $.ui.keyCode.ENTER:
|
2016-05-22 15:19:09 +00:00
|
|
|
this._select(
|
|
|
|
$.Event( event, { currentTarget: this.activeDescendant[ 0 ] } )
|
|
|
|
);
|
2014-06-03 21:18:51 +00:00
|
|
|
return;
|
|
|
|
case $.ui.keyCode.PAGE_UP:
|
2016-04-13 20:19:01 +00:00
|
|
|
this.date.adjust( pageAltKey ? "Y" : "M", -1 );
|
2014-06-03 21:18:51 +00:00
|
|
|
break;
|
|
|
|
case $.ui.keyCode.PAGE_DOWN:
|
2016-04-13 20:19:01 +00:00
|
|
|
this.date.adjust( pageAltKey ? "Y" : "M", 1 );
|
2014-06-03 21:18:51 +00:00
|
|
|
break;
|
|
|
|
case $.ui.keyCode.END:
|
|
|
|
this.date.setDay( this.date.daysInMonth() );
|
|
|
|
break;
|
|
|
|
case $.ui.keyCode.HOME:
|
|
|
|
this.date.setDay( 1 );
|
|
|
|
break;
|
|
|
|
case $.ui.keyCode.LEFT:
|
|
|
|
this.date.adjust( "D", -1 );
|
|
|
|
break;
|
|
|
|
case $.ui.keyCode.UP:
|
|
|
|
this.date.adjust( "D", -7 );
|
|
|
|
break;
|
|
|
|
case $.ui.keyCode.RIGHT:
|
|
|
|
this.date.adjust( "D", 1 );
|
|
|
|
break;
|
|
|
|
case $.ui.keyCode.DOWN:
|
|
|
|
this.date.adjust( "D", 7 );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-24 01:23:24 +00:00
|
|
|
if ( this._needsRefresh() ) {
|
2015-12-02 20:47:25 +00:00
|
|
|
this._updateView();
|
|
|
|
this.activeDescendant.closest( this.grid ).focus();
|
|
|
|
} else {
|
|
|
|
this._setActiveDescendant();
|
2014-06-03 21:18:51 +00:00
|
|
|
}
|
2015-12-02 20:47:25 +00:00
|
|
|
},
|
2014-06-03 21:18:51 +00:00
|
|
|
|
2015-12-02 20:47:25 +00:00
|
|
|
_updateView: function() {
|
|
|
|
if ( this.options.numberOfMonths > 1 && this.date.year() === this.viewDate.year() ) {
|
|
|
|
this.viewDate.adjust( "M", this.options.numberOfMonths *
|
|
|
|
( this.date.month() > this.viewDate.month() ? 1 : -1 )
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
this.viewDate.setTime( this.date.date().getTime() );
|
|
|
|
}
|
|
|
|
|
|
|
|
this.refresh();
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
|
|
|
|
2015-01-24 01:23:24 +00:00
|
|
|
_needsRefresh: function() {
|
2016-12-11 16:54:16 +00:00
|
|
|
if ( this.date.month() !== this.viewDate.month() ||
|
|
|
|
this.date.year() !== this.viewDate.year()
|
|
|
|
) {
|
2015-04-10 22:04:33 +00:00
|
|
|
|
|
|
|
// Check if the needed day is already present in our grid due
|
|
|
|
// to eachDay option changes (eg. other-months demo)
|
2015-12-03 17:16:40 +00:00
|
|
|
return !this._getDateElement( this._getDayId( this.date ) ).length;
|
2015-01-24 01:23:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
2014-06-03 21:18:51 +00:00
|
|
|
_setActiveDescendant: function() {
|
2015-12-03 17:16:40 +00:00
|
|
|
this.activeDescendant = this._updateDayElement( "ui-state-focus" );
|
|
|
|
},
|
|
|
|
|
|
|
|
_updateDayElement: function( state ) {
|
2016-04-16 14:49:40 +00:00
|
|
|
var id = this._getDayId( this.date ),
|
|
|
|
button = this._getDateElement( id ).children( "button" );
|
|
|
|
|
|
|
|
this.grid.attr( "aria-activedescendant", id );
|
2014-06-03 21:18:51 +00:00
|
|
|
|
2016-04-16 14:49:40 +00:00
|
|
|
this._removeClass( this.grid.find( "button." + state ), null, state );
|
|
|
|
this._addClass( button, null, state );
|
2015-12-03 17:16:40 +00:00
|
|
|
|
2016-04-16 14:49:40 +00:00
|
|
|
return button;
|
2015-12-03 17:16:40 +00:00
|
|
|
},
|
2014-12-28 18:59:31 +00:00
|
|
|
|
2015-12-03 17:16:40 +00:00
|
|
|
_getDateElement: function( id ) {
|
|
|
|
return this.grid.find( "#" + $.ui.escapeSelector( id ) );
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
|
|
|
|
2015-07-27 22:42:32 +00:00
|
|
|
_setLocale: function( locale, dateFormat ) {
|
2014-09-04 18:47:48 +00:00
|
|
|
var globalize = new Globalize( locale ),
|
2015-10-08 13:06:55 +00:00
|
|
|
weekdayShortFormatter = globalize.dateFormatter( { raw: "EEEEEE" } ),
|
2015-11-18 16:04:55 +00:00
|
|
|
weekdayNarrowFormatter = globalize.dateFormatter( { raw: "EEEEE" } ),
|
|
|
|
firstDayRaw = globalize.dateFormatter( { raw: "c" } )( new Date( 1970, 0, 3 ) );
|
2015-04-30 11:06:56 +00:00
|
|
|
|
2015-07-27 22:42:32 +00:00
|
|
|
this._format = globalize.dateFormatter( dateFormat );
|
|
|
|
this._parse = globalize.dateParser( dateFormat );
|
2014-09-04 18:47:48 +00:00
|
|
|
this._calendarDateOptions = {
|
2015-11-18 16:04:55 +00:00
|
|
|
firstDay: ( 7 - globalize.parseNumber( firstDayRaw ) ),
|
2015-04-30 11:06:56 +00:00
|
|
|
formatWeekdayShort: function( date ) {
|
2014-09-04 18:47:48 +00:00
|
|
|
|
2015-04-30 11:06:56 +00:00
|
|
|
// Return the short weekday if its length is < 3. Otherwise, its narrow form.
|
2014-09-04 18:47:48 +00:00
|
|
|
var shortWeekday = weekdayShortFormatter( date );
|
2015-04-30 11:06:56 +00:00
|
|
|
|
2014-09-04 18:47:48 +00:00
|
|
|
return shortWeekday.length > 3 ? weekdayNarrowFormatter( date ) : shortWeekday;
|
2015-04-30 11:06:56 +00:00
|
|
|
},
|
2015-10-08 13:06:55 +00:00
|
|
|
formatWeekdayFull: globalize.dateFormatter( { raw: "EEEE" } ),
|
|
|
|
formatMonth: globalize.dateFormatter( { raw: "MMMM" } ),
|
|
|
|
formatWeekOfYear: globalize.dateFormatter( { raw: "w" } ),
|
2014-09-04 18:47:48 +00:00
|
|
|
parse: this._parse
|
|
|
|
};
|
2014-09-04 18:47:48 +00:00
|
|
|
},
|
|
|
|
|
2014-06-03 21:18:51 +00:00
|
|
|
_createCalendar: function() {
|
2016-04-16 14:49:40 +00:00
|
|
|
this.element
|
|
|
|
.attr( "role", "region" )
|
|
|
|
.append( this._buildHeaderButtons() );
|
2014-06-03 21:18:51 +00:00
|
|
|
|
|
|
|
if ( this.options.numberOfMonths === 1 ) {
|
2016-04-16 14:49:40 +00:00
|
|
|
this._buildSinglePicker();
|
2014-06-03 21:18:51 +00:00
|
|
|
} else {
|
2016-04-16 14:49:40 +00:00
|
|
|
this._buildMultiplePicker();
|
2014-06-03 21:18:51 +00:00
|
|
|
}
|
|
|
|
|
2016-12-11 16:54:16 +00:00
|
|
|
this._addClass(
|
|
|
|
this.element, "ui-calendar", "ui-widget ui-widget-content ui-helper-clearfix"
|
|
|
|
);
|
2014-06-03 21:18:51 +00:00
|
|
|
|
2015-08-26 09:45:15 +00:00
|
|
|
this._refreshHeaderButtons();
|
2014-06-19 22:13:20 +00:00
|
|
|
this._createButtonPane();
|
|
|
|
|
2014-06-03 21:18:51 +00:00
|
|
|
this.grid = this.element.find( ".ui-calendar-calendar" );
|
|
|
|
},
|
|
|
|
|
2016-04-16 14:49:40 +00:00
|
|
|
_buildSinglePicker: function() {
|
|
|
|
var header = this._buildHeader();
|
|
|
|
|
|
|
|
this._addClass( header, "ui-calendar-header-first ui-calendar-header-last" );
|
|
|
|
this.element
|
|
|
|
.attr( "aria-labelledby", this.gridId + "-title" )
|
|
|
|
.append( header )
|
|
|
|
.append( this._buildGrid() );
|
|
|
|
},
|
|
|
|
|
2014-06-03 21:18:51 +00:00
|
|
|
_buildMultiplePicker: function() {
|
2016-04-16 14:49:40 +00:00
|
|
|
var element, header,
|
|
|
|
rowBreak = $( "<div>" ),
|
2015-01-24 01:23:24 +00:00
|
|
|
currentDate = this.viewDate,
|
|
|
|
months = this.viewDate.months( this.options.numberOfMonths - 1 ),
|
2016-04-16 14:49:40 +00:00
|
|
|
labelledBy = [],
|
2014-06-03 21:18:51 +00:00
|
|
|
i = 0;
|
|
|
|
|
|
|
|
for ( ; i < months.length; i++ ) {
|
|
|
|
|
2016-12-11 16:54:16 +00:00
|
|
|
// TODO: Shouldn't we pass date as a parameter to build* fns
|
|
|
|
// instead of setting this.date?
|
2015-01-24 01:23:24 +00:00
|
|
|
this.viewDate = months[ i ];
|
2015-12-02 21:02:24 +00:00
|
|
|
this.gridId = this.id + "-" + i;
|
2016-04-16 14:49:40 +00:00
|
|
|
labelledBy.push( this.gridId + "-title" );
|
2015-12-02 21:02:24 +00:00
|
|
|
|
2016-04-16 14:49:40 +00:00
|
|
|
element = $( "<div>" );
|
|
|
|
this._addClass( element, "ui-calendar-group" );
|
2014-06-03 21:18:51 +00:00
|
|
|
|
2016-04-16 14:49:40 +00:00
|
|
|
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() );
|
2014-06-03 21:18:51 +00:00
|
|
|
}
|
|
|
|
|
2016-04-16 14:49:40 +00:00
|
|
|
this._addClass( this.element, "ui-calendar-multi" )
|
|
|
|
._addClass( rowBreak, "ui-calendar-row-break" );
|
2014-06-03 21:18:51 +00:00
|
|
|
|
2016-04-16 14:49:40 +00:00
|
|
|
this.element
|
|
|
|
.attr( "aria-labelledby", labelledBy.join( " " ) )
|
|
|
|
.append( rowBreak );
|
2015-12-02 21:02:24 +00:00
|
|
|
|
2015-01-24 01:23:24 +00:00
|
|
|
this.viewDate = currentDate;
|
2015-12-02 20:47:25 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
_buildHeaderButtons: function() {
|
2016-04-16 14:49:40 +00:00
|
|
|
var buttons = $( "<div>" );
|
2014-06-03 21:18:51 +00:00
|
|
|
|
2016-04-16 15:20:58 +00:00
|
|
|
this._addClass( buttons, "ui-calendar-header-buttons" );
|
2014-06-03 21:18:51 +00:00
|
|
|
|
2016-04-16 14:49:40 +00:00
|
|
|
return buttons
|
2016-04-16 15:20:58 +00:00
|
|
|
.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 );
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
|
|
|
|
2016-04-16 14:49:40 +00:00
|
|
|
_buildHeader: function() {
|
|
|
|
var header = $( "<div>" ),
|
|
|
|
title = $( "<div>", { role: "header", id: this.gridId + "-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 )
|
|
|
|
);
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
_buildTitle: function() {
|
2016-04-16 14:49:40 +00:00
|
|
|
var title = $( "<div>", { role: "alert", id: this.gridId + "-month-label" } ),
|
|
|
|
month = $( "<span>" ).text( this.viewDate.monthName() ),
|
|
|
|
year = $( "<span>" ).text( this.viewDate.year() );
|
|
|
|
|
|
|
|
this._addClass( title, "ui-calendar-title" )
|
|
|
|
._addClass( month, "ui-calendar-month" )
|
|
|
|
._addClass( year, "ui-calendar-year" );
|
|
|
|
|
|
|
|
return title
|
|
|
|
.append( month )
|
|
|
|
.append( " " )
|
|
|
|
.append( year );
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
_buildGrid: function() {
|
2016-04-16 14:49:40 +00:00
|
|
|
var table = $( "<table>", {
|
|
|
|
role: "grid",
|
|
|
|
tabindex: 0,
|
|
|
|
"aria-readonly": true,
|
|
|
|
"aria-labelledby": this.gridId + "-month-label",
|
|
|
|
"aria-activedescendant": this._getDayId( this.date )
|
|
|
|
} );
|
|
|
|
|
|
|
|
this._addClass( table, "ui-calendar-calendar" );
|
|
|
|
|
|
|
|
return table
|
|
|
|
.append( this._buildGridHeading() )
|
|
|
|
.append( this._buildGridBody() );
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
_buildGridHeading: function() {
|
2016-04-16 14:49:40 +00:00
|
|
|
var head = $( "<thead role='presentation'>" ),
|
|
|
|
week = $( "<th>" ),
|
|
|
|
row = $( "<tr role='row'>" ),
|
2014-06-03 21:18:51 +00:00
|
|
|
i = 0,
|
2014-09-04 18:47:48 +00:00
|
|
|
weekDayLength = this.viewDate.weekdays().length,
|
2015-08-25 15:47:13 +00:00
|
|
|
weekdays = this.viewDate.weekdays();
|
2014-06-03 21:18:51 +00:00
|
|
|
|
|
|
|
if ( this.options.showWeek ) {
|
2016-04-16 14:49:40 +00:00
|
|
|
this._addClass( week, "ui-calendar-week-col" );
|
|
|
|
row.append( week.text( this._getTranslation( "weekHeader" ) ) );
|
2014-06-03 21:18:51 +00:00
|
|
|
}
|
2016-04-16 14:49:40 +00:00
|
|
|
|
2015-04-30 11:06:56 +00:00
|
|
|
for ( ; i < weekDayLength; i++ ) {
|
2016-04-16 14:49:40 +00:00
|
|
|
row.append( this._buildGridHeaderCell( weekdays[ i ] ) );
|
2014-06-03 21:18:51 +00:00
|
|
|
}
|
|
|
|
|
2016-04-16 14:49:40 +00:00
|
|
|
return head.append( row );
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
_buildGridHeaderCell: function( day ) {
|
2016-12-11 16:54:16 +00:00
|
|
|
return $( "<th role='columnheader' abbr='" + day.fullname +
|
|
|
|
"' aria-label='" + day.fullname + "'>" +
|
2016-04-16 14:49:40 +00:00
|
|
|
"<span title='" + day.fullname + "'>" + day.shortname + "</span>" +
|
|
|
|
"</th>" );
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
_buildGridBody: function() {
|
2015-01-24 01:23:24 +00:00
|
|
|
var days = this.viewDate.days(),
|
2014-06-03 21:18:51 +00:00
|
|
|
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 ) {
|
2014-06-04 17:07:23 +00:00
|
|
|
var content = "",
|
2016-04-13 21:30:44 +00:00
|
|
|
dateObject = new Date( day.timestamp ),
|
|
|
|
dayName = this._calendarDateOptions.formatWeekdayFull( dateObject ),
|
2014-06-03 21:18:51 +00:00
|
|
|
attributes = [
|
2014-06-04 17:07:23 +00:00
|
|
|
"role='gridcell'",
|
2016-04-13 21:30:44 +00:00
|
|
|
"aria-selected='" + ( this._isCurrent( day ) ? true : false ) + "'",
|
|
|
|
"aria-label='" + dayName + ", " + this._format( dateObject ) + "'",
|
|
|
|
"aria-describedby='" + this.gridId + "-month-label'",
|
|
|
|
"aria-hidden='" + true + "'"
|
2014-06-04 17:07:23 +00:00
|
|
|
],
|
2016-04-13 21:30:44 +00:00
|
|
|
selectable = ( day.selectable && this._isValid( dateObject ) );
|
2014-06-03 21:18:51 +00:00
|
|
|
|
|
|
|
if ( day.render ) {
|
2016-12-11 16:54:16 +00:00
|
|
|
attributes.push(
|
|
|
|
"id='" + this.id + "-" + day.year + "-" + day.month + "-" + day.date + "'"
|
|
|
|
);
|
2014-06-03 21:18:51 +00:00
|
|
|
|
2014-06-04 17:07:23 +00:00
|
|
|
if ( !selectable ) {
|
|
|
|
attributes.push( "aria-disabled='true'" );
|
|
|
|
attributes.push( "class='ui-state-disabled'" );
|
2014-06-03 21:18:51 +00:00
|
|
|
}
|
2014-06-04 17:07:23 +00:00
|
|
|
|
|
|
|
content = this._buildDayElement( day, selectable );
|
2014-06-03 21:18:51 +00:00
|
|
|
}
|
|
|
|
|
2014-06-04 17:07:23 +00:00
|
|
|
return "<td " + attributes.join( " " ) + ">" + content + "</td>";
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
|
|
|
|
2015-01-24 01:23:24 +00:00
|
|
|
_getDayId: function( date ) {
|
|
|
|
return this.id + "-" + date.year() + "-" + date.month() + "-" + date.day();
|
|
|
|
},
|
|
|
|
|
2014-06-04 17:07:23 +00:00
|
|
|
_buildDayElement: function( day, selectable ) {
|
2015-01-20 17:23:49 +00:00
|
|
|
var attributes, content,
|
|
|
|
classes = [ "ui-state-default" ];
|
2014-06-03 21:18:51 +00:00
|
|
|
|
2014-06-04 17:07:23 +00:00
|
|
|
if ( day === this.date && selectable ) {
|
2014-06-03 21:18:51 +00:00
|
|
|
classes.push( "ui-state-focus" );
|
|
|
|
}
|
2015-01-24 01:23:24 +00:00
|
|
|
if ( this._isCurrent( day ) ) {
|
2014-06-03 21:18:51 +00:00
|
|
|
classes.push( "ui-state-active" );
|
|
|
|
}
|
|
|
|
if ( day.today ) {
|
|
|
|
classes.push( "ui-state-highlight" );
|
|
|
|
}
|
|
|
|
if ( day.extraClasses ) {
|
|
|
|
classes.push( day.extraClasses.split( " " ) );
|
|
|
|
}
|
|
|
|
|
2015-01-20 17:23:49 +00:00
|
|
|
attributes = " class='" + classes.join( " " ) + "'";
|
2014-06-04 17:07:23 +00:00
|
|
|
if ( selectable ) {
|
2016-10-11 23:31:22 +00:00
|
|
|
attributes += " tabindex='-1' data-ui-calendar-timestamp='" + day.timestamp + "'";
|
2014-06-04 17:07:23 +00:00
|
|
|
} else {
|
2015-01-20 17:23:49 +00:00
|
|
|
attributes += " disabled='disabled'";
|
2014-06-03 21:18:51 +00:00
|
|
|
}
|
2015-01-20 17:23:49 +00:00
|
|
|
content = "<button" + attributes + ">" + day.date + "</button>";
|
2014-06-03 21:18:51 +00:00
|
|
|
|
|
|
|
if ( day.today ) {
|
2016-12-11 16:54:16 +00:00
|
|
|
content += "<span class='ui-helper-hidden-accessible'>, " +
|
|
|
|
this._getTranslation( "currentText" ) + "</span>";
|
2014-06-03 21:18:51 +00:00
|
|
|
}
|
|
|
|
|
2014-06-04 17:07:23 +00:00
|
|
|
return content;
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
|
|
|
|
2015-01-24 01:23:24 +00:00
|
|
|
_isCurrent: function( day ) {
|
2015-01-24 01:23:24 +00:00
|
|
|
return this.options.value && day.timestamp === this.options.value.getTime();
|
2015-01-24 01:23:24 +00:00
|
|
|
},
|
|
|
|
|
2014-06-19 22:13:20 +00:00
|
|
|
_createButtonPane: function() {
|
2016-04-16 14:49:40 +00:00
|
|
|
this.buttonPane = $( "<div>" );
|
|
|
|
this.buttonSet = $( "<div>" ).appendTo( this.buttonPane );
|
2014-06-19 22:13:20 +00:00
|
|
|
|
2016-12-11 16:54:16 +00:00
|
|
|
this._addClass(
|
|
|
|
this.buttonPane, "ui-calendar-buttonpane", "ui-widget-content ui-helper-clearfix"
|
|
|
|
)
|
2016-04-16 14:49:40 +00:00
|
|
|
._addClass( this.buttonSet, "ui-calendar-buttonset" );
|
2014-06-19 22:13:20 +00:00
|
|
|
|
|
|
|
this._createButtons();
|
|
|
|
},
|
|
|
|
|
|
|
|
_createButtons: function() {
|
|
|
|
var that = this,
|
|
|
|
buttons = this.options.buttons;
|
|
|
|
|
|
|
|
this.buttonPane.remove();
|
|
|
|
this.buttonSet.empty();
|
|
|
|
|
|
|
|
if ( $.isEmptyObject( buttons ) || ( $.isArray( buttons ) && !buttons.length ) ) {
|
2016-04-16 14:49:40 +00:00
|
|
|
this._removeClass( this.element, "ui-calendar-buttons" );
|
2014-06-19 22:13:20 +00:00
|
|
|
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 = {
|
2015-12-02 17:44:20 +00:00
|
|
|
icon: props.icon,
|
|
|
|
iconPosition: props.iconPosition,
|
|
|
|
showLabel: props.showLabel
|
2014-06-19 22:13:20 +00:00
|
|
|
};
|
2015-12-02 17:44:20 +00:00
|
|
|
|
|
|
|
delete props.click;
|
|
|
|
delete props.icon;
|
|
|
|
delete props.iconPosition;
|
|
|
|
delete props.showLabel;
|
|
|
|
|
2014-06-19 22:13:20 +00:00
|
|
|
$( "<button></button>", props )
|
|
|
|
.button( buttonOptions )
|
2015-12-02 17:44:20 +00:00
|
|
|
.appendTo( that.buttonSet )
|
|
|
|
.on( "click", function() {
|
|
|
|
click.apply( that.buttonClickContext, arguments );
|
|
|
|
} );
|
2015-04-30 15:38:01 +00:00
|
|
|
} );
|
2016-04-16 14:49:40 +00:00
|
|
|
|
|
|
|
this._addClass( this.element, "ui-calendar-buttons" );
|
2014-06-19 22:13:20 +00:00
|
|
|
this.buttonPane.appendTo( this.element );
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
// 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
|
2015-12-02 20:47:25 +00:00
|
|
|
// destroyed and recreated instead of just having its text change.
|
2014-06-03 21:18:51 +00:00
|
|
|
refresh: function() {
|
2015-04-30 11:06:56 +00:00
|
|
|
this.labels = this.options.labels;
|
2014-06-03 21:18:51 +00:00
|
|
|
|
2015-12-03 17:16:40 +00:00
|
|
|
// Determine which day grid cell to focus after refresh
|
2014-06-03 21:18:51 +00:00
|
|
|
// TODO: Prevent disabled cells from being focused
|
|
|
|
if ( this.options.numberOfMonths === 1 ) {
|
2016-04-16 14:49:40 +00:00
|
|
|
this.element.find( ".ui-calendar-title" ).replaceWith( this._buildTitle() );
|
2015-12-02 20:47:25 +00:00
|
|
|
this.element.find( ".ui-calendar-calendar" ).replaceWith( this._buildGrid() );
|
2014-06-03 21:18:51 +00:00
|
|
|
} else {
|
|
|
|
this._refreshMultiplePicker();
|
|
|
|
}
|
2015-08-26 09:45:15 +00:00
|
|
|
|
2015-12-02 20:47:25 +00:00
|
|
|
this.grid = this.element.find( ".ui-calendar-calendar" );
|
|
|
|
|
2016-04-16 14:49:40 +00:00
|
|
|
this._setActiveDescendant();
|
2015-08-26 09:45:15 +00:00
|
|
|
this._refreshHeaderButtons();
|
|
|
|
this._createButtons();
|
|
|
|
},
|
|
|
|
|
|
|
|
_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.viewDate.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,
|
2015-10-08 13:06:55 +00:00
|
|
|
( this.options.max.getMonth() <= months[ i ].month() &&
|
2015-08-26 09:45:15 +00:00
|
|
|
this.options.max.getFullYear() === months[ i ].year() ) ||
|
|
|
|
this.options.max.getFullYear() < months[ i ].year()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_disableElement: function( element, state ) {
|
2016-04-16 14:49:40 +00:00
|
|
|
element.attr( "aria-disabled", state );
|
|
|
|
this._toggleClass( element, null, "ui-state-disabled", state );
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
_refreshMultiplePicker: function() {
|
|
|
|
var i = 0;
|
|
|
|
|
|
|
|
for ( ; i < this.options.numberOfMonths; i++ ) {
|
2016-04-16 14:49:40 +00:00
|
|
|
this.element.find( ".ui-calendar-title" ).eq( i ).replaceWith( this._buildTitle() );
|
|
|
|
this.element.find( ".ui-calendar-calendar" ).eq( i ).replaceWith( this._buildGrid() );
|
2015-01-24 01:23:24 +00:00
|
|
|
this.viewDate.adjust( "M", 1 );
|
2014-06-03 21:18:51 +00:00
|
|
|
}
|
2015-01-24 01:23:24 +00:00
|
|
|
this.viewDate.adjust( "M", -this.options.numberOfMonths );
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
2014-06-19 16:59:28 +00:00
|
|
|
|
|
|
|
_getTranslation: function( key ) {
|
|
|
|
return $( "<a>" ).text( this.labels[ key ] ).html();
|
|
|
|
},
|
2014-06-03 21:18:51 +00:00
|
|
|
|
|
|
|
_setHiddenPicker: function() {
|
2015-04-30 15:38:01 +00:00
|
|
|
this.element.attr( {
|
2014-06-03 21:18:51 +00:00
|
|
|
"aria-hidden": "true",
|
|
|
|
"aria-expanded": "false"
|
2015-04-30 15:38:01 +00:00
|
|
|
} );
|
2014-06-03 21:18:51 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
value: function( value ) {
|
|
|
|
if ( arguments.length ) {
|
2015-04-30 11:06:56 +00:00
|
|
|
this.valueAsDate( this._parse( value ) );
|
2014-06-03 21:18:51 +00:00
|
|
|
} else {
|
2016-10-12 09:36:48 +00:00
|
|
|
return this.option( "value" ) === null ?
|
|
|
|
null : this._format( this.option( "value" ) );
|
2014-06-03 21:18:51 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
valueAsDate: function( value ) {
|
|
|
|
if ( arguments.length ) {
|
2014-12-18 16:39:27 +00:00
|
|
|
this.option( "value", value );
|
2014-06-03 21:18:51 +00:00
|
|
|
} else {
|
2014-11-07 17:10:31 +00:00
|
|
|
return this.options.value;
|
2014-06-03 21:18:51 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-06-04 17:07:23 +00:00
|
|
|
_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;
|
|
|
|
},
|
|
|
|
|
2014-06-03 21:18:51 +00:00
|
|
|
_destroy: function() {
|
|
|
|
this.element
|
|
|
|
.removeAttr( "role aria-labelledby" )
|
|
|
|
.removeUniqueId()
|
|
|
|
.empty();
|
|
|
|
},
|
|
|
|
|
2014-12-18 16:39:27 +00:00
|
|
|
_setOptions: function( options ) {
|
|
|
|
var that = this,
|
2015-07-27 22:42:32 +00:00
|
|
|
refresh = false,
|
|
|
|
dateAttributes = false;
|
2014-12-18 16:39:27 +00:00
|
|
|
|
|
|
|
$.each( options, function( key, value ) {
|
|
|
|
that._setOption( key, value );
|
|
|
|
|
|
|
|
if ( key in that.refreshRelatedOptions ) {
|
|
|
|
refresh = true;
|
|
|
|
}
|
2015-07-27 22:42:32 +00:00
|
|
|
if ( key === "dateFormat" || key === "locale" ) {
|
|
|
|
dateAttributes = true;
|
|
|
|
}
|
2015-04-30 15:38:01 +00:00
|
|
|
} );
|
2014-12-18 16:39:27 +00:00
|
|
|
|
2015-07-27 22:42:32 +00:00
|
|
|
if ( dateAttributes ) {
|
|
|
|
this._setLocale( this.options.locale, this.options.dateFormat );
|
|
|
|
this.date.setAttributes( this._calendarDateOptions );
|
|
|
|
this.viewDate.setAttributes( this._calendarDateOptions );
|
|
|
|
}
|
2014-12-18 16:39:27 +00:00
|
|
|
if ( refresh ) {
|
2015-09-27 17:17:02 +00:00
|
|
|
this.viewDate.setTime( this.date.date().getTime() );
|
|
|
|
this.refresh();
|
2014-12-18 16:39:27 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-06-03 21:18:51 +00:00
|
|
|
_setOption: function( key, value ) {
|
|
|
|
if ( key === "value" ) {
|
2014-06-04 17:07:23 +00:00
|
|
|
if ( this._isValid( value ) ) {
|
2015-01-24 01:23:24 +00:00
|
|
|
this.date.setTime( value.getTime() );
|
2016-10-12 09:36:48 +00:00
|
|
|
} else {
|
|
|
|
value = null;
|
2014-06-03 21:18:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:07:23 +00:00
|
|
|
if ( key === "max" || key === "min" ) {
|
2016-10-24 20:24:09 +00:00
|
|
|
if ( $.type( value ) !== "date" || value === null ) {
|
|
|
|
this._super( key, null );
|
|
|
|
} else {
|
2014-06-04 17:07:23 +00:00
|
|
|
this._super( key, value );
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-03 21:18:51 +00:00
|
|
|
this._super( key, value );
|
|
|
|
|
2014-06-19 22:13:20 +00:00
|
|
|
if ( key === "buttons" ) {
|
|
|
|
this._createButtons();
|
|
|
|
}
|
|
|
|
|
2014-09-01 13:36:38 +00:00
|
|
|
if ( key === "disabled" ) {
|
|
|
|
this.element
|
|
|
|
.toggleClass( "ui-state-disabled", value )
|
|
|
|
.attr( "aria-disabled", value );
|
|
|
|
}
|
|
|
|
|
2014-06-03 21:18:51 +00:00
|
|
|
if ( key === "eachDay" ) {
|
2015-01-24 01:23:24 +00:00
|
|
|
this.viewDate.eachDay = value;
|
2014-06-03 21:18:51 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-30 15:38:01 +00:00
|
|
|
} );
|
2014-06-03 21:18:51 +00:00
|
|
|
|
2015-04-30 15:38:01 +00:00
|
|
|
} ) );
|