1
0
mirror of synced 2024-11-22 21:16:10 +03:00

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.
This commit is contained in:
Kevin Brown 2014-10-19 20:40:45 -04:00
parent 7c8601d33b
commit cdfa0499f4
11 changed files with 112 additions and 62 deletions

View File

@ -110,9 +110,9 @@
.select2-container.select2-theme-default .dropdown .results > .options { .select2-container.select2-theme-default .dropdown .results > .options {
max-height: 200px; max-height: 200px;
overflow-y: auto; } 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; } 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; cursor: default;
display: block; display: block;
padding: 6px; } padding: 6px; }

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

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

File diff suppressed because one or more lines are too long

28
dist/js/select2.js vendored
View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

@ -48,13 +48,14 @@ define([
}); });
container.on('open', function () { 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'); self.$selection.attr('aria-expanded', 'true');
}); });
container.on('close', function () { 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.attr('aria-expanded', 'false');
self.$selection.removeAttr('aria-activedescendant');
}); });
this.$selection.on('focus', function (evt) { this.$selection.on('focus', function (evt) {
@ -123,10 +124,6 @@ define([
var formatted = this.display(selection); var formatted = this.display(selection);
this.$selection.find('.rendered-selection').html(formatted); this.$selection.find('.rendered-selection').html(formatted);
if (data[0]._resultId != null) {
this.$selection.attr('aria-activedescendant', data[0]._resultId);
}
}; };
return SingleSelection; return SingleSelection;

View File

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