mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-29 18:09:01 +01:00
The Paged Screen Reader strategy works really well for Narrator
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 <strong>' + inputStr + '</strong>';
|
||||
title.innerHTML = description + '. Type <strong>' + inputStr + '</strong>';
|
||||
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));
|
||||
});
|
||||
document.body.appendChild(doCreateTest(t.description, t.in, t.out));
|
||||
});
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Vendored
-6
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user