Bug 977267 - [a11y] Make autocomplete suggestions accessible to screen readers. r=bgrins

This commit is contained in:
James Teh 2014-08-29 11:36:50 +10:00
parent d35a5f8704
commit b333c262f8
3 changed files with 47 additions and 1 deletions

View File

@ -65,6 +65,8 @@ function AutocompletePopup(aDocument, aOptions = {})
if (!aOptions.onKeypress) {
this._panel.setAttribute("ignorekeys", "true");
}
// Stop this appearing as an alert to accessibility.
this._panel.setAttribute("role", "presentation");
let mainPopupSet = this._document.getElementById("mainPopupSet");
if (mainPopupSet) {
@ -106,6 +108,7 @@ function AutocompletePopup(aDocument, aOptions = {})
if (this.onKeypress) {
this._list.addEventListener("keypress", this.onKeypress, false);
}
this._itemIdCounter = 0;
}
exports.AutocompletePopup = AutocompletePopup;
@ -148,6 +151,8 @@ AutocompletePopup.prototype = {
*/
hidePopup: function AP_hidePopup()
{
// Return accessibility focus to the input.
this._document.activeElement.removeAttribute("aria-activedescendant");
this._panel.hidePopup();
},
@ -295,6 +300,23 @@ AutocompletePopup.prototype = {
this._list.ensureIndexIsVisible(this._list.selectedIndex);
},
/**
* Update accessibility appropriately when the selected item is changed.
*
* @private
*/
_updateAriaActiveDescendant: function AP__updateAriaActiveDescendant()
{
if (!this._list.selectedItem) {
// Return accessibility focus to the input.
this._document.activeElement.removeAttribute("aria-activedescendant");
return;
}
// Focus this for accessibility so users know about the selected item.
this._document.activeElement.setAttribute("aria-activedescendant",
this._list.selectedItem.id);
},
/**
* Clear all the items from the autocomplete list.
*/
@ -340,6 +362,7 @@ AutocompletePopup.prototype = {
if (this.isOpen && this._list.ensureIndexIsVisible) {
this._list.ensureIndexIsVisible(this._list.selectedIndex);
}
this._updateAriaActiveDescendant();
},
/**
@ -362,6 +385,7 @@ AutocompletePopup.prototype = {
if (this.isOpen) {
this._list.ensureIndexIsVisible(this._list.selectedIndex);
}
this._updateAriaActiveDescendant();
},
/**
@ -383,6 +407,8 @@ AutocompletePopup.prototype = {
appendItem: function AP_appendItem(aItem)
{
let listItem = this._document.createElementNS(XUL_NS, "richlistitem");
// Items must have an id for accessibility.
listItem.id = this._panel.id + "_item_" + this._itemIdCounter++;
if (this.direction) {
listItem.setAttribute("dir", this.direction);
}

View File

@ -22,7 +22,14 @@ function consoleOpened(HUD) {
let popup = HUD.jsterm.autocompletePopup;
let input = popup._document.activeElement;
function getActiveDescendant() {
return input.ownerDocument.getElementById(
input.getAttribute("aria-activedescendant"));
}
ok(!popup.isOpen, "popup is not open");
ok(!input.hasAttribute("aria-activedescendant"), "no aria-activedescendant");
popup._panel.addEventListener("popupshown", function() {
popup._panel.removeEventListener("popupshown", arguments.callee, false);
@ -30,6 +37,8 @@ function consoleOpened(HUD) {
ok(popup.isOpen, "popup is open");
is(popup.itemCount, 0, "no items");
ok(!input.hasAttribute("aria-activedescendant"),
"no aria-activedescendant");
popup.setItems(items);
@ -43,31 +52,37 @@ function consoleOpened(HUD) {
is(popup.selectedIndex, 2,
"Index of the first item from bottom is selected.");
is(popup.selectedItem, items[2], "First item from bottom is selected");
ok(getActiveDescendant().selected, "aria-activedescendant is correct");
popup.selectedIndex = 1;
is(popup.selectedIndex, 1, "index 1 is selected");
is(popup.selectedItem, items[1], "item1 is selected");
ok(getActiveDescendant().selected, "aria-activedescendant is correct");
popup.selectedItem = items[2];
is(popup.selectedIndex, 2, "index 2 is selected");
is(popup.selectedItem, items[2], "item2 is selected");
ok(getActiveDescendant().selected, "aria-activedescendant is correct");
is(popup.selectPreviousItem(), items[1], "selectPreviousItem() works");
is(popup.selectedIndex, 1, "index 1 is selected");
is(popup.selectedItem, items[1], "item1 is selected");
ok(getActiveDescendant().selected, "aria-activedescendant is correct");
is(popup.selectNextItem(), items[2], "selectPreviousItem() works");
is(popup.selectedIndex, 2, "index 2 is selected");
is(popup.selectedItem, items[2], "item2 is selected");
ok(getActiveDescendant().selected, "aria-activedescendant is correct");
ok(popup.selectNextItem(), "selectPreviousItem() works");
is(popup.selectedIndex, 0, "index 0 is selected");
is(popup.selectedItem, items[0], "item0 is selected");
ok(getActiveDescendant().selected, "aria-activedescendant is correct");
items.push({label: "label3", value: "value3"});
popup.appendItem(items[3]);
@ -76,15 +91,19 @@ function consoleOpened(HUD) {
popup.selectedIndex = 3;
is(popup.selectedItem, items[3], "item3 is selected");
ok(getActiveDescendant().selected, "aria-activedescendant is correct");
popup.removeItem(items[2]);
is(popup.selectedIndex, 2, "index2 is selected");
is(popup.selectedItem, items[3], "item3 is still selected");
ok(getActiveDescendant().selected, "aria-activedescendant is correct");
is(popup.itemCount, items.length - 1, "item2 removed");
popup.clearItems();
is(popup.itemCount, 0, "items cleared");
ok(!input.hasAttribute("aria-activedescendant"),
"no aria-activedescendant");
popup.hidePopup();
finishTest();

View File

@ -183,7 +183,8 @@ function goUpdateConsoleCommands() {
<textbox class="jsterm-complete-node devtools-monospace"
multiline="true" rows="1" tabindex="-1"/>
<textbox class="jsterm-input-node devtools-monospace"
multiline="true" rows="1" tabindex="0"/>
multiline="true" rows="1" tabindex="0"
aria-autocomplete="list"/>
</stack>
</hbox>
</notificationbox>