From dd7fe3b3fe6c0f705ce86fd5ca807b52fa275833 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 24 May 2017 12:01:12 +0200 Subject: [PATCH] The Paged Screen Reader strategy works really well for Narrator --- .../browser/controller/textAreaHandler.ts | 14 +--- .../browser/controller/textAreaState.ts | 68 +++---------------- src/vs/editor/common/config/editorOptions.ts | 10 --- .../test/browser/controller/imeTester.ts | 32 ++------- .../browser/controller/textAreaState.test.ts | 51 +------------- src/vs/monaco.d.ts | 6 -- 6 files changed, 17 insertions(+), 164 deletions(-) diff --git a/src/vs/editor/browser/controller/textAreaHandler.ts b/src/vs/editor/browser/controller/textAreaHandler.ts index 65a7639b2d53..f9ae737307ec 100644 --- a/src/vs/editor/browser/controller/textAreaHandler.ts +++ b/src/vs/editor/browser/controller/textAreaHandler.ts @@ -8,7 +8,7 @@ import 'vs/css!./textAreaHandler'; import * as platform from 'vs/base/common/platform'; import * as browser from 'vs/base/browser/browser'; import { TextAreaInput, ITextAreaInputHost, IPasteData, ICompositionData } from 'vs/editor/browser/controller/textAreaInput'; -import { ISimpleModel, ITypeData, TextAreaState, IENarratorStrategy, NVDAPagedStrategy } from 'vs/editor/browser/controller/textAreaState'; +import { ISimpleModel, ITypeData, TextAreaState, PagedScreenReaderStrategy } from 'vs/editor/browser/controller/textAreaState'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { Position } from 'vs/editor/common/core/position'; @@ -61,7 +61,6 @@ export class TextAreaHandler extends ViewPart { private _contentHeight: number; private _scrollLeft: number; private _scrollTop: number; - private _experimentalScreenReader: boolean; private _fontInfo: BareFontInfo; private _lineHeight: number; private _emptySelectionClipboard: boolean; @@ -93,7 +92,6 @@ export class TextAreaHandler extends ViewPart { this._contentHeight = conf.layoutInfo.contentHeight; this._scrollLeft = 0; this._scrollTop = 0; - this._experimentalScreenReader = conf.viewInfo.experimentalScreenReader; this._fontInfo = conf.fontInfo; this._lineHeight = conf.lineHeight; this._emptySelectionClipboard = conf.emptySelectionClipboard; @@ -168,13 +166,7 @@ export class TextAreaHandler extends ViewPart { return TextAreaState.EMPTY; } - const selection = this._selections[0]; - - if (this._experimentalScreenReader) { - return NVDAPagedStrategy.fromEditorSelection(currentState, simpleModel, selection); - } - - return IENarratorStrategy.fromEditorSelection(currentState, simpleModel, selection); + return PagedScreenReaderStrategy.fromEditorSelection(currentState, simpleModel, this._selections[0]); } }; @@ -279,8 +271,6 @@ export class TextAreaHandler extends ViewPart { this._fontInfo = conf.fontInfo; } if (e.viewInfo) { - this._experimentalScreenReader = conf.viewInfo.experimentalScreenReader; - this._textAreaInput.writeScreenReaderContent('strategy changed'); this.textArea.setAttribute('aria-label', conf.viewInfo.ariaLabel); } if (e.layoutInfo) { diff --git a/src/vs/editor/browser/controller/textAreaState.ts b/src/vs/editor/browser/controller/textAreaState.ts index 2e3bf4009a45..67cb24979e10 100644 --- a/src/vs/editor/browser/controller/textAreaState.ts +++ b/src/vs/editor/browser/controller/textAreaState.ts @@ -198,79 +198,27 @@ export class TextAreaState { } } -export class IENarratorStrategy { - - public static fromEditorSelection(previousState: TextAreaState, model: ISimpleModel, selection: Range): TextAreaState { - let LIMIT_CHARS = 100; - let PADDING_LINES_COUNT = 0; - - let selectionStartLineNumber = selection.startLineNumber, - selectionStartColumn = selection.startColumn, - selectionEndLineNumber = selection.endLineNumber, - selectionEndColumn = selection.endColumn, - selectionEndLineNumberMaxColumn = model.getLineMaxColumn(selectionEndLineNumber); - - // If the selection is empty and we have switched line numbers, expand selection to full line (helps Narrator trigger a full line read) - if (selection.isEmpty() && previousState && previousState.selectionToken !== selectionStartLineNumber) { - selectionStartColumn = 1; - selectionEndColumn = selectionEndLineNumberMaxColumn; - } - - // `pretext` contains the text before the selection - let pretext = ''; - let startLineNumber = Math.max(1, selectionStartLineNumber - PADDING_LINES_COUNT); - if (startLineNumber < selectionStartLineNumber) { - pretext = model.getValueInRange(new Range(startLineNumber, 1, selectionStartLineNumber, 1), EndOfLinePreference.LF); - } - pretext += model.getValueInRange(new Range(selectionStartLineNumber, 1, selectionStartLineNumber, selectionStartColumn), EndOfLinePreference.LF); - if (pretext.length > LIMIT_CHARS) { - pretext = pretext.substring(pretext.length - LIMIT_CHARS, pretext.length); - } - - - // `posttext` contains the text after the selection - let posttext = ''; - let endLineNumber = Math.min(selectionEndLineNumber + PADDING_LINES_COUNT, model.getLineCount()); - posttext += model.getValueInRange(new Range(selectionEndLineNumber, selectionEndColumn, selectionEndLineNumber, selectionEndLineNumberMaxColumn), EndOfLinePreference.LF); - if (endLineNumber > selectionEndLineNumber) { - posttext = '\n' + model.getValueInRange(new Range(selectionEndLineNumber + 1, 1, endLineNumber, model.getLineMaxColumn(endLineNumber)), EndOfLinePreference.LF); - } - if (posttext.length > LIMIT_CHARS) { - posttext = posttext.substring(0, LIMIT_CHARS); - } - - - // `text` contains the text of the selection - let text = model.getValueInRange(new Range(selectionStartLineNumber, selectionStartColumn, selectionEndLineNumber, selectionEndColumn), EndOfLinePreference.LF); - if (text.length > 2 * LIMIT_CHARS) { - text = text.substring(0, LIMIT_CHARS) + String.fromCharCode(8230) + text.substring(text.length - LIMIT_CHARS, text.length); - } - - return new TextAreaState(pretext + text + posttext, pretext.length, pretext.length + text.length, selectionStartLineNumber); - } -} - -export class NVDAPagedStrategy { +export class PagedScreenReaderStrategy { private static _LINES_PER_PAGE = 10; private static _getPageOfLine(lineNumber: number): number { - return Math.floor((lineNumber - 1) / NVDAPagedStrategy._LINES_PER_PAGE); + return Math.floor((lineNumber - 1) / PagedScreenReaderStrategy._LINES_PER_PAGE); } private static _getRangeForPage(page: number): Range { - let offset = page * NVDAPagedStrategy._LINES_PER_PAGE; + let offset = page * PagedScreenReaderStrategy._LINES_PER_PAGE; let startLineNumber = offset + 1; - let endLineNumber = offset + NVDAPagedStrategy._LINES_PER_PAGE; + let endLineNumber = offset + PagedScreenReaderStrategy._LINES_PER_PAGE; return new Range(startLineNumber, 1, endLineNumber, Constants.MAX_SAFE_SMALL_INTEGER); } public static fromEditorSelection(previousState: TextAreaState, model: ISimpleModel, selection: Range): TextAreaState { - let selectionStartPage = NVDAPagedStrategy._getPageOfLine(selection.startLineNumber); - let selectionStartPageRange = NVDAPagedStrategy._getRangeForPage(selectionStartPage); + let selectionStartPage = PagedScreenReaderStrategy._getPageOfLine(selection.startLineNumber); + let selectionStartPageRange = PagedScreenReaderStrategy._getRangeForPage(selectionStartPage); - let selectionEndPage = NVDAPagedStrategy._getPageOfLine(selection.endLineNumber); - let selectionEndPageRange = NVDAPagedStrategy._getRangeForPage(selectionEndPage); + let selectionEndPage = PagedScreenReaderStrategy._getPageOfLine(selection.endLineNumber); + let selectionEndPageRange = PagedScreenReaderStrategy._getRangeForPage(selectionEndPage); let pretextRange = selectionStartPageRange.intersectRanges(new Range(1, 1, selection.startLineNumber, selection.startColumn)); let pretext = model.getValueInRange(pretextRange, EndOfLinePreference.LF); diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 4787fcbaba59..59056ff82270 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -118,11 +118,6 @@ export interface IEditorOptions { * @internal */ inDiffEditor?: boolean; - /** - * Enable experimental screen reader support. - * Defaults to `true`. - */ - experimentalScreenReader?: boolean; /** * The aria label for the editor's textarea (when it is focused). */ @@ -710,7 +705,6 @@ export interface EditorWrappingInfo { export interface InternalEditorViewOptions { readonly extraEditorClassName: string; readonly disableMonospaceOptimizations: boolean; - readonly experimentalScreenReader: boolean; readonly rulers: number[]; readonly ariaLabel: string; readonly renderLineNumbers: boolean; @@ -963,7 +957,6 @@ export class InternalEditorOptions { return ( a.extraEditorClassName === b.extraEditorClassName && a.disableMonospaceOptimizations === b.disableMonospaceOptimizations - && a.experimentalScreenReader === b.experimentalScreenReader && this._equalsNumberArrays(a.rulers, b.rulers) && a.ariaLabel === b.ariaLabel && a.renderLineNumbers === b.renderLineNumbers @@ -1542,7 +1535,6 @@ export class EditorOptionsValidator { return { extraEditorClassName: _string(opts.extraEditorClassName, defaults.extraEditorClassName), disableMonospaceOptimizations: disableMonospaceOptimizations, - experimentalScreenReader: _boolean(opts.experimentalScreenReader, defaults.experimentalScreenReader), rulers: rulers, ariaLabel: _string(opts.ariaLabel, defaults.ariaLabel), renderLineNumbers: renderLineNumbers, @@ -1641,7 +1633,6 @@ export class InternalEditorOptionsFactory { viewInfo: { extraEditorClassName: opts.viewInfo.extraEditorClassName, disableMonospaceOptimizations: opts.viewInfo.disableMonospaceOptimizations, - experimentalScreenReader: opts.viewInfo.experimentalScreenReader, rulers: opts.viewInfo.rulers, ariaLabel: opts.viewInfo.ariaLabel, renderLineNumbers: opts.viewInfo.renderLineNumbers, @@ -2036,7 +2027,6 @@ export const EDITOR_DEFAULTS: IValidatedEditorOptions = { viewInfo: { extraEditorClassName: '', disableMonospaceOptimizations: false, - experimentalScreenReader: true, rulers: [], ariaLabel: nls.localize('editorViewAccessibleLabel', "Editor content"), renderLineNumbers: true, diff --git a/src/vs/editor/test/browser/controller/imeTester.ts b/src/vs/editor/test/browser/controller/imeTester.ts index 855ab7156b7a..6f8ad840fa8e 100644 --- a/src/vs/editor/test/browser/controller/imeTester.ts +++ b/src/vs/editor/test/browser/controller/imeTester.ts @@ -5,7 +5,7 @@ 'use strict'; import { TextAreaInput, ITextAreaInputHost } from 'vs/editor/browser/controller/textAreaInput'; -import { ISimpleModel, TextAreaState, IENarratorStrategy, NVDAPagedStrategy } from 'vs/editor/browser/controller/textAreaState'; +import { ISimpleModel, TextAreaState, PagedScreenReaderStrategy } from 'vs/editor/browser/controller/textAreaState'; import { Range, IRange } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { createFastDomNode } from 'vs/base/browser/fastDomNode'; @@ -13,11 +13,6 @@ import * as browser from 'vs/base/browser/browser'; // To run this test, open imeTester.html -const enum TextAreaStrategy { - IENarrator, - NVDA -} - class SingleLineTestModel implements ISimpleModel { private _line: string; @@ -67,7 +62,7 @@ class TestView { } } -function doCreateTest(strategy: TextAreaStrategy, description: string, inputStr: string, expectedStr: string): HTMLElement { +function doCreateTest(description: string, inputStr: string, expectedStr: string): HTMLElement { let cursorOffset: number = 0; let cursorLength: number = 0; @@ -77,17 +72,7 @@ function doCreateTest(strategy: TextAreaStrategy, description: string, inputStr: let title = document.createElement('div'); title.className = 'title'; - const toStr = (value: TextAreaStrategy): string => { - if (value === TextAreaStrategy.IENarrator) { - return 'IENarrator'; - } - if (value === TextAreaStrategy.NVDA) { - return 'NVDA'; - } - return '???'; - }; - - title.innerHTML = toStr(strategy) + ' strategy: ' + description + '. Type ' + inputStr + ''; + title.innerHTML = description + '. Type ' + inputStr + ''; container.appendChild(title); let startBtn = document.createElement('button'); @@ -114,11 +99,7 @@ function doCreateTest(strategy: TextAreaStrategy, description: string, inputStr: const selection = new Range(1, 1 + cursorOffset, 1, 1 + cursorOffset + cursorLength); - if (strategy === TextAreaStrategy.IENarrator) { - return IENarratorStrategy.fromEditorSelection(currentState, model, selection); - } - - return NVDAPagedStrategy.fromEditorSelection(currentState, model, selection); + return PagedScreenReaderStrategy.fromEditorSelection(currentState, model, selection); } }; @@ -194,6 +175,5 @@ const TESTS = [ ]; TESTS.forEach((t) => { - document.body.appendChild(doCreateTest(TextAreaStrategy.NVDA, t.description, t.in, t.out)); - document.body.appendChild(doCreateTest(TextAreaStrategy.IENarrator, t.description, t.in, t.out)); -}); \ No newline at end of file + document.body.appendChild(doCreateTest(t.description, t.in, t.out)); +}); diff --git a/src/vs/editor/test/browser/controller/textAreaState.test.ts b/src/vs/editor/test/browser/controller/textAreaState.test.ts index a385e6904f73..cd487fd10dfe 100644 --- a/src/vs/editor/test/browser/controller/textAreaState.test.ts +++ b/src/vs/editor/test/browser/controller/textAreaState.test.ts @@ -5,7 +5,7 @@ 'use strict'; import * as assert from 'assert'; -import { ISimpleModel, TextAreaState, ITextAreaWrapper, IENarratorStrategy } from 'vs/editor/browser/controller/textAreaState'; +import { ISimpleModel, TextAreaState, ITextAreaWrapper, PagedScreenReaderStrategy } from 'vs/editor/browser/controller/textAreaState'; import { Range } from 'vs/editor/common/core/range'; import { EndOfLinePreference } from 'vs/editor/common/editorCommon'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -488,55 +488,6 @@ suite('TextAreaState', () => { '⌨️', 0 ); }); - - function testFromEditorSelectionAndPreviousState(eol: string, lines: string[], range: Range, prevSelectionToken: number): TextAreaState { - let model = new SimpleModel(lines, eol); - let previousState = new TextAreaState('', 0, 0, prevSelectionToken); - return IENarratorStrategy.fromEditorSelection(previousState, model, range); - } - - test('fromEditorSelectionAndPreviousState - no selection on first line', () => { - let actual = testFromEditorSelectionAndPreviousState('\n', [ - 'Just a line', - 'And another line' - ], new Range(1, 1, 1, 1), 0); - assertTextAreaState(actual, 'Just a line', 0, 11, 1); - }); - - test('fromEditorSelectionAndPreviousState - no selection on second line', () => { - let actual = testFromEditorSelectionAndPreviousState('\n', [ - 'Just a line', - 'And another line', - 'And yet another line', - ], new Range(2, 1, 2, 1), 0); - assertTextAreaState(actual, 'And another line', 0, 16, 2); - }); - - test('fromEditorSelectionAndPreviousState - on a long line with selectionToken mismatch', () => { - let aLongLine = 'a'; - for (let i = 0; i < 10; i++) { - aLongLine = aLongLine + aLongLine; - } - let actual = testFromEditorSelectionAndPreviousState('\n', [ - 'Just a line', - aLongLine, - 'And yet another line', - ], new Range(2, 500, 2, 500), 0); - assertTextAreaState(actual, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa…aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 0, 201, 2); - }); - - test('fromEditorSelectionAndPreviousState - on a long line with same selectionToken', () => { - let aLongLine = 'a'; - for (let i = 0; i < 10; i++) { - aLongLine = aLongLine + aLongLine; - } - let actual = testFromEditorSelectionAndPreviousState('\n', [ - 'Just a line', - aLongLine, - 'And yet another line', - ], new Range(2, 500, 2, 500), 2); - assertTextAreaState(actual, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 100, 100, 2); - }); }); class SimpleModel implements ISimpleModel { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 72ca96c80cb1..cee64b0706f5 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -2666,11 +2666,6 @@ declare module monaco.editor { * Configuration options for the editor. */ export interface IEditorOptions { - /** - * Enable experimental screen reader support. - * Defaults to `true`. - */ - experimentalScreenReader?: boolean; /** * The aria label for the editor's textarea (when it is focused). */ @@ -3191,7 +3186,6 @@ declare module monaco.editor { export interface InternalEditorViewOptions { readonly extraEditorClassName: string; readonly disableMonospaceOptimizations: boolean; - readonly experimentalScreenReader: boolean; readonly rulers: number[]; readonly ariaLabel: string; readonly renderLineNumbers: boolean;