jsdialog: a11y: add aria properties for tree / listbox

Signed-off-by: Szymon Kłos <szymon.klos@collabora.com>
Change-Id: I190929780783845b69c518fc9fe549e1a841cb9c
This commit is contained in:
Szymon Kłos 2023-04-13 11:18:10 +02:00 committed by Szymon Kłos
parent 66315f8dc5
commit dd9b703b2c
2 changed files with 57 additions and 20 deletions

View file

@ -3191,7 +3191,8 @@ L.Control.JSDialogBuilder = L.Control.extend({
&& data.type !== 'frame'
&& data.type !== 'expander'
&& data.type !== 'panel'
&& data.type !== 'buttonbox')
&& data.type !== 'buttonbox'
&& data.type !== 'treelistbox')
control.setAttribute('tabIndex', '0');
},

View file

@ -38,6 +38,7 @@
function _createCheckbox(parentContainer, treeViewData, builder, entry) {
var checkbox = L.DomUtil.create('input', builder.options.cssClass + ' ui-treeview-checkbox', parentContainer);
checkbox.type = 'checkbox';
checkbox.tabIndex = -1;
if (entry.state === 'true' || entry.state === true)
checkbox.checked = true;
@ -57,7 +58,24 @@ function _createCheckbox(parentContainer, treeViewData, builder, entry) {
return checkbox;
}
function _treelistboxEntry(parentContainer, treeViewData, entry, builder) {
function _selectEntry(span, checkbox) {
L.DomUtil.addClass(span, 'selected');
span.setAttribute('aria-selected', true);
span.tabIndex = 0;
if (checkbox)
checkbox.removeAttribute('tabindex');
}
function _unselectEntry(item) {
L.DomUtil.removeClass(item, 'selected');
item.removeAttribute('aria-selected');
item.removeAttribute('tabindex');
var itemCheckbox = item.querySelector('input');
if (itemCheckbox)
itemCheckbox.tabIndex = -1;
}
function _treelistboxEntry(parentContainer, treeViewData, entry, builder, isTreeView) {
if (entry.text == '<dummy>')
return;
var disabled = treeViewData.enabled === 'false' || treeViewData.enabled === false;
@ -83,15 +101,16 @@ function _treelistboxEntry(parentContainer, treeViewData, entry, builder) {
}
var span = L.DomUtil.create('span', builder.options.cssClass + ' ui-treeview-entry ' + (entry.children ? ' ui-treeview-expandable' : 'ui-treeview-notexpandable'), li);
span.setAttribute('role', isTreeView ? 'treeitem' : 'option');
var expander = L.DomUtil.create('div', builder.options.cssClass + ' ui-treeview-expander ', span);
if (entry.selected && (entry.selected === 'true' || entry.selected === true))
L.DomUtil.addClass(span, 'selected');
if (entry.state !== undefined)
var checkbox = _createCheckbox(span, treeViewData, builder, entry);
if (entry.selected && (entry.selected === 'true' || entry.selected === true))
_selectEntry(span, checkbox);
var text = L.DomUtil.create('span', builder.options.cssClass + ' ui-treeview-cell', span);
for (var i in entry.columns) {
if (entry.columns[i].collapsed || entry.columns[i].expanded) {
@ -106,14 +125,13 @@ function _treelistboxEntry(parentContainer, treeViewData, entry, builder) {
} else if (entry.columns[i].text) {
var innerText = L.DomUtil.create('span', builder.options.cssClass + ' ui-treeview-cell-text', text);
innerText.innerText = entry.columns[i].text || entry.text;
innerText.tabIndex = 0;
}
}
if (entry.children) {
var ul = L.DomUtil.create('ul', builder.options.cssClass, li);
for (var i in entry.children) {
_treelistboxEntry(ul, treeViewData, entry.children[i], builder);
_treelistboxEntry(ul, treeViewData, entry.children[i], builder, isTreeView);
}
var toggleFunction = function() {
@ -145,8 +163,9 @@ function _treelistboxEntry(parentContainer, treeViewData, entry, builder) {
var singleClick = treeViewData.singleclickactivate === 'true' || treeViewData.singleclickactivate === true;
var clickFunction = function() {
parentContainer.querySelectorAll('.ui-treeview-entry')
.forEach(function (item) { L.DomUtil.removeClass(item, 'selected'); });
L.DomUtil.addClass(span, 'selected');
.forEach(function (item) { _unselectEntry(item); });
_selectEntry(span, checkbox);
builder.callback('treeview', 'select', treeViewData, entry.row, builder);
if (singleClick) {
@ -188,8 +207,9 @@ function _treelistboxEntry(parentContainer, treeViewData, entry, builder) {
if (!singleClick) {
$(text).dblclick(function() {
parentContainer.querySelectorAll('.ui-treeview-entry')
.forEach(function (item) { L.DomUtil.removeClass(item, 'selected'); });
L.DomUtil.addClass(span, 'selected');
.forEach(function (item) { _unselectEntry(item); });
_selectEntry(span, checkbox);
builder.callback('treeview', 'activate', treeViewData, entry.row, builder);
});
@ -200,16 +220,17 @@ function _treelistboxEntry(parentContainer, treeViewData, entry, builder) {
function _headerlistboxEntry(parentContainer, treeViewData, entry, builder) {
var disabled = treeViewData.enabled === 'false' || treeViewData.enabled === false;
if (entry.selected && (entry.selected === 'true' || entry.selected === true))
L.DomUtil.addClass(parentContainer, 'selected');
if (entry.state !== undefined) {
var td = L.DomUtil.create('td', '', parentContainer);
_createCheckbox(td, treeViewData, builder, entry);
var checkbox = _createCheckbox(td, treeViewData, builder, entry);
}
if (entry.selected && (entry.selected === 'true' || entry.selected === true))
_selectEntry(parentContainer, checkbox);
for (var i in entry.columns) {
var td = L.DomUtil.create('td', '', parentContainer);
td.setAttribute('role', 'gridcell');
if (entry.columns[i].collapsed || entry.columns[i].expanded) {
var iconId = entry.columns[i].collapsed ? entry.columns[i].collapsed : entry.columns[i].expanded;
@ -227,8 +248,9 @@ function _headerlistboxEntry(parentContainer, treeViewData, entry, builder) {
if (!disabled) {
var clickFunction = function() {
parentContainer.parentNode.querySelectorAll('.ui-listview-entry')
.forEach(function (item) { L.DomUtil.removeClass(item, 'selected'); });
L.DomUtil.addClass(parentContainer, 'selected');
.forEach(function (item) { _unselectEntry(item); });
_selectEntry(parentContainer, checkbox);
builder.callback('treeview', 'select', treeViewData, entry.row, builder);
};
@ -261,6 +283,7 @@ function _hasIcon(columns) {
function _createHeaders(tbody, data, builder) {
var headers = L.DomUtil.create('tr', builder.options.cssClass + ' ui-treeview-header', tbody);
headers.setAttribute('role', 'row');
var hasCheckboxes = data.entries && data.entries.length && data.entries[0].state !== undefined;
if (hasCheckboxes)
data.headers = [{ text: '' }].concat(data.headers);
@ -269,6 +292,7 @@ function _createHeaders(tbody, data, builder) {
data.headers = [{ text: '' }].concat(data.headers);
for (var h in data.headers) {
var header = L.DomUtil.create('th', builder.options.cssClass, headers);
header.setAttribute('role', 'columnheader');
var headerText = L.DomUtil.create('span', builder.options.cssClass + ' ui-treeview-header-text', header);
headerText.innerText = data.headers[h].text;
var headerSortIcon = L.DomUtil.create('span', builder.options.cssClass + ' ui-treeview-header-sort-icon', header);
@ -340,6 +364,7 @@ function _createHeaders(tbody, data, builder) {
function _treelistboxControl(parentContainer, data, builder) {
var table = L.DomUtil.create('table', builder.options.cssClass + ' ui-treeview', parentContainer);
table.id = data.id;
table.tabIndex = 0;
var disabled = data.enabled === 'false' || data.enabled === false;
if (disabled)
L.DomUtil.addClass(table, 'disabled');
@ -369,19 +394,30 @@ function _treelistboxControl(parentContainer, data, builder) {
if (isHeaderListBox) {
// list view with headers
for (var i in data.entries) {
table.setAttribute('role', 'treegrid');
for (i in data.entries) {
var tr = L.DomUtil.create('tr', builder.options.cssClass + ' ui-listview-entry', tbody);
tr.tabIndex = 0;
tr.setAttribute('role', 'row');
_headerlistboxEntry(tr, data, data.entries[i], builder);
}
var firstSelected = tbody.querySelector('.ui-listview-entry.selected');
} else {
// tree view
var isRealTreeView = false;
for (var i in data.entries) {
if (data.entries[i].children && data.entries[i].children.length) {
isRealTreeView = true;
break;
}
}
table.setAttribute('role', isRealTreeView ? 'tree' : 'listbox');
var ul = L.DomUtil.create('ul', builder.options.cssClass, tbody);
for (i in data.entries) {
_treelistboxEntry(ul, data, data.entries[i], builder);
_treelistboxEntry(ul, data, data.entries[i], builder, isRealTreeView);
}
firstSelected = tbody.querySelector('.ui-treeview-entry.selected');