From 9248949c9db573895c2806b11d528ade2ee9989c Mon Sep 17 00:00:00 2001 From: Felix Nagel Date: Sat, 26 Aug 2017 13:21:45 +0200 Subject: [PATCH 1/7] Calendar: Remove unneeded row and gridcell role attributes --- tests/unit/calendar/core.js | 8 +------- ui/widgets/calendar.js | 3 +-- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/tests/unit/calendar/core.js b/tests/unit/calendar/core.js index a39e7a7064d..009511b1440 100644 --- a/tests/unit/calendar/core.js +++ b/tests/unit/calendar/core.js @@ -401,7 +401,7 @@ QUnit.test( "mouse", function( assert ) { } ); QUnit.test( "ARIA", function( assert ) { - assert.expect( 15 ); + assert.expect( 12 ); var id = this.element.attr( "id" ), headerId = id + "-title", @@ -426,17 +426,11 @@ QUnit.test( "ARIA", function( assert ) { assert.equal( table.children( "thead" ).attr( "role" ), "presentation", "Table head role attribute" ); - assert.equal( table.find( "thead tr" ).attr( "role" ), "row", - "Table head row role attribute" ); assert.equal( table.find( "thead th" ).first().attr( "role" ), "columnheader", "Table head cell role attribute" ); assert.equal( table.children( "tbody" ).attr( "role" ), "presentation", "Table body role attribute" ); - assert.equal( table.find( "tbody tr" ).attr( "role" ), "row", - "Table body row role attribute" ); - assert.equal( table.find( "tbody td" ).first().attr( "role" ), "gridcell", - "Table body cell role attribute" ); assert.equal( table.find( "tbody td" ).first().attr( "aria-describedby" ), monthLabelId, "Table body cell ARIA describedby attribute" ); } ); diff --git a/ui/widgets/calendar.js b/ui/widgets/calendar.js index d9ed4dee30d..be99892648a 100644 --- a/ui/widgets/calendar.js +++ b/ui/widgets/calendar.js @@ -408,7 +408,7 @@ return $.widget( "ui.calendar", { _buildGridHeading: function() { var head = $( "" ), week = $( "" ), - row = $( "" ), + row = $( "" ), i = 0, weekDayLength = this._getViewDate().weekdays().length, weekdays = this._getViewDate().weekdays(); @@ -463,7 +463,6 @@ return $.widget( "ui.calendar", { dateObject = new Date( day.timestamp ), dayName = this._calendarDateOptions.formatWeekdayFull( dateObject ), attributes = [ - "role='gridcell'", "aria-selected='" + ( this._isCurrent( day ) ? true : false ) + "'", "aria-label='" + dayName + ", " + this._format( dateObject ) + "'", "aria-describedby='" + this._getGridId() + "-month-label'" From 931cb89b3876b44e6479f5f07af948433365c4e3 Mon Sep 17 00:00:00 2001 From: Felix Nagel Date: Sat, 26 Aug 2017 13:29:48 +0200 Subject: [PATCH 2/7] Calendar: Remove unneeded aria attributes from day cell --- tests/unit/calendar/core.js | 4 +--- ui/widgets/calendar.js | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/unit/calendar/core.js b/tests/unit/calendar/core.js index 009511b1440..cd67793ab47 100644 --- a/tests/unit/calendar/core.js +++ b/tests/unit/calendar/core.js @@ -401,7 +401,7 @@ QUnit.test( "mouse", function( assert ) { } ); QUnit.test( "ARIA", function( assert ) { - assert.expect( 12 ); + assert.expect( 11 ); var id = this.element.attr( "id" ), headerId = id + "-title", @@ -431,8 +431,6 @@ QUnit.test( "ARIA", function( assert ) { assert.equal( table.children( "tbody" ).attr( "role" ), "presentation", "Table body role attribute" ); - assert.equal( table.find( "tbody td" ).first().attr( "aria-describedby" ), - monthLabelId, "Table body cell ARIA describedby attribute" ); } ); } ); diff --git a/ui/widgets/calendar.js b/ui/widgets/calendar.js index be99892648a..6e907ea0b8e 100644 --- a/ui/widgets/calendar.js +++ b/ui/widgets/calendar.js @@ -461,11 +461,8 @@ return $.widget( "ui.calendar", { _buildDayCell: function( day ) { var content = "", dateObject = new Date( day.timestamp ), - dayName = this._calendarDateOptions.formatWeekdayFull( dateObject ), attributes = [ - "aria-selected='" + ( this._isCurrent( day ) ? true : false ) + "'", - "aria-label='" + dayName + ", " + this._format( dateObject ) + "'", - "aria-describedby='" + this._getGridId() + "-month-label'" + "aria-selected='" + ( this._isCurrent( day ) ? true : false ) + "'" ], selectable = ( day.selectable && this._isValid( dateObject ) ); From 77cd1b3992673b53f60de6bc507f783eb55176dc Mon Sep 17 00:00:00 2001 From: Felix Nagel Date: Sat, 26 Aug 2017 13:31:21 +0200 Subject: [PATCH 3/7] Calendar: Change title element role attribute from alert to status --- tests/unit/calendar/core.js | 2 +- ui/widgets/calendar.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/calendar/core.js b/tests/unit/calendar/core.js index cd67793ab47..c327e013018 100644 --- a/tests/unit/calendar/core.js +++ b/tests/unit/calendar/core.js @@ -414,7 +414,7 @@ QUnit.test( "ARIA", function( assert ) { assert.equal( this.element.find( "#" + headerId ).attr( "role" ), "header", "Header role attribute" ); - assert.equal( this.element.find( "#" + monthLabelId ).attr( "role" ), "alert", + assert.equal( this.element.find( "#" + monthLabelId ).attr( "role" ), "status", "Header month label role attribute" ); assert.equal( table.attr( "role" ), "grid", "Table role attribute" ); diff --git a/ui/widgets/calendar.js b/ui/widgets/calendar.js index 6e907ea0b8e..150b11eef23 100644 --- a/ui/widgets/calendar.js +++ b/ui/widgets/calendar.js @@ -367,7 +367,7 @@ return $.widget( "ui.calendar", { }, _buildTitle: function() { - var title = $( "
", { role: "alert", id: this._getGridId() + "-month-label" } ), + var title = $( "
", { role: "status", id: this._getGridId() + "-month-label" } ), month = this._buildTitleMonth(), year = this._buildTitleYear(); From bba2ac3a318f0ec4bacd6af258423d07c5ef4bc7 Mon Sep 17 00:00:00 2001 From: Felix Nagel Date: Sat, 26 Aug 2017 14:33:48 +0200 Subject: [PATCH 4/7] Calendar: make sure cell attributes change when day is selected --- ui/widgets/calendar.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/widgets/calendar.js b/ui/widgets/calendar.js index 150b11eef23..64c33d7f8ee 100644 --- a/ui/widgets/calendar.js +++ b/ui/widgets/calendar.js @@ -230,6 +230,9 @@ return $.widget( "ui.calendar", { this._removeClass( this.grid.find( "button." + state ), null, state ); this._addClass( button, null, state ); + this.grid.find( "td" ).attr( "aria-selected", false ); + button.parent( "td" ).attr( "aria-selected", true ); + return button; }, From 7f667063e4299764f202b33966fcd40261b9995c Mon Sep 17 00:00:00 2001 From: Felix Nagel Date: Sat, 26 Aug 2017 14:43:26 +0200 Subject: [PATCH 5/7] Calendar: Use aria pressed on button instead of aria-selected on cell --- tests/unit/calendar/methods.js | 8 ++++++-- ui/widgets/calendar.js | 20 +++++++++++--------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/tests/unit/calendar/methods.js b/tests/unit/calendar/methods.js index c0948244057..81880f58420 100644 --- a/tests/unit/calendar/methods.js +++ b/tests/unit/calendar/methods.js @@ -48,12 +48,16 @@ QUnit.test( "widget", function( assert ) { } ); QUnit.test( "value", function( assert ) { - assert.expect( 3 ); + assert.expect( 4 ); this.element.calendar( "value", "1/1/14" ); assert.ok( this.element.find( "button[data-ui-calendar-timestamp]:first" ) .hasClass( "ui-state-active" ), - "first day marked as selected" + "first day marked as selected (class)" + ); + assert.equal( this.element.find( "button[data-ui-calendar-timestamp]:first" ) + .attr( "aria-pressed" ), "true", + "first day marked as selected (attribute)" ); assert.equal( this.element.calendar( "value" ), "1/1/14", "getter" ); diff --git a/ui/widgets/calendar.js b/ui/widgets/calendar.js index 64c33d7f8ee..80fd39cdabd 100644 --- a/ui/widgets/calendar.js +++ b/ui/widgets/calendar.js @@ -227,11 +227,13 @@ return $.widget( "ui.calendar", { this.grid.attr( "aria-activedescendant", id ); - this._removeClass( this.grid.find( "button." + state ), null, state ); + this._removeClass( + this.grid.find( "button." + state ).attr( "aria-pressed", false ), + null, + state + ); this._addClass( button, null, state ); - - this.grid.find( "td" ).attr( "aria-selected", false ); - button.parent( "td" ).attr( "aria-selected", true ); + button.attr( "aria-pressed", true ); return button; }, @@ -464,9 +466,7 @@ return $.widget( "ui.calendar", { _buildDayCell: function( day ) { var content = "", dateObject = new Date( day.timestamp ), - attributes = [ - "aria-selected='" + ( this._isCurrent( day ) ? true : false ) + "'" - ], + attributes = [], selectable = ( day.selectable && this._isValid( dateObject ) ); if ( day.render ) { @@ -491,12 +491,13 @@ return $.widget( "ui.calendar", { _buildDayElement: function( day, selectable ) { var attributes, content, - classes = [ "ui-state-default" ]; + classes = [ "ui-state-default" ], + current = this._isCurrent( day ); if ( day === this._getDate() && selectable ) { classes.push( "ui-state-focus" ); } - if ( this._isCurrent( day ) ) { + if ( current ) { classes.push( "ui-state-active" ); } if ( day.today ) { @@ -509,6 +510,7 @@ return $.widget( "ui.calendar", { attributes = " class='" + classes.join( " " ) + "'"; if ( selectable ) { attributes += " tabindex='-1' data-ui-calendar-timestamp='" + day.timestamp + "'"; + attributes += "aria-pressed='" + ( current ? true : false ) + "'"; } else { attributes += " disabled='disabled'"; } From 968372536d12ccc04177f003ba33cb735f645a61 Mon Sep 17 00:00:00 2001 From: Felix Nagel Date: Sat, 26 Aug 2017 14:47:08 +0200 Subject: [PATCH 6/7] Calendar: Remove aria-pressed attribute from inactive buttons This will improve the experience for screen reader users, since the role of the button will be spoken as "button", rather than "toggle button". --- ui/widgets/calendar.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/widgets/calendar.js b/ui/widgets/calendar.js index 80fd39cdabd..d9781bfcc48 100644 --- a/ui/widgets/calendar.js +++ b/ui/widgets/calendar.js @@ -228,7 +228,7 @@ return $.widget( "ui.calendar", { this.grid.attr( "aria-activedescendant", id ); this._removeClass( - this.grid.find( "button." + state ).attr( "aria-pressed", false ), + this.grid.find( "button." + state ).removeAttr( "aria-pressed" ), null, state ); @@ -490,7 +490,8 @@ return $.widget( "ui.calendar", { }, _buildDayElement: function( day, selectable ) { - var attributes, content, + var content, + attributes = "", classes = [ "ui-state-default" ], current = this._isCurrent( day ); @@ -499,6 +500,7 @@ return $.widget( "ui.calendar", { } if ( current ) { classes.push( "ui-state-active" ); + attributes += " aria-pressed='true'"; } if ( day.today ) { classes.push( "ui-state-highlight" ); @@ -507,10 +509,9 @@ return $.widget( "ui.calendar", { classes.push( day.extraClasses.split( " " ) ); } - attributes = " class='" + classes.join( " " ) + "'"; + attributes += " class='" + classes.join( " " ) + "'"; if ( selectable ) { attributes += " tabindex='-1' data-ui-calendar-timestamp='" + day.timestamp + "'"; - attributes += "aria-pressed='" + ( current ? true : false ) + "'"; } else { attributes += " disabled='disabled'"; } From 020e26111108c582b17134630b4d09fb316961d8 Mon Sep 17 00:00:00 2001 From: Felix Nagel Date: Sat, 26 Aug 2017 14:59:32 +0200 Subject: [PATCH 7/7] Datepicker: Do not open popup when input receives initial focus --- tests/unit/datepicker/core.js | 4 ++-- ui/widgets/datepicker.js | 19 +------------------ 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/tests/unit/datepicker/core.js b/tests/unit/datepicker/core.js index ebbfa060994..934b8714c88 100644 --- a/tests/unit/datepicker/core.js +++ b/tests/unit/datepicker/core.js @@ -35,7 +35,7 @@ QUnit.test( "base structure", function( assert ) { var that = this; - this.element.focus(); + this.element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); setTimeout( function() { assert.ok( that.widget.is( ":visible" ), "Datepicker visible" ); @@ -59,7 +59,7 @@ QUnit.test( "Keyboard handling: focus", function( assert ) { this.element.focus(); setTimeout( function() { - assert.ok( that.widget.is( ":visible" ), "Datepicker opens when receiving focus" ); + assert.ok( !that.widget.is( ":visible" ), "Datepicker keeps closed when receiving focus" ); ready(); }, 100 ); } ); diff --git a/ui/widgets/datepicker.js b/ui/widgets/datepicker.js index 48926ff72b4..a3a7940991a 100644 --- a/ui/widgets/datepicker.js +++ b/ui/widgets/datepicker.js @@ -63,7 +63,6 @@ var widget = $.widget( "ui.datepicker", { "icons", "labels", "locale", "max", "min", "numberOfMonths", "showWeek", "refresh" ], _create: function() { - this.suppressExpandOnFocus = false; this._parse = new Globalize( this.options.locale ).dateParser( this.options.dateFormat ); if ( $.type( this.options.max ) === "string" ) { @@ -165,28 +164,13 @@ var widget = $.widget( "ui.datepicker", { this.refresh(); } }, - mousedown: function( event ) { + mousedown: function() { if ( this.isOpen ) { - this.suppressExpandOnFocus = true; this.close(); return; } - this.open( event ); clearTimeout( this.closeTimer ); }, - focus: function( event ) { - if ( !this.suppressExpandOnFocus && !this.isOpen ) { - this._delay( function() { - this.open( event ); - } ); - } - this._delay( function() { - this.suppressExpandOnFocus = false; - }, 100 ); - }, - blur: function() { - this.suppressExpandOnFocus = false; - }, change: function( event ) { this._trigger( "change", event, { value: this.calendarInstance.valueAsDate() @@ -265,7 +249,6 @@ var widget = $.widget( "ui.datepicker", { }, _focusTrigger: function() { - this.suppressExpandOnFocus = true; this.element.focus(); },