diff options
Diffstat (limited to 'chromium/chrome/browser/resources/chromeos/chromevox/common')
40 files changed, 1878 insertions, 1630 deletions
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/aria_util.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/aria_util.js index 47d2ee96c30..7df05627b2c 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/aria_util.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/aria_util.js @@ -34,7 +34,7 @@ cvox.AriaUtil.NO_ROLE_NAME = ' '; * Note: If you are adding a new mapping, the new message identifier needs a * corresponding braille message. For example, a message id 'tag_button' * requires another message 'tag_button_brl' within messages.js. - * @type {Object.<string, string>} + * @type {Object<string, string>} */ cvox.AriaUtil.WIDGET_ROLE_TO_NAME = { 'alert' : 'aria_role_alert', @@ -79,7 +79,7 @@ cvox.AriaUtil.WIDGET_ROLE_TO_NAME = { * Note: If you are adding a new mapping, the new message identifier needs a * corresponding braille message. For example, a message id 'tag_button' * requires another message 'tag_button_brl' within messages.js. - * @type {Object.<string, string>} + * @type {Object<string, string>} */ cvox.AriaUtil.STRUCTURE_ROLE_TO_NAME = { 'article' : 'aria_role_article', @@ -109,7 +109,7 @@ cvox.AriaUtil.STRUCTURE_ROLE_TO_NAME = { /** - * @type {Array.<Object>} + * @type {Array<Object>} */ cvox.AriaUtil.ATTRIBUTE_VALUE_TO_STATUS = [ { name: 'aria-autocomplete', values: @@ -381,9 +381,9 @@ cvox.AriaUtil.getStateMsgs = function(targetNode, primary) { for (var i = 0, attr; attr = cvox.AriaUtil.ATTRIBUTE_VALUE_TO_STATUS[i]; i++) { var value = targetNode.getAttribute(attr.name); - var msg_id = attr.values[value]; - if (msg_id) { - state.push([msg_id]); + var msgId = attr.values[value]; + if (msgId) { + state.push([msgId]); } } if (targetNode.getAttribute('role') == 'grid') { @@ -583,8 +583,8 @@ cvox.AriaUtil.getActiveDescendantId_ = function(targetNode) { * Returns the list of elements that are one aria-level below. * * @param {Node} parentControl The node whose descendants should be analyzed. - * @param {Array.<string>} role The role(s) of descendant we are looking for. - * @return {Array.<Node>} The array of matching nodes. + * @param {Array<string>} role The role(s) of descendant we are looking for. + * @return {Array<Node>} The array of matching nodes. */ cvox.AriaUtil.getNextLevel = function(parentControl, role) { var result = []; @@ -608,8 +608,8 @@ cvox.AriaUtil.getNextLevel = function(parentControl, role) { * Recursively finds the first node(s) that match the role. * * @param {Element} current The node to start looking at. - * @param {Array.<string>} role The role(s) to match. - * @return {Array.<Element>} The array of matching nodes. + * @param {Array<string>} role The role(s) to match. + * @return {Array<Element>} The array of matching nodes. */ cvox.AriaUtil.getNextLevelItems = function(current, role) { if (current.nodeType != 1) { // If reached a node that is not an element. @@ -838,7 +838,7 @@ cvox.AriaUtil.getAriaRelevant = function(node, change) { * node or contain this node. * * @param {Node} node The node to be checked. - * @return {Array.<Element>} All live regions affected by this node changing. + * @return {Array<Element>} All live regions affected by this node changing. */ cvox.AriaUtil.getLiveRegions = function(node) { var result = []; diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/aural_style_util.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/aural_style_util.js index 568084bccf5..0e8c3b5cf57 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/aural_style_util.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/aural_style_util.js @@ -55,7 +55,7 @@ cvox.AuralStyleConverter.identity = function(value) { * Conversion from an aural style property to Chrome TTS property. * TODO(dtseng): no-op's below need to be supported by the extension API itself * or by ChromeVox. - * @type {Object.<cvox.AuralProperty, string>} + * @type {Object<cvox.AuralProperty, string>} */ cvox.AuralStyleConverter.propertyTable = { VOLUME: 'volume', @@ -86,7 +86,7 @@ cvox.AuralStyleConverter.propertyTable = { * Conversion from an aural style value to Chrome TTS value. * TODO(dtseng): Conversion of aural CSS values is incomplete; everything is an * identity conversion at the moment. - * @type {Object.<cvox.AuralProperty, function(*)>} + * @type {Object<cvox.AuralProperty, function(*)>} */ cvox.AuralStyleConverter.valueTable = { VOLUME: cvox.AuralStyleConverter.identity, @@ -129,7 +129,7 @@ cvox.AuralStyleConverter.convertRule = function(property, value) { /** * Converts an aural CSS style block to a TTS property object. - * @param {Object.<cvox.AuralProperty, *>} style The style. + * @param {Object<cvox.AuralProperty, *>} style The style. * @return {Object} The tts property object. */ cvox.AuralStyleConverter.convertStyle = function(style) { diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/braille_util.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/braille_util.js index 4e2ce623171..bc133b7c5dd 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/braille_util.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/braille_util.js @@ -11,10 +11,13 @@ goog.provide('cvox.BrailleUtil'); 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'); /** @@ -30,7 +33,7 @@ cvox.BrailleUtil.ITEM_SEPARATOR = ' '; * Containers are distinguished from roles by their appearance higher up in the * DOM tree of a selected node. * This list should be very short. - * @type {!Array.<string>} + * @type {!Array<string>} */ cvox.BrailleUtil.CONTAINER = [ 'tag_h1_brl', @@ -51,82 +54,34 @@ cvox.BrailleUtil.CONTAINER = [ * c: replaced with braille container role; this potentially returns whitespace, * so place at the beginning or end of templates for trimming. * v: replaced with braille value. - * @type {Object.<string, string>} + * @type {Object<string, string>} */ cvox.BrailleUtil.TEMPLATE = { 'base': 'c n v r s', 'aria_role_alert': 'r: n', - 'aria_role_button': '[n]', - 'aria_role_textbox': 'n: v r', - 'input_type_button': '[n]', - 'input_type_checkbox': 'n (s)', - 'input_type_email': 'n: v r', - 'input_type_number': 'n: v r', - 'input_type_password': 'n: v r', - 'input_type_search': 'n: v r', - 'input_type_submit': '[n]', - 'input_type_text': 'n: v r', - 'input_type_tel': 'n: v r', - 'input_type_url': 'n: v r', - 'tag_button': '[n]', - 'tag_textarea': 'n: v r' + 'aria_role_button': 'n r s', + 'aria_role_checkbox': 'n r (s)', + 'aria_role_menuitemcheckbox': 'n r (s)', + 'aria_role_menuitemradio': 'n r (s)', + 'aria_role_radio': 'n r (s)', + 'aria_role_textbox': 'n: v r s', + 'input_type_button': 'n r s', + 'input_type_checkbox': 'n r (s)', + 'input_type_email': 'n: v r s', + 'input_type_number': 'n: v r s', + 'input_type_password': 'n: v r s', + 'input_type_radio': 'n r (s)', + 'input_type_search': 'n: v r s', + 'input_type_submit': 'n r s', + 'input_type_text': 'n: v r s', + 'input_type_tel': 'n: v r s', + 'input_type_url': 'n: v r s', + 'tag_button': 'n r s', + 'tag_textarea': 'n: v r s' }; /** - * 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. @@ -165,44 +120,29 @@ cvox.BrailleUtil.getRoleMsg = function(node) { /** - * Gets the braille role of a node. - * See DomUtil for a more precise definition of 'role'. - * @param {Node} node The node. - * @return {string} The string representation. - */ -cvox.BrailleUtil.getRole = function(node) { - if (!node) { - return ''; - } - var roleMsg = cvox.BrailleUtil.getRoleMsg(node); - return roleMsg ? cvox.ChromeVox.msgs.getMsg(roleMsg) : ''; -}; - - -/** - * Gets the braille state of a node. - * @param {Node} node The node. + * Transforms a {@code cvox.NodeState} list of state messages to the + * corresponding messages for braille and expands them into a localized + * string suitable for output on a braille display. + * @param {cvox.NodeState} stateMsgs The states to expand. The content of this + * array is modified. * @return {string} The string representation. + * @private */ -cvox.BrailleUtil.getState = function(node) { - if (!node) { - return ''; - } - return cvox.NodeStateUtil.expand( - cvox.DomUtil.getStateMsgs(node, true).map(function(state) { - // Check to see if a variant of the message with '_brl' exists, - // and use it if so. - // - // Note: many messages are templatized, and if we don't pass any - // argument to substitute, getMsg might throw an error if the - // resulting string is empty. To avoid this, we pass a dummy - // substitution string array here. - var dummySubs = ['dummy', 'dummy', 'dummy']; - if (cvox.ChromeVox.msgs.getMsg(state[0] + '_brl', dummySubs)) { - state[0] += '_brl'; - } - return state; - })); +cvox.BrailleUtil.expandStateMsgs_ = function(stateMsgs) { + stateMsgs.forEach(function(state) { + // Check to see if a variant of the message with '_brl' exists, + // and use it if so. + // + // Note: many messages are templatized, and if we don't pass any + // argument to substitute, getMsg might throw an error if the + // resulting string is empty. To avoid this, we pass a dummy + // substitution string array here. + var dummySubs = ['dummy', 'dummy', 'dummy']; + if (cvox.ChromeVox.msgs.getMsg(state[0] + '_brl', dummySubs)) { + state[0] += '_brl'; + } + }); + return cvox.NodeStateUtil.expand(stateMsgs); }; @@ -228,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. */ @@ -237,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') { @@ -250,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)); } @@ -269,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)); } @@ -297,14 +237,22 @@ cvox.BrailleUtil.getTemplated = function(prev, node, opt_override) { opt_override = opt_override ? opt_override : {}; var roleMsg = opt_override.roleMsg || (node ? cvox.DomUtil.getRoleMsg(node, cvox.VERBOSITY_VERBOSE) : ''); - var role = opt_override.role; - if (!role && opt_override.roleMsg) { - role = cvox.ChromeVox.msgs.getMsg(opt_override.roleMsg + '_brl') || - cvox.ChromeVox.msgs.getMsg(opt_override.roleMsg); - } - role = role || cvox.BrailleUtil.getRole(node); var template = cvox.BrailleUtil.TEMPLATE[roleMsg] || cvox.BrailleUtil.TEMPLATE['base']; + var state = opt_override.state; + if (!state) { + if (node) { + state = cvox.BrailleUtil.expandStateMsgs_( + cvox.DomUtil.getStateMsgs(node, true)); + } else { + state = ''; + } + } + var role = opt_override.role || ''; + if (!role && roleMsg) { + role = cvox.ChromeVox.msgs.getMsg(roleMsg + '_brl') || + cvox.ChromeVox.msgs.getMsg(roleMsg); + } var templated = new cvox.Spannable(); var mapChar = function(c) { @@ -314,7 +262,7 @@ cvox.BrailleUtil.getTemplated = function(prev, node, opt_override) { case 'r': return role; case 's': - return opt_override.state || cvox.BrailleUtil.getState(node); + return state; case 'c': return opt_override.container || cvox.BrailleUtil.getContainer(prev, node); @@ -327,8 +275,13 @@ cvox.BrailleUtil.getTemplated = function(prev, node, opt_override) { for (var i = 0; i < template.length; i++) { var component = mapChar(template[i]); templated.append(component); - // Ignore the next whitespace separator if the current component is empty. - if (!component.toString() && template[i + 1] == ' ') { + // Ignore the next whitespace separator if the current component is empty, + // unless the empty value has a selection, in which case the cursor + // should be placed on the empty space after the empty value. + if (!component.toString() && template[i + 1] == ' ' && + (!(component instanceof cvox.Spannable) || + !/**@type {cvox.Spannable}*/(component).getSpanInstanceOf( + cvox.ValueSelectionSpan))) { i++; } } @@ -338,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. @@ -349,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 @@ -361,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; }; @@ -390,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/chromium/chrome/browser/resources/chromeos/chromevox/common/braille_util_test.unitjs b/chromium/chrome/browser/resources/chromeos/chromevox/common/braille_util_test.unitjs index 7e0a8cfa867..a1ee77ff9f4 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/braille_util_test.unitjs +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/braille_util_test.unitjs @@ -60,7 +60,7 @@ CvoxBrailleUtilUnitTest.prototype = { startIndex: actual.startIndex, endIndex: actual.endIndex }); - assertThat(new cvox.NavBraille(expected), eqJSON(actual)); + assertThat(actual, eqJSON(new cvox.NavBraille(expected))); } }; @@ -120,7 +120,7 @@ TEST_F('CvoxBrailleUtilUnitTest', 'NameTemplate', function() { var button = cvox.CursorSelection.fromNode($('1')); this.assertBrailleEquals( - {text: '[Submit]', + {text: 'Submit btn', startIndex: 0, endIndex: 1 }, this.getBraille_(button, button)); @@ -130,13 +130,13 @@ TEST_F('CvoxBrailleUtilUnitTest', 'NameTemplate', function() { // Note: the cursor appears where text would be typed. this.assertBrailleEquals( - {text: 'Search: edtxt', + {text: 'Search: ed', startIndex: 0, endIndex: 1 }, this.getBraille_(input, input)); inputElement.focus(); this.assertBrailleEquals( - {text: 'Search: edtxt', + {text: 'Search: ed', startIndex: 8, endIndex: 8 }, this.getBraille_(input, input)); @@ -157,7 +157,7 @@ TEST_F('CvoxBrailleUtilUnitTest', 'TextField', function() { // Note: the cursor appears where text would be typed. // The cursor is at the beginning by default. this.assertBrailleEquals( - {text: 'Search: larry edtxt', + {text: 'Search: larry ed', startIndex: 0, endIndex: 1 }, this.getBraille_(input, input)); @@ -165,7 +165,7 @@ TEST_F('CvoxBrailleUtilUnitTest', 'TextField', function() { inputElement.selectionStart = 0; inputElement.selectionEnd = 5; this.assertBrailleEquals( - {text: 'Search: larry edtxt', + {text: 'Search: larry ed', startIndex: 8, endIndex: 13 }, this.getBraille_(input, input)); @@ -184,13 +184,13 @@ TEST_F('CvoxBrailleUtilUnitTest', 'TextFieldEmpty', function() { var input = cvox.CursorSelection.fromNode($('1')); this.assertBrailleEquals( - {text: ': edtxt', + {text: ': ed', startIndex: 0, endIndex: 1 }, this.getBraille_(input, input)); inputElement.focus(); this.assertBrailleEquals( - {text: ': edtxt', + {text: ': ed', startIndex: 2, endIndex: 2 }, this.getBraille_(input, input)); @@ -213,7 +213,7 @@ TEST_F('CvoxBrailleUtilUnitTest', 'TextFieldSelection', function() { inputElem.selectionStart = 2; inputElem.selectionEnd = 5; this.assertBrailleEquals( - {text: ': strawberry edtxt', + {text: ': strawberry ed', startIndex: 4, endIndex: 7 }, this.getBraille_(input, input)); @@ -222,7 +222,7 @@ TEST_F('CvoxBrailleUtilUnitTest', 'TextFieldSelection', function() { inputElem.selectionStart = 10; inputElem.selectionEnd = 10; this.assertBrailleEquals( - {text: ': strawberry edtxt', + {text: ': strawberry ed', startIndex: 12, endIndex: 12 }, this.getBraille_(input, input)); @@ -239,7 +239,7 @@ TEST_F('CvoxBrailleUtilUnitTest', 'StateTemplate', function() { var checkbox = cvox.CursorSelection.fromNode($('1')); this.assertBrailleEquals( - {text: 'Save ( )', + {text: 'Save chk ( )', startIndex: 0, endIndex: 1 }, this.getBraille_(checkbox, checkbox)); @@ -247,7 +247,7 @@ TEST_F('CvoxBrailleUtilUnitTest', 'StateTemplate', function() { $('1').checked = true; this.assertBrailleEquals( - {text: 'Save (x)', + {text: 'Save chk (x)', startIndex: 0, endIndex: 1 }, this.getBraille_(checkbox, checkbox)); @@ -286,7 +286,7 @@ TEST_F('CvoxBrailleUtilUnitTest', 'ContainerTemplate', function() { var navBraille = this.getBraille_( cvox.CursorSelection.fromBody(), link); this.assertBrailleEquals( - {text: 'h1 Skip To Menu int lnk', + {text: 'h1 Skip To Menu intlnk', startIndex: 0, endIndex: 1 }, navBraille); @@ -303,14 +303,33 @@ TEST_F('CvoxBrailleUtilUnitTest', 'LinkSpans', function() { var link2 = $('2'); var navBraille = this.getBraille_( cvox.CursorSelection.fromBody(), cvox.CursorSelection.fromNode(link1)); - assertEquals('Hello int lnk from ChromeVox lnk', + assertEquals('Hello intlnk from ChromeVox lnk', navBraille.text.toString()); assertEquals(link1, navBraille.text.getSpan(0)); - assertEquals(link1, navBraille.text.getSpan(12)); - assertEquals('undefined', typeof navBraille.text.getSpan(13)); - assertEquals('undefined', typeof navBraille.text.getSpan(18)); - assertEquals(link2, navBraille.text.getSpan(19)); - assertEquals(link2, navBraille.text.getSpan(31)); + assertEquals(link1, navBraille.text.getSpan(11)); + assertEquals('undefined', typeof navBraille.text.getSpan(12)); + assertEquals('undefined', typeof navBraille.text.getSpan(17)); + assertEquals(link2, navBraille.text.getSpan(18)); + assertEquals(link2, navBraille.text.getSpan(30)); +}); + + +TEST_F('CvoxBrailleUtilUnitTest', 'VisitedLink', function() { + this.loadHtml('<p><a id="1" href="http://visited.link">Hello</a> there.'); + var link = $('1'); + var navBraille = this.getBraille_( + cvox.CursorSelection.fromBody(), cvox.CursorSelection.fromNode(link)); + this.assertBrailleEquals({text: 'Hello lnk there.', + startIndex: 0, + endIndex: 1}, + navBraille); + cvox.ChromeVox.visitedUrls[link.href] = true; + navBraille = this.getBraille_( + cvox.CursorSelection.fromBody(), cvox.CursorSelection.fromNode(link)); + this.assertBrailleEquals({text: 'Hello vlnk there.', + startIndex: 0, + endIndex: 1}, + navBraille); }); @@ -324,7 +343,7 @@ TEST_F('CvoxBrailleUtilUnitTest', 'NestedElements', function() { var link = $('batman-link'); var navBraille = this.getBraille_( cvox.CursorSelection.fromBody(), cvox.CursorSelection.fromNode(h1)); - assertEquals('h1 Larry, Sergey int lnk and Eric', + assertEquals('h1 Larry, Sergey intlnk and Eric', navBraille.text.toString()); this.assertTextNodeChildOf_(h1, navBraille.text.getSpan(0)); this.assertTextNodeChildOf_(h1, navBraille.text.getSpan(5)); @@ -370,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/chromium/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js index 6f532a96ac2..86fa446e2d9 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js @@ -37,10 +37,10 @@ chrome.extension.inIncognitoContext; /** - * @param {string|Object.<string>=} opt_extensionIdOrConnectInfo Either the + * @param {string|Object<string>=} opt_extensionIdOrConnectInfo Either the * extensionId to connect to, in which case connectInfo params can be * passed in the next optional argument, or the connectInfo params. - * @param {Object.<string>=} opt_connectInfo The connectInfo object, + * @param {Object<string>=} opt_connectInfo The connectInfo object, * if arg1 was the extensionId to connect to. * @return {Port} New port. */ @@ -161,7 +161,7 @@ chrome.runtime.Manifest.Oauth2 = function() {}; /** @type {string} */ chrome.runtime.Manifest.Oauth2.prototype.client_id; -/**@type {!Array.<string>} */ +/**@type {!Array<string>} */ chrome.runtime.Manifest.Oauth2.prototype.scopes; @@ -181,10 +181,10 @@ chrome.runtime.getManifest = function() {}; chrome.runtime.getURL = function(path) {}; /** - * @param {string|!Object.<string>=} opt_extensionIdOrConnectInfo Either the + * @param {string|!Object<string>=} opt_extensionIdOrConnectInfo Either the * extensionId to connect to, in which case connectInfo params can be * passed in the next optional argument, or the connectInfo params. - * @param {!Object.<string>=} opt_connectInfo The connectInfo object, + * @param {!Object<string>=} opt_connectInfo The connectInfo object, * if arg1 was the extensionId to connect to. * @return {!Port} New port. */ @@ -325,7 +325,7 @@ chrome.tabs.captureVisibleTab = function(windowId, options, callback) {}; /** * @param {number} tabId Tab Id. - * @param {Object.<string>=} opt_connectInfo Info Object. + * @param {Object<string>=} opt_connectInfo Info Object. */ chrome.tabs.connect = function(tabId, opt_connectInfo) {}; @@ -365,7 +365,7 @@ chrome.tabs.get = function(tabId, callback) {}; * the public web pages, but there are still existing usages * * @param {number?} windowId Window id. - * @param {function(Array.<Tab>): void} callback Callback. + * @param {function(Array<Tab>): void} callback Callback. */ chrome.tabs.getAllInWindow = function(windowId, callback) {}; @@ -387,7 +387,7 @@ chrome.tabs.getSelected = function(windowId, callback) {}; /** - * @param {Object.<string, (number|Array.<number>)>} highlightInfo + * @param {Object<string, (number|Array<number>)>} highlightInfo * An object with 'windowId' (number) and 'tabs' * (number or array of numbers) keys. * @param {function(Window): void} callback Callback function invoked @@ -407,7 +407,7 @@ chrome.tabs.insertCSS = function(tabId, details, opt_callback) {}; /** * @param {number} tabId Tab id. - * @param {Object.<string, number>} moveProperties An object with 'index' + * @param {Object<string, number>} moveProperties An object with 'index' * and optional 'windowId' keys. * @param {function(Tab): void=} opt_callback Callback. */ @@ -415,18 +415,18 @@ chrome.tabs.move = function(tabId, moveProperties, opt_callback) {}; /** - * @param {Object.<string, (number|string)>} queryInfo An object which may have + * @param {Object<string, (number|string)>} queryInfo An object which may have * 'active', 'pinned', 'highlighted', 'status', 'title', 'url', 'windowId', * and 'windowType' keys. - * @param {function(Array.<Tab>): void=} opt_callback Callback. - * @return {!Array.<Tab>} + * @param {function(Array<Tab>): void=} opt_callback Callback. + * @return {!Array<Tab>} */ chrome.tabs.query = function(queryInfo, opt_callback) {}; /** * @param {number=} opt_tabId Tab id. - * @param {Object.<string, boolean>=} opt_reloadProperties An object which + * @param {Object<string, boolean>=} opt_reloadProperties An object which * may have a 'bypassCache' key. * @param {function(): void=} opt_callback The callback function invoked * after the tab has been reloaded. @@ -435,7 +435,7 @@ chrome.tabs.reload = function(opt_tabId, opt_reloadProperties, opt_callback) {}; /** - * @param {number|Array.<number>} tabIds A tab ID or an array of tab IDs. + * @param {number|Array<number>} tabIds A tab ID or an array of tab IDs. * @param {function(Tab): void=} opt_callback Callback. */ chrome.tabs.remove = function(tabIds, opt_callback) {}; @@ -461,7 +461,7 @@ chrome.tabs.sendRequest = function(tabId, request, opt_callback) {}; /** * @param {number} tabId Tab id. - * @param {Object.<string, (string|boolean)>} updateProperties An object which + * @param {Object<string, (string|boolean)>} updateProperties An object which * may have 'url' or 'selected' key. * @param {function(Tab): void=} opt_callback Callback. */ @@ -532,7 +532,7 @@ chrome.windows.get = function(id, opt_getInfo, opt_callback) {}; /** * @param {Object=} opt_getInfo May have 'populate' key. Or the callback. - * @param {function(!Array.<!ChromeWindow>): void=} opt_callback Callback. + * @param {function(!Array<!ChromeWindow>): void=} opt_callback Callback. */ chrome.windows.getAll = function(opt_getInfo, opt_callback) {}; @@ -598,7 +598,7 @@ chrome.i18n = {}; /** - * @param {function(Array.<string>): void} callback The callback function which + * @param {function(Array<string>): void} callback The callback function which * accepts an array of the accept languages of the browser, such as * 'en-US','en','zh-CN'. */ @@ -607,7 +607,7 @@ chrome.i18n.getAcceptLanguages = function(callback) {}; /** * @param {string} messageName - * @param {(string|Array.<string>)=} opt_args + * @param {(string|Array<string>)=} opt_args * @return {string} */ chrome.i18n.getMessage = function(messageName, opt_args) {}; @@ -664,13 +664,13 @@ TtsVoice.prototype.gender; TtsVoice.prototype.extensionId; -/** @type {Array.<string>} */ +/** @type {Array<string>} */ TtsVoice.prototype.eventTypes; /** * Gets an array of all available voices. - * @param {function(Array.<TtsVoice>)=} opt_callback An optional callback + * @param {function(Array<TtsVoice>)=} opt_callback An optional callback * function. */ chrome.tts.getVoices = function(opt_callback) {}; @@ -708,7 +708,7 @@ chrome.history = {}; /** - * @param {Object.<string, string>} details Object with a 'url' key. + * @param {Object<string, string>} details Object with a 'url' key. */ chrome.history.addUrl = function(details) {}; @@ -720,7 +720,7 @@ chrome.history.deleteAll = function(callback) {}; /** - * @param {Object.<string, string>} range Object with 'startTime' + * @param {Object<string, string>} range Object with 'startTime' * and 'endTime' keys. * @param {function(): void} callback Callback function. */ @@ -728,25 +728,25 @@ chrome.history.deleteRange = function(range, callback) {}; /** - * @param {Object.<string, string>} details Object with a 'url' key. + * @param {Object<string, string>} details Object with a 'url' key. */ chrome.history.deleteUrl = function(details) {}; /** - * @param {Object.<string, string>} details Object with a 'url' key. - * @param {function(!Array.<!VisitItem>): void} callback Callback function. - * @return {!Array.<!VisitItem>} + * @param {Object<string, string>} details Object with a 'url' key. + * @param {function(!Array<!VisitItem>): void} callback Callback function. + * @return {!Array<!VisitItem>} */ chrome.history.getVisits = function(details, callback) {}; /** - * @param {Object.<string, string>} query Object with a 'text' (string) + * @param {Object<string, string>} query Object with a 'text' (string) * key and optional 'startTime' (number), 'endTime' (number) and * 'maxResults' keys. - * @param {function(!Array.<!HistoryItem>): void} callback Callback function. - * @return {!Array.<!HistoryItem>} + * @param {function(!Array<!HistoryItem>): void} callback Callback function. + * @return {!Array<!HistoryItem>} */ chrome.history.search = function(query, callback) {}; @@ -767,8 +767,8 @@ chrome.permissions = {}; /** * @typedef {{ - * permissions: (Array.<string>|undefined), - * origins: (Array.<string>|undefined) + * permissions: (Array<string>|undefined), + * origins: (Array<string>|undefined) * }} * @see http://developer.chrome.com/extensions/permissions.html#type-Permissions */ @@ -914,7 +914,7 @@ ChromeWindow.prototype.width; ChromeWindow.prototype.height; -/** @type {Array.<Tab>} */ +/** @type {Array<Tab>} */ ChromeWindow.prototype.tabs; @@ -983,7 +983,7 @@ Port.prototype.sender; /** - * @param {Object.<string>} obj Message object. + * @param {Object<string>} obj Message object. */ Port.prototype.postMessage = function(obj) {}; @@ -1053,7 +1053,7 @@ BookmarkTreeNode.prototype.dateAdded; BookmarkTreeNode.prototype.dateGroupModified; -/** @type {Array.<BookmarkTreeNode>} */ +/** @type {Array<BookmarkTreeNode>} */ BookmarkTreeNode.prototype.children; @@ -1211,16 +1211,378 @@ chrome.storage.local.remove = function(keys, opt_callback) {}; chrome.storage.onChanged; +// Begin auto generated externs; do not edit. +// The following was generated from: +// +// python tools/json_schema_compiler/compiler.py +// -g externs +// chrome/common/extensions/api/automation.idl + /** * @const */ chrome.automation = {}; /** + * @enum {string} + */ +chrome.automation.EventType = { + activedescendantchanged: 'activedescendantchanged', + alert: 'alert', + ariaAttributeChanged: 'ariaAttributeChanged', + autocorrectionOccured: 'autocorrectionOccured', + blur: 'blur', + checkedStateChanged: 'checkedStateChanged', + childrenChanged: 'childrenChanged', + focus: 'focus', + hide: 'hide', + hover: 'hover', + invalidStatusChanged: 'invalidStatusChanged', + layoutComplete: 'layoutComplete', + liveRegionChanged: 'liveRegionChanged', + loadComplete: 'loadComplete', + locationChanged: 'locationChanged', + menuEnd: 'menuEnd', + menuListItemSelected: 'menuListItemSelected', + menuListValueChanged: 'menuListValueChanged', + menuPopupEnd: 'menuPopupEnd', + menuPopupStart: 'menuPopupStart', + menuStart: 'menuStart', + rowCollapsed: 'rowCollapsed', + rowCountChanged: 'rowCountChanged', + rowExpanded: 'rowExpanded', + scrollPositionChanged: 'scrollPositionChanged', + scrolledToAnchor: 'scrolledToAnchor', + selectedChildrenChanged: 'selectedChildrenChanged', + selection: 'selection', + selectionAdd: 'selectionAdd', + selectionRemove: 'selectionRemove', + show: 'show', + textChanged: 'textChanged', + textSelectionChanged: 'textSelectionChanged', + treeChanged: 'treeChanged', + valueChanged: 'valueChanged', +}; + +/** + * @enum {string} + */ +chrome.automation.RoleType = { + alertDialog: 'alertDialog', + alert: 'alert', + annotation: 'annotation', + application: 'application', + article: 'article', + banner: 'banner', + blockquote: 'blockquote', + busyIndicator: 'busyIndicator', + button: 'button', + buttonDropDown: 'buttonDropDown', + canvas: 'canvas', + caption: 'caption', + cell: 'cell', + checkBox: 'checkBox', + client: 'client', + colorWell: 'colorWell', + columnHeader: 'columnHeader', + column: 'column', + comboBox: 'comboBox', + complementary: 'complementary', + contentInfo: 'contentInfo', + date: 'date', + dateTime: 'dateTime', + definition: 'definition', + descriptionListDetail: 'descriptionListDetail', + descriptionList: 'descriptionList', + descriptionListTerm: 'descriptionListTerm', + desktop: 'desktop', + details: 'details', + dialog: 'dialog', + directory: 'directory', + disclosureTriangle: 'disclosureTriangle', + div: 'div', + document: 'document', + embeddedObject: 'embeddedObject', + figcaption: 'figcaption', + figure: 'figure', + footer: 'footer', + form: 'form', + grid: 'grid', + group: 'group', + heading: 'heading', + iframe: 'iframe', + iframePresentational: 'iframePresentational', + ignored: 'ignored', + imageMapLink: 'imageMapLink', + imageMap: 'imageMap', + image: 'image', + inlineTextBox: 'inlineTextBox', + labelText: 'labelText', + legend: 'legend', + lineBreak: 'lineBreak', + link: 'link', + listBoxOption: 'listBoxOption', + listBox: 'listBox', + listItem: 'listItem', + listMarker: 'listMarker', + list: 'list', + locationBar: 'locationBar', + log: 'log', + main: 'main', + marquee: 'marquee', + math: 'math', + menuBar: 'menuBar', + menuButton: 'menuButton', + menuItem: 'menuItem', + menuItemCheckBox: 'menuItemCheckBox', + menuItemRadio: 'menuItemRadio', + menuListOption: 'menuListOption', + menuListPopup: 'menuListPopup', + menu: 'menu', + meter: 'meter', + navigation: 'navigation', + note: 'note', + outline: 'outline', + pane: 'pane', + paragraph: 'paragraph', + popUpButton: 'popUpButton', + pre: 'pre', + presentational: 'presentational', + progressIndicator: 'progressIndicator', + radioButton: 'radioButton', + radioGroup: 'radioGroup', + region: 'region', + rootWebArea: 'rootWebArea', + rowHeader: 'rowHeader', + row: 'row', + ruby: 'ruby', + ruler: 'ruler', + svgRoot: 'svgRoot', + scrollArea: 'scrollArea', + scrollBar: 'scrollBar', + seamlessWebArea: 'seamlessWebArea', + search: 'search', + searchBox: 'searchBox', + slider: 'slider', + sliderThumb: 'sliderThumb', + spinButtonPart: 'spinButtonPart', + spinButton: 'spinButton', + splitter: 'splitter', + staticText: 'staticText', + status: 'status', + switch: 'switch', + tabGroup: 'tabGroup', + tabList: 'tabList', + tabPanel: 'tabPanel', + tab: 'tab', + tableHeaderContainer: 'tableHeaderContainer', + table: 'table', + textField: 'textField', + time: 'time', + timer: 'timer', + titleBar: 'titleBar', + toggleButton: 'toggleButton', + toolbar: 'toolbar', + treeGrid: 'treeGrid', + treeItem: 'treeItem', + tree: 'tree', + unknown: 'unknown', + tooltip: 'tooltip', + webArea: 'webArea', + webView: 'webView', + window: 'window', +}; + +/** + * @enum {string} + */ +chrome.automation.StateType = { + busy: 'busy', + checked: 'checked', + collapsed: 'collapsed', + default: 'default', + disabled: 'disabled', + editable: 'editable', + enabled: 'enabled', + expanded: 'expanded', + focusable: 'focusable', + focused: 'focused', + haspopup: 'haspopup', + horizontal: 'horizontal', + hovered: 'hovered', + indeterminate: 'indeterminate', + invisible: 'invisible', + linked: 'linked', + multiselectable: 'multiselectable', + offscreen: 'offscreen', + pressed: 'pressed', + protected: 'protected', + readOnly: 'readOnly', + required: 'required', + selectable: 'selectable', + selected: 'selected', + vertical: 'vertical', + visited: 'visited', +}; + +/** + * @enum {string} + */ +chrome.automation.TreeChangeType = { + nodeCreated: 'nodeCreated', + subtreeCreated: 'subtreeCreated', + nodeChanged: 'nodeChanged', + nodeRemoved: 'nodeRemoved', +}; + +/** + * @typedef {{ + * left: number, + * top: number, + * width: number, + * height: number + * }} + */ +chrome.automation.Rect; + +/** + * @typedef {{ + * role: (!chrome.automation.RoleType|undefined), + * state: (Object|undefined), + * attributes: (Object|undefined) + * }} + */ +chrome.automation.FindParams; + +/** + * @constructor + */ +chrome.automation.AutomationEvent = function() {}; + +/** + * @typedef {{ + * target: chrome.automation.AutomationNode, + * type: !chrome.automation.TreeChangeType + * }} + */ +chrome.automation.TreeChange; + +/** * @constructor */ chrome.automation.AutomationNode = function() {}; +/** + * @typedef {{ + * activedescendant: chrome.automation.AutomationNode + * }} + */ +chrome.automation.ActiveDescendantMixin; + +/** + * @typedef {{ + * url: string + * }} + */ +chrome.automation.LinkMixins; + +/** + * @typedef {{ + * docUrl: string, + * docTitle: string, + * docLoaded: boolean, + * docLoadingProgress: number + * }} + */ +chrome.automation.DocumentMixins; + +/** + * @typedef {{ + * scrollX: number, + * scrollXMin: number, + * scrollXMax: number, + * scrollY: number, + * scrollYMin: number, + * scrollYMax: number + * }} + */ +chrome.automation.ScrollableMixins; + +/** + * @typedef {{ + * textSelStart: number, + * textSelEnd: number + * }} + */ +chrome.automation.EditableTextMixins; + +/** + * @typedef {{ + * valueForRange: number, + * minValueForRange: number, + * maxValueForRange: number + * }} + */ +chrome.automation.RangeMixins; + +/** + * @typedef {{ + * tableRowCount: number, + * tableColumnCount: number + * }} + */ +chrome.automation.TableMixins; + +/** + * @typedef {{ + * tableCellColumnIndex: number, + * tableCellColumnSpan: number, + * tableCellRowIndex: number, + * tableCellRowSpan: number + * }} + */ +chrome.automation.TableCellMixins; + +/** + * Get the automation tree for the tab with the given tabId, or the current tab + * if no tabID is given, enabling automation if necessary. Returns a tree with a + * placeholder root node; listen for the "loadComplete" event to get a + * notification that the tree has fully loaded (the previous root node reference + * will stop working at or before this point). + * @param {number} tabId + * @param {function(chrome.automation.AutomationNode):void} callback + * Called when the <code>AutomationNode</code> for the page is available. + */ +chrome.automation.getTree = function(tabId, callback) {}; + +/** + * Get the automation tree for the whole desktop which consists of all on screen + * views. Note this API is currently only supported on Chrome OS. + * @param {function(chrome.automation.AutomationNode):void} callback + * Called when the <code>AutomationNode</code> for the page is available. + */ +chrome.automation.getDesktop = function(callback) {}; + +/** + * Add a tree change observer. Tree change observers are static/global, + * they listen to tree changes across all trees. + * @param {function(chrome.automation.TreeChange):void} observer + * A listener for tree changes on the <code>AutomationNode</code> tree. + */ +chrome.automation.addTreeChangeObserver = function(observer) {}; + +/** + * Remove a tree change observer. + * @param {function(chrome.automation.TreeChange):void} observer + * A listener for tree changes on the <code>AutomationNode</code> tree. + */ +chrome.automation.removeTreeChangeObserver = function(observer) {}; + +// +// End auto generated externs; do not edit. +// + + /** * @type {chrome.automation.RoleType} @@ -1229,11 +1591,26 @@ chrome.automation.AutomationNode.prototype.role; /** + * @type {!Object<chrome.automation.StateType, boolean>} + */ +chrome.automation.AutomationNode.prototype.state; + + +/** + * @type {number} + */ +chrome.automation.AutomationNode.prototype.indexInParent; + + +/** * @type {{ * name: string, + * url: string, * value: string, - * wordStarts: Array.<number>, - * wordEnds: Array.<number> + * textSelStart: number, + * textSelEnd: number, + * wordStarts: Array<number>, + * wordEnds: Array<number> * }} */ chrome.automation.AutomationNode.prototype.attributes; @@ -1246,39 +1623,39 @@ chrome.automation.AutomationNode.prototype.root; /** - * @return {chrome.automation.AutomationNode} + * @type {chrome.automation.AutomationNode} */ -chrome.automation.AutomationNode.prototype.firstChild = function() {}; +chrome.automation.AutomationNode.prototype.firstChild; /** - * @return {chrome.automation.AutomationNode} + * @type {chrome.automation.AutomationNode} */ -chrome.automation.AutomationNode.prototype.lastChild = function() {}; +chrome.automation.AutomationNode.prototype.lastChild; /** - * @return {chrome.automation.AutomationNode} + * @type {chrome.automation.AutomationNode} */ -chrome.automation.AutomationNode.prototype.nextSibling = function() {}; +chrome.automation.AutomationNode.prototype.nextSibling; /** - * @return {chrome.automation.AutomationNode} + * @type {chrome.automation.AutomationNode} */ -chrome.automation.AutomationNode.prototype.previousSibling = function() {}; +chrome.automation.AutomationNode.prototype.previousSibling; /** - * @return {chrome.automation.AutomationNode} + * @type {chrome.automation.AutomationNode} */ -chrome.automation.AutomationNode.prototype.parent = function() {}; +chrome.automation.AutomationNode.prototype.parent; /** - * @return {!Array.<chrome.automation.AutomationNode>} + * @type {!Array<chrome.automation.AutomationNode>} */ -chrome.automation.AutomationNode.prototype.children = function() {}; +chrome.automation.AutomationNode.prototype.children; /** @@ -1305,232 +1682,72 @@ chrome.automation.AutomationNode.prototype.removeEventListener = function(eventType, callback, capture) {}; -chrome.automation.AutomationNode.prototype.focus = function() {}; +/** + * @type {chrome.automation.AutomationNode} + */ +chrome.automation.TreeChange.prototype.target; /** - * @param {function(chrome.automation.AutomationNode)} callback + * @type {chrome.automation.TreeChangeType} */ -chrome.automation.getDesktop = function(callback) {}; +chrome.automation.TreeChange.prototype.type; /** - * @param {function(chrome.automation.AutomationNode)} callback + * @param {function(chrome.automation.TreeChange) : void} + * callback */ -chrome.automation.getTree = function(callback) {}; +chrome.automation.AutomationNode.prototype.addTreeChangeObserver = + function(callback) {}; /** - * @const + * @param {function(chrome.automation.TreeChange) : void} + * callback */ -chrome.commands = {}; +chrome.automation.AutomationNode.prototype.removeTreeChangeObserver = + function(callback) {}; + + +chrome.automation.AutomationNode.prototype.doDefault = function() {}; + + +chrome.automation.AutomationNode.prototype.focus = function() {}; + +/** @type {string} */ +chrome.automation.AutomationNode.prototype.containerLiveStatus; + +/** @type {string} */ +chrome.automation.AutomationNode.prototype.containerLiveRelevant; + +/** @type {boolean} */ +chrome.automation.AutomationNode.prototype.containerLiveAtomic; + +/** @type {boolean} */ +chrome.automation.AutomationNode.prototype.containerLiveBusy; /** - * @type {ChromeEvent} + * @param {Object} findParams */ -chrome.commands.onCommand; +chrome.automation.AutomationNode.prototype.find = function(findParams) {}; -// Begin auto generated externs; do not edit. -// The following was generated from tools/json_schema_compiler/compiler.py. /** - * Possible events fired on an $(ref:automation.AutomationNode). - * @enum {string} + * @const */ -chrome.automation.EventType = { - activedescendantchanged: 'activedescendantchanged', - alert: 'alert', - ariaAttributeChanged: 'ariaAttributeChanged', - autocorrectionOccured: 'autocorrectionOccured', - blur: 'blur', - checkedStateChanged: 'checkedStateChanged', - childrenChanged: 'childrenChanged', - focus: 'focus', - hide: 'hide', - hover: 'hover', - invalidStatusChanged: 'invalidStatusChanged', - layoutComplete: 'layoutComplete', - liveRegionChanged: 'liveRegionChanged', - loadComplete: 'loadComplete', - locationChanged: 'locationChanged', - menuEnd: 'menuEnd', - menuListItemSelected: 'menuListItemSelected', - menuListValueChanged: 'menuListValueChanged', - menuPopupEnd: 'menuPopupEnd', - menuPopupStart: 'menuPopupStart', - menuStart: 'menuStart', - rowCollapsed: 'rowCollapsed', - rowCountChanged: 'rowCountChanged', - rowExpanded: 'rowExpanded', - scrollPositionChanged: 'scrollPositionChanged', - scrolledToAnchor: 'scrolledToAnchor', - selectedChildrenChanged: 'selectedChildrenChanged', - selectedTextChanged: 'selectedTextChanged', - selection: 'selection', - selectionAdd: 'selectionAdd', - selectionRemove: 'selectionRemove', - show: 'show', - textChanged: 'textChanged', - textInserted: 'textInserted', - textRemoved: 'textRemoved', - textSelectionChanged: 'textSelectionChanged', - valueChanged: 'valueChanged' -}; +chrome.commands = {}; + + /** - * Describes the purpose of an $(ref:automation.AutomationNode). - * @enum {string} + * @type {ChromeEvent} */ -chrome.automation.RoleType = { - alertDialog: 'alertDialog', - alert: 'alert', - annotation: 'annotation', - application: 'application', - article: 'article', - banner: 'banner', - browser: 'browser', - busyIndicator: 'busyIndicator', - button: 'button', - buttonDropDown: 'buttonDropDown', - canvas: 'canvas', - cell: 'cell', - checkBox: 'checkBox', - client: 'client', - colorWell: 'colorWell', - columnHeader: 'columnHeader', - column: 'column', - comboBox: 'comboBox', - complementary: 'complementary', - contentInfo: 'contentInfo', - definition: 'definition', - descriptionListDetail: 'descriptionListDetail', - descriptionListTerm: 'descriptionListTerm', - desktop: 'desktop', - dialog: 'dialog', - directory: 'directory', - disclosureTriangle: 'disclosureTriangle', - div: 'div', - document: 'document', - drawer: 'drawer', - editableText: 'editableText', - embeddedObject: 'embeddedObject', - footer: 'footer', - form: 'form', - grid: 'grid', - group: 'group', - growArea: 'growArea', - heading: 'heading', - helpTag: 'helpTag', - horizontalRule: 'horizontalRule', - iframe: 'iframe', - ignored: 'ignored', - imageMapLink: 'imageMapLink', - imageMap: 'imageMap', - image: 'image', - incrementor: 'incrementor', - inlineTextBox: 'inlineTextBox', - labelText: 'labelText', - legend: 'legend', - link: 'link', - listBoxOption: 'listBoxOption', - listBox: 'listBox', - listItem: 'listItem', - listMarker: 'listMarker', - list: 'list', - locationBar: 'locationBar', - log: 'log', - main: 'main', - marquee: 'marquee', - mathElement: 'mathElement', - math: 'math', - matte: 'matte', - menuBar: 'menuBar', - menuButton: 'menuButton', - menuItem: 'menuItem', - menuListOption: 'menuListOption', - menuListPopup: 'menuListPopup', - menu: 'menu', - navigation: 'navigation', - note: 'note', - outline: 'outline', - pane: 'pane', - paragraph: 'paragraph', - popUpButton: 'popUpButton', - presentational: 'presentational', - progressIndicator: 'progressIndicator', - radioButton: 'radioButton', - radioGroup: 'radioGroup', - region: 'region', - rootWebArea: 'rootWebArea', - rowHeader: 'rowHeader', - row: 'row', - rulerMarker: 'rulerMarker', - ruler: 'ruler', - svgRoot: 'svgRoot', - scrollArea: 'scrollArea', - scrollBar: 'scrollBar', - seamlessWebArea: 'seamlessWebArea', - search: 'search', - sheet: 'sheet', - slider: 'slider', - sliderThumb: 'sliderThumb', - spinButtonPart: 'spinButtonPart', - spinButton: 'spinButton', - splitGroup: 'splitGroup', - splitter: 'splitter', - staticText: 'staticText', - status: 'status', - systemWide: 'systemWide', - tabGroup: 'tabGroup', - tabList: 'tabList', - tabPanel: 'tabPanel', - tab: 'tab', - tableHeaderContainer: 'tableHeaderContainer', - table: 'table', - textArea: 'textArea', - textField: 'textField', - timer: 'timer', - titleBar: 'titleBar', - toggleButton: 'toggleButton', - toolbar: 'toolbar', - treeGrid: 'treeGrid', - treeItem: 'treeItem', - tree: 'tree', - unknown: 'unknown', - tooltip: 'tooltip', - valueIndicator: 'valueIndicator', - webArea: 'webArea', - window: 'window' -}; +chrome.commands.onCommand; + /** - * Describes characteristics of an $(ref:automation.AutomationNode). - * @enum {string} + * @param {function(Array<{description: string, + * name: string, + * shortcut: string}>): void} callback */ -chrome.automation.StateType = { - busy: 'busy', - checked: 'checked', - collapsed: 'collapsed', - default: 'default', - disabled: 'disabled', - editable: 'editable', - enabled: 'enabled', - expanded: 'expanded', - focusable: 'focusable', - focused: 'focused', - haspopup: 'haspopup', - hovered: 'hovered', - indeterminate: 'indeterminate', - invisible: 'invisible', - linked: 'linked', - multiselectable: 'multiselectable', - offscreen: 'offscreen', - pressed: 'pressed', - protected: 'protected', - readOnly: 'readOnly', - required: 'required', - selectable: 'selectable', - selected: 'selected', - vertical: 'vertical', - visited: 'visited' -}; -// End auto generated externs; do not edit. +chrome.commands.getAll = function(callback) {}; diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/chromevox.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/chromevox.js index c5f9aa6025d..db20382a06a 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/chromevox.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/chromevox.js @@ -150,11 +150,11 @@ cvox.ChromeVox.verbosity = cvox.VERBOSITY_VERBOSE; cvox.ChromeVox.typingEcho = 0; /** * Echoing on key press events. - * @type {Object.<string, boolean>} + * @type {Object<string, boolean>} */ cvox.ChromeVox.keyEcho = {}; /** - * @type {Object.<string, {x:number, y:number}>} + * @type {Object<string, {x:number, y:number}>} */ cvox.ChromeVox.position = {}; /** @@ -181,10 +181,10 @@ if (cvox.ChromeVox.isChromeOS) { * where the subsequent independent key downs (while modifier keys are down) * are a part of the same shortcut. This array is populated in * cvox.ChromeVoxKbHandler.loadKeyToFunctionsTable(). - * @type {!Array.<cvox.KeySequence>} + * @type {!Array<cvox.KeySequence>} */ cvox.ChromeVox.sequenceSwitchKeyCodes = []; -/** @type {Object.<string, boolean>} */ +/** @type {Object<string, boolean>} */ cvox.ChromeVox.visitedUrls = {}; /** * This function can be called before doing an operation that may trigger @@ -275,3 +275,20 @@ function $(id) { * @param {Array} tabs */ cvox.ChromeVox.injectChromeVoxIntoTabs = function(tabs) {}; + +/** + * Returns whether the document has focus, taking into account whether + * it's hidden and also that if an iframe or webview element has focus, + * the focus is really inside that frame and not in this document. + * @return {boolean} True if the document has focus. + */ +cvox.ChromeVox.documentHasFocus = function() { + if (!document.hasFocus() || document.hidden) { + return false; + } + if (document.activeElement.tagName == 'IFRAME' || + document.activeElement.tagName == 'WEBVIEW') { + return false; + } + return true; +}; diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/chromevox_json.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/chromevox_json.js index ae18d75a726..96c78ca9f31 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/chromevox_json.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/chromevox_json.js @@ -15,9 +15,7 @@ goog.provide('cvox.ChromeVoxJSON'); */ if (!cvox.ChromeVoxJSON) { - /** - * @type {Object} - */ + /** Placeholder object. */ cvox.ChromeVoxJSON = {}; } @@ -227,7 +225,7 @@ if (window.JSON && window.JSON.toString() == '[object JSON]') { if (typeof cvox.ChromeVoxJSON.stringify !== 'function') { /** * @param {*} value Input object. - * @param {(Array.<string>|(function(string, *) : *)|null)=} replacer + * @param {(Array<string>|(function(string, *) : *)|null)=} replacer * Replacer array or function. * @param {(number|string|null)=} space Whitespace character. * @return {string} json string which represents jsonObj. diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/command_store.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/command_store.js index a50e56547f9..3fdf69e409e 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/command_store.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/command_store.js @@ -38,7 +38,7 @@ goog.require('cvox.PlatformFilter'); /** * Returns all of the categories in the store as an array. - * @return {Array.<string>} The collection of categories. + * @return {Array<string>} The collection of categories. */ cvox.CommandStore.categories = function() { var categorySet = {}; @@ -79,7 +79,7 @@ cvox.CommandStore.categoryForCommand = function(command) { /** * Gets all commands for a category. * @param {string} category The category to query. - * @return {Array.<string>} The commands, if any. + * @return {Array<string>} The commands, if any. */ cvox.CommandStore.commandsForCategory = function(category) { var ret = []; @@ -95,7 +95,7 @@ cvox.CommandStore.commandsForCategory = function(category) { /** * List of commands and their properties - * @type {Object.<string, {forward: (undefined|boolean), + * @type {Object<string, {forward: (undefined|boolean), * backward: (undefined|boolean), * announce: boolean, * category: (undefined|string), @@ -678,7 +678,7 @@ cvox.CommandStore.CMD_WHITELIST = { /** * List of find next commands and their associated data. - * @type {Object.<string, {predicate: string, + * @type {Object<string, {predicate: string, * forwardError: string, * backwardError: string}>} * predicate: The name of the predicate. This must be defined in DomPredicates. diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/composite_tts.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/composite_tts.js index 1b1cfb0d628..bba28401525 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/composite_tts.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/composite_tts.js @@ -19,7 +19,7 @@ goog.require('cvox.TtsInterface'); */ cvox.CompositeTts = function() { /** - * @type {Array.<cvox.TtsInterface>} + * @type {Array<cvox.TtsInterface>} * @private */ this.ttsEngines_ = []; diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/content_editable_extractor.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/content_editable_extractor.js index e7f3c4a9cc8..ce0d9415f0d 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/content_editable_extractor.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/content_editable_extractor.js @@ -40,14 +40,14 @@ cvox.ContentEditableExtractor = function() { /** * Map from line index to a data structure containing the start * and end index within the line. - * @type {Object.<number, {startIndex: number, endIndex: number}>} + * @type {Object<number, {startIndex: number, endIndex: number}>} * @private */ this.lines_ = {}; /** * Map from 0-based character index to 0-based line index. - * @type {Array.<number>} + * @type {Array<number>} * @private */ this.characterToLineMap_ = []; @@ -61,7 +61,7 @@ cvox.ContentEditableExtractor.prototype.update = function(element) { /** * Map from line index to a data structure containing the start * and end index within the line. - * @type {Object.<number, {startIndex: number, endIndex: number}>} + * @type {Object<number, {startIndex: number, endIndex: number}>} */ var lines = {0: {startIndex: 0, endIndex: 0}}; var startCursor = new cvox.Cursor(element, 0, ''); diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/description_util.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/description_util.js index 67e161eeda6..0fb55784c3d 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/description_util.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/description_util.js @@ -23,7 +23,7 @@ goog.require('cvox.TraverseMath'); /** * Lists all Node tagName's who's description is derived from its subtree. - * @type {Object.<string, boolean>} + * @type {Object<string, boolean>} */ cvox.DescriptionUtil.COLLECTION_NODE_TYPE = { 'H1': true, @@ -38,7 +38,7 @@ cvox.DescriptionUtil.COLLECTION_NODE_TYPE = { * Get a control's complete description in the same format as if you * navigated to the node. * @param {Element} control A control. - * @param {Array.<Node>=} opt_changedAncestors The changed ancestors that will + * @param {Array<Node>=} opt_changedAncestors The changed ancestors that will * be used to determine what needs to be spoken. If this is not provided, the * ancestors used to determine what needs to be spoken will just be the control * itself and its surrounding control if it has one. @@ -91,7 +91,7 @@ cvox.DescriptionUtil.getControlDescription = * ancestor nodes. The ancestors are in order from the highest in the * tree to the lowest, i.e. ending with the current leaf node. * - * @param {Array.<Node>} ancestorsArray An array of ancestor nodes. + * @param {Array<Node>} ancestorsArray An array of ancestor nodes. * @param {boolean} recursive Whether or not the element's subtree should * be used; true by default. * @param {number} verbosity The verbosity setting. @@ -182,7 +182,7 @@ cvox.DescriptionUtil.getDescriptionFromAncestors = function( * @param {boolean} recursive Whether or not the element's subtree should * be used; true by default. * @param {number} verbosity The verbosity setting. - * @return {!Array.<cvox.NavDescription>} The description of the navigation + * @return {!Array<cvox.NavDescription>} The description of the navigation * action. */ cvox.DescriptionUtil.getDescriptionFromNavigation = @@ -232,7 +232,7 @@ cvox.DescriptionUtil.getDescriptionFromNavigation = * This is an awkward design, and should be changed in the future. * @param {!cvox.CursorSelection} prevSel The previous selection. * @param {!cvox.CursorSelection} sel The selection. - * @return {!Array.<!cvox.NavDescription>} The descriptions as described above. + * @return {!Array<!cvox.NavDescription>} The descriptions as described above. */ cvox.DescriptionUtil.getCollectionDescription = function(prevSel, sel) { var descriptions = cvox.DescriptionUtil.getRawDescriptions_(prevSel, sel); @@ -253,7 +253,7 @@ cvox.DescriptionUtil.subWalker_ = new cvox.BareObjectWalker(); * Returns the descriptions that would be gotten by an object walker. * @param {!cvox.CursorSelection} prevSel The previous selection. * @param {!cvox.CursorSelection} sel The selection. - * @return {!Array.<!cvox.NavDescription>} The descriptions. + * @return {!Array<!cvox.NavDescription>} The descriptions. * @private */ cvox.DescriptionUtil.getRawDescriptions_ = function(prevSel, sel) { @@ -303,7 +303,7 @@ cvox.DescriptionUtil.getRawDescriptions_ = function(prevSel, sel) { * object walker. * @param {?Element} prevnode The previous element if there is one. * @param {!Element} node The target element. - * @return {!Array.<!cvox.NavDescription>} The descriptions. + * @return {!Array<!cvox.NavDescription>} The descriptions. */ cvox.DescriptionUtil.getFullDescriptionsFromChildren = function(prevnode, node) { @@ -352,7 +352,7 @@ cvox.DescriptionUtil.getFullDescriptionsFromChildren = /** * Modify the descriptions to say that it is a collection. - * @param {Array.<cvox.NavDescription>} descriptions The descriptions. + * @param {Array<cvox.NavDescription>} descriptions The descriptions. * @private */ cvox.DescriptionUtil.insertCollectionDescription_ = function(descriptions) { @@ -387,8 +387,8 @@ cvox.DescriptionUtil.insertCollectionDescription_ = function(descriptions) { /** * Pulls the annotations from a description array. - * @param {Array.<cvox.NavDescription>} descriptions The descriptions. - * @return {Array.<string>} The annotations. + * @param {Array<cvox.NavDescription>} descriptions The descriptions. + * @return {Array<string>} The annotations. * @private */ cvox.DescriptionUtil.getAnnotations_ = function(descriptions) { @@ -432,7 +432,7 @@ cvox.DescriptionUtil.isAnnotationCollection_ = function(annotation) { /** * Determines whether to describe the exit of an ancestor chain. - * @param {Array.<Node>} ancestors The ancestors exited during navigation. + * @param {Array<Node>} ancestors The ancestors exited during navigation. * @return {boolean} The result. * @private */ @@ -452,7 +452,7 @@ cvox.DescriptionUtil.shouldDescribeExit_ = function(ancestors) { /** * Generates a description for a math node. * @param {!Node} node The given node. - * @return {!Array.<cvox.NavDescription>} A list of Navigation descriptions. + * @return {!Array<cvox.NavDescription>} A list of Navigation descriptions. */ cvox.DescriptionUtil.getMathDescription = function(node) { // TODO (sorge) This function should evantually be removed. Descriptions diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/dom_predicates.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/dom_predicates.js index f47833243f0..685a8ecf8f4 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/dom_predicates.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/dom_predicates.js @@ -14,7 +14,7 @@ goog.provide('cvox.DomPredicates'); /** * Checkbox. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a checkbox. */ cvox.DomPredicates.checkboxPredicate = function(nodes) { @@ -31,7 +31,7 @@ cvox.DomPredicates.checkboxPredicate = function(nodes) { /** * Radio button. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a radio button. */ cvox.DomPredicates.radioPredicate = function(nodes) { @@ -47,7 +47,7 @@ cvox.DomPredicates.radioPredicate = function(nodes) { /** * Slider. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a slider. */ cvox.DomPredicates.sliderPredicate = function(nodes) { @@ -63,7 +63,7 @@ cvox.DomPredicates.sliderPredicate = function(nodes) { /** * Graphic. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a graphic. */ cvox.DomPredicates.graphicPredicate = function(nodes) { @@ -79,7 +79,7 @@ cvox.DomPredicates.graphicPredicate = function(nodes) { /** * Button. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a button. */ cvox.DomPredicates.buttonPredicate = function(nodes) { @@ -98,7 +98,7 @@ cvox.DomPredicates.buttonPredicate = function(nodes) { /** * Combo box. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a combo box. */ cvox.DomPredicates.comboBoxPredicate = function(nodes) { @@ -115,7 +115,7 @@ cvox.DomPredicates.comboBoxPredicate = function(nodes) { /** * Editable text field. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is an editable text field. */ cvox.DomPredicates.editTextPredicate = function(nodes) { @@ -134,7 +134,7 @@ cvox.DomPredicates.editTextPredicate = function(nodes) { /** * Heading. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a heading. */ cvox.DomPredicates.headingPredicate = function(nodes) { @@ -159,7 +159,7 @@ cvox.DomPredicates.headingPredicate = function(nodes) { /** * Heading level 1. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a heading level 1. * TODO: handle ARIA headings with ARIA heading levels? */ @@ -170,7 +170,7 @@ cvox.DomPredicates.heading1Predicate = function(nodes) { /** * Heading level 2. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a heading level 2. */ cvox.DomPredicates.heading2Predicate = function(nodes) { @@ -180,7 +180,7 @@ cvox.DomPredicates.heading2Predicate = function(nodes) { /** * Heading level 3. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a heading level 3. */ cvox.DomPredicates.heading3Predicate = function(nodes) { @@ -190,7 +190,7 @@ cvox.DomPredicates.heading3Predicate = function(nodes) { /** * Heading level 4. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a heading level 4. */ cvox.DomPredicates.heading4Predicate = function(nodes) { @@ -200,7 +200,7 @@ cvox.DomPredicates.heading4Predicate = function(nodes) { /** * Heading level 5. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a heading level 5. */ cvox.DomPredicates.heading5Predicate = function(nodes) { @@ -210,7 +210,7 @@ cvox.DomPredicates.heading5Predicate = function(nodes) { /** * Heading level 6. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a heading level 6. */ cvox.DomPredicates.heading6Predicate = function(nodes) { @@ -220,7 +220,7 @@ cvox.DomPredicates.heading6Predicate = function(nodes) { /** * Link. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a link. */ cvox.DomPredicates.linkPredicate = function(nodes) { @@ -236,7 +236,7 @@ cvox.DomPredicates.linkPredicate = function(nodes) { /** * Table. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a data table. */ cvox.DomPredicates.tablePredicate = function(nodes) { @@ -251,7 +251,7 @@ cvox.DomPredicates.tablePredicate = function(nodes) { /** * Table Cell. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a table cell. */ cvox.DomPredicates.cellPredicate = function(nodes) { @@ -269,7 +269,7 @@ cvox.DomPredicates.cellPredicate = function(nodes) { /** * Visited link. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a visited link. */ cvox.DomPredicates.visitedLinkPredicate = function(nodes) { @@ -284,7 +284,7 @@ cvox.DomPredicates.visitedLinkPredicate = function(nodes) { /** * List. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a list. */ cvox.DomPredicates.listPredicate = function(nodes) { @@ -301,7 +301,7 @@ cvox.DomPredicates.listPredicate = function(nodes) { /** * List item. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a list item. */ cvox.DomPredicates.listItemPredicate = function(nodes) { @@ -318,7 +318,7 @@ cvox.DomPredicates.listItemPredicate = function(nodes) { /** * Blockquote. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a blockquote. */ cvox.DomPredicates.blockquotePredicate = function(nodes) { @@ -328,7 +328,7 @@ cvox.DomPredicates.blockquotePredicate = function(nodes) { /** * Form field. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is any type of form field. */ cvox.DomPredicates.formFieldPredicate = function(nodes) { @@ -343,7 +343,7 @@ cvox.DomPredicates.formFieldPredicate = function(nodes) { /** * ARIA landmark. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is an ARIA landmark. */ cvox.DomPredicates.landmarkPredicate = function(nodes) { @@ -375,7 +375,7 @@ cvox.DomPredicates.containsTagName_ = function(arr, tagName) { /** * MathML expression - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a math expression. */ cvox.DomPredicates.mathPredicate = function(nodes) { @@ -385,7 +385,7 @@ cvox.DomPredicates.mathPredicate = function(nodes) { /** * SECTION: A section is anything that indicates a new section. This includes * headings and landmarks. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is considered a section marker. */ cvox.DomPredicates.sectionPredicate = function(nodes) { @@ -416,7 +416,7 @@ cvox.DomPredicates.sectionPredicate = function(nodes) { /** * CONTROL: A control is anything that the user can interact with. This includes * form fields and links. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is considered a control. */ cvox.DomPredicates.controlPredicate = function(nodes) { @@ -434,7 +434,7 @@ cvox.DomPredicates.controlPredicate = function(nodes) { /** * Caption. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a caption. */ cvox.DomPredicates.captionPredicate = function(nodes) { @@ -448,7 +448,7 @@ cvox.DomPredicates.captionPredicate = function(nodes) { /** * Article. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a article. */ cvox.DomPredicates.articlePredicate = function(nodes) { @@ -464,7 +464,7 @@ cvox.DomPredicates.articlePredicate = function(nodes) { /** * Media. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a media widget (video or audio). */ cvox.DomPredicates.mediaPredicate = function(nodes) { @@ -480,7 +480,7 @@ cvox.DomPredicates.mediaPredicate = function(nodes) { /** * Ordered List. - * @param {Array.<Node>} nodes An array of nodes to check. + * @param {Array<Node>} nodes An array of nodes to check. * @return {?Node} Node in the array that is a ordered list. */ cvox.DomPredicates.orderedListPredicate = function(nodes) { diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/dom_util.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/dom_util.js index 6f9ba4add25..f27290da55b 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/dom_util.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/dom_util.js @@ -108,7 +108,7 @@ cvox.DomUtil.TAG_TO_INFORMATION_TABLE_BRIEF_MSG = { /** * These tags are treated as text formatters. - * @type {Array.<string>} + * @type {Array<string>} */ cvox.DomUtil.FORMATTING_TAGS = ['B', 'BIG', 'CITE', 'CODE', 'DFN', 'EM', 'I', 'KBD', 'SAMP', 'SMALL', @@ -230,6 +230,9 @@ cvox.DomUtil.hasInvisibleAncestor_ = function(node) { */ cvox.DomUtil.hasVisibleNodeSubtree_ = function(root, recursive) { if (!(root instanceof Element)) { + if (!root.parentElement) { + return false; + } var parentStyle = document.defaultView .getComputedStyle(root.parentElement, null); var isVisibleParent = !cvox.DomUtil.isInvisibleStyle(parentStyle); @@ -946,7 +949,7 @@ cvox.DomUtil.getImageTitle = function(node) { * the complete set of ids they map to, so that we can skip elements that * just label other elements and not double-speak them. We cache this * result and then throw it away at the next event loop. - * @return {Object.<string, boolean>} Set of all ids that are mapped + * @return {Object<string, boolean>} Set of all ids that are mapped * by aria-labelledby. */ cvox.DomUtil.getLabelledByTargets = function() { @@ -1179,7 +1182,7 @@ cvox.DomUtil.computeHasContent_ = function(node) { * is the current node. * * @param {Node} targetNode The node to get ancestors for. - * @return {Array.<Node>} An array of ancestors for the targetNode. + * @return {Array<Node>} An array of ancestors for the targetNode. */ cvox.DomUtil.getAncestors = function(targetNode) { var ancestors = new Array(); @@ -1231,7 +1234,7 @@ cvox.DomUtil.compareAncestors = function(ancestorsA, ancestorsB) { * @param {Node} currentNode The current node. * @param {boolean=} opt_fallback True returns node's ancestors in the case * where node's ancestors is a subset of previousNode's ancestors. - * @return {Array.<Node>} An array of unique ancestors for the current node + * @return {Array<Node>} An array of unique ancestors for the current node * (inclusive). */ cvox.DomUtil.getUniqueAncestors = function( @@ -1262,6 +1265,10 @@ cvox.DomUtil.getRoleMsg = function(targetNode, verbosity) { cvox.DomUtil.isInternalLink(targetNode)) { info = 'internal_link'; } else if (targetNode.tagName == 'A' && + targetNode.getAttribute('href') && + cvox.ChromeVox.visitedUrls[targetNode.href]) { + info = 'visited_link'; + } else if (targetNode.tagName == 'A' && targetNode.getAttribute('name')) { info = ''; // Don't want to add any role to anchors. } else if (targetNode.isContentEditable) { @@ -1393,11 +1400,6 @@ cvox.DomUtil.getStateMsgs = function(targetNode, primary) { info.push(['aria_disabled_true']); } - if (cvox.DomPredicates.linkPredicate([targetNode]) && - cvox.ChromeVox.visitedUrls[targetNode.href]) { - info.push(['visited_url']); - } - if (targetNode.accessKey) { info.push(['access_key', targetNode.accessKey]); } @@ -1969,7 +1971,7 @@ cvox.DomUtil.getContainingTable = function(node, kwargs) { /** * Extracts a table node from a list of nodes. - * @param {Array.<Node>} nodes The list of nodes. + * @param {Array<Node>} nodes The list of nodes. * @param {{allowCaptions: (undefined|boolean)}=} kwargs Optional named args. * allowCaptions: If true, will return true even if inside a caption. False * by default. @@ -2212,7 +2214,7 @@ cvox.DomUtil.countNodes = function(root, p) { * using a depth first search. * @param {Node} root The root of the tree to search. * @param {function(Node) : boolean} p The filter function. - * @param {Array.<Node>} rv The found nodes are added to this array. + * @param {Array<Node>} rv The found nodes are added to this array. * @param {boolean} findOne If true we exit after the first found node. * @param {number} maxChildCount The max child count. This is used as a kill * switch - if there are more nodes than this, terminate the search. @@ -2260,7 +2262,7 @@ cvox.DomUtil.toArray = function(nodeList) { /** * Creates a new element with the same attributes and no children. * @param {Node|Text} node A node to clone. - * @param {Object.<string, boolean>} skipattrs Set the attribute to true to + * @param {Object<string, boolean>} skipattrs Set the attribute to true to * skip it during cloning. * @return {Node|Text} The cloned node. */ @@ -2288,7 +2290,7 @@ cvox.DomUtil.shallowChildlessClone = function(node, skipattrs) { /** * Creates a new element with the same attributes and clones of children. * @param {Node|Text} node A node to clone. - * @param {Object.<string, boolean>} skipattrs Set the attribute to true to + * @param {Object<string, boolean>} skipattrs Set the attribute to true to * skip it during cloning. * @return {Node|Text} The cloned node. */ @@ -2377,7 +2379,7 @@ cvox.DomUtil.getContainingMath = function(node) { /** * Extracts a math node from a list of nodes. - * @param {Array.<Node>} nodes The list of nodes. + * @param {Array<Node>} nodes The list of nodes. * @return {Node} The math node if the list of nodes contains a math node. * Null if it does not. */ @@ -2406,8 +2408,8 @@ cvox.DomUtil.isMath = function(node) { /** * Specifies node classes in which we expect maths expressions a alt text. - * @type {{tex: Array.<string>, - * asciimath: Array.<string>}} + * @type {{tex: Array<string>, + * asciimath: Array<string>}} */ // These are the classes for which we assume they contain Maths in the ALT or // TITLE attribute. @@ -2448,9 +2450,14 @@ cvox.DomUtil.isMathImg = function(node) { if (node.tagName != 'IMG') { return false; } - var className = node.className.toLowerCase(); - return cvox.DomUtil.ALT_MATH_CLASSES.tex.indexOf(className) != -1 || - cvox.DomUtil.ALT_MATH_CLASSES.asciimath.indexOf(className) != -1; + for (var i = 0, className; className = node.classList.item(i); i++) { + className = className.toLowerCase(); + if (cvox.DomUtil.ALT_MATH_CLASSES.tex.indexOf(className) != -1 || + cvox.DomUtil.ALT_MATH_CLASSES.asciimath.indexOf(className) != -1) { + return true; + } + } + return false; }; @@ -2536,7 +2543,7 @@ cvox.DomUtil.getNodeTagName = function(node) { /** * Cleaning up a list of nodes to remove empty text nodes. * @param {NodeList} nodes The nodes list. - * @return {!Array.<Node|string|null>} The cleaned up list of nodes. + * @return {!Array<Node|string|null>} The cleaned up list of nodes. */ cvox.DomUtil.purgeNodes = function(nodes) { return cvox.DomUtil.toArray(nodes). diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/editable_text.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/editable_text.js index 5968c61f33e..d336d37f1d5 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/editable_text.js +++ b/chromium/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,659 +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; - - if (this.brailleHandler_) { - var line = this.getLine(this.getLineIndex(evt.start)); - var lineStart = this.getLineStart(this.getLineIndex(evt.start)); - var start = evt.start - lineStart; - var end = Math.min(evt.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. @@ -790,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 @@ -807,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, @@ -826,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++; @@ -916,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); + } +}; /******************************************/ @@ -1237,9 +552,7 @@ cvox.ChromeVoxEditableContentEditable.prototype.getExtractor = function() { }; -/** - * @override - */ +/** @override */ cvox.ChromeVoxEditableContentEditable.prototype.changed = function(evt) { if (!evt.triggeredByUser) { @@ -1248,6 +561,11 @@ cvox.ChromeVoxEditableContentEditable.prototype.changed = // 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); } diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/editable_text_area_shadow.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/editable_text_area_shadow.js index 58940f2626a..bd381156c69 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/editable_text_area_shadow.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/editable_text_area_shadow.js @@ -23,14 +23,14 @@ cvox.EditableTextAreaShadow = function() { /** * Map from line index to a data structure containing the start * and end index within the line. - * @type {Object.<number, {startIndex: number, endIndex: number}>} + * @type {Object<number, {startIndex: number, endIndex: number}>} * @private */ this.lines_ = {}; /** * Map from 0-based character index to 0-based line index. - * @type {Array.<number>} + * @type {Array<number>} * @private */ this.characterToLineMap_ = []; @@ -72,7 +72,7 @@ cvox.EditableTextAreaShadow.prototype.update = function(element) { /** * Map from line index to a data structure containing the start * and end index within the line. - * @type {Object.<number, {startIndex: number, endIndex: number}>} + * @type {Object<number, {startIndex: number, endIndex: number}>} */ var lines = {0: {startIndex: 0, endIndex: 0}}; diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js new file mode 100644 index 00000000000..573123915ba --- /dev/null +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js @@ -0,0 +1,712 @@ +// 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.ChromeVoxEditableTextBase'); +goog.provide('cvox.TextChangeEvent'); +goog.provide('cvox.TypingEcho'); + +goog.require('cvox.AbstractTts'); +goog.require('cvox.ChromeVox'); +goog.require('cvox.TtsInterface'); +goog.require('goog.i18n.MessageFormat'); + + +/** + * @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. + */ + + +/** + * A class containing the information needed to speak + * a text change event to the user. + * + * @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; +}; + + +/** + * 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; + + /** + * 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.lastChangeDescribed = false; + +}; + + +/** + * 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; + + +/** + * 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) { + 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; +}; + + +/** + * 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; }; + + +/******************************************/ diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/editable_text_test.unitjs b/chromium/chrome/browser/resources/chromeos/chromevox/common/editable_text_test.unitjs index 6da825d3163..2df3086d66b 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/editable_text_test.unitjs +++ b/chromium/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) { @@ -668,3 +669,25 @@ TEST_F('CvoxEditableTextUnitTest', 'TextChangeEvent', function() { assertEquals(1, event3.start); assertEquals(1, event3.end); }); + +TEST_F('CvoxEditableTextUnitTest', 'ContentEditableBraille', function() { + this.loadDoc(function() {/*! + <div id='1' contenteditable='true'> + Some text.<br><br> + After blank line. + </div> + */}); + var element = $('1'); + element.focus(); + var editable = new cvox.ChromeVoxEditableContentEditable( + element, new TestTts()); + var firstLine = 'Some text.\n'; + for (var i = 0; i < firstLine.length; ++i) { + editable.update(true); + TestBraille.assertContent(firstLine, i, i); + window.getSelection().modify('move', 'forward', 'character'); + } + // We should have crossed the line break to the second line which is blank. + editable.update(true); + TestBraille.assertContent('', 0, 0); +}); diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/externs.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/externs.js index 7d34b6d6fc2..2e2886d4237 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/externs.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/externs.js @@ -5,18 +5,3 @@ Range.prototype.getBoundingClientRect; Document.prototype.documentElement.innerWidth; Document.prototype.documentElement.head; - -/** @constructor */ -function WeakMap() {} - -/** - * @param {Object} key - * @return {*} - */ -WeakMap.prototype.get = function(key) {}; - -/** - * @param {Object} key - * @param {*} value - */ -WeakMap.prototype.set = function(key, value) {}; diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/find_util.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/find_util.js index 486d406b6f5..a5ac8a6b371 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/find_util.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/find_util.js @@ -24,7 +24,7 @@ cvox.FindUtil.objectWalker_ = new cvox.BareObjectWalker(); * Finds the next selection that matches the predicate function starting from * sel. Undefined if the nodes in sel are not attached to the document. * @param {!cvox.CursorSelection} sel The selection from which to start. - * @param {function(Array.<Node>):Node} predicate A function taking a + * @param {function(Array<Node>):Node} predicate A function taking a * unique ancestor tree and outputting Node if the ancestor tree matches * the desired node to find. * @param {boolean=} opt_initialNode Whether to start the search from node diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/interframe.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/interframe.js index 5f4b800bf0a..8d7b7fc117f 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/interframe.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/interframe.js @@ -41,6 +41,14 @@ cvox.Interframe.IF_MSG_PREFIX = 'cvox.INTERFRAME:'; cvox.Interframe.SET_ID = 'cvox.INTERFRAME_SET_ID'; /** + * The message used by a child frame to acknowledge an id was set (sent to its + * parent frame. + * @type {string} + * @const + */ +cvox.Interframe.ACK_SET_ID = 'cvox.INTERFRAME_ACK_SET_ID'; + +/** * The ID of this window (relative to its parent farme). * @type {number|string|undefined} */ @@ -49,11 +57,19 @@ cvox.Interframe.id; /** * Array of functions that have been registered as listeners to interframe * messages send to this window. - * @type {Array.<function(Object)>} + * @type {Array<function(Object)>} */ cvox.Interframe.listeners = []; /** + * Maps an id to a function which gets called when a frame first sends an ack + * for a set id msg. + @dict {!Object<number|string, function()>} + * @private + */ +cvox.Interframe.idToCallback_ = {}; + +/** * Flag for unit testing. When false, skips over iframe.contentWindow check * in sendMessageToIframe. This is needed because in the wild, ChromeVox may * not have access to iframe.contentWindow due to the same-origin security @@ -74,6 +90,12 @@ cvox.Interframe.init = function() { cvox.ChromeVoxJSON.parse(suffix)); if (message['command'] == cvox.Interframe.SET_ID) { cvox.Interframe.id = message['id']; + message['command'] = cvox.Interframe.ACK_SET_ID; + cvox.Interframe.sendMessageToParentWindow(message); + } else if (message['command'] == cvox.Interframe.ACK_SET_ID) { + cvox.Interframe.id = message['id']; + var callback = cvox.Interframe.idToCallback_[cvox.Interframe.id]; + callback(); } for (var i = 0, listener; listener = cvox.Interframe.listeners[i]; i++) { listener(message); @@ -196,8 +218,13 @@ cvox.Interframe.sendMessageToParentWindow = function(message) { * @param {number|string} id The ID you want to receive in replies from * this iframe. * @param {HTMLIFrameElement} iframe The iframe to assign. + * @param {function()=} opt_callback Called when a ack msg arrives from the + *frame. */ -cvox.Interframe.sendIdToIFrame = function(id, iframe) { +cvox.Interframe.sendIdToIFrame = function(id, iframe, opt_callback) { + if (opt_callback) { + cvox.Interframe.idToCallback_[id] = opt_callback; + } var message = {'command': cvox.Interframe.SET_ID, 'id': id}; cvox.Interframe.sendMessageToIFrame(message, iframe); }; diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/key_sequence.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/key_sequence.js index 5759399cb27..0a6f3d51c01 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/key_sequence.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/key_sequence.js @@ -11,6 +11,7 @@ goog.provide('cvox.KeySequence'); goog.require('cvox.ChromeVox'); +goog.require('cvox.PlatformFilter'); /** @@ -47,6 +48,9 @@ cvox.KeySequence = function( /** @type {boolean} */ this.doubleTap = !!opt_doubleTap; + /** @type {cvox.PlatformFilter} */ + this.platformFilter; + if (opt_cvoxModifier == undefined) { this.cvoxModifier = this.isCVoxModifierActive(originalEvent); } else { @@ -96,7 +100,7 @@ cvox.KeySequence = function( // TODO(dtseng): This is incomplete; pull once we have appropriate libs. /** * Maps a keypress keycode to a keydown or keyup keycode. - * @type {Object.<number, number>} + * @type {Object<number, number>} */ cvox.KeySequence.KEY_PRESS_CODE = { 39: 222, @@ -114,7 +118,7 @@ cvox.KeySequence.KEY_PRESS_CODE = { * A cache of all key sequences that have been set as double-tappable. We need * this cache because repeated key down computations causes ChromeVox to become * less responsive. This list is small so we currently use an array. - * @type {!Array.<cvox.KeySequence>} + * @type {!Array<cvox.KeySequence>} */ cvox.KeySequence.doubleTapCache = []; diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/key_util.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/key_util.js index 9bbf893c5ef..5ff64d01d7a 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/key_util.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/key_util.js @@ -9,10 +9,18 @@ goog.provide('cvox.KeyUtil'); +goog.provide('cvox.SimpleKeyEvent'); goog.require('cvox.ChromeVox'); goog.require('cvox.KeySequence'); +/** + * @typedef {{ctrlKey: (boolean|undefined), + * altKey: (boolean|undefined), + * shiftKey: (boolean|undefined), + * keyCode: (number|undefined)}} + */ +cvox.SimpleKeyEvent; /** * Create the namespace @@ -59,7 +67,7 @@ cvox.KeyUtil.maxSeqLength = 2; /** * Convert a key event into a Key Sequence representation. * - * @param {Event} keyEvent The keyEvent to convert. + * @param {Event|cvox.SimpleKeyEvent} keyEvent The keyEvent to convert. * @return {cvox.KeySequence} A key sequence representation of the key event. */ cvox.KeyUtil.keyEventToKeySequence = function(keyEvent) { @@ -199,7 +207,7 @@ cvox.KeyUtil.modStringToKeyCode = function(keyString) { /** * Returns the key codes of a string respresentation of the ChromeVox modifiers. * - * @return {Array.<number>} Array of key codes. + * @return {Array<number>} Array of key codes. */ cvox.KeyUtil.cvoxModKeyCodes = function() { var modKeyCombo = cvox.ChromeVox.modKeyStr.split(/\+/g); diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/math_semantic_attr.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/math_semantic_attr.js index 69b616eab54..55428e861fb 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/math_semantic_attr.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/math_semantic_attr.js @@ -55,7 +55,7 @@ goog.require('cvox.SemanticUtil'); cvox.SemanticAttr = function() { // Punctuation Characters. /** - * @type {Array.<string>} + * @type {Array<string>} */ this.generalPunctuations = [ @@ -75,28 +75,28 @@ cvox.SemanticAttr = function() { this.invisibleComma_ = cvox.SemanticUtil.numberToUnicode(0x2063); this.generalPunctuations.push(this.invisibleComma_); /** - * @type {Array.<string>} + * @type {Array<string>} */ this.ellipses = [ '…', '⋮', '⋯', '⋰', '⋱', '︙' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.fullStops = [ '.', '﹒', '.' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.dashes = [ '‒', '–', '—', '―', '〜', '︱', '︲', '﹘' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.primes = [ @@ -108,7 +108,7 @@ cvox.SemanticAttr = function() { // record pairs of opening/closing and top/bottom fences. /** * Mapping opening to closing fences. - * @type {Object.<string, string>} + * @type {Object<string, string>} */ this.openClosePairs = { @@ -137,7 +137,7 @@ cvox.SemanticAttr = function() { }; /** * Mapping top to bottom fences. - * @type {Object.<string, string>} + * @type {Object<string, string>} */ this.topBottomPairs = { @@ -146,31 +146,31 @@ cvox.SemanticAttr = function() { '﹃': '﹄', '﹇': '﹈' }; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.leftFences = cvox.SemanticUtil.objectsToKeys(this.openClosePairs); /** - * @type {Array.<string>} + * @type {Array<string>} */ this.rightFences = cvox.SemanticUtil.objectsToValues(this.openClosePairs); this.rightFences.push('〟'); /** - * @type {Array.<string>} + * @type {Array<string>} */ this.topFences = cvox.SemanticUtil.objectsToKeys(this.topBottomPairs); /** - * @type {Array.<string>} + * @type {Array<string>} */ this.bottomFences = cvox.SemanticUtil.objectsToValues(this.topBottomPairs); /** - * @type {Array.<string>} + * @type {Array<string>} */ this.neutralFences = [ '|', '¦', '‖', '❘', '⦀', '⫴', '¦', '|' ]; /** Array of all fences. - * @type {Array.<string>} + * @type {Array<string>} */ this.fences = this.neutralFences.concat( this.leftFences, this.rightFences, this.topFences, this.bottomFences); @@ -178,7 +178,7 @@ cvox.SemanticAttr = function() { // Identifiers. // Latin Alphabets. /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalLatin = [ @@ -186,7 +186,7 @@ cvox.SemanticAttr = function() { 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallLatin = [ @@ -196,7 +196,7 @@ cvox.SemanticAttr = function() { 'ı', 'ȷ' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalLatinFullWidth = [ @@ -204,7 +204,7 @@ cvox.SemanticAttr = function() { 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallLatinFullWidth = [ @@ -212,7 +212,7 @@ cvox.SemanticAttr = function() { 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalLatinBold = [ @@ -220,7 +220,7 @@ cvox.SemanticAttr = function() { '𝐍', '𝐎', '𝐏', '𝐐', '𝐑', '𝐒', '𝐓', '𝐔', '𝐕', '𝐖', '𝐗', '𝐘', '𝐙' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallLatinBold = [ @@ -228,7 +228,7 @@ cvox.SemanticAttr = function() { '𝐧', '𝐨', '𝐩', '𝐪', '𝐫', '𝐬', '𝐭', '𝐮', '𝐯', '𝐰', '𝐱', '𝐲', '𝐳' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalLatinItalic = [ @@ -236,7 +236,7 @@ cvox.SemanticAttr = function() { '𝑁', '𝑂', '𝑃', '𝑄', '𝑅', '𝑆', '𝑇', '𝑈', '𝑉', '𝑊', '𝑋', '𝑌', '𝑍' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallLatinItalic = [ @@ -246,7 +246,7 @@ cvox.SemanticAttr = function() { '𝚤', '𝚥' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalLatinScript = [ @@ -256,7 +256,7 @@ cvox.SemanticAttr = function() { '℘' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallLatinScript = [ @@ -266,7 +266,7 @@ cvox.SemanticAttr = function() { 'ℓ' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalLatinBoldScript = [ @@ -274,7 +274,7 @@ cvox.SemanticAttr = function() { '𝓝', '𝓞', '𝓟', '𝓠', '𝓡', '𝓢', '𝓣', '𝓤', '𝓥', '𝓦', '𝓧', '𝓨', '𝓩' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallLatinBoldScript = [ @@ -282,7 +282,7 @@ cvox.SemanticAttr = function() { '𝓷', '𝓸', '𝓹', '𝓺', '𝓻', '𝓼', '𝓽', '𝓾', '𝓿', '𝔀', '𝔁', '𝔂', '𝔃' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalLatinFraktur = [ @@ -290,7 +290,7 @@ cvox.SemanticAttr = function() { '𝔑', '𝔒', '𝔓', '𝔔', 'ℜ', '𝔖', '𝔗', '𝔘', '𝔙', '𝔚', '𝔛', '𝔜', 'ℨ' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallLatinFraktur = [ @@ -298,7 +298,7 @@ cvox.SemanticAttr = function() { '𝔫', '𝔬', '𝔭', '𝔮', '𝔯', '𝔰', '𝔱', '𝔲', '𝔳', '𝔴', '𝔵', '𝔶', '𝔷' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalLatinDoubleStruck = [ @@ -306,7 +306,7 @@ cvox.SemanticAttr = function() { 'ℕ', '𝕆', 'ℙ', 'ℚ', 'ℝ', '𝕊', '𝕋', '𝕌', '𝕍', '𝕎', '𝕏', '𝕐', 'ℤ' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallLatinDoubleStruck = [ @@ -314,7 +314,7 @@ cvox.SemanticAttr = function() { '𝕟', '𝕠', '𝕡', '𝕢', '𝕣', '𝕤', '𝕥', '𝕦', '𝕧', '𝕨', '𝕩', '𝕪', '𝕫' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalLatinBoldFraktur = [ @@ -322,7 +322,7 @@ cvox.SemanticAttr = function() { '𝕹', '𝕺', '𝕻', '𝕼', '𝕽', '𝕾', '𝕿', '𝖀', '𝖁', '𝖂', '𝖃', '𝖄', '𝖅' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallLatinBoldFraktur = [ @@ -330,7 +330,7 @@ cvox.SemanticAttr = function() { '𝖓', '𝖔', '𝖕', '𝖖', '𝖗', '𝖘', '𝖙', '𝖚', '𝖛', '𝖜', '𝖝', '𝖞', '𝖟' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalLatinSansSerif = [ @@ -338,7 +338,7 @@ cvox.SemanticAttr = function() { '𝖭', '𝖮', '𝖯', '𝖰', '𝖱', '𝖲', '𝖳', '𝖴', '𝖵', '𝖶', '𝖷', '𝖸', '𝖹' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallLatinSansSerif = [ @@ -346,7 +346,7 @@ cvox.SemanticAttr = function() { '𝗇', '𝗈', '𝗉', '𝗊', '𝗋', '𝗌', '𝗍', '𝗎', '𝗏', '𝗐', '𝗑', '𝗒', '𝗓' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalLatinSansSerifBold = [ @@ -354,7 +354,7 @@ cvox.SemanticAttr = function() { '𝗡', '𝗢', '𝗣', '𝗤', '𝗥', '𝗦', '𝗧', '𝗨', '𝗩', '𝗪', '𝗫', '𝗬', '𝗭' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallLatinSansSerifBold = [ @@ -362,7 +362,7 @@ cvox.SemanticAttr = function() { '𝗻', '𝗼', '𝗽', '𝗾', '𝗿', '𝘀', '𝘁', '𝘂', '𝘃', '𝘄', '𝘅', '𝘆', '𝘇' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalLatinSansSerifItalic = [ @@ -370,7 +370,7 @@ cvox.SemanticAttr = function() { '𝘕', '𝘖', '𝘗', '𝘘', '𝘙', '𝘚', '𝘛', '𝘜', '𝘝', '𝘞', '𝘟', '𝘠', '𝘡' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallLatinSansSerifItalic = [ @@ -378,7 +378,7 @@ cvox.SemanticAttr = function() { '𝘯', '𝘰', '𝘱', '𝘲', '𝘳', '𝘴', '𝘵', '𝘶', '𝘷', '𝘸', '𝘹', '𝘺', '𝘻' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalLatinMonospace = [ @@ -386,7 +386,7 @@ cvox.SemanticAttr = function() { '𝙽', '𝙾', '𝙿', '𝚀', '𝚁', '𝚂', '𝚃', '𝚄', '𝚅', '𝚆', '𝚇', '𝚈', '𝚉' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallLatinMonospace = [ @@ -394,7 +394,7 @@ cvox.SemanticAttr = function() { '𝚗', '𝚘', '𝚙', '𝚚', '𝚛', '𝚜', '𝚝', '𝚞', '𝚟', '𝚠', '𝚡', '𝚢', '𝚣' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.latinDoubleStruckItalic = [ @@ -403,7 +403,7 @@ cvox.SemanticAttr = function() { // Greek Alphabets /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalGreek = [ @@ -411,7 +411,7 @@ cvox.SemanticAttr = function() { 'Ξ', 'Ο', 'Π', 'Ρ', 'Σ', 'Τ', 'Υ', 'Φ', 'Χ', 'Ψ', 'Ω' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallGreek = [ @@ -419,7 +419,7 @@ cvox.SemanticAttr = function() { 'ξ', 'ο', 'π', 'ρ', 'ς', 'σ', 'τ', 'υ', 'φ', 'χ', 'ψ', 'ω' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalGreekBold = [ @@ -427,7 +427,7 @@ cvox.SemanticAttr = function() { '𝚵', '𝚶', '𝚷', '𝚸', '𝚺', '𝚻', '𝚼', '𝚽', '𝚾', '𝚿', '𝛀' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallGreekBold = [ @@ -435,7 +435,7 @@ cvox.SemanticAttr = function() { '𝛏', '𝛐', '𝛑', '𝛒', '𝛓', '𝛔', '𝛕', '𝛖', '𝛗', '𝛘', '𝛙', '𝛚' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalGreekItalic = [ @@ -443,7 +443,7 @@ cvox.SemanticAttr = function() { '𝛯', '𝛰', '𝛱', '𝛲', '𝛴', '𝛵', '𝛶', '𝛷', '𝛸', '𝛹', '𝛺' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallGreekItalic = [ @@ -451,7 +451,7 @@ cvox.SemanticAttr = function() { '𝜉', '𝜊', '𝜋', '𝜌', '𝜍', '𝜎', '𝜏', '𝜐', '𝜑', '𝜒', '𝜓', '𝜔' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.capitalGreekSansSerifBold = [ @@ -459,7 +459,7 @@ cvox.SemanticAttr = function() { '𝝣', '𝝤', '𝝥', '𝝦', '𝝨', '𝝩', '𝝪', '𝝫', '𝝬', '𝝭', '𝝮' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.smallGreekSansSerifBold = [ @@ -467,7 +467,7 @@ cvox.SemanticAttr = function() { '𝝽', '𝝾', '𝝿', '𝞀', '𝞁', '𝞂', '𝞃', '𝞄', '𝞅', '𝞆', '𝞇', '𝞈' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.greekDoubleStruck = [ @@ -476,7 +476,7 @@ cvox.SemanticAttr = function() { // Other alphabets. /** - * @type {Array.<string>} + * @type {Array<string>} */ this.hebrewLetters = [ @@ -485,7 +485,7 @@ cvox.SemanticAttr = function() { //Operator symbols /** - * @type {Array.<string>} + * @type {Array<string>} */ this.additions = [ @@ -494,7 +494,7 @@ cvox.SemanticAttr = function() { '◁', '⩞', '⊕' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ /** * Invisible operator for plus. @@ -504,7 +504,7 @@ cvox.SemanticAttr = function() { this.invisiblePlus_ = cvox.SemanticUtil.numberToUnicode(0x2064); this.additions.push(this.invisiblePlus_); /** - * @type {Array.<string>} + * @type {Array<string>} */ this.multiplications = [ @@ -519,7 +519,7 @@ cvox.SemanticAttr = function() { this.invisibleTimes_ = cvox.SemanticUtil.numberToUnicode(0x2062); this.multiplications.push(this.invisibleTimes_); /** - * @type {Array.<string>} + * @type {Array<string>} */ this.subtractions = [ @@ -527,7 +527,7 @@ cvox.SemanticAttr = function() { '⨫', '⨬', '⨺', '⩁', '⩬', '﹣', '-', '‐', '‑' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.divisions = [ @@ -542,7 +542,7 @@ cvox.SemanticAttr = function() { //Relation symbols /** - * @type {Array.<string>} + * @type {Array<string>} */ this.equalities = [ @@ -552,7 +552,7 @@ cvox.SemanticAttr = function() { '⩴', '⩵', '⩶', '⩷', '⩸', '⋕', '⩭', '⩪', '⩫', '⩬', '﹦', '=' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.inequalities = [ @@ -569,14 +569,14 @@ cvox.SemanticAttr = function() { '⫷', '⫸', '⫹', '⫺', '⧀', '⧁', '﹤', '﹥', '<', '>' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.relations = [ // TODO (sorge): Add all the other relations. ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.arrows = [ @@ -613,7 +613,7 @@ cvox.SemanticAttr = function() { //Big operation symbols /** - * @type {Array.<string>} + * @type {Array<string>} */ this.sumOps = [ @@ -622,7 +622,7 @@ cvox.SemanticAttr = function() { '⨆', '⨇', '⨈', '⨉', '⨊', '⨋', '⫼', '⫿' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.intOps = [ @@ -630,7 +630,7 @@ cvox.SemanticAttr = function() { '⨐', '⨑', '⨒', '⨓', '⨔', '⨕', '⨖', '⨗', '⨘', '⨙', '⨚', '⨛', '⨜' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.prefixOps = // TODO (sorge) Insert nabla, differential operators etc. @@ -638,7 +638,7 @@ cvox.SemanticAttr = function() { '∀', '∃' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.operatorBits = // TODO (sorge) What to do if single glyphs of big ops occur on their own. @@ -652,70 +652,70 @@ cvox.SemanticAttr = function() { // Numbers. // Digits. /** - * @type {Array.<string>} + * @type {Array<string>} */ this.digitsNormal = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.digitsFullWidth = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.digitsBold = [ '𝟎', '𝟏', '𝟐', '𝟑', '𝟒', '𝟓', '𝟔', '𝟕', '𝟖', '𝟗' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.digitsDoubleStruck = [ '𝟘', '𝟙', '𝟚', '𝟛', '𝟜', '𝟝', '𝟞', '𝟟', '𝟠', '𝟡' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.digitsSansSerif = [ '𝟢', '𝟣', '𝟤', '𝟥', '𝟦', '𝟧', '𝟨', '𝟩', '𝟪', '𝟫' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.digitsSansSerifBold = [ '𝟬', '𝟭', '𝟮', '𝟯', '𝟰', '𝟱', '𝟲', '𝟳', '𝟴', '𝟵' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.digitsMonospace = [ '𝟶', '𝟷', '𝟸', '𝟹', '𝟺', '𝟻', '𝟼', '𝟽', '𝟾', '𝟿' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.digitsSuperscript = [ '²', '³', '¹', '⁰', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.digitsSubscript = [ '₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.fractions = [ @@ -723,7 +723,7 @@ cvox.SemanticAttr = function() { '⅚', '⅛', '⅜', '⅝', '⅞', '⅟', '↉' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.enclosedNumbers = // Encircled numbers. @@ -738,7 +738,7 @@ cvox.SemanticAttr = function() { '㉙', '㉚', '㉛', '㉜', '㉝', '㉞', '㉟', '㊱', '㊲', '㊳', '㊴', '㊵', '㊶', '㊷', '㊸', '㊹', '㊺', '㊻', '㊼', '㊽', '㊾', '㊿']; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.fencedNumbers = // Numbers in Parenthesis. @@ -747,7 +747,7 @@ cvox.SemanticAttr = function() { '⒁', '⒂', '⒃', '⒄', '⒅', '⒆', '⒇' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.punctuatedNumbers = // Numbers with other punctuation. @@ -756,25 +756,25 @@ cvox.SemanticAttr = function() { '🄀', '🄁', '🄂', '🄃', '🄄', '🄅', '🄆', '🄇', '🄈', '🄉', '🄊' // comma. ]; /** Array of all single digits. - * @type {Array.<string>} + * @type {Array<string>} */ this.digits = this.digitsNormal.concat( this.digitsFullWidth, this.digitsBold, this.digitsDoubleStruck, this.digitsSansSerif, this.digitsSansSerifBold, this.digitsMonospace); /** Array of all non-digit number symbols. - * @type {Array.<string>} + * @type {Array<string>} */ this.numbers = this.fractions.concat( this.digitsSuperscript, this.digitsSubscript, this.enclosedNumbers, this.fencedNumbers, this.punctuatedNumbers); /** Array of all number symbols. - * @type {Array.<string>} + * @type {Array<string>} */ this.allNumbers = this.digits.concat(this.numbers); // Functions. /** - * @type {Array.<string>} + * @type {Array<string>} */ this.trigonometricFunctions = [ @@ -782,7 +782,7 @@ cvox.SemanticAttr = function() { 'arccsc', 'arcsec', 'arcsin', 'arctan' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.hyperbolicFunctions = [ @@ -791,21 +791,21 @@ cvox.SemanticAttr = function() { 'arccosh', 'arccoth', 'arccsch', 'arcsech', 'arcsinh', 'arctanh' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.algebraicFunctions = [ 'deg', 'det', 'dim', 'hom', 'ker', 'Tr', 'tr' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.elementaryFunctions = [ 'log', 'ln', 'lg', 'exp', 'expt', 'gcd', 'gcd', 'arg', 'im', 're', 'Pr' ]; /** All predefined prefix functions. - * @type {Array.<string>} + * @type {Array<string>} */ this.prefixFunctions = this.trigonometricFunctions.concat( this.hyperbolicFunctions, @@ -814,7 +814,7 @@ cvox.SemanticAttr = function() { ); /** Limit functions are handled separately as they can have lower (and upper) * limiting expressions. - * @type {Array.<string>} + * @type {Array<string>} */ this.limitFunctions = [ @@ -822,7 +822,7 @@ cvox.SemanticAttr = function() { 'projlim' ]; /** - * @type {Array.<string>} + * @type {Array<string>} */ this.infixFunctions = [ @@ -830,7 +830,7 @@ cvox.SemanticAttr = function() { ]; /** * Default assignments of semantic attributes. - * @type {Array.<{set: Array.<string>, + * @type {Array<{set: Array<string>, * role: cvox.SemanticAttr.Role, * type: cvox.SemanticAttr.Type, * font: cvox.SemanticAttr.Font}>} The semantic meaning of the symbol. diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/math_semantic_tree.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/math_semantic_tree.js index 647aaec6d7f..991ae3244ca 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/math_semantic_tree.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/math_semantic_tree.js @@ -50,7 +50,7 @@ cvox.SemanticTree.Node = function(id) { /** @type {number} */ this.id = id; - /** @type {Array.<Element>} */ + /** @type {Array<Element>} */ this.mathml = []; /** @type {cvox.SemanticTree.Node} */ @@ -65,7 +65,7 @@ cvox.SemanticTree.Node = function(id) { /** @type {cvox.SemanticAttr.Font} */ this.font = cvox.SemanticAttr.Font.UNKNOWN; - /** @type {!Array.<cvox.SemanticTree.Node>} */ + /** @type {!Array<cvox.SemanticTree.Node>} */ this.childNodes = []; /** @type {string} */ @@ -73,7 +73,7 @@ cvox.SemanticTree.Node = function(id) { /** Branch nodes can store additional nodes that can be useful. * E.g. a node of type FENCED can have the opening and closing fences here. - * @type {!Array.<cvox.SemanticTree.Node>} + * @type {!Array<cvox.SemanticTree.Node>} */ this.contentNodes = []; }; @@ -83,7 +83,7 @@ cvox.SemanticTree.Node = function(id) { * Retrieve all subnodes (including the node itself) that satisfy a given * predicate. * @param {function(cvox.SemanticTree.Node): boolean} pred The predicate. - * @return {!Array.<cvox.SemanticTree.Node>} The nodes in the tree for which the + * @return {!Array<cvox.SemanticTree.Node>} The nodes in the tree for which the * predicate holds. */ cvox.SemanticTree.Node.prototype.querySelectorAll = function(pred) { @@ -124,7 +124,7 @@ cvox.SemanticTree.Node.prototype.querySelectorAll = function(pred) { /** * Translates a list of nodes into XML representation. * @param {string} tag Name of the enclosing tag. - * @param {!Array.<!cvox.SemanticTree.Node>} nodes A list of nodes. + * @param {!Array<!cvox.SemanticTree.Node>} nodes A list of nodes. * @return {Node} An XML representation of the node list. */ var xmlNodeList = function(tag, nodes) { @@ -283,7 +283,7 @@ cvox.SemanticTree.Node.prototype.updateContent_ = function(content) { * Adds MathML nodes to the node's store of MathML nodes if necessary only, as * we can not necessarily assume that the MathML of the content nodes and * children are all disjoint. - * @param {Array.<Node>} mmlNodes List of MathML nodes. + * @param {Array<Node>} mmlNodes List of MathML nodes. * @private */ cvox.SemanticTree.Node.prototype.addMathmlNodes_ = function(mmlNodes) { @@ -297,7 +297,7 @@ cvox.SemanticTree.Node.prototype.addMathmlNodes_ = function(mmlNodes) { /** * Removes MathML nodes from the node's store of MathML nodes. - * @param {Array.<Node>} mmlNodes List of MathML nodes. + * @param {Array<Node>} mmlNodes List of MathML nodes. * @private */ cvox.SemanticTree.Node.prototype.removeMathmlNodes_ = function(mmlNodes) { @@ -493,8 +493,8 @@ cvox.SemanticTree.prototype.parseMathml_ = function(mml) { /** * Parse a list of MathML nodes into the semantic tree. - * @param {Array.<Element>} mmls A list of MathML nodes. - * @return {!Array.<cvox.SemanticTree.Node>} The list of resulting semantic + * @param {Array<Element>} mmls A list of MathML nodes. + * @return {!Array<cvox.SemanticTree.Node>} The list of resulting semantic * node. * @private */ @@ -549,8 +549,8 @@ cvox.SemanticTree.prototype.makeLeafNode_ = function(mml) { /** * Create a branching node. * @param {!cvox.SemanticAttr.Type} type The type of the node. - * @param {!Array.<cvox.SemanticTree.Node>} children The child nodes. - * @param {!Array.<cvox.SemanticTree.Node>} contentNodes The content Nodes. + * @param {!Array<cvox.SemanticTree.Node>} children The child nodes. + * @param {!Array<cvox.SemanticTree.Node>} contentNodes The content Nodes. * @param {string=} content Content string if there is any. * @return {!cvox.SemanticTree.Node} The new node. * @private @@ -577,7 +577,7 @@ cvox.SemanticTree.prototype.makeBranchNode_ = function( /** * Create a branching node for an implicit operation, currently assumed to * be of multiplicative type. - * @param {!Array.<!cvox.SemanticTree.Node>} nodes The operands. + * @param {!Array<!cvox.SemanticTree.Node>} nodes The operands. * @return {!cvox.SemanticTree.Node} The new branch node. * @private */ @@ -596,7 +596,7 @@ cvox.SemanticTree.prototype.makeImplicitNode_ = function(nodes) { /** * Create a branching node for an infix operation. - * @param {!Array.<cvox.SemanticTree.Node>} children The operands. + * @param {!Array<cvox.SemanticTree.Node>} children The operands. * @param {!cvox.SemanticTree.Node} opNode The operator. * @return {!cvox.SemanticTree.Node} The new branch node. * @private @@ -612,7 +612,7 @@ cvox.SemanticTree.prototype.makeInfixNode_ = function(children, opNode) { * one content (thereby concatenating the content of each node into a single * content string) with the inner node as a child. * @param {!cvox.SemanticTree.Node} inner The inner node. - * @param {!Array.<cvox.SemanticTree.Node>} nodeList List of nodes. + * @param {!Array<cvox.SemanticTree.Node>} nodeList List of nodes. * @param {!cvox.SemanticAttr.Type} type The new type of the node. * @return {!cvox.SemanticTree.Node} The new branch node. * @private @@ -635,7 +635,7 @@ cvox.SemanticTree.prototype.makeConcatNode_ = function(inner, nodeList, type) { * Example: + - a becomes (+ (- (a))) * Input: a [+, -] -> Output: content: '+ -', child: a * @param {!cvox.SemanticTree.Node} node The inner node. - * @param {!Array.<cvox.SemanticTree.Node>} prefixes Prefix operators + * @param {!Array<cvox.SemanticTree.Node>} prefixes Prefix operators * from the outermost to the innermost. * @return {!cvox.SemanticTree.Node} The new branch node. * @private @@ -662,7 +662,7 @@ cvox.SemanticTree.prototype.makePrefixNode_ = function(node, prefixes) { * Example: a - + becomes (((a) -) +) * Input: a [-, +] -> Output: content: '- +', child: a * @param {!cvox.SemanticTree.Node} node The inner node. - * @param {!Array.<cvox.SemanticTree.Node>} postfixes Postfix operators from + * @param {!Array<cvox.SemanticTree.Node>} postfixes Postfix operators from * innermost to outermost. * @return {!cvox.SemanticTree.Node} The new branch node. * @private @@ -683,7 +683,7 @@ cvox.SemanticTree.prototype.makePostfixNode_ = function(node, postfixes) { * * This is the main heuristic to rewrite a flat row of terms into a meaningful * term tree. - * @param {!Array.<cvox.SemanticTree.Node>} nodes The list of nodes. + * @param {!Array<cvox.SemanticTree.Node>} nodes The list of nodes. * @return {!cvox.SemanticTree.Node} The root node of the syntax tree. * @private */ @@ -702,7 +702,7 @@ cvox.SemanticTree.prototype.processRow_ = function(nodes) { /** * Constructs a syntax tree with relation and operator precedence from a list * of nodes. - * @param {!Array.<!cvox.SemanticTree.Node>} nodes The list of nodes. + * @param {!Array<!cvox.SemanticTree.Node>} nodes The list of nodes. * @return {!cvox.SemanticTree.Node} The root node of the syntax tree. * @private */ @@ -732,7 +732,7 @@ cvox.SemanticTree.prototype.processRelationsInRow_ = function(nodes) { /** * Constructs a syntax tree with operator precedence from a list nodes. - * @param {!Array.<!cvox.SemanticTree.Node>} nodes The list of nodes. + * @param {!Array<!cvox.SemanticTree.Node>} nodes The list of nodes. * @return {!cvox.SemanticTree.Node} The root node of the syntax tree. * @private */ @@ -762,7 +762,7 @@ cvox.SemanticTree.prototype.processOperationsInRow_ = function(nodes) { // At this point, we know that split.head is not empty! var node = this.makePrefixNode_( this.makeImplicitNode_( - /** @type {!Array.<!cvox.SemanticTree.Node>} */ (split.head)), + /** @type {!Array<!cvox.SemanticTree.Node>} */ (split.head)), prefix); if (!split.div) { return node; @@ -774,11 +774,11 @@ cvox.SemanticTree.prototype.processOperationsInRow_ = function(nodes) { /** * Recursively constructs syntax tree with operator precedence from a list nodes * given a initial root node. - * @param {!Array.<cvox.SemanticTree.Node>} nodes The list of nodes. + * @param {!Array<cvox.SemanticTree.Node>} nodes The list of nodes. * @param {!cvox.SemanticTree.Node} root Initial tree. * @param {!cvox.SemanticTree.Node} lastop Last operator that has not been * processed yet. - * @param {Array.<cvox.SemanticTree.Node>=} prefixes Operator nodes that will + * @param {Array<cvox.SemanticTree.Node>=} prefixes Operator nodes that will * become prefix operation (or postfix in case they come after last operand). * @return {!cvox.SemanticTree.Node} The root node of the syntax tree. * @private @@ -918,8 +918,8 @@ cvox.SemanticTree.prototype.appendExistingOperator_ = function(root, op, node) { * number of matching fences. E.g. || a|b || would be turned into a fenced * node with fences || and content a|b. * 4. Any remaining unmatched delimiters are turned into punctuation nodes. - * @param {!Array.<!cvox.SemanticTree.Node>} nodes The list of nodes. - * @return {!Array.<!cvox.SemanticTree.Node>} The new list of nodes. + * @param {!Array<!cvox.SemanticTree.Node>} nodes The list of nodes. + * @return {!Array<!cvox.SemanticTree.Node>} The new list of nodes. * @private */ cvox.SemanticTree.prototype.getFencesInRow_ = function(nodes) { @@ -934,13 +934,13 @@ cvox.SemanticTree.prototype.getFencesInRow_ = function(nodes) { * Recursively processes a list of nodes and combines all the fenced expressions * into single nodes. It also processes singular fences, building expressions * that are only fenced left or right. - * @param {!Array.<cvox.SemanticTree.Node>} fences FIFO queue of fence nodes. - * @param {!Array.<Array.<cvox.SemanticTree.Node>>} content FIFO queue content + * @param {!Array<cvox.SemanticTree.Node>} fences FIFO queue of fence nodes. + * @param {!Array<Array<cvox.SemanticTree.Node>>} content FIFO queue content * between fences. - * @param {!Array.<cvox.SemanticTree.Node>} openStack LIFO stack of open fences. - * @param {!Array.<!Array.<cvox.SemanticTree.Node>>} contentStack LIFO stack of + * @param {!Array<cvox.SemanticTree.Node>} openStack LIFO stack of open fences. + * @param {!Array<!Array<cvox.SemanticTree.Node>>} contentStack LIFO stack of * content between fences yet to be processed. - * @return {!Array.<cvox.SemanticTree.Node>} A list of nodes with all fenced + * @return {!Array<cvox.SemanticTree.Node>} A list of nodes with all fenced * expressions processed. * @private */ @@ -1057,10 +1057,10 @@ cvox.SemanticTree.prototype.processFences_ = function( // TODO (sorge) The following could be done with linear programming. /** * Trys to combine neutral fences as much as possible. - * @param {!Array.<!cvox.SemanticTree.Node>} fences A list of neutral fences. - * @param {!Array.<!Array.<cvox.SemanticTree.Node>>} content Intermediate + * @param {!Array<!cvox.SemanticTree.Node>} fences A list of neutral fences. + * @param {!Array<!Array<cvox.SemanticTree.Node>>} content Intermediate * content. Observe that |content| = |fences| - 1 - * @return {!Array.<cvox.SemanticTree.Node>} List of node with fully fenced + * @return {!Array<cvox.SemanticTree.Node>} List of node with fully fenced * nodes. * @private */ @@ -1099,12 +1099,12 @@ cvox.SemanticTree.prototype.processNeutralFences_ = function(fences, content) { * return: [c1 | c2 | c3 ], c4, ... cn * @param {!cvox.SemanticTree.Node} leftFence The left fence. * @param {!cvox.SemanticTree.Node} rightFence The right fence. - * @param {!Array.<cvox.SemanticTree.Node>} midFences A list of intermediate + * @param {!Array<cvox.SemanticTree.Node>} midFences A list of intermediate * fences. - * @param {!Array.<!Array.<cvox.SemanticTree.Node>>} content Intermediate + * @param {!Array<!Array<cvox.SemanticTree.Node>>} content Intermediate * content. Observe that |content| = |fences| - 1 + k where k >= 0 is the * remainder. - * @return {!Array.<!Array.<cvox.SemanticTree.Node>>} List of content nodes + * @return {!Array<!Array<cvox.SemanticTree.Node>>} List of content nodes * where the first is the fully fenced node wrt. the given left and right * fence. * @private @@ -1163,7 +1163,7 @@ cvox.SemanticTree.fenceToPunct_ = function(fence) { * Create a fenced node. * @param {cvox.SemanticTree.Node} ofence Opening fence. * @param {cvox.SemanticTree.Node} cfence Closing fence. - * @param {!Array.<cvox.SemanticTree.Node>} content The content + * @param {!Array<cvox.SemanticTree.Node>} content The content * between the fences. * @return {!cvox.SemanticTree.Node} The new node. * @private @@ -1184,8 +1184,8 @@ cvox.SemanticTree.prototype.makeHorizontalFencedNode_ = function( /** * Combines sequences of punctuated expressions in a list of nodes. - * @param {!Array.<cvox.SemanticTree.Node>} nodes The list of nodes. - * @return {!Array.<cvox.SemanticTree.Node>} The new list of nodes. + * @param {!Array<cvox.SemanticTree.Node>} nodes The list of nodes. + * @return {!Array<cvox.SemanticTree.Node>} The new list of nodes. * @private */ cvox.SemanticTree.prototype.getPunctuationInRow_ = function(nodes) { @@ -1219,9 +1219,9 @@ cvox.SemanticTree.prototype.getPunctuationInRow_ = function(nodes) { /** * Create a punctuated node. - * @param {!Array.<!cvox.SemanticTree.Node>} nodes List of all nodes separated + * @param {!Array<!cvox.SemanticTree.Node>} nodes List of all nodes separated * by punctuations. - * @param {!Array.<!cvox.SemanticTree.Node>} punctuations List of all separating + * @param {!Array<!cvox.SemanticTree.Node>} punctuations List of all separating * punctations. Observe that punctations is a subset of nodes. * @return {!cvox.SemanticTree.Node} * @private @@ -1248,7 +1248,7 @@ cvox.SemanticTree.prototype.makePunctuatedNode_ = function( * Creates a limit node from a sub/superscript or over/under node if the central * element is a big operator. Otherwise it creates the standard elements. * @param {string} mmlTag The tag name of the original node. - * @param {!Array.<!cvox.SemanticTree.Node>} children The children of the + * @param {!Array<!cvox.SemanticTree.Node>} children The children of the * original node. * @return {!cvox.SemanticTree.Node} The newly created limit node. * @private @@ -1331,10 +1331,10 @@ cvox.SemanticTree.prototype.makeLimitNode_ = function(mmlTag, children) { * symbol. If we have an explicit function application symbol * following the expression we turn into a prefix function. Otherwise * we decide heuristically if we could have a function application. - * @param {!Array.<cvox.SemanticTree.Node>} restNodes The remainder list of + * @param {!Array<cvox.SemanticTree.Node>} restNodes The remainder list of * nodes. - * @param {!Array.<cvox.SemanticTree.Node>=} result The result node list. - * @return {!Array.<!cvox.SemanticTree.Node>} The fully processed list. + * @param {!Array<cvox.SemanticTree.Node>=} result The result node list. + * @return {!Array<!cvox.SemanticTree.Node>} The fully processed list. * @private */ cvox.SemanticTree.prototype.getFunctionsInRow_ = function(restNodes, result) { @@ -1360,7 +1360,7 @@ cvox.SemanticTree.prototype.getFunctionsInRow_ = function(restNodes, result) { /** * Classifies a function wrt. the heuristic that should be applied. * @param {!cvox.SemanticTree.Node} funcNode The node to be classified. - * @param {!Array.<cvox.SemanticTree.Node>} restNodes The remainder list of + * @param {!Array<cvox.SemanticTree.Node>} restNodes The remainder list of * nodes. They can useful to look ahead if there is an explicit function * application. If there is one, it will be destructively removed! * @return {!string} The string specifying the heuristic. @@ -1422,10 +1422,10 @@ cvox.SemanticTree.propagatePrefixFunc_ = function(funcNode) { * Computes the arguments for a function from a list of nodes depending on the * given heuristic. * @param {!cvox.SemanticTree.Node} func A function node. - * @param {!Array.<cvox.SemanticTree.Node>} rest List of nodes to choose + * @param {!Array<cvox.SemanticTree.Node>} rest List of nodes to choose * arguments from. * @param {string} heuristic The heuristic to follow. - * @return {!Array.<!cvox.SemanticTree.Node>} The function and the remainder of + * @return {!Array<!cvox.SemanticTree.Node>} The function and the remainder of * the rest list. * @private */ @@ -1482,12 +1482,12 @@ cvox.SemanticTree.prototype.getFunctionArgs_ = function(func, rest, heuristic) { /** * Tail recursive function to obtain integral arguments. - * @param {!Array.<cvox.SemanticTree.Node>} nodes List of nodes to take + * @param {!Array<cvox.SemanticTree.Node>} nodes List of nodes to take * arguments from. - * @param {Array.<cvox.SemanticTree.Node>=} args List of integral arguments. - * @return {{integrand: !Array.<cvox.SemanticTree.Node>, + * @param {Array<cvox.SemanticTree.Node>=} args List of integral arguments. + * @return {{integrand: !Array<cvox.SemanticTree.Node>, * intvar: cvox.SemanticTree.Node, - * rest: !Array.<cvox.SemanticTree.Node>}} + * rest: !Array<cvox.SemanticTree.Node>}} * Result split into integrand, integral variable and the remaining * elements. * @private @@ -1664,8 +1664,8 @@ cvox.SemanticTree.generalFunctionBoundary_ = function(node) { /** * Rewrites tables into matrices or case statements in a list of nodes. - * @param {!Array.<cvox.SemanticTree.Node>} nodes List of nodes to rewrite. - * @return {!Array.<cvox.SemanticTree.Node>} The new list of nodes. + * @param {!Array<cvox.SemanticTree.Node>} nodes List of nodes to rewrite. + * @return {!Array<cvox.SemanticTree.Node>} The new list of nodes. * @private */ cvox.SemanticTree.prototype.processTablesInRow_ = function(nodes) { @@ -1745,7 +1745,7 @@ cvox.SemanticTree.prototype.tableToMatrixOrVector_ = function(node) { * Heuristic to decide if we have a case statement: An expression with a * singular open fence before it. * @param {!cvox.SemanticTree.Node} table A table node. - * @param {!Array.<cvox.SemanticTree.Node>} prevNodes A list of previous nodes. + * @param {!Array<cvox.SemanticTree.Node>} prevNodes A list of previous nodes. * @return {boolean} True if we believe we have a case statement. * @private */ @@ -1852,13 +1852,13 @@ cvox.SemanticTree.assignRoleToRow_ = function(row, role) { /** * Splits a list of nodes wrt. to a given predicate. - * @param {Array.<cvox.SemanticTree.Node>} nodes A list of nodes. + * @param {Array<cvox.SemanticTree.Node>} nodes A list of nodes. * @param {!function(cvox.SemanticTree.Node): boolean} pred Predicate for the * partitioning relation. * @param {boolean=} reverse If true slicing is done from the end. - * @return {{head: !Array.<cvox.SemanticTree.Node>, + * @return {{head: !Array<cvox.SemanticTree.Node>, * div: cvox.SemanticTree.Node, - * tail: !Array.<cvox.SemanticTree.Node>}} The split list. + * tail: !Array<cvox.SemanticTree.Node>}} The split list. * @private */ cvox.SemanticTree.sliceNodes_ = function(nodes, pred, reverse) { @@ -1889,11 +1889,11 @@ cvox.SemanticTree.sliceNodes_ = function(nodes, pred, reverse) { /** * Partitions a list of nodes wrt. to a given predicate. Effectively works like * a PER on the ordered set of nodes. - * @param {!Array.<!cvox.SemanticTree.Node>} nodes A list of nodes. + * @param {!Array<!cvox.SemanticTree.Node>} nodes A list of nodes. * @param {!function(cvox.SemanticTree.Node): boolean} pred Predicate for the * partitioning relation. - * @return {{rel: !Array.<cvox.SemanticTree.Node>, - * comp: !Array.<!Array.<cvox.SemanticTree.Node>>}} + * @return {{rel: !Array<cvox.SemanticTree.Node>, + * comp: !Array<!Array<cvox.SemanticTree.Node>>}} * The partitioning given in terms of a collection of elements satisfying * the predicate and a collection of complementary sets lying inbetween the * related elements. Observe that we always have |comp| = |rel| + 1. diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/math_semantic_util.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/math_semantic_util.js index 525fe4867fc..b444a584bdf 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/math_semantic_util.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/math_semantic_util.js @@ -17,8 +17,8 @@ cvox.SemanticUtil = function() { }; /** * Merges keys of objects into an array. - * @param {...Object.<string, string>} objects Optional objects. - * @return {Array.<string>} Array of all keys of the objects. + * @param {...Object<string, string>} objects Optional objects. + * @return {Array<string>} Array of all keys of the objects. */ cvox.SemanticUtil.objectsToKeys = function(objects) { objects = Array.prototype.slice.call(arguments, 0); @@ -29,8 +29,8 @@ cvox.SemanticUtil.objectsToKeys = function(objects) { /** * Merges values of objects into an array. - * @param {...Object.<string, string>} objects Optional objects. - * @return {Array.<string>} Array of all values of the objects. + * @param {...Object<string, string>} objects Optional objects. + * @return {Array<string>} Array of all values of the objects. */ cvox.SemanticUtil.objectsToValues = function(objects) { objects = Array.prototype.slice.call(arguments, 0); @@ -96,7 +96,7 @@ cvox.SemanticUtil.tagName = function(node) { /** * List of MathML Tags that are to be ignored. - * @type {Array.<string>} + * @type {Array<string>} * @const */ cvox.SemanticUtil.IGNORETAGS = [ @@ -107,7 +107,7 @@ cvox.SemanticUtil.IGNORETAGS = [ /** * List of MathML Tags to be ignore if they have no children. - * @type {Array.<string>} + * @type {Array<string>} * @const */ cvox.SemanticUtil.EMPTYTAGS = ['MATH', 'MROW', 'MPADDED', 'MSTYLE']; @@ -118,8 +118,8 @@ cvox.SemanticUtil.EMPTYTAGS = ['MATH', 'MROW', 'MPADDED', 'MSTYLE']; * ignored if they have empty children. * Observe that this is currently not recursive, i.e. will not take care of * pathological cases, where content is hidden in incorrectly used tags! - * @param {Array.<Element>} nodes The node list to be cleaned. - * @return {Array.<Element>} The cleansed list. + * @param {Array<Element>} nodes The node list to be cleaned. + * @return {Array<Element>} The cleansed list. */ cvox.SemanticUtil.purgeNodes = function(nodes) { var nodeArray = []; diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/math_util.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/math_util.js index 34641dedef9..4de27ae3913 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/math_util.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/math_util.js @@ -16,7 +16,7 @@ goog.require('cvox.XpathUtil'); * Checks if a node is in a given class of MathML nodes. * @private * @param {!Node} node The node to test. - * @param {Array.<string>} tags List of tag names. + * @param {Array<string>} tags List of tag names. * @return {boolean} True if node has a tag name included in tags. */ cvox.MathUtil.isMathmlNodeOfClass_ = function(node, tags) { @@ -28,7 +28,7 @@ cvox.MathUtil.isMathmlNodeOfClass_ = function(node, tags) { * Checks if a node is in a given class of MathJax nodes. * @private * @param {!Node} node The node to test. - * @param {Array.<string>} tags List of tag names. + * @param {Array<string>} tags List of tag names. * @return {boolean} True if node has a tag name included in tags. */ cvox.MathUtil.isMathjaxNodeOfClass_ = function(node, tags) { @@ -46,7 +46,7 @@ cvox.MathUtil.isMathjaxNodeOfClass_ = function(node, tags) { * of MathML or MathJax nodes. * @private * @param {!Node} node The node to test. - * @param {Array.<string>} tags List of tag names. + * @param {Array<string>} tags List of tag names. * @return {boolean} True if node has a tag name included in tags. */ cvox.MathUtil.isMathNodeOfClass_ = function(node, tags) { @@ -58,7 +58,7 @@ cvox.MathUtil.isMathNodeOfClass_ = function(node, tags) { /** * Array of MathML Token Elements. - * @type {!Array.<string>} + * @type {!Array<string>} */ cvox.MathUtil.TOKEN_LIST = ['MI', 'MN', 'MO', 'MTEXT', 'MSPACE', 'MS']; @@ -82,7 +82,7 @@ cvox.MathUtil.isToken = function(element) { /** * Array of MathML Layout Schemata. - * @type {!Array.<string>} + * @type {!Array<string>} */ cvox.MathUtil.LAYOUT_LIST = ['MROW', 'MFRAC', 'MSQRT', 'MROOT', 'MSTYLE', 'MERROR', 'MPADDED', 'MPHANTOM', 'MFENCED', @@ -113,7 +113,7 @@ cvox.MathUtil.isLayout = function(element) { /** * Array of MathML Script Schemata. - * @type {!Array.<string>} + * @type {!Array<string>} */ cvox.MathUtil.SCRIPT_LIST = ['MSUB', 'MSUP', 'MSUBSUP', 'MUNDER', 'MOVER', 'MUNDEROVER', 'MMULTISCRIPTS', 'MPRESCRIPTS']; @@ -143,7 +143,7 @@ cvox.MathUtil.isScript = function(element) { /** * Array of MathML Table and Matrix tokens. - * @type {!Array.<string>} + * @type {!Array<string>} */ cvox.MathUtil.TABLES_LIST = ['MTABLE', 'MLABELEDTR', 'MTR', 'MTD', 'MALIGNGROUP', 'MALIGNMARK']; @@ -168,7 +168,7 @@ cvox.MathUtil.isTables = function(element) { /** * Array of MathML Elementary Layout Schemata. - * @type {!Array.<string>} + * @type {!Array<string>} */ cvox.MathUtil.ELEMENTARY_LIST = ['MSTACK', 'MLONGDIV', 'MSGROUP', 'MSROW', 'MSCARRIES', 'MSCARRY', 'MSLINE']; @@ -197,7 +197,7 @@ cvox.MathUtil.isElementary = function(element) { /** * Array of all valid tags in a MathML expression. * This is a union of all other token lists. - * @type {!Array.<string>} + * @type {!Array<string>} */ cvox.MathUtil.MATHML_TAG_LIST = [cvox.MathUtil.TOKEN_LIST, cvox.MathUtil.LAYOUT_LIST, @@ -221,7 +221,7 @@ cvox.MathUtil.isMathmlTag = function(element) { /** * Array of MathML Whitespace and Alignment tokens. * These are elements that can occur in the other token lists. - * @type {!Array.<string>} + * @type {!Array<string>} */ cvox.MathUtil.WHITESPACE_LIST = ['MSROW', 'MROW', 'MSPACE', 'MPHANTOM', 'MPADDED']; diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/memoize.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/memoize.js index 271722c99e5..227b26f2646 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/memoize.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/memoize.js @@ -51,7 +51,7 @@ cvox.Memoize = function() { * to function result. This variable is null when we're out of scope, and it's * a map from string to WeakMap to result when we're in scope. * - * @type {?Object.<string, WeakMap.<Node, *> >} + * @type {?Object<string, WeakMap<Node, *> >} * @private */ cvox.Memoize.nodeMap_ = null; diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/nav_braille.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/nav_braille.js deleted file mode 100644 index f74b63d5a06..00000000000 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/nav_braille.js +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2014 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 A simple container object for the brailling of a - * navigation from one object to another. - * - */ - - -goog.provide('cvox.NavBraille'); - -goog.require('cvox.ChromeVox'); -goog.require('cvox.CursorSelection'); -goog.require('cvox.Spannable'); - -/** - * A class capturing the braille for navigation from one object to - * another. - * @param {{text: (undefined|string|!cvox.Spannable), - * startIndex: (undefined|number), - * endIndex: (undefined|number)}} kwargs The arguments for braille. - * text The text of the object itself, including text from - * titles, labels, etc. - * startIndex The beginning of a selection within text. - * endIndex The end of a selection within text. - * @constructor - */ -cvox.NavBraille = function(kwargs) { - /** - * Text, annotated with DOM nodes. - * @type {!cvox.Spannable} - */ - this.text = (kwargs.text instanceof cvox.Spannable) ? - kwargs.text : new cvox.Spannable(kwargs.text); - - /** - * Selection start index. - * @type {number} - */ - this.startIndex = goog.isDef(kwargs.startIndex) ? kwargs.startIndex : -1; - - /** - * Selection end index. - * @type {number} - */ - this.endIndex = goog.isDef(kwargs.endIndex) ? - kwargs.endIndex : this.startIndex; -}; - -/** - * Convenience for creating simple braille output. - * @param {string|!cvox.Spannable} text Text to represent in braille. - * @return {!cvox.NavBraille} Braille output without a cursor. - */ -cvox.NavBraille.fromText = function(text) { - return new cvox.NavBraille({'text': text}); -}; - - -/** - * Creates a NavBraille from its serialized json form as created - * by toJson(). - * @param {!Object} json the serialized json object. - * @return {!cvox.NavBraille} - */ -cvox.NavBraille.fromJson = function(json) { - if (typeof json.startIndex !== 'number' || - typeof json.endIndex !== 'number') { - throw 'Invalid start or end index in serialized NavBraille: ' + json; - } - return new cvox.NavBraille({ - text: cvox.Spannable.fromJson(json.spannable), - startIndex: json.startIndex, - endIndex: json.endIndex - }); -}; - - -/** - * @return {boolean} true if this braille description is empty. - */ -cvox.NavBraille.prototype.isEmpty = function() { - return this.text.getLength() == 0; -}; - - -/** - * @return {string} A string representation of this object. - */ -cvox.NavBraille.prototype.toString = function() { - return 'NavBraille(text="' + this.text.toString() + '" ' + - ' startIndex="' + this.startIndex + '" ' + - ' endIndex="' + this.endIndex + '")'; -}; - - -/** - * Returns a plain old data object with the same data. - * Suitable for JSON encoding. - * - * @return {{spannable: Object, - * startIndex: number, - * endIndex: number}} JSON equivalent. - */ -cvox.NavBraille.prototype.toJson = function() { - return { - spannable: this.text.toJson(), - startIndex: this.startIndex, - endIndex: this.endIndex - }; -}; - - -/** - * Sends braille to the background page. - */ -cvox.NavBraille.prototype.write = function() { - cvox.ChromeVox.braille.write(this); -}; diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/nav_description.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/nav_description.js index 1a946467500..e143ca17d1d 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/nav_description.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/nav_description.js @@ -23,7 +23,7 @@ goog.require('cvox.QueueMode'); * text: (string), * userValue: (undefined|string), * annotation: (undefined|string), - * earcons: (undefined|Array.<number>), + * earcons: (undefined|Array<number>), * personality: (undefined|Object), * hint: (undefined|string), category: (undefined|string)}} kwargs The arguments for this diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/nav_math_description.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/nav_math_description.js index 4e4bdf0ca21..c4023070d6c 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/nav_math_description.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/nav_math_description.js @@ -20,7 +20,7 @@ goog.require('cvox.NavDescription'); * text: (string), * userValue: (undefined|string), * annotation: (undefined|string), - * earcons: (undefined|Array.<number>), + * earcons: (undefined|Array<number>), * personality: (undefined|Object), * hint: (undefined|string), * category: (undefined|string), diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/node_state.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/node_state.js index 4793b3ecfb7..6abc835bd65 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/node_state.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/node_state.js @@ -16,7 +16,7 @@ goog.provide('cvox.NodeStateUtil'); * cvox.ChromeVox.getMsg() call. For example [list_position, 3, 5] maps to * getMsg('list_position', [3, 5]); * - * @typedef {!Array.<!Array.<string|number>>} + * @typedef {!Array<!Array<string|number>>} */ cvox.NodeState; diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/page_selection.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/page_selection.js index 0517c58f1cd..ad39e4a59e3 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/page_selection.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/page_selection.js @@ -37,7 +37,7 @@ cvox.PageSelection = function(sel) { * @param {!cvox.CursorSelection} prevSel Previous CursorSelection in * navigation. * @param {!cvox.CursorSelection} curSel Current CursorSelection in navigation. - * @return {Array.<cvox.NavDescription>} The new description. + * @return {Array<cvox.NavDescription>} The new description. */ cvox.PageSelection.prototype.getDescription = function(navShifter, prevSel, curSel) { @@ -71,7 +71,7 @@ cvox.PageSelection.prototype.getDescription = * Use this description when you want to describe the entire selection * represented by this instance. * - * @return {Array.<cvox.NavDescription>} The new description. + * @return {Array<cvox.NavDescription>} The new description. */ cvox.PageSelection.prototype.getFullDescription = function() { return [new cvox.NavDescription( diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/selection_util.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/selection_util.js index 74c5cc4b4b0..3057d2efc9b 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/selection_util.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/selection_util.js @@ -207,7 +207,7 @@ cvox.SelectionUtil.isRangeValid = function(range) { * Returns absolute top and left positions of an element. * * @param {!Node} node The element for which to compute the position. - * @return {Array.<number>} Index 0 is the left; index 1 is the top. + * @return {Array<number>} Index 0 is the left; index 1 is the top. * @private */ cvox.SelectionUtil.findPos_ = function(node) { @@ -588,6 +588,7 @@ cvox.SelectionUtil.getText = function() { * if you want i18n tests to pass. * * @return {string} The text. + * @private */ cvox.SelectionUtil.getSelectionText_ = function() { return '' + window.getSelection(); diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/spannable.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/spannable.js index ea113a8041e..b4773e274a4 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/spannable.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/spannable.js @@ -12,7 +12,7 @@ goog.require('goog.object'); /** * @constructor - * @param {string=} opt_string Initial value of the spannable. + * @param {string|!cvox.Spannable=} opt_string Initial value of the spannable. * @param {*=} opt_annotation Initial annotation for the entire string. */ cvox.Spannable = function(opt_string, opt_annotation) { @@ -21,15 +21,19 @@ cvox.Spannable = function(opt_string, opt_annotation) { * @type {string} * @private */ - this.string_ = opt_string || ''; + this.string_ = opt_string instanceof cvox.Spannable ? '' : opt_string || ''; /** * Spans (annotations). - * @type {!Array.<!{ value: *, start: number, end: number }>} + * @type {!Array<!{ value: *, start: number, end: number }>} * @private */ this.spans_ = []; + // Append the initial spannable. + if (opt_string instanceof cvox.Spannable) + this.append(opt_string); + // Optionally annotate the entire string. if (goog.isDef(opt_annotation)) { var len = this.string_.length; @@ -135,6 +139,22 @@ cvox.Spannable.prototype.getSpanInstanceOf = function(constructor) { } }; +/** + * Returns all span values which are an instance of a given constructor. + * @param {!Function} constructor Constructor. + * @return {!Array<Object>} Array of object. + */ +cvox.Spannable.prototype.getSpansInstanceOf = function(constructor) { + var ret = []; + for (var i = 0; i < this.spans_.length; i++) { + var span = this.spans_[i]; + if (span.value instanceof constructor) { + ret.push(span.value); + } + } + return ret; +}; + /** * Returns all spans matching a position. @@ -385,7 +405,7 @@ cvox.Spannable.SerializeInfo_; /** * The serialized format of a spannable. - * @typedef {{string: string, spans: Array.<cvox.Spannable.SerializedSpan_>}} + * @typedef {{string: string, spans: Array<cvox.Spannable.SerializedSpan_>}} * @private */ cvox.Spannable.SerializedSpannable_; @@ -400,7 +420,7 @@ cvox.Spannable.SerializedSpan_; /** * Maps type names to serialization info objects. - * @type {Object.<string, cvox.Spannable.SerializeInfo_>} + * @type {Object<string, cvox.Spannable.SerializeInfo_>} * @private */ cvox.Spannable.serializableSpansByName_ = {}; diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/string_util.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/string_util.js new file mode 100644 index 00000000000..5b771c5a774 --- /dev/null +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/string_util.js @@ -0,0 +1,32 @@ +// 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 Utilities for strings. + */ + +goog.provide('StringUtil'); + +/** + * @constructor + */ +StringUtil = function() {}; + +/** + * Returns the length of the longest common prefix of two strings. + * @param {string} first The first string. + * @param {string} second The second string. + * @return {number} The length of the longest common prefix, which may be 0 + * for an empty common prefix. + */ +StringUtil.longestCommonPrefixLength = function(first, second) { + var limit = Math.min(first.length, second.length); + var i; + for (i = 0; i < limit; ++i) { + if (first.charAt(i) != second.charAt(i)) { + break; + } + } + return i; +}; diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/string_util_test.unitjs b/chromium/chrome/browser/resources/chromeos/chromevox/common/string_util_test.unitjs new file mode 100644 index 00000000000..efd31a5afdb --- /dev/null +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/string_util_test.unitjs @@ -0,0 +1,32 @@ +// 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. + +// Include test fixture. +GEN_INCLUDE(['../testing/chromevox_unittest_base.js']); + +/** + * Test fixture. + * @constructor + * @extends {ChromeVoxUnitTestBase} + */ +function StringUtilUnitTest() { + ChromeVoxUnitTestBase.call(this); +} + +StringUtilUnitTest.prototype = { + __proto__: ChromeVoxUnitTestBase.prototype, + + /** @override */ + closureModuleDeps: [ + 'StringUtil', + ], +}; + +TEST_F('StringUtilUnitTest', 'longestCommonPrefixLength', function() { + var lcpl = StringUtil.longestCommonPrefixLength; + assertEquals(0, lcpl('', '')); + assertEquals(0, lcpl('', 'hello')); + assertEquals(0, lcpl('hello', '')); + assertEquals(1, lcpl('hi', 'hello')); +}); diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_content.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_content.js index 4df917ef969..4ca1ec4183c 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_content.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_content.js @@ -115,7 +115,7 @@ cvox.TraverseContent.kParagraph = 'paragraph'; /** * A constant array of all granularities. - * @type {Array.<string>} + * @type {Array<string>} * @const */ cvox.TraverseContent.kAllGrains = diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_math.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_math.js index 83a622035d9..df4814ee58d 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_math.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_math.js @@ -30,14 +30,14 @@ cvox.TraverseMath = function() { /** * Dictionary of all LaTeX elements in the page if there are any. - * @type {!Object.<string, !Node>} + * @type {!Object<string, !Node>} * @private */ this.allTexs_ = {}; /** * Dictionary of all MathJaxs elements in the page if there are any. - * @type {!Object.<string, !Node>} + * @type {!Object<string, !Node>} * @private */ this.allMathjaxs_ = {}; @@ -45,7 +45,7 @@ cvox.TraverseMath = function() { /** * Dictionary of all MathJaxs elements that have not yet been translated at * page load or during MathJax rendering. - * @type {!Object.<string, !Node>} + * @type {!Object<string, !Node>} * @private */ this.todoMathjaxs_ = {}; @@ -65,13 +65,13 @@ cvox.TraverseMath = function() { /** * List of domain names. - * @type {Array.<string>} + * @type {Array<string>} */ this.allDomains = []; /** * List of style names. - * @type {Array.<string>} + * @type {Array<string>} */ this.allStyles = []; @@ -337,8 +337,8 @@ cvox.TraverseMath.prototype.nextParentChild = function(r) { /** * Adds a list of domains and styles to the existing one. - * @param {Array.<string>} domains List of domain names. - * @param {Array.<string>} styles List of style names. + * @param {Array<string>} domains List of domain names. + * @param {Array<string>} styles List of style names. */ cvox.TraverseMath.prototype.addDomainsAndStyles = function(domains, styles) { this.allDomains.push.apply( diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_table.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_table.js index 6253fa07f75..8927c1d8846 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_table.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_table.js @@ -22,7 +22,19 @@ goog.require('cvox.TraverseUtil'); * An object that represents an active table cell inside the shadow table. * @constructor */ -function ShadowTableNode() {} +function ShadowTableNode() { + /** + * The cells that are row headers of the corresponding active table cell + * @type {!Array} + */ + this.rowHeaderCells = []; + + /** + * The cells that are column headers of the corresponding active table cell + * @type {!Array} + */ + this.colHeaderCells = []; +} /** @@ -68,21 +80,6 @@ ShadowTableNode.prototype.activeCell; /** - * The cells that are row headers of the corresponding active table cell - * @type {!Array} - */ -ShadowTableNode.prototype.rowHeaderCells = []; - - -/** - * The cells that are column headers of the corresponding active table cell - * @type {!Array} - */ -ShadowTableNode.prototype.colHeaderCells = []; - - - -/** * Initializes the traversal with the provided table node. * * @constructor @@ -114,7 +111,7 @@ cvox.TraverseTable = function(tableNode) { * the (1,3) position, eliminating the need to check for predecessor cells * with rowspan/colspan every time we traverse the table. * - * @type {!Array.<Array.<ShadowTableNode>>} + * @type {!Array<Array<ShadowTableNode>>} * @private */ this.shadowTable_ = []; @@ -125,7 +122,7 @@ cvox.TraverseTable = function(tableNode) { * initialization and then only recalculated if the table changes. * This array is used by findHeaderCells() to determine table row headers * and column headers. - * @type {Array.<ShadowTableNode>} + * @type {Array<ShadowTableNode>} * @private */ this.candidateHeaders_ = []; @@ -136,7 +133,7 @@ cvox.TraverseTable = function(tableNode) { * other cells) then the first one will be associated with the ID. This means * that shadow nodes that have spanned set to true will not be included in * this array. - * @type {Array.<ShadowTableNode>} + * @type {Array<ShadowTableNode>} * @private */ this.idToShadowNode_ = []; @@ -265,7 +262,7 @@ cvox.TraverseTable.prototype.initialize = function(tableNode) { * Finds the cell cursor containing the specified node within the table. * Returns null if there is no close cell. * @param {!Node} node The node for which to find the cursor. - * @return {Array.<number>} The table index for the node. + * @return {Array<number>} The table index for the node. */ cvox.TraverseTable.prototype.findNearestCursor = function(node) { // TODO (stoarca): The current structure for representing the @@ -856,7 +853,7 @@ cvox.TraverseTable.prototype.getCell = function() { /** * Gets the cell at the specified location. - * @param {Array.<number>} index The index <i, j> of the required cell. + * @param {Array<number>} index The index <i, j> of the required cell. * @return {?Node} The cell <TD> or <TH> or role='gridcell' node at the * specified location. Null if that cell does not exist. */ @@ -1220,7 +1217,7 @@ cvox.TraverseTable.prototype.goToCol = function(index) { /** * Moves to the cell at the specified index <i, j> in the table. Updates the * cell cursor. - * @param {Array.<number>} index The index <i, j> of the required cell. + * @param {Array<number>} index The index <i, j> of the required cell. * @return {boolean} Either: * 1) True if the index is valid and the update has been made. * 2) False if the index is not valid (either less than 0, greater than diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_util.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_util.js index 18781e376d6..7ae41862861 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_util.js +++ b/chromium/chrome/browser/resources/chromeos/chromevox/common/traverse_util.js @@ -111,8 +111,8 @@ cvox.TraverseUtil.isHidden = function(node) { * @param {cvox.Cursor} cursor The cursor location where the search should * start. On exit, the cursor will be immediately to the right of the * character returned. - * @param {Array.<Element>} elementsEntered Any HTML elements entered. - * @param {Array.<Element>} elementsLeft Any HTML elements left. + * @param {Array<Element>} elementsEntered Any HTML elements entered. + * @param {Array<Element>} elementsLeft Any HTML elements left. * @return {?string} The character found, or null if the bottom of the * document has been reached. */ @@ -205,8 +205,8 @@ cvox.TraverseUtil.forwardsChar = function( * @param {cvox.Cursor} cursor The cursor location where the search should * start. On exit, the cursor will be immediately to the left of the * character returned. - * @param {Array.<Element>} elementsEntered Any HTML elements entered. - * @param {Array.<Element>} elementsLeft Any HTML elements left. + * @param {Array<Element>} elementsEntered Any HTML elements entered. + * @param {Array<Element>} elementsLeft Any HTML elements left. * @return {?string} The previous character, or null if the top of the * document has been reached. */ @@ -310,8 +310,8 @@ cvox.TraverseUtil.backwardsChar = function( * the char. * @param {!cvox.Cursor} endCursor The position to start searching for the next * char. On exit, will point to the position past the char. - * @param {Array.<Element>} elementsEntered Any HTML elements entered. - * @param {Array.<Element>} elementsLeft Any HTML elements left. + * @param {Array<Element>} elementsEntered Any HTML elements entered. + * @param {Array<Element>} elementsLeft Any HTML elements left. * initial and final cursor position will be pushed onto this array. * @param {boolean} skipWhitespace If true, will keep scanning until a * non-whitespace character is found. @@ -373,8 +373,8 @@ cvox.TraverseUtil.getNextChar = function( * char. On exit, will point to the position before the char. * @param {!cvox.Cursor} endCursor The position to start searching for the next * char. On exit, will point to the position past the char. - * @param {Array.<Element>} elementsEntered Any HTML elements entered. - * @param {Array.<Element>} elementsLeft Any HTML elements left. + * @param {Array<Element>} elementsEntered Any HTML elements entered. + * @param {Array<Element>} elementsLeft Any HTML elements left. * initial and final cursor position will be pushed onto this array. * @param {boolean} skipWhitespace If true, will keep scanning until a * non-whitespace character is found. @@ -431,8 +431,8 @@ cvox.TraverseUtil.getPreviousChar = function( * word returned. * @param {cvox.Cursor} endCursor The position to start searching for the next * word. On exit, will point to the end of the word returned. - * @param {Array.<Element>} elementsEntered Any HTML elements entered. - * @param {Array.<Element>} elementsLeft Any HTML elements left. + * @param {Array<Element>} elementsEntered Any HTML elements entered. + * @param {Array<Element>} elementsLeft Any HTML elements left. * @return {?string} The next word, or null if the bottom of the * document has been reached. */ @@ -492,8 +492,8 @@ cvox.TraverseUtil.getNextWord = function(startCursor, endCursor, * word returned. * @param {cvox.Cursor} endCursor On exit, will point to the end of the * word returned. - * @param {Array.<Element>} elementsEntered Any HTML elements entered. - * @param {Array.<Element>} elementsLeft Any HTML elements left. + * @param {Array<Element>} elementsEntered Any HTML elements entered. + * @param {Array<Element>} elementsLeft Any HTML elements left. * @return {?string} The previous word, or null if the bottom of the * document has been reached. */ @@ -546,9 +546,9 @@ cvox.TraverseUtil.getPreviousWord = function(startCursor, endCursor, /** * Given elements entered and left, and break tags, returns true if the * current word should break. - * @param {Array.<Element>} elementsEntered Any HTML elements entered. - * @param {Array.<Element>} elementsLeft Any HTML elements left. - * @param {Object.<string, boolean>} breakTags Associative array of tags + * @param {Array<Element>} elementsEntered Any HTML elements entered. + * @param {Array<Element>} elementsLeft Any HTML elements left. + * @param {Object<string, boolean>} breakTags Associative array of tags * that should break. * @return {boolean} True if elementsEntered or elementsLeft include an * element with one of these tags. @@ -584,9 +584,9 @@ cvox.TraverseUtil.includesBreakTagOrSkippedNode = function( * sentence. * @param {cvox.Cursor} endCursor The position to start searching for the next * sentence. On exit, will point to the end of the returned string. - * @param {Array.<Element>} elementsEntered Any HTML elements entered. - * @param {Array.<Element>} elementsLeft Any HTML elements left. - * @param {Object.<string, boolean>} breakTags Associative array of tags + * @param {Array<Element>} elementsEntered Any HTML elements entered. + * @param {Array<Element>} elementsLeft Any HTML elements left. + * @param {Object<string, boolean>} breakTags Associative array of tags * that should break the sentence. * @return {?string} The next sentence, or null if the bottom of the * document has been reached. @@ -610,9 +610,9 @@ cvox.TraverseUtil.getNextSentence = function( * @param {cvox.Cursor} startCursor The position to start searching for the next * sentence. On exit, will point to the start of the returned string. * @param {cvox.Cursor} endCursor On exit, the end of the returned string. - * @param {Array.<Element>} elementsEntered Any HTML elements entered. - * @param {Array.<Element>} elementsLeft Any HTML elements left. - * @param {Object.<string, boolean>} breakTags Associative array of tags + * @param {Array<Element>} elementsEntered Any HTML elements entered. + * @param {Array<Element>} elementsLeft Any HTML elements left. + * @param {Object<string, boolean>} breakTags Associative array of tags * that should break the sentence. * @return {?string} The previous sentence, or null if the bottom of the * document has been reached. @@ -636,9 +636,9 @@ cvox.TraverseUtil.getPreviousSentence = function( * @param {cvox.Cursor} startCursor On exit, marks the beginning of the line. * @param {cvox.Cursor} endCursor The position to start searching for the next * line. On exit, will point to the end of the returned string. - * @param {Array.<Element>} elementsEntered Any HTML elements entered. - * @param {Array.<Element>} elementsLeft Any HTML elements left. - * @param {Object.<string, boolean>} breakTags Associative array of tags + * @param {Array<Element>} elementsEntered Any HTML elements entered. + * @param {Array<Element>} elementsLeft Any HTML elements left. + * @param {Object<string, boolean>} breakTags Associative array of tags * that should break the line. * @return {?string} The next line, or null if the bottom of the * document has been reached. @@ -682,9 +682,9 @@ cvox.TraverseUtil.getNextLine = function( * @param {cvox.Cursor} startCursor The position to start searching for the next * line. On exit, will point to the start of the returned string. * @param {cvox.Cursor} endCursor On exit, the end of the returned string. - * @param {Array.<Element>} elementsEntered Any HTML elements entered. - * @param {Array.<Element>} elementsLeft Any HTML elements left. - * @param {Object.<string, boolean>} breakTags Associative array of tags + * @param {Array<Element>} elementsEntered Any HTML elements entered. + * @param {Array<Element>} elementsLeft Any HTML elements left. + * @param {Object<string, boolean>} breakTags Associative array of tags * that should break the line. * @return {?string} The previous line, or null if the bottom of the * document has been reached. @@ -729,8 +729,8 @@ cvox.TraverseUtil.getPreviousLine = function( * paragraph. * @param {cvox.Cursor} endCursor The position to start searching for the next * paragraph. On exit, will point to the end of the returned string. - * @param {Array.<Element>} elementsEntered Any HTML elements entered. - * @param {Array.<Element>} elementsLeft Any HTML elements left. + * @param {Array<Element>} elementsEntered Any HTML elements entered. + * @param {Array<Element>} elementsLeft Any HTML elements left. * @return {?string} The next paragraph, or null if the bottom of the * document has been reached. */ @@ -765,8 +765,8 @@ cvox.TraverseUtil.getNextParagraph = function(startCursor, endCursor, * @param {cvox.Cursor} startCursor The position to start searching for the next * paragraph. On exit, will point to the start of the returned string. * @param {cvox.Cursor} endCursor On exit, the end of the returned string. - * @param {Array.<Element>} elementsEntered Any HTML elements entered. - * @param {Array.<Element>} elementsLeft Any HTML elements left. + * @param {Array<Element>} elementsEntered Any HTML elements entered. + * @param {Array<Element>} elementsLeft Any HTML elements left. * @return {?string} The previous paragraph, or null if the bottom of the * document has been reached. */ @@ -815,9 +815,9 @@ cvox.TraverseUtil.getPreviousParagraph = function( * next string. * @param {cvox.Cursor} endCursor The position to start searching for the next * string. On exit, will point to the end of the returned string. - * @param {Array.<Element>} elementsEntered Any HTML elements entered. - * @param {Array.<Element>} elementsLeft Any HTML elements left. - * @param {function(string, string, Array.<Element>, Array.<Element>)} + * @param {Array<Element>} elementsEntered Any HTML elements entered. + * @param {Array<Element>} elementsLeft Any HTML elements left. + * @param {function(string, string, Array<Element>, Array<Element>)} * breakBefore Function that takes the string so far, next word to be * added, and elements entered and left, and returns true if the string * should be ended before adding this word. @@ -877,9 +877,9 @@ cvox.TraverseUtil.getNextString = function( * string returned. * @param {cvox.Cursor} endCursor On exit, will point to the end of the * string returned. - * @param {Array.<Element>} elementsEntered Any HTML elements entered. - * @param {Array.<Element>} elementsLeft Any HTML elements left. - * @param {function(string, string, Array.<Element>, Array.<Element>)} + * @param {Array<Element>} elementsEntered Any HTML elements entered. + * @param {Array<Element>} elementsLeft Any HTML elements left. + * @param {function(string, string, Array<Element>, Array<Element>)} * breakBefore Function that takes the string so far, the word to be * added, and nodes crossed, and returns true if the string should be * ended before adding this word. |