Bug 1833709 - Update message list ARIA role from listbox to tree if needed. r=darktrojan
**How to test this** - Use a screen reader, or simply the code inspector - Switch between threaded, unthreaded, and Grouped by Sort - Ensure that the table body role changes between tree and listbox respecting this patter: - Threded: tree - Unthreded: listbox - Grouped by Sort: tree I also improved a bit the handling of the dummy row. Differential Revision: https://phabricator.services.mozilla.com/D179162 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
9587905b77
Коммит
f4a4eefe32
|
@ -2129,6 +2129,9 @@ var folderPane = {
|
|||
// At this point `dbViewWrapperListener.onCreatedView` gets called,
|
||||
// setting up gDBView and scrolling threadTree to the right end.
|
||||
|
||||
threadPane.updateListRole(
|
||||
!gViewWrapper?.showThreaded && !gViewWrapper?.showGroupedBySort
|
||||
);
|
||||
threadPane.restoreSortIndicator();
|
||||
threadPane.restoreSelection();
|
||||
threadPaneHeader.onFolderSelected();
|
||||
|
@ -4914,6 +4917,16 @@ var threadPane = {
|
|||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the ARIA Role of the tree view table body to properly communicate
|
||||
* to assistive techonology the type of list we're rendering.
|
||||
*
|
||||
* @param {boolean} isListbox - If the list should have a listbox role.
|
||||
*/
|
||||
updateListRole(isListbox) {
|
||||
threadTree.table.body.setAttribute("role", isListbox ? "listbox" : "tree");
|
||||
},
|
||||
};
|
||||
|
||||
var messagePane = {
|
||||
|
@ -5316,6 +5329,18 @@ customElements.whenDefined("tree-view-table-row").then(() => {
|
|||
let ariaLabelPromises = [];
|
||||
|
||||
const propertiesSet = new Set(properties.value.split(" "));
|
||||
|
||||
if (propertiesSet.has("dummy")) {
|
||||
const cell = this.querySelector(".subjectcol-column");
|
||||
const textIndex = textColumns.indexOf("subjectCol");
|
||||
const label = cellTexts[textIndex];
|
||||
const span = cell.querySelector(".subject-line span");
|
||||
cell.title = span.textContent = label;
|
||||
this.setAttribute("aria-label", label);
|
||||
this.dataset.properties = "dummy";
|
||||
return;
|
||||
}
|
||||
|
||||
this.dataset.properties = properties.value.trim();
|
||||
|
||||
for (let column of threadPane.columns) {
|
||||
|
@ -5775,6 +5800,7 @@ var sortController = {
|
|||
}
|
||||
},
|
||||
sortByThread() {
|
||||
threadPane.updateListRole(false);
|
||||
gViewWrapper.showThreaded = true;
|
||||
this.sortThreadPane("byDate");
|
||||
},
|
||||
|
@ -5856,18 +5882,23 @@ var sortController = {
|
|||
},
|
||||
toggleThreaded() {
|
||||
if (gViewWrapper.showThreaded) {
|
||||
threadPane.updateListRole(true);
|
||||
gViewWrapper.showUnthreaded = true;
|
||||
} else {
|
||||
threadPane.updateListRole(false);
|
||||
gViewWrapper.showThreaded = true;
|
||||
}
|
||||
},
|
||||
sortThreaded() {
|
||||
threadPane.updateListRole(false);
|
||||
gViewWrapper.showThreaded = true;
|
||||
},
|
||||
groupBySort() {
|
||||
threadPane.updateListRole(false);
|
||||
gViewWrapper.showGroupedBySort = true;
|
||||
},
|
||||
sortUnthreaded() {
|
||||
threadPane.updateListRole(true);
|
||||
gViewWrapper.showUnthreaded = true;
|
||||
},
|
||||
sortAscending() {
|
||||
|
|
|
@ -2354,7 +2354,7 @@ class TreeViewTableBody extends HTMLTableSectionElement {
|
|||
|
||||
this.tabIndex = 0;
|
||||
this.setAttribute("is", "tree-view-table-body");
|
||||
this.setAttribute("role", "treeview");
|
||||
this.setAttribute("role", "tree");
|
||||
this.setAttribute("aria-multiselectable", "true");
|
||||
|
||||
let treeView = this.closest("tree-view");
|
||||
|
@ -2412,11 +2412,16 @@ class TreeViewTableRow extends HTMLTableRowElement {
|
|||
}
|
||||
|
||||
set index(index) {
|
||||
this.setAttribute(
|
||||
"role",
|
||||
this.list.table.body.getAttribute("role") === "tree"
|
||||
? "treeitem"
|
||||
: "option"
|
||||
);
|
||||
this.setAttribute("aria-posinset", index + 1);
|
||||
this.id = `${this.list.id}-row${index}`;
|
||||
|
||||
const isGroup = this.view.isContainer(index);
|
||||
this.setAttribute("role", isGroup ? "group" : "treeitem");
|
||||
this.classList.toggle("children", isGroup);
|
||||
|
||||
const isGroupOpen = this.view.isContainerOpen(index);
|
||||
|
|
|
@ -53,6 +53,17 @@ add_task(async function testSwitchToCardsView() {
|
|||
"The tree view should not switch to a card layout"
|
||||
);
|
||||
|
||||
Assert.equal(
|
||||
threadTree.table.body.getAttribute("role"),
|
||||
"tree",
|
||||
"The message list table should be presented as Tree View"
|
||||
);
|
||||
Assert.equal(
|
||||
threadTree.getRowAtIndex(0).getAttribute("role"),
|
||||
"treeitem",
|
||||
"The message row should be presented as Tree Item"
|
||||
);
|
||||
|
||||
displayContext = about3Pane.document.getElementById(
|
||||
"threadPaneDisplayContext"
|
||||
);
|
||||
|
@ -90,6 +101,16 @@ add_task(async function testSwitchToCardsView() {
|
|||
"thread-card",
|
||||
"tree view in cards layout"
|
||||
);
|
||||
Assert.equal(
|
||||
threadTree.table.body.getAttribute("role"),
|
||||
"tree",
|
||||
"The message list table should remain as Tree View"
|
||||
);
|
||||
Assert.equal(
|
||||
threadTree.getRowAtIndex(0).getAttribute("role"),
|
||||
"treeitem",
|
||||
"The message row should remain as Tree Item"
|
||||
);
|
||||
|
||||
let row = threadTree.getRowAtIndex(0);
|
||||
let star = row.querySelector(".button-star");
|
||||
|
|
|
@ -559,3 +559,42 @@ async function restoreMessages() {
|
|||
sourceMessageIDs.indexOf(b.messageId)
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function testThreadTreeA11yRoles() {
|
||||
Assert.equal(
|
||||
threadTree.table.body.getAttribute("role"),
|
||||
"listbox",
|
||||
"The tree view should be presented as ListBox"
|
||||
);
|
||||
Assert.equal(
|
||||
threadTree.getRowAtIndex(0).getAttribute("role"),
|
||||
"option",
|
||||
"The message row should be presented as Option"
|
||||
);
|
||||
|
||||
about3Pane.sortController.sortThreaded();
|
||||
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
() => threadTree.table.body.getAttribute("role") == "tree",
|
||||
"The tree view should switch to a Tree View role"
|
||||
);
|
||||
Assert.equal(
|
||||
threadTree.getRowAtIndex(0).getAttribute("role"),
|
||||
"treeitem",
|
||||
"The message row should be presented as Tree Item"
|
||||
);
|
||||
|
||||
about3Pane.sortController.groupBySort();
|
||||
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
() => threadTree.table.body.getAttribute("role") == "tree",
|
||||
"The message list table should remain presented as Tree View"
|
||||
);
|
||||
Assert.equal(
|
||||
threadTree.getRowAtIndex(0).getAttribute("role"),
|
||||
"treeitem",
|
||||
"The first dummy message row should be presented as Tree Item"
|
||||
);
|
||||
|
||||
about3Pane.sortController.sortUnthreaded();
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче