/*! * 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, labels: { "datePickerRole": "date picker", "nextText": "Next", "prevText": "Prev", "weekHeader": "Wk" }, locale: "en", max: null, min: null, numberOfMonths: 1, showWeek: false, value: null, // callbacks 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.gridId = this.id; this.labels = this.options.labels; this.buttonClickContext = this.element[ 0 ]; this._setLocale( this.options.locale, this.options.dateFormat ); this.date = new $.ui.date( this.options.value, this._calendarDateOptions ); this.viewDate = this.date.clone(); this.viewDate.eachDay = this.options.eachDay; this._on( this.element, { "click .ui-calendar-prev": function( event ) { event.preventDefault(); this.date.adjust( "M", -this.options.numberOfMonths ); this._updateView(); }, "click .ui-calendar-next": function( event ) { event.preventDefault(); this.date.adjust( "M", this.options.numberOfMonths ); this._updateView(); }, "mousedown .ui-calendar-calendar button": function( event ) { this._setOption( "value", new Date( $( event.currentTarget ).data( "timestamp" ) ) ); this._updateDayElement( "ui-state-active" ); // Allow datepicker to handle focus if ( this._trigger( "select", event ) !== false ) { this.activeDescendant.closest( this.grid ).focus(); event.preventDefault(); } }, "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" ); }, _handleKeydown: function( event ) { var pageAltKey = ( event.altKey || event.ctrlKey && event.shiftKey ); switch ( event.keyCode ) { case $.ui.keyCode.ENTER: this.activeDescendant.mousedown(); return; case $.ui.keyCode.PAGE_UP: this.date.adjust( pageAltKey ? "Y" : "M", -1 ); break; case $.ui.keyCode.PAGE_DOWN: this.date.adjust( pageAltKey ? "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: return; } if ( this._needsRefresh() ) { this._updateView(); this.activeDescendant.closest( this.grid ).focus(); } else { this._setActiveDescendant(); } }, _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(); }, _needsRefresh: function() { if ( this.date.month() !== this.viewDate.month() || this.date.year() !== this.viewDate.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.date ) ).length; } return false; }, _setActiveDescendant: function() { this.activeDescendant = this._updateDayElement( "ui-state-focus" ); }, _updateDayElement: function( state ) { var id = this._getDayId( this.date ), 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.gridId + "-title" ) .append( header ) .append( this._buildGrid() ); }, _buildMultiplePicker: function() { var element, header, rowBreak = $( "
" ), currentDate = this.viewDate, months = this.viewDate.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.date? this.viewDate = months[ i ]; this.gridId = this.id + "-" + i; labelledBy.push( this.gridId + "-title" ); element = $( "
" ); 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.viewDate = currentDate; }, _buildHeaderButtons: function() { var buttons = $( "
" ); this.prevButton = $( "