未验证 提交 33187ab3 编写于 作者: I Isidor Nikolic 提交者: GitHub

Merge pull request #97825 from microsoft/isidorn/accessibilityInformation

vscode api: introduce accessibilityInformation
......@@ -44,7 +44,7 @@ export interface IListViewDragAndDrop<T> extends IListDragAndDrop<T> {
export interface IListViewAccessibilityProvider<T> {
getSetSize?(element: T, index: number, listLength: number): number;
getPosInSet?(element: T, index: number): number;
getRole?(element: T): string;
getRole?(element: T): string | undefined;
isChecked?(element: T): boolean | undefined;
}
......@@ -158,7 +158,7 @@ class ListViewAccessibilityProvider<T> implements Required<IListViewAccessibilit
readonly getSetSize: (element: any, index: number, listLength: number) => number;
readonly getPosInSet: (element: any, index: number) => number;
readonly getRole: (element: T) => string;
readonly getRole: (element: T) => string | undefined;
readonly isChecked: (element: T) => boolean | undefined;
constructor(accessibilityProvider?: IListViewAccessibilityProvider<T>) {
......@@ -652,7 +652,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
if (!item.row) {
item.row = this.cache.alloc(item.templateId);
const role = this.accessibilityProvider.getRole(item.element);
const role = this.accessibilityProvider.getRole(item.element) || 'listitem';
item.row!.domNode!.setAttribute('role', role);
const checked = this.accessibilityProvider.isChecked(item.element);
if (typeof checked !== 'undefined') {
......
......@@ -32,3 +32,8 @@ export const enum AccessibilitySupport {
}
export const CONTEXT_ACCESSIBILITY_MODE_ENABLED = new RawContextKey<boolean>('accessibilityModeEnabled', false);
export interface IAccessibilityInformation {
label: string;
role?: string;
}
......@@ -1039,6 +1039,11 @@ declare module 'vscode' {
*/
label?: string | TreeItemLabel | /* for compilation */ any;
/**
* Accessibility information used when screen reader interacts with this tree item.
*/
accessibilityInformation?: AccessibilityInformation;
/**
* @param label Label describing this item
* @param collapsibleState [TreeItemCollapsibleState](#TreeItemCollapsibleState) of the tree item. Default is [TreeItemCollapsibleState.None](#TreeItemCollapsibleState.None)
......@@ -1100,6 +1105,11 @@ declare module 'vscode' {
*/
name: string;
/**
* Accessibility information used when screen reader interacts with this status bar item.
*/
accessibilityInformation?: AccessibilityInformation;
/**
* The alignment of the status bar item.
*/
......@@ -1986,6 +1996,11 @@ declare module 'vscode' {
*/
contextValue?: string;
/**
* Accessibility information used when screen reader interacts with this timeline item.
*/
accessibilityInformation?: AccessibilityInformation;
/**
* @param label A human-readable string describing the timeline item
* @param timestamp A timestamp (in milliseconds since 1 January 1970 00:00:00) for when the timeline item occurred
......@@ -2133,4 +2148,24 @@ declare module 'vscode' {
}
//#endregion
//#region Accessibility information: https://github.com/microsoft/vscode/issues/95360
/**
* Accessibility information which controls screen reader behavior.
*/
export interface AccessibilityInformation {
label: string;
role?: string;
}
export interface StatusBarItem {
/**
* Accessibility information used when screen reader interacts with this StatusBar item
*/
accessibilityInformation?: AccessibilityInformation;
}
//#endregion
}
......@@ -9,6 +9,7 @@ import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { dispose } from 'vs/base/common/lifecycle';
import { Command } from 'vs/editor/common/modes';
import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility';
@extHostNamedCustomer(MainContext.MainThreadStatusBar)
export class MainThreadStatusBar implements MainThreadStatusBarShape {
......@@ -25,9 +26,14 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
this.entries.clear();
}
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined): void {
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation): void {
// if there are icons in the text use the tooltip for the aria label
const ariaLabel = text.indexOf('$(') === -1 ? text : tooltip || text;
let ariaLabel: string;
if (accessibilityInformation) {
ariaLabel = accessibilityInformation.label;
} else {
ariaLabel = text.indexOf('$(') === -1 ? text : tooltip || text;
}
const entry: IStatusbarEntry = { text, tooltip, command, color, ariaLabel };
if (typeof priority === 'undefined') {
......
......@@ -531,12 +531,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
let id: string;
let name: string;
let alignment: number | undefined;
let accessibilityInformation: vscode.AccessibilityInformation | undefined = undefined;
if (alignmentOrOptions && typeof alignmentOrOptions !== 'number') {
id = alignmentOrOptions.id;
name = alignmentOrOptions.name;
alignment = alignmentOrOptions.alignment;
priority = alignmentOrOptions.priority;
accessibilityInformation = alignmentOrOptions.accessibilityInformation;
} else {
id = extension.identifier.value;
name = nls.localize('extensionLabel', "{0} (Extension)", extension.displayName || extension.name);
......@@ -544,7 +546,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
priority = priority;
}
return extHostStatusBar.createStatusBarEntry(id, name, alignment, priority);
return extHostStatusBar.createStatusBarEntry(id, name, alignment, priority, accessibilityInformation);
},
setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): vscode.Disposable {
return extHostStatusBar.setStatusBarMessage(text, timeoutOrThenable);
......
......@@ -56,6 +56,7 @@ import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/cal
import { Dto } from 'vs/base/common/types';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { DebugConfigurationProviderTriggerKind } from 'vs/workbench/api/common/extHostTypes';
import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility';
export interface IEnvironment {
isExtensionDevelopmentDebug: boolean;
......@@ -545,7 +546,7 @@ export interface MainThreadQuickOpenShape extends IDisposable {
}
export interface MainThreadStatusBarShape extends IDisposable {
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: ICommandDto | undefined, color: string | ThemeColor | undefined, alignment: statusbar.StatusbarAlignment, priority: number | undefined): void;
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: ICommandDto | undefined, color: string | ThemeColor | undefined, alignment: statusbar.StatusbarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation | undefined): void;
$dispose(id: number): void;
}
......
......@@ -35,8 +35,9 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
private _timeoutHandle: any;
private _proxy: MainThreadStatusBarShape;
private _commands: CommandsConverter;
private _accessibilityInformation?: vscode.AccessibilityInformation;
constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, id: string, name: string, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number) {
constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, id: string, name: string, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number, accessibilityInformation?: vscode.AccessibilityInformation) {
this._id = ExtHostStatusBarEntry.ID_GEN++;
this._proxy = proxy;
this._commands = commands;
......@@ -44,6 +45,7 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
this._statusName = name;
this._alignment = alignment;
this._priority = priority;
this._accessibilityInformation = accessibilityInformation;
}
public get id(): number {
......@@ -74,6 +76,10 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
return this._command?.fromApi;
}
public get accessibilityInformation(): vscode.AccessibilityInformation | undefined {
return this._accessibilityInformation;
}
public set text(text: string) {
this._text = text;
this.update();
......@@ -136,7 +142,7 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
// Set to status bar
this._proxy.$setEntry(this.id, this._statusId, this._statusName, this.text, this.tooltip, this._command?.internal, this.color,
this._alignment === ExtHostStatusBarAlignment.Left ? MainThreadStatusBarAlignment.LEFT : MainThreadStatusBarAlignment.RIGHT,
this._priority);
this._priority, this._accessibilityInformation);
}, 0);
}
......@@ -196,8 +202,8 @@ export class ExtHostStatusBar {
this._statusMessage = new StatusBarMessage(this);
}
createStatusBarEntry(id: string, name: string, alignment?: ExtHostStatusBarAlignment, priority?: number): vscode.StatusBarItem {
return new ExtHostStatusBarEntry(this._proxy, this._commands, id, name, alignment, priority);
createStatusBarEntry(id: string, name: string, alignment?: ExtHostStatusBarAlignment, priority?: number, accessibilityInformation?: vscode.AccessibilityInformation): vscode.StatusBarItem {
return new ExtHostStatusBarEntry(this._proxy, this._commands, id, name, alignment, priority, accessibilityInformation);
}
setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): Disposable {
......
......@@ -152,7 +152,8 @@ export class ExtHostTimeline implements IExtHostTimeline {
command: item.command ? commandConverter.toInternal(item.command, disposables) : undefined,
icon: icon,
iconDark: iconDark,
themeIcon: themeIcon
themeIcon: themeIcon,
accessibilityInformation: item.accessibilityInformation
};
};
};
......@@ -188,4 +189,3 @@ export class ExtHostTimeline implements IExtHostTimeline {
function getUriKey(uri: URI | undefined): string | undefined {
return uri?.toString();
}
......@@ -486,7 +486,7 @@ class ExtHostTreeView<T> extends Disposable {
return node;
}
private createTreeNode(element: T, extensionTreeItem: vscode.TreeItem, parent: TreeNode | Root): TreeNode {
private createTreeNode(element: T, extensionTreeItem: vscode.TreeItem2, parent: TreeNode | Root): TreeNode {
const disposable = new DisposableStore();
const handle = this.createHandle(element, extensionTreeItem, parent);
const icon = this.getLightIconPath(extensionTreeItem);
......@@ -502,7 +502,8 @@ class ExtHostTreeView<T> extends Disposable {
icon,
iconDark: this.getDarkIconPath(extensionTreeItem) || icon,
themeIcon: extensionTreeItem.iconPath instanceof ThemeIcon ? { id: extensionTreeItem.iconPath.id } : undefined,
collapsibleState: isUndefinedOrNull(extensionTreeItem.collapsibleState) ? TreeItemCollapsibleState.None : extensionTreeItem.collapsibleState
collapsibleState: isUndefinedOrNull(extensionTreeItem.collapsibleState) ? TreeItemCollapsibleState.None : extensionTreeItem.collapsibleState,
accessibilityInformation: extensionTreeItem.accessibilityInformation
};
return {
......
......@@ -425,8 +425,15 @@ export class TreeView extends Disposable implements ITreeView {
identityProvider: new TreeViewIdentityProvider(),
accessibilityProvider: {
getAriaLabel(element: ITreeItem): string {
if (element.accessibilityInformation) {
return element.accessibilityInformation.label;
}
return element.tooltip ? element.tooltip : element.label ? element.label.label : '';
},
getRole(element: ITreeItem): string | undefined {
return element.accessibilityInformation?.role;
},
getWidgetAriaLabel(): string {
return widgetAriaLabel;
}
......
......@@ -22,6 +22,7 @@ import { SetMap } from 'vs/base/common/collections';
import { IProgressIndicator } from 'vs/platform/progress/common/progress';
import Severity from 'vs/base/common/severity';
import { IPaneComposite } from 'vs/workbench/common/panecomposite';
import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility';
export const TEST_VIEW_CONTAINER_ID = 'workbench.view.extension.test';
......@@ -634,6 +635,8 @@ export interface ITreeItem {
command?: Command;
children?: ITreeItem[];
accessibilityInformation?: IAccessibilityInformation;
}
export interface ITreeViewDataProvider {
......
......@@ -883,7 +883,7 @@ export class TimelinePane extends ViewPane {
if (isLoadMoreCommand(element)) {
return element.ariaLabel;
}
return element.ariaLabel ?? localize('timeline.aria.item', "{0}: {1}", element.relativeTime ?? '', element.label);
return element.accessibilityInformation ? element.accessibilityInformation.label : localize('timeline.aria.item', "{0}: {1}", element.relativeTime ?? '', element.label);
},
getWidgetAriaLabel(): string {
return localize('timeline', "Timeline");
......
......@@ -10,6 +10,7 @@ import { URI } from 'vs/base/common/uri';
import { Command } from 'vs/editor/common/modes';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility';
export function toKey(extension: ExtensionIdentifier | string, source: string) {
return `${typeof extension === 'string' ? extension : ExtensionIdentifier.toKey(extension)}|${source}`;
......@@ -24,7 +25,7 @@ export interface TimelineItem {
id?: string;
timestamp: number;
label: string;
ariaLabel?: string;
accessibilityInformation?: IAccessibilityInformation;
icon?: URI,
iconDark?: URI,
themeIcon?: { id: string },
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册