VolkerE has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/349135 )

Change subject: SelectWidget/MenuSelectWidget: Maintain `aria-activedescendant` 
attribute on focus owner
......................................................................


SelectWidget/MenuSelectWidget: Maintain `aria-activedescendant` attribute on 
focus owner

Our SelectWidget does not allow individual OptionWidgets to have
focus. Instead, it keeps track internally of which of the options
really is active (e.g. which option arrow navigation is relative to,
or which option will be selected if the user presses the enter key).
This makes some implementation details a bit easier.

However, it means we have to somehow inform assistive technology about
the currently active option, since they can't guess it from the focus.
This is done by setting `aria-activedescendant` on the DOM element
which actually has focus (the focus owner).

This is made a little more complicated because the SelectWidget can
stand on its own (e.g. RadioSelectWidget), in which case it is the
focus owner itself, or it can be a part of a larger widget (e.g.
MenuSelectWidget/DropdownInputWidget), in which case the focus owner
is usually somewhere else.

As a bonus, SelectWidget will now move focus to the focus owner when
one of its options is focussed. The only situation where this makes a
difference is when a MenuOptionWidget is focussed through its accesskey.

Bug: T149654
Change-Id: Ie993345e44ddb43dfbe2bebe0e12fd2bd9f5812e
---
M src/widgets/MenuSelectWidget.js
M src/widgets/SelectWidget.js
M tests/QUnit.assert.equalDomElement.js
3 files changed, 44 insertions(+), 10 deletions(-)

Approvals:
  jenkins-bot: Verified
  VolkerE: Looks good to me, approved



diff --git a/src/widgets/MenuSelectWidget.js b/src/widgets/MenuSelectWidget.js
index de8d457..8533f96 100644
--- a/src/widgets/MenuSelectWidget.js
+++ b/src/widgets/MenuSelectWidget.js
@@ -65,6 +65,9 @@
 
        // Initialization
        this.$element.addClass( 'oo-ui-menuSelectWidget' );
+       if ( config.widget ) {
+               this.setFocusOwner( config.widget.$tabIndexed );
+       }
 
        // Initially hidden - using #toggle may cause errors if subclasses 
override toggle with methods
        // that reference properties not initialized at that time of parent 
class construction
@@ -320,6 +323,7 @@
                        this.toggleClipping( true );
 
                        if ( this.getSelectedItem() ) {
+                               this.$focusOwner.attr( 'aria-activedescendant', 
this.getSelectedItem().getElementId() );
                                this.getSelectedItem().scrollElementIntoView( { 
duration: 0 } );
                        }
 
@@ -328,6 +332,7 @@
                                this.getElementDocument().addEventListener( 
'mousedown', this.onDocumentMouseDownHandler, true );
                        }
                } else {
+                       this.$focusOwner.removeAttr( 'aria-activedescendant' );
                        this.unbindKeyDownListener();
                        this.unbindKeyPressListener();
                        this.getElementDocument().removeEventListener( 
'mousedown', this.onDocumentMouseDownHandler, true );
diff --git a/src/widgets/SelectWidget.js b/src/widgets/SelectWidget.js
index 444a63e..46bc3ac 100644
--- a/src/widgets/SelectWidget.js
+++ b/src/widgets/SelectWidget.js
@@ -77,6 +77,7 @@
        this.$element
                .addClass( 'oo-ui-selectWidget oo-ui-selectWidget-depressed' )
                .attr( 'role', 'listbox' );
+       this.setFocusOwner( this.$element );
        if ( Array.isArray( config.items ) ) {
                this.addItems( config.items );
        }
@@ -169,7 +170,7 @@
        }
 
        if ( event.target !== this.$element[ 0 ] ) {
-               this.$element.focus();
+               this.$focusOwner.focus();
        }
 };
 
@@ -583,6 +584,11 @@
                }
        }
        if ( changed ) {
+               if ( item ) {
+                       this.$focusOwner.attr( 'aria-activedescendant', 
item.getElementId() );
+               } else {
+                       this.$focusOwner.removeAttr( 'aria-activedescendant' );
+               }
                this.emit( 'highlight', item );
        }
 
@@ -681,6 +687,13 @@
                }
        }
        if ( changed ) {
+               if ( item && !item.constructor.static.highlightable ) {
+                       if ( item ) {
+                               this.$focusOwner.attr( 'aria-activedescendant', 
item.getElementId() );
+                       } else {
+                               this.$focusOwner.removeAttr( 
'aria-activedescendant' );
+                       }
+               }
                this.emit( 'select', item );
        }
 
@@ -856,3 +869,15 @@
 
        return this;
 };
+
+/**
+ * Set the DOM element which has focus while the user is interacting with this 
SelectWidget.
+ *
+ * Currently this is just used to set `aria-activedescendant` on it.
+ *
+ * @protected
+ * @param {jQuery} $focusOwner
+ */
+OO.ui.SelectWidget.prototype.setFocusOwner = function ( $focusOwner ) {
+       this.$focusOwner = $focusOwner;
+};
diff --git a/tests/QUnit.assert.equalDomElement.js 
b/tests/QUnit.assert.equalDomElement.js
index 8d69f23..e406748 100644
--- a/tests/QUnit.assert.equalDomElement.js
+++ b/tests/QUnit.assert.equalDomElement.js
@@ -32,6 +32,7 @@
                                attributes: {},
                                children: []
                        },
+                       autogeneratedAttributes = [ 'id', 'for', 'aria-owns', 
'aria-activedescendant' ],
                        // This is used to gather certain properties and 
pretend they are attributes.
                        // Take note of casing differences.
                        propertyAttributes = {
@@ -83,17 +84,20 @@
 
                // Filter out acceptable differences between OOjs UI's PHP 
widgets and JS widgets
                // Automatically generated IDs (Tag::generateElementId(), 
OO.ui.generateElementId())
-               if ( summary.attributes.id !== undefined && 
summary.attributes.id.match( /^(ooui-|oojsui-)/ ) ) {
+               for ( i = 0; i < autogeneratedAttributes.length; i++ ) {
+                       attribute = autogeneratedAttributes[ i ];
+                       if (
+                               summary.attributes[ attribute ] !== undefined &&
+                               summary.attributes[ attribute ].match( 
/^(ooui-|oojsui-)/ )
+                       ) {
+                               summary.attributes[ attribute ] = 
'(autogenerated)';
+                       }
+               }
+               if ( summary.attributes.id === '(autogenerated)' ) {
                        // The 'id' might be missing on the JS side, while PHP 
always generates them for infusion.
+                       // For other attributes using autogenerated ids, the 
value might differ, but the attribute
+                       // should be either present in both PHP and JS, or 
missing in both PHP and JS.
                        delete summary.attributes.id;
-               }
-               // For other attributes using autogenerated ids, the value 
might differ, but the attribute
-               // should be either present in both PHP and JS, or missing in 
both PHP and JS.
-               if ( summary.attributes.for !== undefined && 
summary.attributes.for.match( /^(ooui-|oojsui-)/ ) ) {
-                       summary.attributes.for = '(autogenerated)';
-               }
-               if ( summary.attributes[ 'aria-owns' ] !== undefined && 
summary.attributes[ 'aria-owns' ].match( /^(ooui-|oojsui-)/ ) ) {
-                       summary.attributes[ 'aria-owns' ] = '(autogenerated)';
                }
                // Infusion data
                if ( summary.attributes[ 'data-ooui' ] !== undefined ) {

-- 
To view, visit https://gerrit.wikimedia.org/r/349135
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ie993345e44ddb43dfbe2bebe0e12fd2bd9f5812e
Gerrit-PatchSet: 6
Gerrit-Project: oojs/ui
Gerrit-Branch: master
Gerrit-Owner: Bartosz DziewoƄski <matma....@gmail.com>
Gerrit-Reviewer: TheDJ <hartman.w...@gmail.com>
Gerrit-Reviewer: VolkerE <volke...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to