提交 bcfc2b81 编写于 作者: C Christof Marti

Announce number of results in QuickPick for screen readers (fixes #52542)

上级 dae69dbf
......@@ -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() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册