Skip to content

Commit c42e107

Browse files
authored
Merge pull request microsoft#186229 from microsoft/aamunger/accessibility
notebook accessibility help
2 parents 0f5502c + da693d2 commit c42e107

File tree

3 files changed

+76
-27
lines changed

3 files changed

+76
-27
lines changed

src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ import { NotebookKernelHistoryService } from 'vs/workbench/contrib/notebook/brow
112112
import { INotebookLoggingService } from 'vs/workbench/contrib/notebook/common/notebookLoggingService';
113113
import { NotebookLoggingService } from 'vs/workbench/contrib/notebook/browser/services/notebookLoggingServiceImpl';
114114
import product from 'vs/platform/product/common/product';
115+
import { AccessibilityHelpAction } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
116+
import { NOTEBOOK_IS_ACTIVE_EDITOR } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
117+
import { runAccessibilityHelpAction } from 'vs/workbench/contrib/notebook/browser/notebookAccessibilityHelp';
115118

116119
/*--------------------------------------------------------------------------------------------- */
117120

@@ -672,6 +675,20 @@ class NotebookLanguageSelectorScoreRefine {
672675
}
673676
}
674677

678+
class NotebookAccessibilityHelpContribution extends Disposable {
679+
static ID: 'chatAccessibilityHelpContribution';
680+
constructor() {
681+
super();
682+
this._register(AccessibilityHelpAction.addImplementation(105, 'notebook', async accessor => {
683+
const codeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor() || accessor.get(ICodeEditorService).getFocusedCodeEditor();
684+
if (!codeEditor) {
685+
return;
686+
}
687+
runAccessibilityHelpAction(accessor, codeEditor);
688+
}, NOTEBOOK_IS_ACTIVE_EDITOR));
689+
}
690+
}
691+
675692
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
676693
workbenchContributionsRegistry.registerWorkbenchContribution(NotebookContribution, LifecyclePhase.Starting);
677694
workbenchContributionsRegistry.registerWorkbenchContribution(CellContentProvider, LifecyclePhase.Starting);
@@ -680,6 +697,7 @@ workbenchContributionsRegistry.registerWorkbenchContribution(RegisterSchemasCont
680697
workbenchContributionsRegistry.registerWorkbenchContribution(NotebookEditorManager, LifecyclePhase.Ready);
681698
workbenchContributionsRegistry.registerWorkbenchContribution(NotebookLanguageSelectorScoreRefine, LifecyclePhase.Ready);
682699
workbenchContributionsRegistry.registerWorkbenchContribution(SimpleNotebookWorkingCopyEditorHandler, LifecyclePhase.Ready);
700+
workbenchContributionsRegistry.registerWorkbenchContribution(NotebookAccessibilityHelpContribution, LifecyclePhase.Eventually);
683701

684702
registerSingleton(INotebookService, NotebookService, InstantiationType.Delayed);
685703
registerSingleton(INotebookEditorWorkerService, NotebookEditorWorkerServiceImpl, InstantiationType.Delayed);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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 { localize } from 'vs/nls';
7+
import { format } from 'vs/base/common/strings';
8+
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
9+
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
10+
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
11+
import { AccessibleViewType, IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
12+
13+
export function getAccessibilityHelpText(accessor: ServicesAccessor): string {
14+
const keybindingService = accessor.get(IKeybindingService);
15+
const content = [];
16+
content.push(localize('notebook.overview', 'The notebook view is a collection of code and markdown cells. Code cells can be executed and will produce output directly below the cell.'));
17+
content.push(descriptionForCommand('notebook.cell.edit',
18+
localize('notebook.cell.edit', 'The Edit Cell command ({0}) will focus on the cell input.'),
19+
localize('notebook.cell.editNoKb', 'The Edit Cell command will focus on the cell input and is currently not triggerable by a keybinding.'), keybindingService));
20+
content.push(descriptionForCommand('notebook.cell.quitEdit',
21+
localize('notebook.cell.quitEdit', 'The Quit Edit command ({0}) will set focus on the cell container. The default (Escape) key may need to be pressed twice first exit the virtual cursor if active.'),
22+
localize('notebook.cell.quitEditNoKb', 'The Quit Edit command will set focus on the cell container and is currently not triggerable by a keybinding.'), keybindingService));
23+
content.push(descriptionForCommand('notebook.cell.focusInOutput',
24+
localize('notebook.cell.focusInOutput', 'The Focus Output command ({0}) will set focus in the cell\'s output.'),
25+
localize('notebook.cell.focusInOutputNoKb', 'The Quit Edit command will set focus in the cell\'s output and is currently not triggerable by a keybinding.'), keybindingService));
26+
content.push(localize('notebook.cellNavigation', 'The up and down arrows will move focus between cells while focused on the outer cell container'));
27+
content.push(descriptionForCommand('notebook.cell.executeAndFocusContainer',
28+
localize('notebook.cell.executeAndFocusContainer', 'The Execute Cell command ({0}) executes the cell that currently has focus.',),
29+
localize('notebook.cell.executeAndFocusContainerNoKb', 'The Execute Cell command executes the cell that currently has focus and is currently not triggerable by a keybinding.'), keybindingService));
30+
content.push(localize('notebook.cell.insertCodeCellBelowAndFocusContainer', 'The Insert Cell Above/Below commands will create new empty code cells'));
31+
content.push(localize('notebook.changeCellType', 'The Change Cell to Code/Markdown commands are used to switch between cell types.'));
32+
33+
34+
return content.join('\n');
35+
}
36+
37+
function descriptionForCommand(commandId: string, msg: string, noKbMsg: string, keybindingService: IKeybindingService): string {
38+
const kb = keybindingService.lookupKeybinding(commandId);
39+
if (kb) {
40+
return format(msg, kb.getAriaLabel());
41+
}
42+
return format(noKbMsg, commandId);
43+
}
44+
45+
export async function runAccessibilityHelpAction(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
46+
const accessibleViewService = accessor.get(IAccessibleViewService);
47+
const helpText = getAccessibilityHelpText(accessor);
48+
const provider = accessibleViewService.registerProvider({
49+
id: 'notebook',
50+
provideContent: () => helpText,
51+
onClose: () => {
52+
editor.focus();
53+
provider.dispose();
54+
},
55+
options: { type: AccessibleViewType.HelpMenu, ariaLabel: 'Notebook accessibility help' }
56+
});
57+
accessibleViewService.show('notebook');
58+
}

src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import 'vs/css!./media/notebookCellOutput';
1515
import { PixelRatio } from 'vs/base/browser/browser';
1616
import * as DOM from 'vs/base/browser/dom';
1717
import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';
18-
import * as aria from 'vs/base/browser/ui/aria/aria';
1918
import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
2019
import { DeferredPromise, runWhenIdle, SequencerByKey } from 'vs/base/common/async';
2120
import { CancellationToken } from 'vs/base/common/cancellation';
@@ -91,7 +90,6 @@ import { INotebookLoggingService } from 'vs/workbench/contrib/notebook/common/no
9190
import { Schemas } from 'vs/base/common/network';
9291
import { DropIntoEditorController } from 'vs/editor/contrib/dropOrPasteInto/browser/dropIntoEditorController';
9392
import { CopyPasteController } from 'vs/editor/contrib/dropOrPasteInto/browser/copyPasteController';
94-
import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
9593

9694
const $ = DOM.$;
9795

@@ -2239,28 +2237,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
22392237
return undefined;
22402238
}
22412239

2242-
private _cellFocusAria(cell: ICellViewModel, focusItem: 'editor' | 'container' | 'output') {
2243-
const index = this._notebookViewModel?.getCellIndex(cell);
2244-
const verboseLabel = this.configurationService.getValue(AccessibilityVerbositySettingId.Notebook);
2245-
if (index !== undefined && index >= 0) {
2246-
let position = '';
2247-
switch (focusItem) {
2248-
case 'editor':
2249-
position = `the inner ${cell.cellKind === CellKind.Markup ? 'markdown' : 'code'} editor is focused` + (verboseLabel ? `, press escape to focus the cell container` : '');
2250-
break;
2251-
case 'output':
2252-
position = `the cell output is focused` + (verboseLabel ? `, press escape to focus the cell container` : '');
2253-
break;
2254-
case 'container':
2255-
position = `the ${cell.cellKind === CellKind.Markup ? 'markdown preview' : 'cell container'} is focused` + (verboseLabel ? `, press enter to focus the inner ${cell.cellKind === CellKind.Markup ? 'markdown' : 'code'} editor` : '');
2256-
break;
2257-
default:
2258-
break;
2259-
}
2260-
aria.alert(`Cell ${this._notebookViewModel?.getCellIndex(cell)}, ${position} `);
2261-
}
2262-
}
2263-
22642240
private _toggleNotebookCellSelection(selectedCell: ICellViewModel, selectFromPrevious: boolean): void {
22652241
const currentSelections = this._list.getSelectedElements();
22662242
const isSelected = currentSelections.includes(selectedCell);
@@ -2300,7 +2276,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
23002276

23012277
if (focusItem === 'editor') {
23022278
this.focusElement(cell);
2303-
this._cellFocusAria(cell, focusItem);
23042279
this._list.focusView();
23052280

23062281
cell.updateEditState(CellEditState.Editing, 'focusNotebookCell');
@@ -2330,7 +2305,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
23302305
}
23312306
} else if (focusItem === 'output') {
23322307
this.focusElement(cell);
2333-
this._cellFocusAria(cell, focusItem);
23342308

23352309
if (!this.hasEditorFocus()) {
23362310
this._list.focusView();
@@ -2359,7 +2333,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
23592333
cell.focusMode = CellFocusMode.Container;
23602334

23612335
this.focusElement(cell);
2362-
this._cellFocusAria(cell, focusItem);
23632336
if (!options?.skipReveal) {
23642337
if (typeof options?.focusEditorLine === 'number') {
23652338
this._cursorNavMode.set(true);

0 commit comments

Comments
 (0)