/*! * 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 = $( "
" ), 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 = $( "
" ); 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 = $( "
" ); 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 = $( "