Bläddra i källkod

Accessibility matches better

Now the accessibility for the single select box better matches what
is picked up for a native select.

This fixes an issue with us always setting `aria-activedescendant`,
which caused Orca to always say the full path to the selected
result, instead of saying that the box was a combobox with a
selection. This means that the `aria-activedescendant` attribute
will now only be set when the dropdown is open.

This also switches the results list from a listbox to a tree, which
is what Firefox tells screen readers that a standard select is.
Combined with a change to use `role=group` and `aria-label` for
option group labels, screen readers will now announce the group
that they are in as well.
Kevin Brown 10 år sedan
förälder
incheckning
cdfa0499f4

+ 2 - 2
dist/css/select2.css

@@ -110,9 +110,9 @@
 .select2-container.select2-theme-default .dropdown .results > .options {
   max-height: 200px;
   overflow-y: auto; }
-.select2-container.select2-theme-default .dropdown .results .options .option.group {
+.select2-container.select2-theme-default .dropdown .results .options .option[role=group] {
   padding: 0; }
-  .select2-container.select2-theme-default .dropdown .results .options .option.group .group-label {
+  .select2-container.select2-theme-default .dropdown .results .options .option[role=group] .group-label {
     cursor: default;
     display: block;
     padding: 6px; }

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
dist/css/select2.min.css


+ 21 - 11
dist/js/select2.amd.full.js

@@ -163,7 +163,7 @@ define('select2/results',[
 
   Results.prototype.render = function () {
     var $results = $(
-      '<ul class="options" role="listbox"></ul>'
+      '<ul class="options" role="tree"></ul>'
     );
 
     if (this.options.get('multiple')) {
@@ -236,12 +236,13 @@ define('select2/results',[
 
   Results.prototype.option = function (data) {
     var $option = $(
-      '<li class="option" role="option" aria-selected="false"></li>'
+      '<li class="option" role="treeitem" aria-selected="false"></li>'
     );
 
     if (data.children) {
       $option
-        .addClass('group')
+        .attr('role', 'group')
+        .attr('aria-label', data.text)
         .removeAttr('aria-selected');
 
       var $label = $('<strong class="group-label"></strong>');
@@ -297,20 +298,32 @@ define('select2/results',[
       self.clear();
       self.append(params.data);
 
-      self.setClasses();
+      if (container.isOpen()) {
+        self.setClasses();
+      }
     });
 
     container.on('results:append', function (params) {
       self.append(params.data);
 
-      self.setClasses();
+      if (container.isOpen()) {
+        self.setClasses();
+      }
     });
 
     container.on('select', function () {
+      if (!container.isOpen()) {
+        return;
+      }
+
       self.setClasses();
     });
 
     container.on('unselect', function () {
+      if (!container.isOpen()) {
+        return;
+      }
+
       self.setClasses();
     });
 
@@ -580,13 +593,14 @@ define('select2/selection/single',[
     });
 
     container.on('open', function () {
-      // When the dropdown is open, aria-expended="true"
+      // When the dropdown is open, aria-expanded="true"
       self.$selection.attr('aria-expanded', 'true');
     });
 
     container.on('close', function () {
-      // When the dropdown is closed, aria-expended="false"
+      // When the dropdown is closed, aria-expanded="false"
       self.$selection.attr('aria-expanded', 'false');
+      self.$selection.removeAttr('aria-activedescendant');
     });
 
     this.$selection.on('focus', function (evt) {
@@ -655,10 +669,6 @@ define('select2/selection/single',[
     var formatted = this.display(selection);
 
     this.$selection.find('.rendered-selection').html(formatted);
-
-    if (data[0]._resultId != null) {
-      this.$selection.attr('aria-activedescendant', data[0]._resultId);
-    }
   };
 
   return SingleSelection;

+ 21 - 11
dist/js/select2.amd.js

@@ -163,7 +163,7 @@ define('select2/results',[
 
   Results.prototype.render = function () {
     var $results = $(
-      '<ul class="options" role="listbox"></ul>'
+      '<ul class="options" role="tree"></ul>'
     );
 
     if (this.options.get('multiple')) {
@@ -236,12 +236,13 @@ define('select2/results',[
 
   Results.prototype.option = function (data) {
     var $option = $(
-      '<li class="option" role="option" aria-selected="false"></li>'
+      '<li class="option" role="treeitem" aria-selected="false"></li>'
     );
 
     if (data.children) {
       $option
-        .addClass('group')
+        .attr('role', 'group')
+        .attr('aria-label', data.text)
         .removeAttr('aria-selected');
 
       var $label = $('<strong class="group-label"></strong>');
@@ -297,20 +298,32 @@ define('select2/results',[
       self.clear();
       self.append(params.data);
 
-      self.setClasses();
+      if (container.isOpen()) {
+        self.setClasses();
+      }
     });
 
     container.on('results:append', function (params) {
       self.append(params.data);
 
-      self.setClasses();
+      if (container.isOpen()) {
+        self.setClasses();
+      }
     });
 
     container.on('select', function () {
+      if (!container.isOpen()) {
+        return;
+      }
+
       self.setClasses();
     });
 
     container.on('unselect', function () {
+      if (!container.isOpen()) {
+        return;
+      }
+
       self.setClasses();
     });
 
@@ -580,13 +593,14 @@ define('select2/selection/single',[
     });
 
     container.on('open', function () {
-      // When the dropdown is open, aria-expended="true"
+      // When the dropdown is open, aria-expanded="true"
       self.$selection.attr('aria-expanded', 'true');
     });
 
     container.on('close', function () {
-      // When the dropdown is closed, aria-expended="false"
+      // When the dropdown is closed, aria-expanded="false"
       self.$selection.attr('aria-expanded', 'false');
+      self.$selection.removeAttr('aria-activedescendant');
     });
 
     this.$selection.on('focus', function (evt) {
@@ -655,10 +669,6 @@ define('select2/selection/single',[
     var formatted = this.display(selection);
 
     this.$selection.find('.rendered-selection').html(formatted);
-
-    if (data[0]._resultId != null) {
-      this.$selection.attr('aria-activedescendant', data[0]._resultId);
-    }
   };
 
   return SingleSelection;

+ 21 - 11
dist/js/select2.full.js

@@ -9701,7 +9701,7 @@ define('select2/results',[
 
   Results.prototype.render = function () {
     var $results = $(
-      '<ul class="options" role="listbox"></ul>'
+      '<ul class="options" role="tree"></ul>'
     );
 
     if (this.options.get('multiple')) {
@@ -9774,12 +9774,13 @@ define('select2/results',[
 
   Results.prototype.option = function (data) {
     var $option = $(
-      '<li class="option" role="option" aria-selected="false"></li>'
+      '<li class="option" role="treeitem" aria-selected="false"></li>'
     );
 
     if (data.children) {
       $option
-        .addClass('group')
+        .attr('role', 'group')
+        .attr('aria-label', data.text)
         .removeAttr('aria-selected');
 
       var $label = $('<strong class="group-label"></strong>');
@@ -9835,20 +9836,32 @@ define('select2/results',[
       self.clear();
       self.append(params.data);
 
-      self.setClasses();
+      if (container.isOpen()) {
+        self.setClasses();
+      }
     });
 
     container.on('results:append', function (params) {
       self.append(params.data);
 
-      self.setClasses();
+      if (container.isOpen()) {
+        self.setClasses();
+      }
     });
 
     container.on('select', function () {
+      if (!container.isOpen()) {
+        return;
+      }
+
       self.setClasses();
     });
 
     container.on('unselect', function () {
+      if (!container.isOpen()) {
+        return;
+      }
+
       self.setClasses();
     });
 
@@ -10118,13 +10131,14 @@ define('select2/selection/single',[
     });
 
     container.on('open', function () {
-      // When the dropdown is open, aria-expended="true"
+      // When the dropdown is open, aria-expanded="true"
       self.$selection.attr('aria-expanded', 'true');
     });
 
     container.on('close', function () {
-      // When the dropdown is closed, aria-expended="false"
+      // When the dropdown is closed, aria-expanded="false"
       self.$selection.attr('aria-expanded', 'false');
+      self.$selection.removeAttr('aria-activedescendant');
     });
 
     this.$selection.on('focus', function (evt) {
@@ -10193,10 +10207,6 @@ define('select2/selection/single',[
     var formatted = this.display(selection);
 
     this.$selection.find('.rendered-selection').html(formatted);
-
-    if (data[0]._resultId != null) {
-      this.$selection.attr('aria-activedescendant', data[0]._resultId);
-    }
   };
 
   return SingleSelection;

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
dist/js/select2.full.min.js


+ 21 - 11
dist/js/select2.js

@@ -592,7 +592,7 @@ define('select2/results',[
 
   Results.prototype.render = function () {
     var $results = $(
-      '<ul class="options" role="listbox"></ul>'
+      '<ul class="options" role="tree"></ul>'
     );
 
     if (this.options.get('multiple')) {
@@ -665,12 +665,13 @@ define('select2/results',[
 
   Results.prototype.option = function (data) {
     var $option = $(
-      '<li class="option" role="option" aria-selected="false"></li>'
+      '<li class="option" role="treeitem" aria-selected="false"></li>'
     );
 
     if (data.children) {
       $option
-        .addClass('group')
+        .attr('role', 'group')
+        .attr('aria-label', data.text)
         .removeAttr('aria-selected');
 
       var $label = $('<strong class="group-label"></strong>');
@@ -726,20 +727,32 @@ define('select2/results',[
       self.clear();
       self.append(params.data);
 
-      self.setClasses();
+      if (container.isOpen()) {
+        self.setClasses();
+      }
     });
 
     container.on('results:append', function (params) {
       self.append(params.data);
 
-      self.setClasses();
+      if (container.isOpen()) {
+        self.setClasses();
+      }
     });
 
     container.on('select', function () {
+      if (!container.isOpen()) {
+        return;
+      }
+
       self.setClasses();
     });
 
     container.on('unselect', function () {
+      if (!container.isOpen()) {
+        return;
+      }
+
       self.setClasses();
     });
 
@@ -1009,13 +1022,14 @@ define('select2/selection/single',[
     });
 
     container.on('open', function () {
-      // When the dropdown is open, aria-expended="true"
+      // When the dropdown is open, aria-expanded="true"
       self.$selection.attr('aria-expanded', 'true');
     });
 
     container.on('close', function () {
-      // When the dropdown is closed, aria-expended="false"
+      // When the dropdown is closed, aria-expanded="false"
       self.$selection.attr('aria-expanded', 'false');
+      self.$selection.removeAttr('aria-activedescendant');
     });
 
     this.$selection.on('focus', function (evt) {
@@ -1084,10 +1098,6 @@ define('select2/selection/single',[
     var formatted = this.display(selection);
 
     this.$selection.find('.rendered-selection').html(formatted);
-
-    if (data[0]._resultId != null) {
-      this.$selection.attr('aria-activedescendant', data[0]._resultId);
-    }
   };
 
   return SingleSelection;

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
dist/js/select2.min.js


+ 18 - 5
src/js/select2/results.js

@@ -13,7 +13,7 @@ define([
 
   Results.prototype.render = function () {
     var $results = $(
-      '<ul class="options" role="listbox"></ul>'
+      '<ul class="options" role="tree"></ul>'
     );
 
     if (this.options.get('multiple')) {
@@ -86,12 +86,13 @@ define([
 
   Results.prototype.option = function (data) {
     var $option = $(
-      '<li class="option" role="option" aria-selected="false"></li>'
+      '<li class="option" role="treeitem" aria-selected="false"></li>'
     );
 
     if (data.children) {
       $option
-        .addClass('group')
+        .attr('role', 'group')
+        .attr('aria-label', data.text)
         .removeAttr('aria-selected');
 
       var $label = $('<strong class="group-label"></strong>');
@@ -147,20 +148,32 @@ define([
       self.clear();
       self.append(params.data);
 
-      self.setClasses();
+      if (container.isOpen()) {
+        self.setClasses();
+      }
     });
 
     container.on('results:append', function (params) {
       self.append(params.data);
 
-      self.setClasses();
+      if (container.isOpen()) {
+        self.setClasses();
+      }
     });
 
     container.on('select', function () {
+      if (!container.isOpen()) {
+        return;
+      }
+
       self.setClasses();
     });
 
     container.on('unselect', function () {
+      if (!container.isOpen()) {
+        return;
+      }
+
       self.setClasses();
     });
 

+ 3 - 6
src/js/select2/selection/single.js

@@ -48,13 +48,14 @@ define([
     });
 
     container.on('open', function () {
-      // When the dropdown is open, aria-expended="true"
+      // When the dropdown is open, aria-expanded="true"
       self.$selection.attr('aria-expanded', 'true');
     });
 
     container.on('close', function () {
-      // When the dropdown is closed, aria-expended="false"
+      // When the dropdown is closed, aria-expanded="false"
       self.$selection.attr('aria-expanded', 'false');
+      self.$selection.removeAttr('aria-activedescendant');
     });
 
     this.$selection.on('focus', function (evt) {
@@ -123,10 +124,6 @@ define([
     var formatted = this.display(selection);
 
     this.$selection.find('.rendered-selection').html(formatted);
-
-    if (data[0]._resultId != null) {
-      this.$selection.attr('aria-activedescendant', data[0]._resultId);
-    }
   };
 
   return SingleSelection;

+ 1 - 1
src/scss/theme/default/layout.scss

@@ -85,7 +85,7 @@
 
       .options {
         .option {
-          &.group {
+          &[role=group] {
             padding: 0;
 
             .group-label {

Vissa filer visades inte eftersom för många filer har ändrats