vpat 48: announce selection for default virtualized table (#4391)

* vpat 48: announce selection for default virt table

For simpler virtualized tables
(e.g. style manager in Zotero_Preferences.Cite), the table
does not get re-rendered when selection changes, so
aria-activedescendant does not get updated in render().

- a single function to update aria-activedescendant of the table
- call it in _updateTree of the tree selection because _onSelection
is not called the very first time a table is rendered. In that case, after
restart, collectionTree would have a selected row but no aria-activedescendant
- remove this.forceUpdate() from selection handlers of itemTree and
collectionTree because judging by the coment it's main purpose was to set
aria-activedescendant through render()
- set aria-activedescendant in _onSelection handler
of virtualized table. 
- construct and set aria-label for rows build via
makeRowRenderer of VirtualizedTable so that is is
announced when the row is selected.
This commit is contained in:
abaevbog 2024-07-17 00:34:16 -07:00 committed by GitHub
parent a46f1bcbbb
commit 40fd5efe05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 17 additions and 10 deletions

View file

@ -220,8 +220,6 @@ var CollectionTree = class CollectionTree extends LibraryTree {
} }
} }
} }
// Update aria-activedescendant on the tree
this.forceUpdate();
if (shouldDebounce) { if (shouldDebounce) {
this._onSelectionChangeDebounced(); this._onSelectionChangeDebounced();
} }

View file

@ -256,6 +256,7 @@ class TreeSelection {
_updateTree(shouldDebounce) { _updateTree(shouldDebounce) {
if (!this.selectEventsSuppressed && this._tree.props.onSelectionChange) { if (!this.selectEventsSuppressed && this._tree.props.onSelectionChange) {
this._tree.props.onSelectionChange(this, shouldDebounce); this._tree.props.onSelectionChange(this, shouldDebounce);
this._tree._setAriaAciveDescendant();
} }
} }
@ -1281,12 +1282,6 @@ class VirtualizedTable extends React.Component {
if (this.props.role == 'treegrid') { if (this.props.role == 'treegrid') {
props['aria-readonly'] = true; props['aria-readonly'] = true;
} }
if (this.selection.count > 0) {
const elem = this._jsWindow && this._jsWindow.getElementByIndex(this.selection.focused);
if (elem) {
props['aria-activedescendant'] = elem.id;
}
}
let jsWindowProps = { let jsWindowProps = {
id: this._jsWindowID, id: this._jsWindowID,
className: "virtualized-table-body", className: "virtualized-table-body",
@ -1434,6 +1429,15 @@ class VirtualizedTable extends React.Component {
this._columns = new Columns(this); this._columns = new Columns(this);
await new Promise((resolve) => {this.forceUpdate(resolve)}); await new Promise((resolve) => {this.forceUpdate(resolve)});
} }
// Set aria-activedescendant on table container
_setAriaAciveDescendant() {
if (!this.selection.focused) return;
let selected = this._jsWindow?.getElementByIndex(this.selection.focused);
if (selected) {
selected.closest(".virtualized-table").setAttribute("aria-activedescendant", selected.id);
}
}
} }
/** /**
@ -1771,6 +1775,7 @@ function makeRowRenderer(getRowData) {
div.classList.toggle('selected', selection.isSelected(index)); div.classList.toggle('selected', selection.isSelected(index));
div.classList.toggle('focused', selection.focused == index); div.classList.toggle('focused', selection.focused == index);
const rowData = getRowData(index); const rowData = getRowData(index);
let ariaLabel = "";
if (columns.length) { if (columns.length) {
for (let column of columns) { for (let column of columns) {
@ -1782,12 +1787,18 @@ function makeRowRenderer(getRowData) {
else { else {
div.appendChild(renderCell(index, rowData[column.dataKey], column)); div.appendChild(renderCell(index, rowData[column.dataKey], column));
} }
let columnName = column.label;
if (column.label in Zotero.Intl.strings) {
columnName = Zotero.getString(column.label);
}
ariaLabel += `${columnName}: ${rowData[column.dataKey]} `;
} }
} }
else { else {
div.appendChild(renderCell(index, rowData)); div.appendChild(renderCell(index, rowData));
} }
div.setAttribute("aria-label", ariaLabel);
return div; return div;
}; };
} }

View file

@ -3121,8 +3121,6 @@ var ItemTree = class ItemTree extends LibraryTree {
this.tree.invalidateRow(this._rowMap[id]); this.tree.invalidateRow(this._rowMap[id]);
} }
} }
// Update aria-activedescendant on the tree
this.forceUpdate();
this.duplicateMouseSelection = false; this.duplicateMouseSelection = false;
if (shouldDebounce) { if (shouldDebounce) {
this._onSelectionChangeDebounced(); this._onSelectionChangeDebounced();