зеркало из https://github.com/mozilla/gecko-dev.git
Bug 977267 - [a11y] Make autocomplete suggestions accessible to screen readers. r=bgrins
This commit is contained in:
Родитель
f3188bd805
Коммит
ee9e873e22
|
@ -65,6 +65,8 @@ function AutocompletePopup(aDocument, aOptions = {})
|
||||||
if (!aOptions.onKeypress) {
|
if (!aOptions.onKeypress) {
|
||||||
this._panel.setAttribute("ignorekeys", "true");
|
this._panel.setAttribute("ignorekeys", "true");
|
||||||
}
|
}
|
||||||
|
// Stop this appearing as an alert to accessibility.
|
||||||
|
this._panel.setAttribute("role", "presentation");
|
||||||
|
|
||||||
let mainPopupSet = this._document.getElementById("mainPopupSet");
|
let mainPopupSet = this._document.getElementById("mainPopupSet");
|
||||||
if (mainPopupSet) {
|
if (mainPopupSet) {
|
||||||
|
@ -106,6 +108,7 @@ function AutocompletePopup(aDocument, aOptions = {})
|
||||||
if (this.onKeypress) {
|
if (this.onKeypress) {
|
||||||
this._list.addEventListener("keypress", this.onKeypress, false);
|
this._list.addEventListener("keypress", this.onKeypress, false);
|
||||||
}
|
}
|
||||||
|
this._itemIdCounter = 0;
|
||||||
}
|
}
|
||||||
exports.AutocompletePopup = AutocompletePopup;
|
exports.AutocompletePopup = AutocompletePopup;
|
||||||
|
|
||||||
|
@ -148,6 +151,8 @@ AutocompletePopup.prototype = {
|
||||||
*/
|
*/
|
||||||
hidePopup: function AP_hidePopup()
|
hidePopup: function AP_hidePopup()
|
||||||
{
|
{
|
||||||
|
// Return accessibility focus to the input.
|
||||||
|
this._document.activeElement.removeAttribute("aria-activedescendant");
|
||||||
this._panel.hidePopup();
|
this._panel.hidePopup();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -295,6 +300,23 @@ AutocompletePopup.prototype = {
|
||||||
this._list.ensureIndexIsVisible(this._list.selectedIndex);
|
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.
|
* Clear all the items from the autocomplete list.
|
||||||
*/
|
*/
|
||||||
|
@ -340,6 +362,7 @@ AutocompletePopup.prototype = {
|
||||||
if (this.isOpen && this._list.ensureIndexIsVisible) {
|
if (this.isOpen && this._list.ensureIndexIsVisible) {
|
||||||
this._list.ensureIndexIsVisible(this._list.selectedIndex);
|
this._list.ensureIndexIsVisible(this._list.selectedIndex);
|
||||||
}
|
}
|
||||||
|
this._updateAriaActiveDescendant();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -362,6 +385,7 @@ AutocompletePopup.prototype = {
|
||||||
if (this.isOpen) {
|
if (this.isOpen) {
|
||||||
this._list.ensureIndexIsVisible(this._list.selectedIndex);
|
this._list.ensureIndexIsVisible(this._list.selectedIndex);
|
||||||
}
|
}
|
||||||
|
this._updateAriaActiveDescendant();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -383,6 +407,8 @@ AutocompletePopup.prototype = {
|
||||||
appendItem: function AP_appendItem(aItem)
|
appendItem: function AP_appendItem(aItem)
|
||||||
{
|
{
|
||||||
let listItem = this._document.createElementNS(XUL_NS, "richlistitem");
|
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) {
|
if (this.direction) {
|
||||||
listItem.setAttribute("dir", this.direction);
|
listItem.setAttribute("dir", this.direction);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,14 @@ function consoleOpened(HUD) {
|
||||||
|
|
||||||
let popup = HUD.jsterm.autocompletePopup;
|
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(!popup.isOpen, "popup is not open");
|
||||||
|
ok(!input.hasAttribute("aria-activedescendant"), "no aria-activedescendant");
|
||||||
|
|
||||||
popup._panel.addEventListener("popupshown", function() {
|
popup._panel.addEventListener("popupshown", function() {
|
||||||
popup._panel.removeEventListener("popupshown", arguments.callee, false);
|
popup._panel.removeEventListener("popupshown", arguments.callee, false);
|
||||||
|
@ -30,6 +37,8 @@ function consoleOpened(HUD) {
|
||||||
ok(popup.isOpen, "popup is open");
|
ok(popup.isOpen, "popup is open");
|
||||||
|
|
||||||
is(popup.itemCount, 0, "no items");
|
is(popup.itemCount, 0, "no items");
|
||||||
|
ok(!input.hasAttribute("aria-activedescendant"),
|
||||||
|
"no aria-activedescendant");
|
||||||
|
|
||||||
popup.setItems(items);
|
popup.setItems(items);
|
||||||
|
|
||||||
|
@ -43,31 +52,37 @@ function consoleOpened(HUD) {
|
||||||
is(popup.selectedIndex, 2,
|
is(popup.selectedIndex, 2,
|
||||||
"Index of the first item from bottom is selected.");
|
"Index of the first item from bottom is selected.");
|
||||||
is(popup.selectedItem, items[2], "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;
|
popup.selectedIndex = 1;
|
||||||
|
|
||||||
is(popup.selectedIndex, 1, "index 1 is selected");
|
is(popup.selectedIndex, 1, "index 1 is selected");
|
||||||
is(popup.selectedItem, items[1], "item1 is selected");
|
is(popup.selectedItem, items[1], "item1 is selected");
|
||||||
|
ok(getActiveDescendant().selected, "aria-activedescendant is correct");
|
||||||
|
|
||||||
popup.selectedItem = items[2];
|
popup.selectedItem = items[2];
|
||||||
|
|
||||||
is(popup.selectedIndex, 2, "index 2 is selected");
|
is(popup.selectedIndex, 2, "index 2 is selected");
|
||||||
is(popup.selectedItem, items[2], "item2 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.selectPreviousItem(), items[1], "selectPreviousItem() works");
|
||||||
|
|
||||||
is(popup.selectedIndex, 1, "index 1 is selected");
|
is(popup.selectedIndex, 1, "index 1 is selected");
|
||||||
is(popup.selectedItem, items[1], "item1 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.selectNextItem(), items[2], "selectPreviousItem() works");
|
||||||
|
|
||||||
is(popup.selectedIndex, 2, "index 2 is selected");
|
is(popup.selectedIndex, 2, "index 2 is selected");
|
||||||
is(popup.selectedItem, items[2], "item2 is selected");
|
is(popup.selectedItem, items[2], "item2 is selected");
|
||||||
|
ok(getActiveDescendant().selected, "aria-activedescendant is correct");
|
||||||
|
|
||||||
ok(popup.selectNextItem(), "selectPreviousItem() works");
|
ok(popup.selectNextItem(), "selectPreviousItem() works");
|
||||||
|
|
||||||
is(popup.selectedIndex, 0, "index 0 is selected");
|
is(popup.selectedIndex, 0, "index 0 is selected");
|
||||||
is(popup.selectedItem, items[0], "item0 is selected");
|
is(popup.selectedItem, items[0], "item0 is selected");
|
||||||
|
ok(getActiveDescendant().selected, "aria-activedescendant is correct");
|
||||||
|
|
||||||
items.push({label: "label3", value: "value3"});
|
items.push({label: "label3", value: "value3"});
|
||||||
popup.appendItem(items[3]);
|
popup.appendItem(items[3]);
|
||||||
|
@ -76,15 +91,19 @@ function consoleOpened(HUD) {
|
||||||
|
|
||||||
popup.selectedIndex = 3;
|
popup.selectedIndex = 3;
|
||||||
is(popup.selectedItem, items[3], "item3 is selected");
|
is(popup.selectedItem, items[3], "item3 is selected");
|
||||||
|
ok(getActiveDescendant().selected, "aria-activedescendant is correct");
|
||||||
|
|
||||||
popup.removeItem(items[2]);
|
popup.removeItem(items[2]);
|
||||||
|
|
||||||
is(popup.selectedIndex, 2, "index2 is selected");
|
is(popup.selectedIndex, 2, "index2 is selected");
|
||||||
is(popup.selectedItem, items[3], "item3 is still 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");
|
is(popup.itemCount, items.length - 1, "item2 removed");
|
||||||
|
|
||||||
popup.clearItems();
|
popup.clearItems();
|
||||||
is(popup.itemCount, 0, "items cleared");
|
is(popup.itemCount, 0, "items cleared");
|
||||||
|
ok(!input.hasAttribute("aria-activedescendant"),
|
||||||
|
"no aria-activedescendant");
|
||||||
|
|
||||||
popup.hidePopup();
|
popup.hidePopup();
|
||||||
finishTest();
|
finishTest();
|
||||||
|
|
|
@ -183,7 +183,8 @@ function goUpdateConsoleCommands() {
|
||||||
<textbox class="jsterm-complete-node devtools-monospace"
|
<textbox class="jsterm-complete-node devtools-monospace"
|
||||||
multiline="true" rows="1" tabindex="-1"/>
|
multiline="true" rows="1" tabindex="-1"/>
|
||||||
<textbox class="jsterm-input-node devtools-monospace"
|
<textbox class="jsterm-input-node devtools-monospace"
|
||||||
multiline="true" rows="1" tabindex="0"/>
|
multiline="true" rows="1" tabindex="0"
|
||||||
|
aria-autocomplete="list"/>
|
||||||
</stack>
|
</stack>
|
||||||
</hbox>
|
</hbox>
|
||||||
</notificationbox>
|
</notificationbox>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче