mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-11 05:30:03 -05:00
Announce number of results in QuickPick for screen readers (fixes #52542)
This commit is contained in:
@@ -103,6 +103,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
|
||||
private inputBox: InputBox;
|
||||
private inputContainer: Builder;
|
||||
private helpText: Builder;
|
||||
private resultCount: Builder;
|
||||
private treeContainer: Builder;
|
||||
private progressBar: ProgressBar;
|
||||
private visible: boolean;
|
||||
@@ -232,6 +233,12 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
|
||||
});
|
||||
});
|
||||
|
||||
// Result count for screen readers
|
||||
this.resultCount = div.div({
|
||||
'class': 'quick-open-result-count',
|
||||
'aria-live': 'polite'
|
||||
}).clone();
|
||||
|
||||
// Tree
|
||||
this.treeContainer = div.div({
|
||||
'class': 'quick-open-tree'
|
||||
@@ -628,9 +635,12 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
|
||||
// Indicate entries to tree
|
||||
this.tree.layout();
|
||||
|
||||
const entries = input ? input.entries.filter(e => this.isElementVisible(input, e)) : [];
|
||||
this.updateResultCount(entries.length);
|
||||
|
||||
// Handle auto focus
|
||||
if (input && input.entries.some(e => this.isElementVisible(input, e))) {
|
||||
this.autoFocus(input, autoFocus);
|
||||
if (entries.length) {
|
||||
this.autoFocus(input, entries, autoFocus);
|
||||
}
|
||||
}, errors.onUnexpectedError);
|
||||
}
|
||||
@@ -643,8 +653,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
|
||||
return input.filter.isVisible(e);
|
||||
}
|
||||
|
||||
private autoFocus(input: IModel<any>, autoFocus: IAutoFocus = {}): void {
|
||||
const entries = input.entries.filter(e => this.isElementVisible(input, e));
|
||||
private autoFocus(input: IModel<any>, entries: any[], autoFocus: IAutoFocus = {}): void {
|
||||
|
||||
// First check for auto focus of prefix matches
|
||||
if (autoFocus.autoFocusPrefixMatch) {
|
||||
@@ -725,11 +734,13 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
|
||||
// Indicate entries to tree
|
||||
this.tree.layout();
|
||||
|
||||
const entries = input ? input.entries.filter(e => this.isElementVisible(input, e)) : [];
|
||||
this.updateResultCount(entries.length);
|
||||
|
||||
// Handle auto focus
|
||||
if (autoFocus) {
|
||||
let doAutoFocus = autoFocus && input && input.entries.some(e => this.isElementVisible(input, e));
|
||||
if (doAutoFocus) {
|
||||
this.autoFocus(input, autoFocus);
|
||||
if (entries.length) {
|
||||
this.autoFocus(input, entries, autoFocus);
|
||||
}
|
||||
}
|
||||
}, errors.onUnexpectedError);
|
||||
@@ -769,6 +780,10 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
|
||||
return height;
|
||||
}
|
||||
|
||||
updateResultCount(count: number) {
|
||||
this.resultCount.text(nls.localize({ key: 'quickInput.visibleCount', comment: ['This tells the user how many items are shown in a list of items to select from. The items can be anything. Currently not visible, but read by screen readers.'] }, "{0} Results", count));
|
||||
}
|
||||
|
||||
hide(reason?: HideReason): void {
|
||||
if (!this.isVisible()) {
|
||||
return;
|
||||
|
||||
@@ -35,6 +35,11 @@
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-result-count {
|
||||
position: absolute;
|
||||
left: -10000px;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree {
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
@@ -69,6 +69,11 @@
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.quick-input-visible-count {
|
||||
position: absolute;
|
||||
left: -10000px;
|
||||
}
|
||||
|
||||
.quick-input-count {
|
||||
align-self: center;
|
||||
position: absolute;
|
||||
|
||||
@@ -62,6 +62,7 @@ interface QuickInputUI {
|
||||
rightActionBar: ActionBar;
|
||||
checkAll: HTMLInputElement;
|
||||
inputBox: QuickInputBox;
|
||||
visibleCount: CountBadge;
|
||||
count: CountBadge;
|
||||
message: HTMLElement;
|
||||
progressBar: ProgressBar;
|
||||
@@ -79,6 +80,7 @@ type Visibilities = {
|
||||
title?: boolean;
|
||||
checkAll?: boolean;
|
||||
inputBox?: boolean;
|
||||
visibleCount?: boolean;
|
||||
count?: boolean;
|
||||
message?: boolean;
|
||||
list?: boolean;
|
||||
@@ -481,6 +483,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
this.ui.list.setElements(this.items);
|
||||
this.ui.list.filter(this.ui.inputBox.value);
|
||||
this.ui.checkAll.checked = this.ui.list.getAllVisibleChecked();
|
||||
this.ui.visibleCount.setCount(this.ui.list.getVisibleCount());
|
||||
this.ui.count.setCount(this.ui.list.getCheckedCount());
|
||||
if (!this.canSelectMany) {
|
||||
this.ui.list.focus('First');
|
||||
@@ -515,7 +518,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
}
|
||||
this.ui.list.matchOnDescription = this.matchOnDescription;
|
||||
this.ui.list.matchOnDetail = this.matchOnDetail;
|
||||
this.ui.setVisibilities(this.canSelectMany ? { title: !!this.title || !!this.step, checkAll: true, inputBox: true, count: true, ok: true, list: true } : { title: !!this.title || !!this.step, inputBox: true, list: true });
|
||||
this.ui.setVisibilities(this.canSelectMany ? { title: !!this.title || !!this.step, checkAll: true, inputBox: true, visibleCount: true, count: true, ok: true, list: true } : { title: !!this.title || !!this.step, inputBox: true, visibleCount: true, list: true });
|
||||
}
|
||||
|
||||
configureQuickNavigate(quickNavigate: IQuickNavigateConfiguration) {
|
||||
@@ -705,6 +708,7 @@ export class QuickInputService extends Component implements IQuickInputService {
|
||||
private layoutDimensions: dom.Dimension;
|
||||
private titleBar: HTMLElement;
|
||||
private filterContainer: HTMLElement;
|
||||
private visibleCountContainer: HTMLElement;
|
||||
private countContainer: HTMLElement;
|
||||
private okContainer: HTMLElement;
|
||||
private ok: Button;
|
||||
@@ -789,7 +793,12 @@ export class QuickInputService extends Component implements IQuickInputService {
|
||||
|
||||
const inputBox = this._register(new QuickInputBox(this.filterContainer));
|
||||
|
||||
this.visibleCountContainer = dom.append(this.filterContainer, $('.quick-input-visible-count'));
|
||||
this.visibleCountContainer.setAttribute('aria-live', 'polite');
|
||||
const visibleCount = new CountBadge(this.visibleCountContainer, { countFormat: localize({ key: 'quickInput.visibleCount', comment: ['This tells the user how many items are shown in a list of items to select from. The items can be anything. Currently not visible, but read by screen readers.'] }, "{0} Results") });
|
||||
|
||||
this.countContainer = dom.append(this.filterContainer, $('.quick-input-count'));
|
||||
this.countContainer.setAttribute('aria-live', 'polite');
|
||||
const count = new CountBadge(this.countContainer, { countFormat: localize({ key: 'quickInput.countSelected', comment: ['This tells the user how many items are selected in a list of items to select from. The items can be anything.'] }, "{0} Selected") });
|
||||
this._register(attachBadgeStyler(count, this.themeService));
|
||||
|
||||
@@ -811,6 +820,9 @@ export class QuickInputService extends Component implements IQuickInputService {
|
||||
this._register(list.onChangedAllVisibleChecked(checked => {
|
||||
checkAll.checked = checked;
|
||||
}));
|
||||
this._register(list.onChangedVisibleCount(c => {
|
||||
visibleCount.setCount(c);
|
||||
}));
|
||||
this._register(list.onChangedCheckedCount(c => {
|
||||
count.setCount(c);
|
||||
}));
|
||||
@@ -880,6 +892,7 @@ export class QuickInputService extends Component implements IQuickInputService {
|
||||
rightActionBar,
|
||||
checkAll,
|
||||
inputBox,
|
||||
visibleCount,
|
||||
count,
|
||||
message,
|
||||
progressBar,
|
||||
@@ -1047,6 +1060,7 @@ export class QuickInputService extends Component implements IQuickInputService {
|
||||
this.ui.inputBox.placeholder = '';
|
||||
this.ui.inputBox.password = false;
|
||||
this.ui.inputBox.showDecoration(Severity.Ignore);
|
||||
this.ui.visibleCount.setCount(0);
|
||||
this.ui.count.setCount(0);
|
||||
this.ui.message.textContent = '';
|
||||
this.ui.progressBar.stop();
|
||||
@@ -1069,6 +1083,7 @@ export class QuickInputService extends Component implements IQuickInputService {
|
||||
this.ui.title.style.display = visibilities.title ? '' : 'none';
|
||||
this.ui.checkAll.style.display = visibilities.checkAll ? '' : 'none';
|
||||
this.filterContainer.style.display = visibilities.inputBox ? '' : 'none';
|
||||
this.visibleCountContainer.style.display = visibilities.visibleCount ? '' : 'none';
|
||||
this.countContainer.style.display = visibilities.count ? '' : 'none';
|
||||
this.okContainer.style.display = visibilities.ok ? '' : 'none';
|
||||
this.ui.message.style.display = visibilities.message ? '' : 'none';
|
||||
|
||||
@@ -160,6 +160,8 @@ export class QuickInputList {
|
||||
onChangedAllVisibleChecked: Event<boolean> = this._onChangedAllVisibleChecked.event;
|
||||
private _onChangedCheckedCount = new Emitter<number>();
|
||||
onChangedCheckedCount: Event<number> = this._onChangedCheckedCount.event;
|
||||
private _onChangedVisibleCount = new Emitter<number>();
|
||||
onChangedVisibleCount: Event<number> = this._onChangedVisibleCount.event;
|
||||
private _onChangedCheckedElements = new Emitter<IQuickPickItem[]>();
|
||||
onChangedCheckedElements: Event<IQuickPickItem[]> = this._onChangedCheckedElements.event;
|
||||
private _onLeave = new Emitter<void>();
|
||||
@@ -255,6 +257,17 @@ export class QuickInputList {
|
||||
return count;
|
||||
}
|
||||
|
||||
getVisibleCount() {
|
||||
let count = 0;
|
||||
const elements = this.elements;
|
||||
for (let i = 0, n = elements.length; i < n; i++) {
|
||||
if (!elements[i].hidden) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
setAllVisibleChecked(checked: boolean) {
|
||||
try {
|
||||
this._fireCheckedEvents = false;
|
||||
@@ -284,6 +297,7 @@ export class QuickInputList {
|
||||
}, new Map<IQuickPickItem, number>());
|
||||
this.list.splice(0, this.list.length, this.elements);
|
||||
this.list.setFocus([]);
|
||||
this._onChangedVisibleCount.fire(this.elements.length);
|
||||
}
|
||||
|
||||
getFocusedElements() {
|
||||
@@ -415,6 +429,7 @@ export class QuickInputList {
|
||||
this.list.layout();
|
||||
|
||||
this._onChangedAllVisibleChecked.fire(this.getAllVisibleChecked());
|
||||
this._onChangedVisibleCount.fire(shownElements.length);
|
||||
}
|
||||
|
||||
toggleCheckbox() {
|
||||
|
||||
Reference in New Issue
Block a user