From 501c67ef2474f0ee28e00300223ad0d2a7c2655b Mon Sep 17 00:00:00 2001 From: Felix Nagel Date: Wed, 2 Dec 2015 21:47:25 +0100 Subject: [PATCH] Calendar: Fix focus issues * Change next / prev button structure for better tabindex * Improve focus and active handling --- themes/base/calendar.css | 4 ++ ui/widgets/calendar.js | 80 ++++++++++++++++++++-------------------- 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/themes/base/calendar.css b/themes/base/calendar.css index def9fe4ff..961209bdc 100644 --- a/themes/base/calendar.css +++ b/themes/base/calendar.css @@ -18,6 +18,10 @@ position: relative; padding: .2em 0; } +.ui-calendar .ui-calendar-header-buttons { + position: relative; + z-index: 1; +} .ui-calendar .ui-calendar-prev, .ui-calendar .ui-calendar-next { cursor: pointer; diff --git a/ui/widgets/calendar.js b/ui/widgets/calendar.js index e4ed97bb9..9184b3b0d 100644 --- a/ui/widgets/calendar.js +++ b/ui/widgets/calendar.js @@ -89,14 +89,12 @@ return $.widget( "ui.calendar", { "click .ui-calendar-prev": function( event ) { event.preventDefault(); this.date.adjust( "M", -this.options.numberOfMonths ); - this.viewDate.setTime( this.date.date().getTime() ); - this.refresh(); + this._updateView(); }, "click .ui-calendar-next": function( event ) { event.preventDefault(); this.date.adjust( "M", this.options.numberOfMonths ); - this.viewDate.setTime( this.date.date().getTime() ); - this.refresh(); + this._updateView(); }, "mousedown .ui-calendar-calendar button": function( event ) { event.preventDefault(); @@ -104,16 +102,17 @@ return $.widget( "ui.calendar", { this._setOption( "value", new Date( $( event.currentTarget ).data( "timestamp" ) ) ); this.refresh(); this._trigger( "select", event ); - this.grid.focus(); + this.activeDescendant.closest( this.grid ).focus(); }, - "mouseenter .ui-calendar-header button": "_hover", - "mouseleave .ui-calendar-header button": "_hover", + "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 ) { @@ -150,24 +149,27 @@ return $.widget( "ui.calendar", { this.date.adjust( "D", 7 ); break; default: - event.preventDefault(); return; } if ( this._needsRefresh() ) { - 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 ) - ); - this.refresh(); - } else { - this.viewDate.setTime( this.date.date().getTime() ); - this.refresh(); - } - this.grid.focus(); + this._updateView(); + this.activeDescendant.closest( this.grid ).focus(); + } else { + this._setActiveDescendant(); } + }, - 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() { @@ -222,12 +224,12 @@ return $.widget( "ui.calendar", { _createCalendar: function() { var classes = "ui-calendar ui-widget ui-widget-content ui-helper-clearfix ui-corner-all", - pickerHtml = ""; + pickerHtml = this._buildHeaderButtons(); if ( this.options.numberOfMonths === 1 ) { - pickerHtml = this._buildHeader() + this._buildGrid(); + pickerHtml += this._buildHeader() + this._buildGrid(); } else { - pickerHtml = this._buildMultiplePicker(); + pickerHtml += this._buildMultiplePicker(); classes += " ui-calendar-multi"; } @@ -266,15 +268,10 @@ return $.widget( "ui.calendar", { headerClass += " ui-corner-right"; } - html += "
" + - "
"; - if ( months[ i ].first ) { - html += this._buildPreviousLink(); - } else if ( months[ i ].last ) { - html += this._buildNextLink(); - } - - html += this._buildTitlebar() + "
" + this._buildGrid() + "
"; + html += "
"; + html += "
" + + this._buildTitlebar() + "
"; + html += this._buildGrid() + "
"; } html += "
"; @@ -286,9 +283,14 @@ return $.widget( "ui.calendar", { _buildHeader: function() { return "
" + + this._buildTitlebar() + + "
"; + }, + + _buildHeaderButtons: function() { + return "
" + this._buildPreviousLink() + this._buildNextLink() + - this._buildTitlebar() + "
"; }, @@ -505,22 +507,22 @@ return $.widget( "ui.calendar", { // 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. Additionally, interacting - // with the prev and next links would cause loss of focus issues because the links being - // interacted with will disappear while focused. + // destroyed and recreated instead of just having its text change. refresh: function() { this.labels = this.options.labels; // Determine which day gridcell to focus after refresh // TODO: Prevent disabled cells from being focused if ( this.options.numberOfMonths === 1 ) { - this.grid = $( this._buildGrid() ); this.element.find( ".ui-calendar-title" ).html( this._buildTitle() ); - this.element.find( ".ui-calendar-calendar" ).replaceWith( this.grid ); + 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(); }, @@ -571,10 +573,6 @@ return $.widget( "ui.calendar", { this.viewDate.adjust( "M", 1 ); } this.viewDate.adjust( "M", -this.options.numberOfMonths ); - - // TODO: This assumes focus is on the first grid. For multi pickers, the widget needs - // to maintain the currently focused grid and base queries like this off of it. - this.element.find( ".ui-state-focus" ).not( ":first" ).removeClass( "ui-state-focus" ); }, _getTranslation: function( key ) { -- 2.39.5