From 099889e8991773b0faf193d8e669d6151251f3d9 Mon Sep 17 00:00:00 2001 From: plundblad Date: Fri, 30 Jan 2015 02:50:00 -0800 Subject: [PATCH] Refactorings to reduce dependencies in ChromeVox 2. Mainly, this breaks out braille span classes and the EditableTextBase class into their own files. This removes lots of dependencies on code that should only run in the content script in ChromeVox classic from the ChromeVox next background script. BUG= Review URL: https://codereview.chromium.org/889593002 Cr-Commit-Position: refs/heads/master@{#313895} --- .../chromevox/braille/braille_input_handler.js | 5 +- .../braille/braille_input_handler_test.unitjs | 1 - .../braille/expanding_braille_translator.js | 10 +- .../expanding_braille_translator_test.unitjs | 12 +- .../resources/chromeos/chromevox/braille/spans.js | 65 ++ .../chromevox/background/tabs_api_handler.js | 1 + .../chromeos/chromevox/common/braille_util.js | 81 +- .../chromevox/common/braille_util_test.unitjs | 12 +- .../chromeos/chromevox/common/editable_text.js | 816 ++------------------- .../{editable_text.js => editable_text_base.js} | 678 +---------------- .../chromevox/common/editable_text_test.unitjs | 3 +- .../chromevox/cvox2/background/background.js | 9 - .../chromeos/chromevox/cvox2/background/output.js | 8 +- .../host/chrome/braille_integration_test.unitjs | 7 +- .../chromevox/walkers/layout_line_walker.js | 3 +- .../chromevox/walkers/structural_line_walker.js | 1 + .../walkers/structural_line_walker_test.unitjs | 1 - 17 files changed, 185 insertions(+), 1528 deletions(-) create mode 100644 chrome/browser/resources/chromeos/chromevox/braille/spans.js copy chrome/browser/resources/chromeos/chromevox/common/{editable_text.js => editable_text_base.js} (52%) diff --git a/chrome/browser/resources/chromeos/chromevox/braille/braille_input_handler.js b/chrome/browser/resources/chromeos/chromevox/braille/braille_input_handler.js index 04e99a38857d..1232d122ae98 100644 --- a/chrome/browser/resources/chromeos/chromevox/braille/braille_input_handler.js +++ b/chrome/browser/resources/chromeos/chromevox/braille/braille_input_handler.js @@ -133,9 +133,8 @@ cvox.BrailleInputHandler.prototype.init = function() { * spans. */ cvox.BrailleInputHandler.prototype.onDisplayContentChanged = function(text) { - var valueSpan = text.getSpanInstanceOf(cvox.BrailleUtil.ValueSpan); - var selectionSpan = text.getSpanInstanceOf( - cvox.BrailleUtil.ValueSelectionSpan); + var valueSpan = text.getSpanInstanceOf(cvox.ValueSpan); + var selectionSpan = text.getSpanInstanceOf(cvox.ValueSelectionSpan); if (!(valueSpan && selectionSpan)) { return; } diff --git a/chrome/browser/resources/chromeos/chromevox/braille/braille_input_handler_test.unitjs b/chrome/browser/resources/chromeos/chromevox/braille/braille_input_handler_test.unitjs index dada2c43c317..59fa53e7f55c 100644 --- a/chrome/browser/resources/chromeos/chromevox/braille/braille_input_handler_test.unitjs +++ b/chrome/browser/resources/chromeos/chromevox/braille/braille_input_handler_test.unitjs @@ -391,7 +391,6 @@ CvoxBrailleInputHandlerUnitTest.prototype = { closureModuleDeps: [ 'cvox.BrailleInputHandler', 'cvox.BrailleUtil', - 'cvox.Spannable', ], /** diff --git a/chrome/browser/resources/chromeos/chromevox/braille/expanding_braille_translator.js b/chrome/browser/resources/chromeos/chromevox/braille/expanding_braille_translator.js index 6d8b9f64ca34..bfab6c0ae075 100644 --- a/chrome/browser/resources/chromeos/chromevox/braille/expanding_braille_translator.js +++ b/chrome/browser/resources/chromeos/chromevox/braille/expanding_braille_translator.js @@ -9,9 +9,10 @@ goog.provide('cvox.ExpandingBrailleTranslator'); -goog.require('cvox.BrailleUtil'); goog.require('cvox.LibLouis'); goog.require('cvox.Spannable'); +goog.require('cvox.ValueSelectionSpan'); +goog.require('cvox.ValueSpan'); /** @@ -48,7 +49,7 @@ cvox.ExpandingBrailleTranslator = /** * What expansion to apply to the part of the translated string marked by the - * {@code cvox.BrailleUtil.ValueSpan} spannable. + * {@code cvox.ValueSpan} spannable. * @enum {number} */ cvox.ExpandingBrailleTranslator.ExpansionType = { @@ -200,7 +201,7 @@ cvox.ExpandingBrailleTranslator.prototype.findExpandRanges_ = function( var result = []; if (this.uncontractedTranslator_ && expansionType != cvox.ExpandingBrailleTranslator.ExpansionType.NONE) { - var value = text.getSpanInstanceOf(cvox.BrailleUtil.ValueSpan); + var value = text.getSpanInstanceOf(cvox.ValueSpan); if (value) { // The below type casts are valid because the ranges must be valid when // the span is known to exist. @@ -234,8 +235,7 @@ cvox.ExpandingBrailleTranslator.prototype.findExpandRanges_ = function( */ cvox.ExpandingBrailleTranslator.prototype.addRangesForSelection_ = function( text, valueStart, valueEnd, outRanges) { - var selection = text.getSpanInstanceOf( - cvox.BrailleUtil.ValueSelectionSpan); + var selection = text.getSpanInstanceOf(cvox.ValueSelectionSpan); if (!selection) { return; } diff --git a/chrome/browser/resources/chromeos/chromevox/braille/expanding_braille_translator_test.unitjs b/chrome/browser/resources/chromeos/chromevox/braille/expanding_braille_translator_test.unitjs index 5afc9bccb9aa..bd598dd6e272 100644 --- a/chrome/browser/resources/chromeos/chromevox/braille/expanding_braille_translator_test.unitjs +++ b/chrome/browser/resources/chromeos/chromevox/braille/expanding_braille_translator_test.unitjs @@ -18,10 +18,11 @@ CvoxExpandingBrailleTranslatorUnitTest.prototype = { /** @override */ closureModuleDeps: [ - 'cvox.BrailleUtil', 'cvox.ExpandingBrailleTranslator', 'cvox.LibLouis', 'cvox.Spannable', + 'cvox.ValueSelectionSpan', + 'cvox.ValueSpan', ] }; @@ -73,8 +74,8 @@ function assertArrayBufferMatches(expected, actual) { TEST_F('CvoxExpandingBrailleTranslatorUnitTest', 'TranslationError', function() { - var text = new cvox.Spannable('error ok', new cvox.BrailleUtil.ValueSpan()); - text.setSpan(new cvox.BrailleUtil.ValueSelectionSpan, 0, 0); + var text = new cvox.Spannable('error ok', new cvox.ValueSpan()); + text.setSpan(new cvox.ValueSelectionSpan, 0, 0); var contractedTranslator = new FakeTranslator('c'); // Translator that always results in an error. var uncontractedTranslator = { @@ -199,11 +200,10 @@ function runTranslationTestVariants(testCase, contracted, valueExpansion) { function createText(text, opt_selectionStart, opt_selectionEnd) { var result = new cvox.Spannable(text); - result.setSpan( - new cvox.BrailleUtil.ValueSpan, 0, text.length); + result.setSpan(new cvox.ValueSpan, 0, text.length); if (goog.isDef(opt_selectionStart)) { result.setSpan( - new cvox.BrailleUtil.ValueSelectionSpan, + new cvox.ValueSelectionSpan, opt_selectionStart, goog.isDef(opt_selectionEnd) ? opt_selectionEnd : opt_selectionStart); } diff --git a/chrome/browser/resources/chromeos/chromevox/braille/spans.js b/chrome/browser/resources/chromeos/chromevox/braille/spans.js new file mode 100644 index 000000000000..560fa0fca679 --- /dev/null +++ b/chrome/browser/resources/chromeos/chromevox/braille/spans.js @@ -0,0 +1,65 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Objects used in spannables as annotations for ARIA values + * and selections. + */ + +goog.provide('cvox.ValueSelectionSpan'); +goog.provide('cvox.ValueSpan'); + +goog.require('cvox.Spannable'); + +/** + * Attached to the value region of a braille spannable. + * @param {number} offset The offset of the span into the value. + * @constructor + */ +cvox.ValueSpan = function(offset) { + /** + * The offset of the span into the value. + * @type {number} + */ + this.offset = offset; +}; + + +/** + * Creates a value span from a json serializable object. + * @param {!Object} obj The json serializable object to convert. + * @return {!cvox.ValueSpan} The value span. + */ +cvox.ValueSpan.fromJson = function(obj) { + return new cvox.ValueSpan(obj.offset); +}; + + +/** + * Converts this object to a json serializable object. + * @return {!Object} The JSON representation. + */ +cvox.ValueSpan.prototype.toJson = function() { + return this; +}; + + +cvox.Spannable.registerSerializableSpan( + cvox.ValueSpan, + 'cvox.ValueSpan', + cvox.ValueSpan.fromJson, + cvox.ValueSpan.prototype.toJson); + + +/** + * Attached to the selected text within a value. + * @constructor + */ +cvox.ValueSelectionSpan = function() { +}; + + +cvox.Spannable.registerStatelessSerializableSpan( + cvox.ValueSelectionSpan, + 'cvox.ValueSelectionSpan'); diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js b/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js index afbd98fcc034..cc03d579ecfd 100644 --- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js +++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js @@ -12,6 +12,7 @@ goog.provide('cvox.TabsApiHandler'); goog.require('cvox.AbstractEarcons'); goog.require('cvox.AbstractTts'); goog.require('cvox.BrailleInterface'); +goog.require('cvox.ChromeVox'); goog.require('cvox.NavBraille'); diff --git a/chrome/browser/resources/chromeos/chromevox/common/braille_util.js b/chrome/browser/resources/chromeos/chromevox/common/braille_util.js index c7ff09466109..e73e7c6e3415 100644 --- a/chrome/browser/resources/chromeos/chromevox/common/braille_util.js +++ b/chrome/browser/resources/chromeos/chromevox/common/braille_util.js @@ -8,15 +8,16 @@ goog.provide('cvox.BrailleUtil'); -goog.provide('cvox.BrailleUtil.ValueSelectionSpan'); -goog.provide('cvox.BrailleUtil.ValueSpan'); goog.require('cvox.ChromeVox'); goog.require('cvox.DomUtil'); +goog.require('cvox.EditableTextAreaShadow'); goog.require('cvox.Focuser'); goog.require('cvox.NavBraille'); goog.require('cvox.NodeStateUtil'); goog.require('cvox.Spannable'); +goog.require('cvox.ValueSelectionSpan'); +goog.require('cvox.ValueSpan'); /** @@ -81,59 +82,6 @@ cvox.BrailleUtil.TEMPLATE = { /** - * Attached to the value region of a braille spannable. - * @param {number} offset The offset of the span into the value. - * @constructor - */ -cvox.BrailleUtil.ValueSpan = function(offset) { - /** - * The offset of the span into the value. - * @type {number} - */ - this.offset = offset; -}; - - -/** - * Creates a value span from a json serializable object. - * @param {!Object} obj The json serializable object to convert. - * @return {!cvox.BrailleUtil.ValueSpan} The value span. - */ -cvox.BrailleUtil.ValueSpan.fromJson = function(obj) { - return new cvox.BrailleUtil.ValueSpan(obj.offset); -}; - - -/** - * Converts this object to a json serializable object. - * @return {!Object} The JSON representation. - */ -cvox.BrailleUtil.ValueSpan.prototype.toJson = function() { - return this; -}; - - -cvox.Spannable.registerSerializableSpan( - cvox.BrailleUtil.ValueSpan, - 'cvox.BrailleUtil.ValueSpan', - cvox.BrailleUtil.ValueSpan.fromJson, - cvox.BrailleUtil.ValueSpan.prototype.toJson); - - -/** - * Attached to the selected text within a value. - * @constructor - */ -cvox.BrailleUtil.ValueSelectionSpan = function() { -}; - - -cvox.Spannable.registerStatelessSerializableSpan( - cvox.BrailleUtil.ValueSelectionSpan, - 'cvox.BrailleUtil.ValueSelectionSpan'); - - -/** * Gets the braille name for a node. * See DomUtil for a more precise definition of 'name'. * Additionally, whitespace is trimmed. @@ -220,8 +168,8 @@ cvox.BrailleUtil.getContainer = function(prev, node) { /** - * Gets the braille value of a node. A cvox.BrailleUtil.ValueSpan will be - * attached, along with (possibly) a cvox.BrailleUtil.ValueSelectionSpan. + * Gets the braille value of a node. A {@code cvox.ValueSpan} will be + * attached, along with (possibly) a {@code cvox.ValueSelectionSpan}. * @param {Node} node The node. * @return {!cvox.Spannable} The value spannable. */ @@ -229,7 +177,7 @@ cvox.BrailleUtil.getValue = function(node) { if (!node) { return new cvox.Spannable(); } - var valueSpan = new cvox.BrailleUtil.ValueSpan(0 /* offset */); + var valueSpan = new cvox.ValueSpan(0 /* offset */); if (cvox.DomUtil.isInputTypeText(node)) { var value = node.value; if (node.type === 'password') { @@ -242,7 +190,7 @@ cvox.BrailleUtil.getValue = function(node) { node.selectionStart, 0, spannable.getLength()); var selectionEnd = cvox.BrailleUtil.clamp_( node.selectionEnd, 0, spannable.getLength()); - spannable.setSpan(new cvox.BrailleUtil.ValueSelectionSpan(), + spannable.setSpan(new cvox.ValueSelectionSpan(), Math.min(selectionStart, selectionEnd), Math.max(selectionStart, selectionEnd)); } @@ -261,7 +209,7 @@ cvox.BrailleUtil.getValue = function(node) { node.selectionStart - lineStart, 0, spannable.getLength()); var selectionEnd = cvox.BrailleUtil.clamp_( node.selectionEnd - lineStart, 0, spannable.getLength()); - spannable.setSpan(new cvox.BrailleUtil.ValueSelectionSpan(), + spannable.setSpan(new cvox.ValueSelectionSpan(), Math.min(selectionStart, selectionEnd), Math.max(selectionStart, selectionEnd)); } @@ -333,7 +281,7 @@ cvox.BrailleUtil.getTemplated = function(prev, node, opt_override) { if (!component.toString() && template[i + 1] == ' ' && (!(component instanceof cvox.Spannable) || !/**@type {cvox.Spannable}*/(component).getSpanInstanceOf( - cvox.BrailleUtil.ValueSelectionSpan))) { + cvox.ValueSelectionSpan))) { i++; } } @@ -343,8 +291,8 @@ cvox.BrailleUtil.getTemplated = function(prev, node, opt_override) { /** * Creates a braille value from a string and, optionally, a selection range. - * A cvox.BrailleUtil.ValueSpan will be - * attached, along with a cvox.BrailleUtil.ValueSelectionSpan if applicable. + * A {@code cvox.ValueSpan} will be attached, along with a + * {@code cvox.ValueSelectionSpan} if applicable. * @param {string} text The text to display as the value. * @param {number=} opt_selStart Selection start. * @param {number=} opt_selEnd Selection end if different from selection start. @@ -354,7 +302,7 @@ cvox.BrailleUtil.getTemplated = function(prev, node, opt_override) { cvox.BrailleUtil.createValue = function(text, opt_selStart, opt_selEnd, opt_textOffset) { var spannable = new cvox.Spannable( - text, new cvox.BrailleUtil.ValueSpan(opt_textOffset || 0)); + text, new cvox.ValueSpan(opt_textOffset || 0)); if (goog.isDef(opt_selStart)) { opt_selEnd = goog.isDef(opt_selEnd) ? opt_selEnd : opt_selStart; // TODO(plundblad): This looses the distinction between the selection @@ -366,8 +314,7 @@ cvox.BrailleUtil.createValue = function(text, opt_selStart, opt_selEnd, opt_selEnd = temp; } - spannable.setSpan(new cvox.BrailleUtil.ValueSelectionSpan(), - opt_selStart, opt_selEnd); + spannable.setSpan(new cvox.ValueSelectionSpan(), opt_selStart, opt_selEnd); } return spannable; }; @@ -395,7 +342,7 @@ cvox.BrailleUtil.click = function(braille, opt_displayPosition) { node instanceof HTMLTextAreaElement)) { var valueSpan = spans.filter( function(s) { - return s instanceof cvox.BrailleUtil.ValueSpan; + return s instanceof cvox.ValueSpan; })[0]; if (valueSpan) { if (document.activeElement !== node) { diff --git a/chrome/browser/resources/chromeos/chromevox/common/braille_util_test.unitjs b/chrome/browser/resources/chromeos/chromevox/common/braille_util_test.unitjs index 11cdf72468fc..a1ee77ff9f44 100644 --- a/chrome/browser/resources/chromeos/chromevox/common/braille_util_test.unitjs +++ b/chrome/browser/resources/chromeos/chromevox/common/braille_util_test.unitjs @@ -389,32 +389,32 @@ TEST_F('CvoxBrailleUtilUnitTest', 'CreateValue', function() { // Value without a selection. s = cvox.BrailleUtil.createValue('value'); assertEquals('value', s.toString()); - assertUndefined(s.getSpanInstanceOf(cvox.BrailleUtil.ValueSelectionSpan)); - valueSpan = s.getSpanInstanceOf(cvox.BrailleUtil.ValueSpan); + assertUndefined(s.getSpanInstanceOf(cvox.ValueSelectionSpan)); + valueSpan = s.getSpanInstanceOf(cvox.ValueSpan); assertEquals(0, s.getSpanStart(valueSpan)); assertEquals(s.getLength(), s.getSpanEnd(valueSpan)); // Value with a carret at the start of the text. s = cvox.BrailleUtil.createValue('value', 0); - selectionSpan = s.getSpanInstanceOf(cvox.BrailleUtil.ValueSelectionSpan); + selectionSpan = s.getSpanInstanceOf(cvox.ValueSelectionSpan); assertEquals(0, s.getSpanStart(selectionSpan)); assertEquals(0, s.getSpanEnd(selectionSpan)); // Value with a carret inside the text. s = cvox.BrailleUtil.createValue('value', 1); - selectionSpan = s.getSpanInstanceOf(cvox.BrailleUtil.ValueSelectionSpan); + selectionSpan = s.getSpanInstanceOf(cvox.ValueSelectionSpan); assertEquals(1, s.getSpanStart(selectionSpan)); assertEquals(1, s.getSpanEnd(selectionSpan)); // Value with a carret at the end of the text. s = cvox.BrailleUtil.createValue('value', 5); - selectionSpan = s.getSpanInstanceOf(cvox.BrailleUtil.ValueSelectionSpan); + selectionSpan = s.getSpanInstanceOf(cvox.ValueSelectionSpan); assertEquals(5, s.getSpanStart(selectionSpan)); assertEquals(5, s.getSpanEnd(selectionSpan)); // All of the value selected selected with reversed start and end. s = cvox.BrailleUtil.createValue('value', 5, 0); - selectionSpan = s.getSpanInstanceOf(cvox.BrailleUtil.ValueSelectionSpan); + selectionSpan = s.getSpanInstanceOf(cvox.ValueSelectionSpan); assertEquals(0, s.getSpanStart(selectionSpan)); assertEquals(5, s.getSpanEnd(selectionSpan)); }); diff --git a/chrome/browser/resources/chromeos/chromevox/common/editable_text.js b/chrome/browser/resources/chromeos/chromevox/common/editable_text.js index 54312e0eb0e7..d336d37f1d56 100644 --- a/chrome/browser/resources/chromeos/chromevox/common/editable_text.js +++ b/chrome/browser/resources/chromeos/chromevox/common/editable_text.js @@ -3,106 +3,34 @@ // found in the LICENSE file. goog.provide('cvox.ChromeVoxEditableContentEditable'); +goog.provide('cvox.ChromeVoxEditableElement'); goog.provide('cvox.ChromeVoxEditableHTMLInput'); goog.provide('cvox.ChromeVoxEditableTextArea'); -goog.provide('cvox.ChromeVoxEditableTextBase'); -goog.provide('cvox.TextChangeEvent'); goog.provide('cvox.TextHandlerInterface'); -goog.provide('cvox.TypingEcho'); goog.require('cvox.BrailleTextHandler'); +goog.require('cvox.ChromeVoxEditableTextBase'); goog.require('cvox.ContentEditableExtractor'); goog.require('cvox.DomUtil'); goog.require('cvox.EditableTextAreaShadow'); +goog.require('cvox.TextChangeEvent'); goog.require('cvox.TtsInterface'); -goog.require('goog.i18n.MessageFormat'); /** - * @fileoverview Gives the user spoken feedback as they type, select text, - * and move the cursor in editable text controls, including multiline - * controls. + * @fileoverview Gives the user spoken and braille feedback as they type, + * select text, and move the cursor in editable HTML text controls, including + * multiline controls and contenteditable regions. * - * The majority of the code is in ChromeVoxEditableTextBase, a generalized - * class that takes the current state in the form of a text string, a - * cursor start location and a cursor end location, and calls a speak - * method with the resulting text to be spoken. If the control is multiline, - * information about line breaks (including automatic ones) is also needed. - * - * Two subclasses, ChromeVoxEditableHTMLInput and + * The two subclasses, ChromeVoxEditableHTMLInput and * ChromeVoxEditableTextArea, take a HTML input (type=text) or HTML * textarea node (respectively) in the constructor, and automatically * handle retrieving the current state of the control, including * computing line break information for a textarea using an offscreen - * shadow object. It is still the responsibility of the user of this - * class to trap key and focus events and call this class's update - * method. - * - */ - - -/** - * A class containing the information needed to speak - * a text change event to the user. + * shadow object. It is the responsibility of the user of these classes to + * trap key and focus events and call the update method as needed. * - * @constructor - * @param {string} newValue The new string value of the editable text control. - * @param {number} newStart The new 0-based start cursor/selection index. - * @param {number} newEnd The new 0-based end cursor/selection index. - * @param {boolean} triggeredByUser . - */ -cvox.TextChangeEvent = function(newValue, newStart, newEnd, triggeredByUser) { - this.value = newValue; - this.start = newStart; - this.end = newEnd; - this.triggeredByUser = triggeredByUser; - - // Adjust offsets to be in left to right order. - if (this.start > this.end) { - var tempOffset = this.end; - this.end = this.start; - this.start = tempOffset; - } -}; - - -/** - * A list of typing echo options. - * This defines the way typed characters get spoken. - * CHARACTER: echoes typed characters. - * WORD: echoes a word once a breaking character is typed (i.e. spacebar). - * CHARACTER_AND_WORD: combines CHARACTER and WORD behavior. - * NONE: speaks nothing when typing. - * COUNT: The number of possible echo levels. - * @enum - */ -cvox.TypingEcho = { - CHARACTER: 0, - WORD: 1, - CHARACTER_AND_WORD: 2, - NONE: 3, - COUNT: 4 -}; - - -/** - * @param {number} cur Current typing echo. - * @return {number} Next typing echo. - */ -cvox.TypingEcho.cycle = function(cur) { - return (cur + 1) % cvox.TypingEcho.COUNT; -}; - - -/** - * Return if characters should be spoken given the typing echo option. - * @param {number} typingEcho Typing echo option. - * @return {boolean} Whether the character should be spoken. */ -cvox.TypingEcho.shouldSpeakChar = function(typingEcho) { - return typingEcho == cvox.TypingEcho.CHARACTER_AND_WORD || - typingEcho == cvox.TypingEcho.CHARACTER; -}; /** @@ -120,676 +48,6 @@ cvox.TextHandlerInterface.prototype.changed = function(evt) {}; /** - * A class representing an abstracted editable text control. - * @param {string} value The string value of the editable text control. - * @param {number} start The 0-based start cursor/selection index. - * @param {number} end The 0-based end cursor/selection index. - * @param {boolean} isPassword Whether the text control if a password field. - * @param {cvox.TtsInterface} tts A TTS object. - * @constructor - */ -cvox.ChromeVoxEditableTextBase = function(value, start, end, isPassword, tts) { - /** - * Current value of the text field. - * @type {string} - * @protected - */ - this.value = value; - - /** - * 0-based selection start index. - * @type {number} - * @protected - */ - this.start = start; - - /** - * 0-based selection end index. - * @type {number} - * @protected - */ - this.end = end; - - /** - * True if this is a password field. - * @type {boolean} - * @protected - */ - this.isPassword = isPassword; - - /** - * Text-to-speech object implementing speak() and stop() methods. - * @type {cvox.TtsInterface} - * @protected - */ - this.tts = tts; - - /** - * Whether or not the text field is multiline. - * @type {boolean} - * @protected - */ - this.multiline = false; - - /** - * An optional handler for braille output. - * @type {cvox.BrailleTextHandler|undefined} - * @private - */ - this.brailleHandler_ = cvox.ChromeVox.braille ? - new cvox.BrailleTextHandler(cvox.ChromeVox.braille) : undefined; -}; - - -/** - * Performs setup for this element. - */ -cvox.ChromeVoxEditableTextBase.prototype.setup = function() {}; - - -/** - * Performs teardown for this element. - */ -cvox.ChromeVoxEditableTextBase.prototype.teardown = function() {}; - - -/** - * Whether or not moving the cursor from one character to another considers - * the cursor to be a block (false) or an i-beam (true). - * - * If the cursor is a block, then the value of the character to the right - * of the cursor index is always read when the cursor moves, no matter what - * the previous cursor location was - this is how PC screenreaders work. - * - * If the cursor is an i-beam, moving the cursor by one character reads the - * character that was crossed over, which may be the character to the left or - * right of the new cursor index depending on the direction. - * - * If the current platform is a Mac, we will use an i-beam cursor. If not, - * then we will use the block cursor. - * - * @type {boolean} - */ -cvox.ChromeVoxEditableTextBase.useIBeamCursor = cvox.ChromeVox.isMac; - - -/** - * Switches on or off typing echo based on events. When set, editable text - * updates for single-character insertions are handled in event watcher's key - * press handler. - * @type {boolean} - */ -cvox.ChromeVoxEditableTextBase.eventTypingEcho = false; - - -/** - * The maximum number of characters that are short enough to speak in response - * to an event. For example, if the user selects "Hello", we will speak - * "Hello, selected", but if the user selects 1000 characters, we will speak - * "text selected" instead. - * - * @type {number} - */ -cvox.ChromeVoxEditableTextBase.prototype.maxShortPhraseLen = 60; - - -/** - * Whether or not the text control is a password. - * - * @type {boolean} - */ -cvox.ChromeVoxEditableTextBase.prototype.isPassword = false; - - -/** - * Whether or not the last update to the text and selection was described. - * - * Some consumers of this flag like |ChromeVoxEventWatcher| depend on and - * react to when this flag is false by generating alternative feedback. - * @type {boolean} - */ -cvox.ChromeVoxEditableTextBase.prototype.lastChangeDescribed = false; - - -/** - * Get the line number corresponding to a particular index. - * Default implementation that can be overridden by subclasses. - * @param {number} index The 0-based character index. - * @return {number} The 0-based line number corresponding to that character. - */ -cvox.ChromeVoxEditableTextBase.prototype.getLineIndex = function(index) { - return 0; -}; - - -/** - * Get the start character index of a line. - * Default implementation that can be overridden by subclasses. - * @param {number} index The 0-based line index. - * @return {number} The 0-based index of the first character in this line. - */ -cvox.ChromeVoxEditableTextBase.prototype.getLineStart = function(index) { - return 0; -}; - - -/** - * Get the end character index of a line. - * Default implementation that can be overridden by subclasses. - * @param {number} index The 0-based line index. - * @return {number} The 0-based index of the end of this line. - */ -cvox.ChromeVoxEditableTextBase.prototype.getLineEnd = function(index) { - return this.value.length; -}; - - -/** - * Get the full text of the current line. - * @param {number} index The 0-based line index. - * @return {string} The text of the line. - */ -cvox.ChromeVoxEditableTextBase.prototype.getLine = function(index) { - var lineStart = this.getLineStart(index); - var lineEnd = this.getLineEnd(index); - return this.value.substr(lineStart, lineEnd - lineStart); -}; - - -/** - * @param {string} ch The character to test. - * @return {boolean} True if a character is whitespace. - */ -cvox.ChromeVoxEditableTextBase.prototype.isWhitespaceChar = function(ch) { - return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; -}; - - -/** - * @param {string} ch The character to test. - * @return {boolean} True if a character breaks a word, used to determine - * if the previous word should be spoken. - */ -cvox.ChromeVoxEditableTextBase.prototype.isWordBreakChar = function(ch) { - return !!ch.match(/^\W$/); -}; - - -/** - * @param {cvox.TextChangeEvent} evt The new text changed event to test. - * @return {boolean} True if the event, when compared to the previous text, - * should trigger description. - */ -cvox.ChromeVoxEditableTextBase.prototype.shouldDescribeChange = function(evt) { - if (evt.value == this.value && - evt.start == this.start && - evt.end == this.end) { - return false; - } - return true; -}; - - -/** - * Speak text, but if it's a single character, describe the character. - * @param {string} str The string to speak. - * @param {boolean=} opt_triggeredByUser True if the speech was triggered by a - * user action. - * @param {Object=} opt_personality Personality used to speak text. - */ -cvox.ChromeVoxEditableTextBase.prototype.speak = - function(str, opt_triggeredByUser, opt_personality) { - // If there is a node associated with the editable text object, - // make sure that node has focus before speaking it. - if (this.node && (document.activeElement != this.node)) { - return; - } - var queueMode = cvox.QueueMode.QUEUE; - if (opt_triggeredByUser === true) { - queueMode = cvox.QueueMode.FLUSH; - } - this.tts.speak(str, queueMode, opt_personality || {}); -}; - - -/** - * Update the state of the text and selection and describe any changes as - * appropriate. - * - * @param {cvox.TextChangeEvent} evt The text change event. - */ -cvox.ChromeVoxEditableTextBase.prototype.changed = function(evt) { - if (!this.shouldDescribeChange(evt)) { - this.lastChangeDescribed = false; - return; - } - - if (evt.value == this.value) { - this.describeSelectionChanged(evt); - } else { - this.describeTextChanged(evt); - } - this.lastChangeDescribed = true; - - this.value = evt.value; - this.start = evt.start; - this.end = evt.end; - - this.brailleCurrentLine_(); -}; - - -/** - * Shows the current line on the braille display. - * @private - */ -cvox.ChromeVoxEditableTextBase.prototype.brailleCurrentLine_ = function() { - if (this.brailleHandler_) { - var lineIndex = this.getLineIndex(this.start); - var line = this.getLine(lineIndex); - // Collapsable whitespace inside the contenteditable is represented - // as non-breaking spaces. This confuses braille input (which relies on - // the text being added to be the same as the text in the input field). - // Since the non-breaking spaces are just an artifact of how - // contenteditable is implemented, normalize to normal spaces instead. - if (this instanceof cvox.ChromeVoxEditableContentEditable) { - line = line.replace(/\u00A0/g, ' '); - } - var lineStart = this.getLineStart(lineIndex); - var start = this.start - lineStart; - var end = Math.min(this.end - lineStart, line.length); - this.brailleHandler_.changed(line, start, end, this.multiline, this.node, - lineStart); - } -}; - -/** - * Describe a change in the selection or cursor position when the text - * stays the same. - * @param {cvox.TextChangeEvent} evt The text change event. - */ -cvox.ChromeVoxEditableTextBase.prototype.describeSelectionChanged = - function(evt) { - // TODO(deboer): Factor this into two function: - // - one to determine the selection event - // - one to speak - - if (this.isPassword) { - this.speak((new goog.i18n.MessageFormat(cvox.ChromeVox.msgs.getMsg('dot')) - .format({'COUNT': 1})), evt.triggeredByUser); - return; - } - if (evt.start == evt.end) { - // It's currently a cursor. - if (this.start != this.end) { - // It was previously a selection, so just announce 'unselected'. - this.speak(cvox.ChromeVox.msgs.getMsg('Unselected'), evt.triggeredByUser); - } else if (this.getLineIndex(this.start) != - this.getLineIndex(evt.start)) { - // Moved to a different line; read it. - var lineValue = this.getLine(this.getLineIndex(evt.start)); - if (lineValue == '') { - lineValue = cvox.ChromeVox.msgs.getMsg('text_box_blank'); - } else if (/^\s+$/.test(lineValue)) { - lineValue = cvox.ChromeVox.msgs.getMsg('text_box_whitespace'); - } - this.speak(lineValue, evt.triggeredByUser); - } else if (this.start == evt.start + 1 || - this.start == evt.start - 1) { - // Moved by one character; read it. - if (!cvox.ChromeVoxEditableTextBase.useIBeamCursor) { - if (evt.start == this.value.length) { - if (cvox.ChromeVox.verbosity == cvox.VERBOSITY_VERBOSE) { - this.speak(cvox.ChromeVox.msgs.getMsg('end_of_text_verbose'), - evt.triggeredByUser); - } else { - this.speak(cvox.ChromeVox.msgs.getMsg('end_of_text_brief'), - evt.triggeredByUser); - } - } else { - this.speak(this.value.substr(evt.start, 1), - evt.triggeredByUser, - {'phoneticCharacters': evt.triggeredByUser}); - } - } else { - this.speak(this.value.substr(Math.min(this.start, evt.start), 1), - evt.triggeredByUser, - {'phoneticCharacters': evt.triggeredByUser}); - } - } else { - // Moved by more than one character. Read all characters crossed. - this.speak(this.value.substr(Math.min(this.start, evt.start), - Math.abs(this.start - evt.start)), evt.triggeredByUser); - } - } else { - // It's currently a selection. - if (this.start + 1 == evt.start && - this.end == this.value.length && - evt.end == this.value.length) { - // Autocomplete: the user typed one character of autocompleted text. - this.speak(this.value.substr(this.start, 1), evt.triggeredByUser); - this.speak(this.value.substr(evt.start)); - } else if (this.start == this.end) { - // It was previously a cursor. - this.speak(this.value.substr(evt.start, evt.end - evt.start), - evt.triggeredByUser); - this.speak(cvox.ChromeVox.msgs.getMsg('selected')); - } else if (this.start == evt.start && this.end < evt.end) { - this.speak(this.value.substr(this.end, evt.end - this.end), - evt.triggeredByUser); - this.speak(cvox.ChromeVox.msgs.getMsg('added_to_selection')); - } else if (this.start == evt.start && this.end > evt.end) { - this.speak(this.value.substr(evt.end, this.end - evt.end), - evt.triggeredByUser); - this.speak(cvox.ChromeVox.msgs.getMsg('removed_from_selection')); - } else if (this.end == evt.end && this.start > evt.start) { - this.speak(this.value.substr(evt.start, this.start - evt.start), - evt.triggeredByUser); - this.speak(cvox.ChromeVox.msgs.getMsg('added_to_selection')); - } else if (this.end == evt.end && this.start < evt.start) { - this.speak(this.value.substr(this.start, evt.start - this.start), - evt.triggeredByUser); - this.speak(cvox.ChromeVox.msgs.getMsg('removed_from_selection')); - } else { - // The selection changed but it wasn't an obvious extension of - // a previous selection. Just read the new selection. - this.speak(this.value.substr(evt.start, evt.end - evt.start), - evt.triggeredByUser); - this.speak(cvox.ChromeVox.msgs.getMsg('selected')); - } - } -}; - - -/** - * Describe a change where the text changes. - * @param {cvox.TextChangeEvent} evt The text change event. - */ -cvox.ChromeVoxEditableTextBase.prototype.describeTextChanged = function(evt) { - var personality = {}; - if (evt.value.length < this.value.length) { - personality = cvox.AbstractTts.PERSONALITY_DELETED; - } - if (this.isPassword) { - this.speak((new goog.i18n.MessageFormat(cvox.ChromeVox.msgs.getMsg('dot')) - .format({'COUNT': 1})), evt.triggeredByUser, personality); - return; - } - - var value = this.value; - var len = value.length; - var newLen = evt.value.length; - var autocompleteSuffix = ''; - // Make a copy of evtValue and evtEnd to avoid changing anything in - // the event itself. - var evtValue = evt.value; - var evtEnd = evt.end; - - // First, see if there's a selection at the end that might have been - // added by autocomplete. If so, strip it off into a separate variable. - if (evt.start < evtEnd && evtEnd == newLen) { - autocompleteSuffix = evtValue.substr(evt.start); - evtValue = evtValue.substr(0, evt.start); - evtEnd = evt.start; - } - - // Now see if the previous selection (if any) was deleted - // and any new text was inserted at that character position. - // This would handle pasting and entering text by typing, both from - // a cursor and from a selection. - var prefixLen = this.start; - var suffixLen = len - this.end; - if (newLen >= prefixLen + suffixLen + (evtEnd - evt.start) && - evtValue.substr(0, prefixLen) == value.substr(0, prefixLen) && - evtValue.substr(newLen - suffixLen) == value.substr(this.end)) { - // However, in a dynamic content editable, defer to authoritative events - // (clipboard, key press) to reduce guess work when observing insertions. - // Only use this logic when observing deletions (and insertion of word - // breakers). - // TODO(dtseng): Think about a more reliable way to do this. - if (!(this instanceof cvox.ChromeVoxEditableContentEditable) || - newLen < len || - this.isWordBreakChar(evt.value[newLen - 1] || '')) { - this.describeTextChangedHelper( - evt, prefixLen, suffixLen, autocompleteSuffix, personality); - } - return; - } - - // Next, see if one or more characters were deleted from the previous - // cursor position and the new cursor is in the expected place. This - // handles backspace, forward-delete, and similar shortcuts that delete - // a word or line. - prefixLen = evt.start; - suffixLen = newLen - evtEnd; - if (this.start == this.end && - evt.start == evtEnd && - evtValue.substr(0, prefixLen) == value.substr(0, prefixLen) && - evtValue.substr(newLen - suffixLen) == - value.substr(len - suffixLen)) { - this.describeTextChangedHelper( - evt, prefixLen, suffixLen, autocompleteSuffix, personality); - return; - } - - // If all else fails, we assume the change was not the result of a normal - // user editing operation, so we'll have to speak feedback based only - // on the changes to the text, not the cursor position / selection. - // First, restore the autocomplete text if any. - evtValue += autocompleteSuffix; - - // Try to do a diff between the new and the old text. If it is a one character - // insertion/deletion at the start or at the end, just speak that character. - if ((evtValue.length == (value.length + 1)) || - ((evtValue.length + 1) == value.length)) { - // The user added text either to the beginning or the end. - if (evtValue.length > value.length) { - if (evtValue.indexOf(value) == 0) { - this.speak(evtValue[evtValue.length - 1], evt.triggeredByUser, - personality); - return; - } else if (evtValue.indexOf(value) == 1) { - this.speak(evtValue[0], evt.triggeredByUser, personality); - return; - } - } - // The user deleted text either from the beginning or the end. - if (evtValue.length < value.length) { - if (value.indexOf(evtValue) == 0) { - this.speak(value[value.length - 1], evt.triggeredByUser, personality); - return; - } else if (value.indexOf(evtValue) == 1) { - this.speak(value[0], evt.triggeredByUser, personality); - return; - } - } - } - - if (this.multiline) { - // Fall back to announce deleted but omit the text that was deleted. - if (evt.value.length < this.value.length) { - this.speak(cvox.ChromeVox.msgs.getMsg('text_deleted'), - evt.triggeredByUser, personality); - } - // The below is a somewhat loose way to deal with non-standard - // insertions/deletions. Intentionally skip for multiline since deletion - // announcements are covered above and insertions are non-standard (possibly - // due to auto complete). Since content editable's often refresh content by - // removing and inserting entire chunks of text, this type of logic often - // results in unintended consequences such as reading all text when only one - // character has been entered. - return; - } - - // If the text is short, just speak the whole thing. - if (newLen <= this.maxShortPhraseLen) { - this.describeTextChangedHelper(evt, 0, 0, '', personality); - return; - } - - // Otherwise, look for the common prefix and suffix, but back up so - // that we can speak complete words, to be minimally confusing. - prefixLen = 0; - while (prefixLen < len && - prefixLen < newLen && - value[prefixLen] == evtValue[prefixLen]) { - prefixLen++; - } - while (prefixLen > 0 && !this.isWordBreakChar(value[prefixLen - 1])) { - prefixLen--; - } - - suffixLen = 0; - while (suffixLen < (len - prefixLen) && - suffixLen < (newLen - prefixLen) && - value[len - suffixLen - 1] == evtValue[newLen - suffixLen - 1]) { - suffixLen++; - } - while (suffixLen > 0 && !this.isWordBreakChar(value[len - suffixLen])) { - suffixLen--; - } - - this.describeTextChangedHelper(evt, prefixLen, suffixLen, '', personality); -}; - - -/** - * The function called by describeTextChanged after it's figured out - * what text was deleted, what text was inserted, and what additional - * autocomplete text was added. - * @param {cvox.TextChangeEvent} evt The text change event. - * @param {number} prefixLen The number of characters in the common prefix - * of this.value and newValue. - * @param {number} suffixLen The number of characters in the common suffix - * of this.value and newValue. - * @param {string} autocompleteSuffix The autocomplete string that was added - * to the end, if any. It should be spoken at the end of the utterance - * describing the change. - * @param {Object=} opt_personality Personality to speak the text. - */ -cvox.ChromeVoxEditableTextBase.prototype.describeTextChangedHelper = function( - evt, prefixLen, suffixLen, autocompleteSuffix, opt_personality) { - var len = this.value.length; - var newLen = evt.value.length; - var deletedLen = len - prefixLen - suffixLen; - var deleted = this.value.substr(prefixLen, deletedLen); - var insertedLen = newLen - prefixLen - suffixLen; - var inserted = evt.value.substr(prefixLen, insertedLen); - var utterance = ''; - var triggeredByUser = evt.triggeredByUser; - - if (insertedLen > 1) { - utterance = inserted; - } else if (insertedLen == 1) { - if ((cvox.ChromeVox.typingEcho == cvox.TypingEcho.WORD || - cvox.ChromeVox.typingEcho == cvox.TypingEcho.CHARACTER_AND_WORD) && - this.isWordBreakChar(inserted) && - prefixLen > 0 && - !this.isWordBreakChar(evt.value.substr(prefixLen - 1, 1))) { - // Speak previous word. - var index = prefixLen; - while (index > 0 && !this.isWordBreakChar(evt.value[index - 1])) { - index--; - } - if (index < prefixLen) { - utterance = evt.value.substr(index, prefixLen + 1 - index); - } else { - utterance = inserted; - triggeredByUser = false; // Implies QUEUE_MODE_QUEUE. - } - } else if (cvox.ChromeVox.typingEcho == cvox.TypingEcho.CHARACTER || - cvox.ChromeVox.typingEcho == cvox.TypingEcho.CHARACTER_AND_WORD) { - // This particular case is handled in event watcher. See the key press - // handler for more details. - utterance = cvox.ChromeVoxEditableTextBase.eventTypingEcho ? '' : - inserted; - } - } else if (deletedLen > 1 && !autocompleteSuffix) { - utterance = deleted + ', deleted'; - } else if (deletedLen == 1) { - utterance = deleted; - } - - if (autocompleteSuffix && utterance) { - utterance += ', ' + autocompleteSuffix; - } else if (autocompleteSuffix) { - utterance = autocompleteSuffix; - } - - if (utterance) { - this.speak(utterance, triggeredByUser, opt_personality); - } -}; - - -/** - * Moves the cursor forward by one character. - * @return {boolean} True if the action was handled. - */ -cvox.ChromeVoxEditableTextBase.prototype.moveCursorToNextCharacter = - function() { return false; }; - - -/** - * Moves the cursor backward by one character. - * @return {boolean} True if the action was handled. - */ -cvox.ChromeVoxEditableTextBase.prototype.moveCursorToPreviousCharacter = - function() { return false; }; - - -/** - * Moves the cursor forward by one word. - * @return {boolean} True if the action was handled. - */ -cvox.ChromeVoxEditableTextBase.prototype.moveCursorToNextWord = - function() { return false; }; - - -/** - * Moves the cursor backward by one word. - * @return {boolean} True if the action was handled. - */ -cvox.ChromeVoxEditableTextBase.prototype.moveCursorToPreviousWord = - function() { return false; }; - - -/** - * Moves the cursor forward by one line. - * @return {boolean} True if the action was handled. - */ -cvox.ChromeVoxEditableTextBase.prototype.moveCursorToNextLine = - function() { return false; }; - - -/** - * Moves the cursor backward by one line. - * @return {boolean} True if the action was handled. - */ -cvox.ChromeVoxEditableTextBase.prototype.moveCursorToPreviousLine = - function() { return false; }; - - -/** - * Moves the cursor forward by one paragraph. - * @return {boolean} True if the action was handled. - */ -cvox.ChromeVoxEditableTextBase.prototype.moveCursorToNextParagraph = - function() { return false; }; - - -/** - * Moves the cursor backward by one paragraph. - * @return {boolean} True if the action was handled. - */ -cvox.ChromeVoxEditableTextBase.prototype.moveCursorToPreviousParagraph = - function() { return false; }; - - -/******************************************/ - - -/** * A subclass of ChromeVoxEditableTextBase a text element that's part of * the webpage DOM. Contains common code shared by both EditableHTMLInput * and EditableTextArea, but that might not apply to a non-DOM text box. @@ -807,6 +65,14 @@ cvox.ChromeVoxEditableElement = function(node, value, start, end, isPassword, goog.base(this, value, start, end, isPassword, tts); /** + * An optional handler for braille output. + * @type {cvox.BrailleTextHandler|undefined} + * @private + */ + this.brailleHandler_ = cvox.ChromeVox.braille ? + new cvox.BrailleTextHandler(cvox.ChromeVox.braille) : undefined; + + /** * The DOM node which allows text input. * @type {Element} * @protected @@ -824,12 +90,7 @@ goog.inherits(cvox.ChromeVoxEditableElement, cvox.ChromeVoxEditableTextBase); -/** - * Update the state of the text and selection and describe any changes as - * appropriate. - * - * @param {cvox.TextChangeEvent} evt The text change event. - */ +/** @override */ cvox.ChromeVoxEditableElement.prototype.changed = function(evt) { // Ignore changes to the cursor and selection if they happen immediately // after the description was just spoken. This avoid double-speaking when, @@ -843,10 +104,24 @@ cvox.ChromeVoxEditableElement.prototype.changed = function(evt) { this.justSpokeDescription_ = false; } goog.base(this, 'changed', evt); + if (this.lastChangeDescribed) { + this.brailleCurrentLine_(); + } }; /** @override */ +cvox.ChromeVoxEditableElement.prototype.speak = function( + str, opt_triggeredByUser, opt_personality) { + // If there is a node associated with the editable text object, + // make sure that node has focus before speaking it. + if (this.node && (document.activeElement != this.node)) { + return; + } + goog.base(this, 'speak', str, opt_triggeredByUser, opt_personality); +}; + +/** @override */ cvox.ChromeVoxEditableElement.prototype.moveCursorToNextCharacter = function() { var node = this.node; node.selectionEnd++; @@ -933,6 +208,29 @@ cvox.ChromeVoxEditableElement.prototype.moveCursorToPreviousParagraph = return true; }; +/** + * Shows the current line on the braille display. + * @private + */ +cvox.ChromeVoxEditableElement.prototype.brailleCurrentLine_ = function() { + if (this.brailleHandler_) { + var lineIndex = this.getLineIndex(this.start); + var line = this.getLine(lineIndex); + // Collapsable whitespace inside the contenteditable is represented + // as non-breaking spaces. This confuses braille input (which relies on + // the text being added to be the same as the text in the input field). + // Since the non-breaking spaces are just an artifact of how + // contenteditable is implemented, normalize to normal spaces instead. + if (this instanceof cvox.ChromeVoxEditableContentEditable) { + line = line.replace(/\u00A0/g, ' '); + } + var lineStart = this.getLineStart(lineIndex); + var start = this.start - lineStart; + var end = Math.min(this.end - lineStart, line.length); + this.brailleHandler_.changed(line, start, end, this.multiline, this.node, + lineStart); + } +}; /******************************************/ @@ -1254,9 +552,7 @@ cvox.ChromeVoxEditableContentEditable.prototype.getExtractor = function() { }; -/** - * @override - */ +/** @override */ cvox.ChromeVoxEditableContentEditable.prototype.changed = function(evt) { if (!evt.triggeredByUser) { diff --git a/chrome/browser/resources/chromeos/chromevox/common/editable_text.js b/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js similarity index 52% copy from chrome/browser/resources/chromeos/chromevox/common/editable_text.js copy to chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js index 54312e0eb0e7..d7d7bd47dac7 100644 --- a/chrome/browser/resources/chromeos/chromevox/common/editable_text.js +++ b/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js @@ -1,43 +1,26 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. +// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -goog.provide('cvox.ChromeVoxEditableContentEditable'); -goog.provide('cvox.ChromeVoxEditableHTMLInput'); -goog.provide('cvox.ChromeVoxEditableTextArea'); goog.provide('cvox.ChromeVoxEditableTextBase'); goog.provide('cvox.TextChangeEvent'); -goog.provide('cvox.TextHandlerInterface'); goog.provide('cvox.TypingEcho'); - -goog.require('cvox.BrailleTextHandler'); -goog.require('cvox.ContentEditableExtractor'); -goog.require('cvox.DomUtil'); -goog.require('cvox.EditableTextAreaShadow'); +goog.require('cvox.ChromeVox'); goog.require('cvox.TtsInterface'); goog.require('goog.i18n.MessageFormat'); + /** - * @fileoverview Gives the user spoken feedback as they type, select text, - * and move the cursor in editable text controls, including multiline - * controls. - * - * The majority of the code is in ChromeVoxEditableTextBase, a generalized - * class that takes the current state in the form of a text string, a - * cursor start location and a cursor end location, and calls a speak - * method with the resulting text to be spoken. If the control is multiline, - * information about line breaks (including automatic ones) is also needed. - * - * Two subclasses, ChromeVoxEditableHTMLInput and - * ChromeVoxEditableTextArea, take a HTML input (type=text) or HTML - * textarea node (respectively) in the constructor, and automatically - * handle retrieving the current state of the control, including - * computing line break information for a textarea using an offscreen - * shadow object. It is still the responsibility of the user of this - * class to trap key and focus events and call this class's update - * method. + * @fileoverview Generalized logic for providing spoken feedback when editing + * text fields, both single and multiline fields. * + * {@code ChromeVoxEditableTextBase} is a generalized class that takes the + * current state in the form of a text string, a cursor start location and a + * cursor end location, and calls a speak method with the resulting text to + * be spoken. This class can be used directly for single line fields or + * extended to override methods that extract lines for multiline fields + * or to provide other customizations. */ @@ -106,20 +89,6 @@ cvox.TypingEcho.shouldSpeakChar = function(typingEcho) { /** - * An interface for being notified when the text changes. - * @interface - */ -cvox.TextHandlerInterface = function() {}; - - -/** - * Called when text changes. - * @param {cvox.TextChangeEvent} evt The text change event. - */ -cvox.TextHandlerInterface.prototype.changed = function(evt) {}; - - -/** * A class representing an abstracted editable text control. * @param {string} value The string value of the editable text control. * @param {number} start The 0-based start cursor/selection index. @@ -172,12 +141,14 @@ cvox.ChromeVoxEditableTextBase = function(value, start, end, isPassword, tts) { this.multiline = false; /** - * An optional handler for braille output. - * @type {cvox.BrailleTextHandler|undefined} - * @private + * Whether or not the last update to the text and selection was described. + * + * Some consumers of this flag like |ChromeVoxEventWatcher| depend on and + * react to when this flag is false by generating alternative feedback. + * @type {boolean} */ - this.brailleHandler_ = cvox.ChromeVox.braille ? - new cvox.BrailleTextHandler(cvox.ChromeVox.braille) : undefined; + this.lastChangeDescribed = false; + }; @@ -234,24 +205,6 @@ cvox.ChromeVoxEditableTextBase.prototype.maxShortPhraseLen = 60; /** - * Whether or not the text control is a password. - * - * @type {boolean} - */ -cvox.ChromeVoxEditableTextBase.prototype.isPassword = false; - - -/** - * Whether or not the last update to the text and selection was described. - * - * Some consumers of this flag like |ChromeVoxEventWatcher| depend on and - * react to when this flag is false by generating alternative feedback. - * @type {boolean} - */ -cvox.ChromeVoxEditableTextBase.prototype.lastChangeDescribed = false; - - -/** * Get the line number corresponding to a particular index. * Default implementation that can be overridden by subclasses. * @param {number} index The 0-based character index. @@ -339,11 +292,6 @@ cvox.ChromeVoxEditableTextBase.prototype.shouldDescribeChange = function(evt) { */ cvox.ChromeVoxEditableTextBase.prototype.speak = function(str, opt_triggeredByUser, opt_personality) { - // If there is a node associated with the editable text object, - // make sure that node has focus before speaking it. - if (this.node && (document.activeElement != this.node)) { - return; - } var queueMode = cvox.QueueMode.QUEUE; if (opt_triggeredByUser === true) { queueMode = cvox.QueueMode.FLUSH; @@ -374,36 +322,10 @@ cvox.ChromeVoxEditableTextBase.prototype.changed = function(evt) { this.value = evt.value; this.start = evt.start; this.end = evt.end; - - this.brailleCurrentLine_(); }; /** - * Shows the current line on the braille display. - * @private - */ -cvox.ChromeVoxEditableTextBase.prototype.brailleCurrentLine_ = function() { - if (this.brailleHandler_) { - var lineIndex = this.getLineIndex(this.start); - var line = this.getLine(lineIndex); - // Collapsable whitespace inside the contenteditable is represented - // as non-breaking spaces. This confuses braille input (which relies on - // the text being added to be the same as the text in the input field). - // Since the non-breaking spaces are just an artifact of how - // contenteditable is implemented, normalize to normal spaces instead. - if (this instanceof cvox.ChromeVoxEditableContentEditable) { - line = line.replace(/\u00A0/g, ' '); - } - var lineStart = this.getLineStart(lineIndex); - var start = this.start - lineStart; - var end = Math.min(this.end - lineStart, line.length); - this.brailleHandler_.changed(line, start, end, this.multiline, this.node, - lineStart); - } -}; - -/** * Describe a change in the selection or cursor position when the text * stays the same. * @param {cvox.TextChangeEvent} evt The text change event. @@ -787,567 +709,3 @@ cvox.ChromeVoxEditableTextBase.prototype.moveCursorToPreviousParagraph = /******************************************/ - - -/** - * A subclass of ChromeVoxEditableTextBase a text element that's part of - * the webpage DOM. Contains common code shared by both EditableHTMLInput - * and EditableTextArea, but that might not apply to a non-DOM text box. - * @param {Element} node A DOM node which allows text input. - * @param {string} value The string value of the editable text control. - * @param {number} start The 0-based start cursor/selection index. - * @param {number} end The 0-based end cursor/selection index. - * @param {boolean} isPassword Whether the text control if a password field. - * @param {cvox.TtsInterface} tts A TTS object. - * @extends {cvox.ChromeVoxEditableTextBase} - * @constructor - */ -cvox.ChromeVoxEditableElement = function(node, value, start, end, isPassword, - tts) { - goog.base(this, value, start, end, isPassword, tts); - - /** - * The DOM node which allows text input. - * @type {Element} - * @protected - */ - this.node = node; - - /** - * True if the description was just spoken. - * @type {boolean} - * @private - */ - this.justSpokeDescription_ = false; -}; -goog.inherits(cvox.ChromeVoxEditableElement, - cvox.ChromeVoxEditableTextBase); - - -/** - * Update the state of the text and selection and describe any changes as - * appropriate. - * - * @param {cvox.TextChangeEvent} evt The text change event. - */ -cvox.ChromeVoxEditableElement.prototype.changed = function(evt) { - // Ignore changes to the cursor and selection if they happen immediately - // after the description was just spoken. This avoid double-speaking when, - // for example, a text field is focused and then a moment later the - // contents are selected. If the value changes, though, this change will - // not be ignored. - if (this.justSpokeDescription_ && this.value == evt.value) { - this.value = evt.value; - this.start = evt.start; - this.end = evt.end; - this.justSpokeDescription_ = false; - } - goog.base(this, 'changed', evt); -}; - - -/** @override */ -cvox.ChromeVoxEditableElement.prototype.moveCursorToNextCharacter = function() { - var node = this.node; - node.selectionEnd++; - node.selectionStart = node.selectionEnd; - cvox.ChromeVoxEventWatcher.handleTextChanged(true); - return true; -}; - - -/** @override */ -cvox.ChromeVoxEditableElement.prototype.moveCursorToPreviousCharacter = - function() { - var node = this.node; - node.selectionStart--; - node.selectionEnd = node.selectionStart; - cvox.ChromeVoxEventWatcher.handleTextChanged(true); - return true; -}; - - -/** @override */ -cvox.ChromeVoxEditableElement.prototype.moveCursorToNextWord = function() { - var node = this.node; - var length = node.value.length; - var re = /\W+/gm; - var substring = node.value.substring(node.selectionEnd); - var match = re.exec(substring); - if (match !== null && match.index == 0) { - // Ignore word-breaking sequences right next to the cursor. - match = re.exec(substring); - } - var index = (match === null) ? length : match.index + node.selectionEnd; - node.selectionStart = node.selectionEnd = index; - cvox.ChromeVoxEventWatcher.handleTextChanged(true); - return true; -}; - - -/** @override */ -cvox.ChromeVoxEditableElement.prototype.moveCursorToPreviousWord = function() { - var node = this.node; - var length = node.value.length; - var re = /\W+/gm; - var substring = node.value.substring(0, node.selectionStart); - var index = 0; - while (re.exec(substring) !== null) { - if (re.lastIndex < node.selectionStart) { - index = re.lastIndex; - } - } - node.selectionStart = node.selectionEnd = index; - cvox.ChromeVoxEventWatcher.handleTextChanged(true); - return true; -}; - - -/** @override */ -cvox.ChromeVoxEditableElement.prototype.moveCursorToNextParagraph = - function() { - var node = this.node; - var length = node.value.length; - var index = node.selectionEnd >= length ? length : - node.value.indexOf('\n', node.selectionEnd); - if (index < 0) { - index = length; - } - node.selectionStart = node.selectionEnd = index + 1; - cvox.ChromeVoxEventWatcher.handleTextChanged(true); - return true; -}; - - -/** @override */ -cvox.ChromeVoxEditableElement.prototype.moveCursorToPreviousParagraph = - function() { - var node = this.node; - var index = node.selectionStart <= 0 ? 0 : - node.value.lastIndexOf('\n', node.selectionStart - 2) + 1; - if (index < 0) { - index = 0; - } - node.selectionStart = node.selectionEnd = index; - cvox.ChromeVoxEventWatcher.handleTextChanged(true); - return true; -}; - - -/******************************************/ - - -/** - * A subclass of ChromeVoxEditableElement for an HTMLInputElement. - * @param {HTMLInputElement} node The HTMLInputElement node. - * @param {cvox.TtsInterface} tts A TTS object. - * @extends {cvox.ChromeVoxEditableElement} - * @implements {cvox.TextHandlerInterface} - * @constructor - */ -cvox.ChromeVoxEditableHTMLInput = function(node, tts) { - this.node = node; - this.setup(); - goog.base(this, - node, - node.value, - node.selectionStart, - node.selectionEnd, - node.type === 'password', - tts); -}; -goog.inherits(cvox.ChromeVoxEditableHTMLInput, - cvox.ChromeVoxEditableElement); - - -/** - * Performs setup for this input node. - * This accounts for exception-throwing behavior introduced by crbug.com/324360. - * @override - */ -cvox.ChromeVoxEditableHTMLInput.prototype.setup = function() { - if (!this.node) { - return; - } - if (!cvox.DomUtil.doesInputSupportSelection(this.node)) { - this.originalType = this.node.type; - this.node.type = 'text'; - } -}; - - -/** - * Performs teardown for this input node. - * This accounts for exception-throwing behavior introduced by crbug.com/324360. - * @override - */ -cvox.ChromeVoxEditableHTMLInput.prototype.teardown = function() { - if (this.node && this.originalType) { - this.node.type = this.originalType; - } -}; - - -/** - * Update the state of the text and selection and describe any changes as - * appropriate. - * - * @param {boolean} triggeredByUser True if this was triggered by a user action. - */ -cvox.ChromeVoxEditableHTMLInput.prototype.update = function(triggeredByUser) { - var newValue = this.node.value; - var textChangeEvent = new cvox.TextChangeEvent(newValue, - this.node.selectionStart, - this.node.selectionEnd, - triggeredByUser); - this.changed(textChangeEvent); -}; - - -/******************************************/ - - -/** - * A subclass of ChromeVoxEditableElement for an HTMLTextAreaElement. - * @param {HTMLTextAreaElement} node The HTMLTextAreaElement node. - * @param {cvox.TtsInterface} tts A TTS object. - * @extends {cvox.ChromeVoxEditableElement} - * @implements {cvox.TextHandlerInterface} - * @constructor - */ -cvox.ChromeVoxEditableTextArea = function(node, tts) { - goog.base(this, node, node.value, node.selectionStart, node.selectionEnd, - false /* isPassword */, tts); - this.multiline = true; - - /** - * True if the shadow is up-to-date with the current value of this text area. - * @type {boolean} - * @private - */ - this.shadowIsCurrent_ = false; -}; -goog.inherits(cvox.ChromeVoxEditableTextArea, - cvox.ChromeVoxEditableElement); - - -/** - * An offscreen div used to compute the line numbers. A single div is - * shared by all instances of the class. - * @type {!cvox.EditableTextAreaShadow|undefined} - * @private - */ -cvox.ChromeVoxEditableTextArea.shadow_; - - -/** - * Update the state of the text and selection and describe any changes as - * appropriate. - * - * @param {boolean} triggeredByUser True if this was triggered by a user action. - */ -cvox.ChromeVoxEditableTextArea.prototype.update = function(triggeredByUser) { - if (this.node.value != this.value) { - this.shadowIsCurrent_ = false; - } - var textChangeEvent = new cvox.TextChangeEvent(this.node.value, - this.node.selectionStart, this.node.selectionEnd, triggeredByUser); - this.changed(textChangeEvent); -}; - - -/** - * Get the line number corresponding to a particular index. - * @param {number} index The 0-based character index. - * @return {number} The 0-based line number corresponding to that character. - */ -cvox.ChromeVoxEditableTextArea.prototype.getLineIndex = function(index) { - return this.getShadow().getLineIndex(index); -}; - - -/** - * Get the start character index of a line. - * @param {number} index The 0-based line index. - * @return {number} The 0-based index of the first character in this line. - */ -cvox.ChromeVoxEditableTextArea.prototype.getLineStart = function(index) { - return this.getShadow().getLineStart(index); -}; - - -/** - * Get the end character index of a line. - * @param {number} index The 0-based line index. - * @return {number} The 0-based index of the end of this line. - */ -cvox.ChromeVoxEditableTextArea.prototype.getLineEnd = function(index) { - return this.getShadow().getLineEnd(index); -}; - - -/** - * Update the shadow object, an offscreen div used to compute line numbers. - * @return {!cvox.EditableTextAreaShadow} The shadow object. - */ -cvox.ChromeVoxEditableTextArea.prototype.getShadow = function() { - var shadow = cvox.ChromeVoxEditableTextArea.shadow_; - if (!shadow) { - shadow = cvox.ChromeVoxEditableTextArea.shadow_ = - new cvox.EditableTextAreaShadow(); - } - if (!this.shadowIsCurrent_) { - shadow.update(this.node); - this.shadowIsCurrent_ = true; - } - return shadow; -}; - - -/** @override */ -cvox.ChromeVoxEditableTextArea.prototype.moveCursorToNextLine = function() { - var node = this.node; - var length = node.value.length; - if (node.selectionEnd >= length) { - return false; - } - var shadow = this.getShadow(); - var lineIndex = shadow.getLineIndex(node.selectionEnd); - var lineStart = shadow.getLineStart(lineIndex); - var offset = node.selectionEnd - lineStart; - var lastLine = (length == 0) ? 0 : shadow.getLineIndex(length - 1); - var newCursorPosition = (lineIndex >= lastLine) ? length : - Math.min(shadow.getLineStart(lineIndex + 1) + offset, - shadow.getLineEnd(lineIndex + 1)); - node.selectionStart = node.selectionEnd = newCursorPosition; - cvox.ChromeVoxEventWatcher.handleTextChanged(true); - return true; -}; - - -/** @override */ -cvox.ChromeVoxEditableTextArea.prototype.moveCursorToPreviousLine = function() { - var node = this.node; - if (node.selectionStart <= 0) { - return false; - } - var shadow = this.getShadow(); - var lineIndex = shadow.getLineIndex(node.selectionStart); - var lineStart = shadow.getLineStart(lineIndex); - var offset = node.selectionStart - lineStart; - var newCursorPosition = (lineIndex <= 0) ? 0 : - Math.min(shadow.getLineStart(lineIndex - 1) + offset, - shadow.getLineEnd(lineIndex - 1)); - node.selectionStart = node.selectionEnd = newCursorPosition; - cvox.ChromeVoxEventWatcher.handleTextChanged(true); - return true; -}; - - -/******************************************/ - - -/** - * A subclass of ChromeVoxEditableElement for elements that are contentEditable. - * This is also used for a region of HTML with the ARIA role of "textbox", - * so that an author can create a pure-JavaScript editable text object - this - * will work the same as contentEditable as long as the DOM selection is - * updated properly within the textbox when it has focus. - * @param {Element} node The root contentEditable node. - * @param {cvox.TtsInterface} tts A TTS object. - * @extends {cvox.ChromeVoxEditableElement} - * @implements {cvox.TextHandlerInterface} - * @constructor - */ -cvox.ChromeVoxEditableContentEditable = function(node, tts) { - goog.base(this, node, '', 0, 0, false /* isPassword */, tts); - - - /** - * True if the ContentEditableExtractor is current with this field's data. - * @type {boolean} - * @private - */ - this.extractorIsCurrent_ = false; - - var extractor = this.getExtractor(); - this.value = extractor.getText(); - this.start = extractor.getStartIndex(); - this.end = extractor.getEndIndex(); - this.multiline = true; -}; -goog.inherits(cvox.ChromeVoxEditableContentEditable, - cvox.ChromeVoxEditableElement); - -/** - * A helper used to compute the line numbers. A single object is - * shared by all instances of the class. - * @type {!cvox.ContentEditableExtractor|undefined} - * @private - */ -cvox.ChromeVoxEditableContentEditable.extractor_; - - -/** - * Update the state of the text and selection and describe any changes as - * appropriate. - * - * @param {boolean} triggeredByUser True if this was triggered by a user action. - */ -cvox.ChromeVoxEditableContentEditable.prototype.update = - function(triggeredByUser) { - this.extractorIsCurrent_ = false; - var textChangeEvent = new cvox.TextChangeEvent( - this.getExtractor().getText(), - this.getExtractor().getStartIndex(), - this.getExtractor().getEndIndex(), - triggeredByUser); - this.changed(textChangeEvent); -}; - - -/** - * Get the line number corresponding to a particular index. - * @param {number} index The 0-based character index. - * @return {number} The 0-based line number corresponding to that character. - */ -cvox.ChromeVoxEditableContentEditable.prototype.getLineIndex = function(index) { - return this.getExtractor().getLineIndex(index); -}; - - -/** - * Get the start character index of a line. - * @param {number} index The 0-based line index. - * @return {number} The 0-based index of the first character in this line. - */ -cvox.ChromeVoxEditableContentEditable.prototype.getLineStart = function(index) { - return this.getExtractor().getLineStart(index); -}; - - -/** - * Get the end character index of a line. - * @param {number} index The 0-based line index. - * @return {number} The 0-based index of the end of this line. - */ -cvox.ChromeVoxEditableContentEditable.prototype.getLineEnd = function(index) { - return this.getExtractor().getLineEnd(index); -}; - - -/** - * Update the extractor object, an offscreen div used to compute line numbers. - * @return {!cvox.ContentEditableExtractor} The extractor object. - */ -cvox.ChromeVoxEditableContentEditable.prototype.getExtractor = function() { - var extractor = cvox.ChromeVoxEditableContentEditable.extractor_; - if (!extractor) { - extractor = cvox.ChromeVoxEditableContentEditable.extractor_ = - new cvox.ContentEditableExtractor(); - } - if (!this.extractorIsCurrent_) { - extractor.update(this.node); - this.extractorIsCurrent_ = true; - } - return extractor; -}; - - -/** - * @override - */ -cvox.ChromeVoxEditableContentEditable.prototype.changed = - function(evt) { - if (!evt.triggeredByUser) { - return; - } - // Take over here if we can't describe a change; assume it's a blank line. - if (!this.shouldDescribeChange(evt)) { - this.speak(cvox.ChromeVox.msgs.getMsg('text_box_blank'), true); - if (this.brailleHandler_) { - this.brailleHandler_.changed('' /*line*/, 0 /*start*/, 0 /*end*/, - true /*multiline*/, null /*element*/, - evt.start /*lineStart*/); - } - } else { - goog.base(this, 'changed', evt); - } -}; - - -/** @override */ -cvox.ChromeVoxEditableContentEditable.prototype.moveCursorToNextCharacter = - function() { - window.getSelection().modify('move', 'forward', 'character'); - cvox.ChromeVoxEventWatcher.handleTextChanged(true); - return true; -}; - - -/** @override */ -cvox.ChromeVoxEditableContentEditable.prototype.moveCursorToPreviousCharacter = - function() { - window.getSelection().modify('move', 'backward', 'character'); - cvox.ChromeVoxEventWatcher.handleTextChanged(true); - return true; -}; - - -/** @override */ -cvox.ChromeVoxEditableContentEditable.prototype.moveCursorToNextParagraph = - function() { - window.getSelection().modify('move', 'forward', 'paragraph'); - cvox.ChromeVoxEventWatcher.handleTextChanged(true); - return true; -}; - -/** @override */ -cvox.ChromeVoxEditableContentEditable.prototype.moveCursorToPreviousParagraph = - function() { - window.getSelection().modify('move', 'backward', 'paragraph'); - cvox.ChromeVoxEventWatcher.handleTextChanged(true); - return true; -}; - - -/** - * @override - */ -cvox.ChromeVoxEditableContentEditable.prototype.shouldDescribeChange = - function(evt) { - var sel = window.getSelection(); - var cursor = new cvox.Cursor(sel.baseNode, sel.baseOffset, ''); - - // This is a very specific work around because of our buggy content editable - // support. Blank new lines are not captured in the line indexing data - // structures. - // Scenario: given a piece of text like: - // - // Some Title - // - // Description - // Footer - // - // The new lines after Title are not traversed to by TraverseUtil. A root fix - // would make changes there. However, considering the fickle nature of that - // code, we specifically detect for new lines here. - if (Math.abs(this.start - evt.start) != 1 && - this.start == this.end && - evt.start == evt.end && - sel.baseNode == sel.extentNode && - sel.baseOffset == sel.extentOffset && - sel.baseNode.nodeType == Node.ELEMENT_NODE && - sel.baseNode.querySelector('BR') && - cvox.TraverseUtil.forwardsChar(cursor, [], [])) { - // This case detects if the range selection surrounds a new line, - // but there is still content after the new line (like the example - // above after "Title"). In these cases, we "pretend" we're the - // last character so we speak "blank". - return false; - } - - // Otherwise, we should never speak "blank" no matter what (even if - // we're at the end of a content editable). - return true; -}; diff --git a/chrome/browser/resources/chromeos/chromevox/common/editable_text_test.unitjs b/chrome/browser/resources/chromeos/chromevox/common/editable_text_test.unitjs index d22ae1eba8de..2df3086d66bf 100644 --- a/chrome/browser/resources/chromeos/chromevox/common/editable_text_test.unitjs +++ b/chrome/browser/resources/chromeos/chromevox/common/editable_text_test.unitjs @@ -95,6 +95,7 @@ CvoxEditableTextUnitTest.prototype = { /** @override */ closureModuleDeps: [ + 'cvox.ChromeVoxEditableElement', 'cvox.ChromeVoxEditableHTMLInput', 'cvox.ChromeVoxEditableTextBase', 'cvox.ChromeVoxEventWatcher', @@ -275,7 +276,7 @@ TEST_F('CvoxEditableTextUnitTest', 'Selection', function() { TEST_F('CvoxEditableTextUnitTest', 'MultiLineText', function() { var str = 'This string\nspans\nfive lines.\n \n'; var tts = new TestTts(); - var obj = new cvox.ChromeVoxEditableTextBase(str, 0, 0, false, tts); + var obj = new cvox.ChromeVoxEditableElement(null, str, 0, 0, false, tts); obj.multiline = true; obj.getLineIndex = function(index) { if (index >= 33) { diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js index 2776b6f9f258..c33060899fe3 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js @@ -18,15 +18,6 @@ goog.require('cursors.Cursor'); goog.require('cvox.ChromeVoxEditableTextBase'); goog.require('cvox.TabsApiHandler'); -// Define types here due to editable_text.js's implicit dependency with -// ChromeVoxEventWatcher. -/** @type {Object} */ -cvox.ChromeVoxEventWatcher; -/** @type {function(boolean)} */ -cvox.ChromeVoxEventWatcher.handleTextChanged; -/** @type {function()} */ -cvox.ChromeVoxEventWatcher.setUpTextHandler; - goog.scope(function() { var AutomationNode = chrome.automation.AutomationNode; var Dir = AutomationUtil.Dir; diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js index f093bac9b3d8..101e896d2d76 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js @@ -13,9 +13,9 @@ goog.require('AutomationUtil.Dir'); goog.require('cursors.Cursor'); goog.require('cursors.Range'); goog.require('cursors.Unit'); -goog.require('cvox.BrailleUtil.ValueSelectionSpan'); -goog.require('cvox.BrailleUtil.ValueSpan'); goog.require('cvox.Spannable'); +goog.require('cvox.ValueSelectionSpan'); +goog.require('cvox.ValueSpan'); goog.scope(function() { var Dir = AutomationUtil.Dir; @@ -338,9 +338,9 @@ Output.prototype = { } else { startIndex = valueStart + selSpan.startIndex; endIndex = valueStart + selSpan.endIndex; - this.brailleBuffer_.setSpan(new cvox.BrailleUtil.ValueSpan(valueStart), + this.brailleBuffer_.setSpan(new cvox.ValueSpan(valueStart), valueStart, valueEnd); - this.brailleBuffer_.setSpan(new cvox.BrailleUtil.ValueSelectionSpan(), + this.brailleBuffer_.setSpan(new cvox.ValueSelectionSpan(), startIndex, endIndex); } } diff --git a/chrome/browser/resources/chromeos/chromevox/host/chrome/braille_integration_test.unitjs b/chrome/browser/resources/chromeos/chromevox/host/chrome/braille_integration_test.unitjs index 2289d4cb1026..d718fe84bf91 100644 --- a/chrome/browser/resources/chromeos/chromevox/host/chrome/braille_integration_test.unitjs +++ b/chrome/browser/resources/chromeos/chromevox/host/chrome/braille_integration_test.unitjs @@ -24,9 +24,10 @@ CvoxBrailleIntegrationUnitTest.prototype = { 'cvox.BrailleBackground', 'cvox.BrailleInputHandler', 'cvox.BrailleKeyCommand', - 'cvox.BrailleUtil', 'cvox.ChromeBraille', 'cvox.ExpandingBrailleTranslator', + 'cvox.ValueSelectionSpan', + 'cvox.ValueSpan', ], /** @override */ @@ -146,8 +147,8 @@ TEST_F('CvoxBrailleIntegrationUnitTest', 'Write', function() { }); TEST_F('CvoxBrailleIntegrationUnitTest', 'WriteWithSpans', function() { - var selectionSpan = new cvox.BrailleUtil.ValueSelectionSpan(); - var valueSpan = new cvox.BrailleUtil.ValueSpan(20); + var selectionSpan = new cvox.ValueSelectionSpan(); + var valueSpan = new cvox.ValueSpan(20); var toSend = cvox.NavBraille.fromText( new cvox.Spannable('Hello', valueSpan)); toSend.text.setSpan(selectionSpan, 0, 0); diff --git a/chrome/browser/resources/chromeos/chromevox/walkers/layout_line_walker.js b/chrome/browser/resources/chromeos/chromevox/walkers/layout_line_walker.js index 8495713e8a00..b46a089df197 100644 --- a/chrome/browser/resources/chromeos/chromevox/walkers/layout_line_walker.js +++ b/chrome/browser/resources/chromeos/chromevox/walkers/layout_line_walker.js @@ -214,8 +214,7 @@ cvox.LayoutLineWalker.prototype.extend_ = function(start) { cvox.LayoutLineWalker.prototype.appendBraille_ = function( prevSel, sel, cur, braille) { var item = this.subWalker_.getBraille(prevSel, cur).text; - var valueSelectionSpan = item.getSpanInstanceOf( - cvox.BrailleUtil.ValueSelectionSpan); + var valueSelectionSpan = item.getSpanInstanceOf(cvox.ValueSelectionSpan); if (braille.text.getLength() > 0) { braille.text.append(cvox.BrailleUtil.ITEM_SEPARATOR); diff --git a/chrome/browser/resources/chromeos/chromevox/walkers/structural_line_walker.js b/chrome/browser/resources/chromeos/chromevox/walkers/structural_line_walker.js index ff665102aa25..376b04fb89d9 100644 --- a/chrome/browser/resources/chromeos/chromevox/walkers/structural_line_walker.js +++ b/chrome/browser/resources/chromeos/chromevox/walkers/structural_line_walker.js @@ -10,6 +10,7 @@ goog.provide('cvox.StructuralLineWalker'); goog.require('cvox.AbstractSelectionWalker'); +goog.require('cvox.BrailleUtil'); goog.require('cvox.TraverseContent'); /** diff --git a/chrome/browser/resources/chromeos/chromevox/walkers/structural_line_walker_test.unitjs b/chrome/browser/resources/chromeos/chromevox/walkers/structural_line_walker_test.unitjs index e7f41af454ee..7dc9b1596052 100644 --- a/chrome/browser/resources/chromeos/chromevox/walkers/structural_line_walker_test.unitjs +++ b/chrome/browser/resources/chromeos/chromevox/walkers/structural_line_walker_test.unitjs @@ -17,7 +17,6 @@ CvoxStructuralLineWalkerUnitTest.prototype = { /** @override */ closureModuleDeps: [ - 'cvox.BrailleUtil', 'cvox.StructuralLineWalker', 'cvox.TestMsgs', ], -- 2.11.4.GIT