未验证 提交 d2e16e50 编写于 作者: C Christopher Leidigh 提交者: GitHub

Settings: Fix aria labels using role=form. Fixes: #54836 (#57314)

上级 4f162b7b
......@@ -481,6 +481,10 @@ export class SettingsEditor2 extends BaseEditor {
}));
this.settingsTree.getHTMLElement().attributes.removeNamedItem('tabindex');
// Have to redefine role of the tree widget to form for input elements
// TODO:CDL make this an option for tree
this.settingsTree.getHTMLElement().setAttribute('role', 'form');
this._register(this.settingsTree.onDidScroll(() => {
this.updateTreeScrollSync();
}));
......
......@@ -733,7 +733,7 @@ export class SettingsRenderer implements ITreeRenderer {
// Also have to ignore embedded links - too buried to stop propagation
toDispose.push(DOM.addDisposableListener(descriptionElement, DOM.EventType.MOUSE_DOWN, (e) => {
const targetElement = <HTMLElement>e.toElement;
const targetId = descriptionElement.getAttribute('checkbox-label-target-id');
const targetId = descriptionElement.getAttribute('checkbox_label_target_id');
// Make sure we are not a link and the target ID matches
// Toggle target checkbox
......@@ -1012,10 +1012,12 @@ export class SettingsRenderer implements ITreeRenderer {
template.descriptionElement.innerText = element.description;
}
const baseId = (element.displayCategory + '_' + element.displayLabel).replace(/ /g, '_').toLowerCase();
template.descriptionElement.id = baseId + '_setting_description';
if (templateId === SETTINGS_BOOL_TEMPLATE_ID) {
// Add checkbox target to description clickable and able to toggle checkbox
const checkbox_id = (element.displayCategory + '_' + element.displayLabel).replace(/ /g, '_') + '_Item';
template.descriptionElement.setAttribute('checkbox-label-target-id', checkbox_id);
template.descriptionElement.setAttribute('checkbox_label_target_id', baseId + '_setting_item');
}
if (element.overriddenScopeList.length) {
......@@ -1027,6 +1029,12 @@ export class SettingsRenderer implements ITreeRenderer {
} else {
template.otherOverridesElement.textContent = '';
}
// Remove tree attributes - sometimes overridden by tree - should be managed there
template.containerElement.parentElement.removeAttribute('role');
template.containerElement.parentElement.removeAttribute('aria-level');
template.containerElement.parentElement.removeAttribute('aria-posinset');
template.containerElement.parentElement.removeAttribute('aria-setsize');
}
private renderDescriptionMarkdown(text: string, disposeables: IDisposable[]): HTMLElement {
......@@ -1077,21 +1085,21 @@ export class SettingsRenderer implements ITreeRenderer {
// Setup and add ARIA attributes
// Create id and label for control/input element - parent is wrapper div
const id = (dataElement.displayCategory + '_' + dataElement.displayLabel).replace(/ /g, '_');
const baseId = (dataElement.displayCategory + '_' + dataElement.displayLabel).replace(/ /g, '_').toLowerCase();
const modifiedText = dataElement.isConfigured ? 'Modified' : '';
const label = ' ' + dataElement.displayCategory + ' ' + dataElement.displayLabel + ' checkbox ' + (dataElement.value ? 'checked ' : 'unchecked ') + modifiedText;
const label = dataElement.displayCategory + ' ' + dataElement.displayLabel + ' ' + modifiedText;
// We use the parent control div for the aria-labelledby target
// Does not appear you can use the direct label on the element itself within a tree
template.checkbox.domNode.parentElement.setAttribute('id', id);
template.checkbox.domNode.parentElement.id = baseId + '_setting_label';
template.checkbox.domNode.parentElement.setAttribute('aria-label', label);
// Labels will not be read on descendent input elements of the parent treeitem
// unless defined as role=treeitem and indirect aria-labelledby approach
// TODO: Determine method to normally label input items with value read last
template.checkbox.domNode.setAttribute('id', id + '_Item');
template.checkbox.domNode.setAttribute('role', 'treeitem');
template.checkbox.domNode.setAttribute('aria-labelledby', id + '_Item ' + id);
template.checkbox.domNode.id = baseId + '_setting_item';
template.checkbox.domNode.setAttribute('role', 'checkbox');
template.checkbox.domNode.setAttribute('aria-labelledby', baseId + '_setting_label');
template.checkbox.domNode.setAttribute('aria-describedby', baseId + '_setting_description');
}
......@@ -1107,7 +1115,8 @@ export class SettingsRenderer implements ITreeRenderer {
}));
const modifiedText = dataElement.isConfigured ? 'Modified' : '';
const label = ' ' + dataElement.displayCategory + ' ' + dataElement.displayLabel + ' combobox ' + modifiedText;
const label = dataElement.displayCategory + ' ' + dataElement.displayLabel + ' ' + modifiedText;
const baseId = (dataElement.displayCategory + '_' + dataElement.displayLabel).replace(/ /g, '_').toLowerCase();
template.selectBox.setAriaLabel(label);
......@@ -1117,8 +1126,9 @@ export class SettingsRenderer implements ITreeRenderer {
template.onChange = idx => onChange(dataElement.setting.enum[idx]);
if (template.controlElement.firstElementChild) {
// SelectBox needs to be treeitem to read correctly within tree
template.controlElement.firstElementChild.setAttribute('role', 'treeitem');
// SelectBox needs to have treeitem changed to combobox to read correctly within tree
template.controlElement.firstElementChild.setAttribute('role', 'combobox');
template.controlElement.firstElementChild.setAttribute('aria-describedby', baseId + '_setting_description');
}
template.enumDescriptionElement.innerHTML = '';
......@@ -1126,26 +1136,25 @@ export class SettingsRenderer implements ITreeRenderer {
private renderText(dataElement: SettingsTreeSettingElement, template: ISettingTextItemTemplate, onChange: (value: string) => void): void {
const modifiedText = dataElement.isConfigured ? 'Modified' : '';
const label = ' ' + dataElement.displayCategory + ' ' + dataElement.displayLabel + ' ' + modifiedText;
template.onChange = null;
const label = dataElement.displayCategory + ' ' + dataElement.displayLabel + ' ' + modifiedText; template.onChange = null;
template.inputBox.value = dataElement.value;
template.onChange = value => { renderValidations(dataElement, template, false, label); onChange(value); };
// Setup and add ARIA attributes
// Create id and label for control/input element - parent is wrapper div
const id = (dataElement.displayCategory + '_' + dataElement.displayLabel).replace(/ /g, '_');
const baseId = (dataElement.displayCategory + '_' + dataElement.displayLabel).replace(/ /g, '_').toLowerCase();
// We use the parent control div for the aria-labelledby target
// Does not appear you can use the direct label on the element itself within a tree
template.inputBox.inputElement.parentElement.setAttribute('id', id);
template.inputBox.inputElement.parentElement.id = baseId + '_setting_label';
template.inputBox.inputElement.parentElement.setAttribute('aria-label', label);
// Labels will not be read on descendent input elements of the parent treeitem
// unless defined as role=treeitem and indirect aria-labelledby approach
// TODO: Determine method to normally label input items with value read last
template.inputBox.inputElement.setAttribute('id', id + 'item');
template.inputBox.inputElement.setAttribute('role', 'treeitem');
template.inputBox.inputElement.setAttribute('aria-labelledby', id + 'item ' + id);
template.inputBox.inputElement.id = baseId + '_setting_item';
template.inputBox.inputElement.setAttribute('role', 'textbox');
template.inputBox.inputElement.setAttribute('aria-labelledby', baseId + '_setting_label');
template.inputBox.inputElement.setAttribute('aria-describedby', baseId + '_setting_description');
renderValidations(dataElement, template, true, label);
}
......@@ -1153,8 +1162,7 @@ export class SettingsRenderer implements ITreeRenderer {
private renderNumber(dataElement: SettingsTreeSettingElement, template: ISettingTextItemTemplate, onChange: (value: number) => void): void {
const modifiedText = dataElement.isConfigured ? 'Modified' : '';
const label = ' ' + dataElement.displayCategory + ' ' + dataElement.displayLabel + ' number ' + modifiedText;
const numParseFn = (dataElement.valueType === 'integer' || dataElement.valueType === 'nullable-integer')
const label = dataElement.displayCategory + ' ' + dataElement.displayLabel + ' number ' + modifiedText; const numParseFn = (dataElement.valueType === 'integer' || dataElement.valueType === 'nullable-integer')
? parseInt : parseFloat;
const nullNumParseFn = (dataElement.valueType === 'nullable-integer' || dataElement.valueType === 'nullable-number')
......@@ -1166,19 +1174,19 @@ export class SettingsRenderer implements ITreeRenderer {
// Setup and add ARIA attributes
// Create id and label for control/input element - parent is wrapper div
const id = (dataElement.displayCategory + '_' + dataElement.displayLabel).replace(/ /g, '_');
const baseId = (dataElement.displayCategory + '_' + dataElement.displayLabel).replace(/ /g, '_').toLowerCase();
// We use the parent control div for the aria-labelledby target
// Does not appear you can use the direct label on the element itself within a tree
template.inputBox.inputElement.parentElement.setAttribute('id', id);
template.inputBox.inputElement.parentElement.id = baseId + '_setting_label';
template.inputBox.inputElement.parentElement.setAttribute('aria-label', label);
// Labels will not be read on descendent input elements of the parent treeitem
// unless defined as role=treeitem and indirect aria-labelledby approach
// TODO: Determine method to normally label input items with value read last
template.inputBox.inputElement.setAttribute('id', id + 'item');
template.inputBox.inputElement.setAttribute('role', 'treeitem');
template.inputBox.inputElement.setAttribute('aria-labelledby', id + 'item ' + id);
template.inputBox.inputElement.id = baseId + '_setting_item';
template.inputBox.inputElement.setAttribute('role', 'textbox');
template.inputBox.inputElement.setAttribute('aria-labelledby', baseId + '_setting_label');
template.inputBox.inputElement.setAttribute('aria-describedby', baseId + '_setting_description');
renderValidations(dataElement, template, true, label);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册