Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/accessibility/browser/accessibilityStatus.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Disposable, MutableDisposable } from '../../../../base/common/lifecycle.js';
7
import { Event } from '../../../../base/common/event.js';
8
import Severity from '../../../../base/common/severity.js';
9
import { localize } from '../../../../nls.js';
10
import { IAccessibilityService } from '../../../../platform/accessibility/common/accessibility.js';
11
import { CommandsRegistry } from '../../../../platform/commands/common/commands.js';
12
import { ConfigurationTarget, IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
13
import { INotificationHandle, INotificationService, NotificationPriority } from '../../../../platform/notification/common/notification.js';
14
import { IWorkbenchContribution } from '../../../common/contributions.js';
15
import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from '../../../services/statusbar/browser/statusbar.js';
16
import { IOpenerService } from '../../../../platform/opener/common/opener.js';
17
18
export class AccessibilityStatus extends Disposable implements IWorkbenchContribution {
19
20
static readonly ID = 'workbench.contrib.accessibilityStatus';
21
22
private screenReaderNotification: INotificationHandle | null = null;
23
private promptedScreenReader: boolean = false;
24
private readonly screenReaderModeElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
25
26
constructor(
27
@IConfigurationService private readonly configurationService: IConfigurationService,
28
@INotificationService private readonly notificationService: INotificationService,
29
@IAccessibilityService private readonly accessibilityService: IAccessibilityService,
30
@IStatusbarService private readonly statusbarService: IStatusbarService,
31
@IOpenerService private readonly openerService: IOpenerService,
32
) {
33
super();
34
35
this._register(CommandsRegistry.registerCommand({ id: 'showEditorScreenReaderNotification', handler: () => this.showScreenReaderNotification() }));
36
37
this.updateScreenReaderModeElement(this.accessibilityService.isScreenReaderOptimized());
38
39
this.registerListeners();
40
}
41
42
private registerListeners(): void {
43
this._register(this.accessibilityService.onDidChangeScreenReaderOptimized(() => this.onScreenReaderModeChange()));
44
45
this._register(this.configurationService.onDidChangeConfiguration(c => {
46
if (c.affectsConfiguration('editor.accessibilitySupport')) {
47
this.onScreenReaderModeChange();
48
}
49
}));
50
}
51
52
private showScreenReaderNotification(): void {
53
this.screenReaderNotification = this.notificationService.prompt(
54
Severity.Info,
55
localize('screenReaderDetectedExplanation.question', "Screen reader usage detected. Do you want to enable {0} to optimize the editor for screen reader usage?", 'editor.accessibilitySupport'),
56
[{
57
label: localize('screenReaderDetectedExplanation.answerYes', "Yes"),
58
run: () => {
59
this.configurationService.updateValue('editor.accessibilitySupport', 'on', ConfigurationTarget.USER);
60
}
61
}, {
62
label: localize('screenReaderDetectedExplanation.answerNo', "No"),
63
run: () => {
64
this.configurationService.updateValue('editor.accessibilitySupport', 'off', ConfigurationTarget.USER);
65
}
66
},
67
{
68
label: localize('screenReaderDetectedExplanation.answerLearnMore', "Learn More"),
69
run: () => {
70
this.openerService.open('https://code.visualstudio.com/docs/editor/accessibility#_screen-readers');
71
}
72
}],
73
{
74
sticky: true,
75
priority: NotificationPriority.URGENT
76
}
77
);
78
79
Event.once(this.screenReaderNotification.onDidClose)(() => this.screenReaderNotification = null);
80
}
81
private updateScreenReaderModeElement(visible: boolean): void {
82
if (visible) {
83
if (!this.screenReaderModeElement.value) {
84
const text = localize('screenReaderDetected', "Screen Reader Optimized");
85
this.screenReaderModeElement.value = this.statusbarService.addEntry({
86
name: localize('status.editor.screenReaderMode', "Screen Reader Mode"),
87
text,
88
ariaLabel: text,
89
command: 'showEditorScreenReaderNotification',
90
kind: 'prominent',
91
showInAllWindows: true
92
}, 'status.editor.screenReaderMode', StatusbarAlignment.RIGHT, 100.6);
93
}
94
} else {
95
this.screenReaderModeElement.clear();
96
}
97
}
98
99
private onScreenReaderModeChange(): void {
100
101
// We only support text based editors
102
const screenReaderDetected = this.accessibilityService.isScreenReaderOptimized();
103
if (screenReaderDetected) {
104
const screenReaderConfiguration = this.configurationService.getValue('editor.accessibilitySupport');
105
if (screenReaderConfiguration === 'auto') {
106
if (!this.promptedScreenReader) {
107
this.promptedScreenReader = true;
108
setTimeout(() => this.showScreenReaderNotification(), 100);
109
}
110
}
111
}
112
113
if (this.screenReaderNotification) {
114
this.screenReaderNotification.close();
115
}
116
this.updateScreenReaderModeElement(this.accessibilityService.isScreenReaderOptimized());
117
}
118
}
119
120