提交 dd7fe3b3 编写于 作者: A Alex Dima

The Paged Screen Reader strategy works really well for Narrator

上级 725414d3
......@@ -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));
});
\ No newline at end of file
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 {
......
......@@ -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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册