/*!
* jQuery UI Calendar @VERSION
* http://jqueryui.com
*
* Copyright 2014 jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Datepicker
//>>group: Widgets
//>>description: Displays a calendar for inline date selection.
//>>docs: http://api.jqueryui.com/calendar/
//>>demos: http://jqueryui.com/calendar/
(function( factory ) {
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
// TODO Add globalize and $.date
// TODO: Keep button even if its optional?
define([
"jquery",
"./core",
"./widget",
"./button"
], factory );
} else {
// Browser globals
factory( jQuery );
}
}(function( $ ) {
return $.widget( "ui.calendar", {
version: "@VERSION",
options: {
buttons: [],
dateFormat: { date: "short" },
eachDay: $.noop,
max: null,
min: null,
numberOfMonths: 1,
showWeek: false,
value: null,
// callbacks
select: null
},
refreshRelatedOptions: {
eachDay: true,
max: true,
min: true,
showWeek: true,
value: true
},
_create: function() {
this.id = this.element.uniqueId().attr( "id" );
this.labels = Globalize.translate( "datepicker" );
this.buttonClickContext = this.element[ 0 ];
this.date = $.date( this.options.value, this.options.dateFormat );
this.date.eachDay = this.options.eachDay;
this.options.value = this.date.date();
this._on( this.element, {
"click .ui-calendar-prev": function( event ) {
event.preventDefault();
this.date.adjust( "M", -this.options.numberOfMonths );
this.refresh();
},
"click .ui-calendar-next": function( event ) {
event.preventDefault();
this.date.adjust( "M", this.options.numberOfMonths );
this.refresh();
},
"mousedown .ui-calendar-calendar button": function( event ) {
event.preventDefault();
// TODO Exclude clicks on lead days or handle them correctly
// TODO Store/read more then just date, also required for multi month picker
this._select( event, $( event.currentTarget ).data( "timestamp" ) );
this.grid.focus();
},
"mouseenter .ui-calendar-header button": "_hover",
"mouseleave .ui-calendar-header button": "_hover",
"mouseenter .ui-calendar-calendar button": "_hover",
"mouseleave .ui-calendar-calendar button": "_hover",
"keydown .ui-calendar-calendar": "_handleKeydown"
});
this._createCalendar();
},
_hover: function( event ) {
$( event.currentTarget ).toggleClass( "ui-state-hover" );
},
_handleKeydown: function( event ) {
var oldMonth = this.date.month(),
oldYear = this.date.year();
// TODO: Handle for pickers with multiple months
switch ( event.keyCode ) {
case $.ui.keyCode.ENTER:
this.activeDescendant.mousedown();
return;
case $.ui.keyCode.PAGE_UP:
this.date.adjust( event.altKey ? "Y" : "M", -1 );
break;
case $.ui.keyCode.PAGE_DOWN:
this.date.adjust( event.altKey ? "Y" : "M", 1 );
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:
event.preventDefault();
return;
}
if ( this.date.month() !== oldMonth || this.date.year() !== oldYear ) {
this.refresh();
this.grid.focus();
}
this._setActiveDescendant();
},
_setActiveDescendant: function() {
var id = this.id + "-" + this.date.day();
this.grid
.attr( "aria-activedescendant", id )
.find( ".ui-state-focus" )
.removeClass( "ui-state-focus" );
this.activeDescendant = this.grid.find(
this._sanitizeSelector( "#" + id ) + " > button"
).addClass( "ui-state-focus" );
},
_createCalendar: function() {
var classes = "ui-calendar ui-widget ui-widget-content ui-helper-clearfix ui-corner-all",
pickerHtml = "";
if ( this.options.numberOfMonths === 1 ) {
pickerHtml = this._buildHeader() + this._buildGrid();
} else {
pickerHtml = this._buildMultiplePicker();
classes += " ui-calendar-multi";
}
this.element
.addClass( classes )
.attr({
role: "region",
"aria-labelledby": this.id + "-title"
})
.html( pickerHtml );
this._createButtonPane();
this.grid = this.element.find( ".ui-calendar-calendar" );
},
_buildMultiplePicker: function() {
var headerClass,
html = "",
currentDate = this.date,
months = this.date.months( this.options.numberOfMonths - 1 ),
i = 0;
for ( ; i < months.length; i++ ) {
// TODO: Shouldn't we pass date as a parameter to build* fns instead of setting this.date?
this.date = months[ i ];
headerClass = "ui-calendar-header ui-widget-header ui-helper-clearfix";
if ( months[ i ].first ) {
headerClass += " ui-corner-left";
} else if ( months[ i ].last ) {
headerClass += " ui-corner-right";
}
html += "
" +
"
";
if ( months[ i ].first ) {
html += this._buildPreviousLink();
} else if ( months[ i ].last ) {
html += this._buildNextLink();
}
html += this._buildTitlebar() + "