| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview Processes events related to editing text and emits the | 6 * @fileoverview Processes events related to editing text and emits the |
| 7 * appropriate spoken and braille feedback. | 7 * appropriate spoken and braille feedback. |
| 8 */ | 8 */ |
| 9 | 9 |
| 10 goog.provide('editing.TextEditHandler'); | 10 goog.provide('editing.TextEditHandler'); |
| 11 | 11 |
| 12 goog.require('AutomationTreeWalker'); | 12 goog.require('AutomationTreeWalker'); |
| 13 goog.require('AutomationUtil'); | 13 goog.require('AutomationUtil'); |
| 14 goog.require('Output'); | 14 goog.require('Output'); |
| 15 goog.require('Output.EventType'); | 15 goog.require('Output.EventType'); |
| 16 goog.require('cursors.Cursor'); | 16 goog.require('cursors.Cursor'); |
| 17 goog.require('cursors.Range'); | 17 goog.require('cursors.Range'); |
| 18 goog.require('cvox.ChromeVoxEditableTextBase'); | 18 goog.require('cvox.ChromeVoxEditableTextBase'); |
| 19 | 19 |
| 20 goog.scope(function() { | 20 goog.scope(function() { |
| 21 var AutomationEvent = chrome.automation.AutomationEvent; | 21 var AutomationEvent = chrome.automation.AutomationEvent; |
| 22 var AutomationNode = chrome.automation.AutomationNode; | 22 var AutomationNode = chrome.automation.AutomationNode; |
| 23 var Cursor = cursors.Cursor; | 23 var Cursor = cursors.Cursor; |
| 24 var Dir = constants.Dir; | 24 var Dir = AutomationUtil.Dir; |
| 25 var EventType = chrome.automation.EventType; | 25 var EventType = chrome.automation.EventType; |
| 26 var Range = cursors.Range; | 26 var Range = cursors.Range; |
| 27 var RoleType = chrome.automation.RoleType; | 27 var RoleType = chrome.automation.RoleType; |
| 28 var Movement = cursors.Movement; | 28 var Movement = cursors.Movement; |
| 29 var Unit = cursors.Unit; | 29 var Unit = cursors.Unit; |
| 30 | 30 |
| 31 /** | 31 /** |
| 32 * A handler for automation events in a focused text field or editable root | 32 * A handler for automation events in a focused text field or editable root |
| 33 * such as a |contenteditable| subtree. | 33 * such as a |contenteditable| subtree. |
| 34 * @constructor | 34 * @constructor |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 if (!this.multiline) | 134 if (!this.multiline) |
| 135 return 0; | 135 return 0; |
| 136 var breaks = this.node_.lineBreaks || []; | 136 var breaks = this.node_.lineBreaks || []; |
| 137 var index = 0; | 137 var index = 0; |
| 138 while (index < breaks.length && breaks[index] <= charIndex) | 138 while (index < breaks.length && breaks[index] <= charIndex) |
| 139 ++index; | 139 ++index; |
| 140 return index; | 140 return index; |
| 141 }, | 141 }, |
| 142 | 142 |
| 143 /** @override */ | 143 /** @override */ |
| 144 describeLine: function(lineIndex, triggeredByUser) { | |
| 145 if (!this.node_.state.richlyEditable) { | |
| 146 cvox.ChromeVoxEditableTextBase.prototype.describeLine.call( | |
| 147 this, lineIndex, triggeredByUser); | |
| 148 return; | |
| 149 } | |
| 150 var line = this.getSelectedAutomationLine_(); | |
| 151 if (line) { | |
| 152 new Output().withRichSpeech(line, null, Output.EventType.NAVIGATE) | |
| 153 .go(); | |
| 154 } | |
| 155 }, | |
| 156 | |
| 157 /** @override */ | |
| 158 getLineStart: function(lineIndex) { | 144 getLineStart: function(lineIndex) { |
| 159 if (!this.multiline || lineIndex == 0) | 145 if (!this.multiline || lineIndex == 0) |
| 160 return 0; | 146 return 0; |
| 161 var breaks = this.getLineBreaks_(); | 147 var breaks = this.getLineBreaks_(); |
| 162 return breaks[lineIndex - 1] || this.node_.value.length; | 148 return breaks[lineIndex - 1] || this.node_.value.length; |
| 163 }, | 149 }, |
| 164 | 150 |
| 165 /** @override */ | 151 /** @override */ |
| 166 getLineEnd: function(lineIndex) { | 152 getLineEnd: function(lineIndex) { |
| 167 var breaks = this.getLineBreaks_(); | 153 var breaks = this.getLineBreaks_(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 180 * @private | 166 * @private |
| 181 */ | 167 */ |
| 182 getLineBreaks_: function() { | 168 getLineBreaks_: function() { |
| 183 // node.lineBreaks is undefined when the multiline field has no line | 169 // node.lineBreaks is undefined when the multiline field has no line |
| 184 // breaks. | 170 // breaks. |
| 185 return this.node_.lineBreaks || []; | 171 return this.node_.lineBreaks || []; |
| 186 }, | 172 }, |
| 187 | 173 |
| 188 /** @private */ | 174 /** @private */ |
| 189 outputBraille_: function() { | 175 outputBraille_: function() { |
| 190 // First line in a multiline field. | 176 var isFirstLine = false; // First line in a multiline field. |
| 191 var lineIndex = this.getLineIndex(this.start); | |
| 192 var isFirstLine = this.multiline && lineIndex == 0; | |
| 193 var output = new Output(); | 177 var output = new Output(); |
| 194 var range; | 178 var range; |
| 195 if (this.node_.state.richlyEditable) { | 179 if (this.multiline) { |
| 196 range = this.getSelectedAutomationLine_(); | 180 var lineIndex = this.getLineIndex(this.start); |
| 197 } else if (this.multiline) { | 181 if (lineIndex == 0) { |
| 198 if (isFirstLine) | 182 isFirstLine = true; |
| 199 output.formatForBraille('$name', this.node_); | 183 output.formatForBraille('$name', this.node_); |
| 184 } |
| 200 range = new Range( | 185 range = new Range( |
| 201 new Cursor(this.node_, this.getLineStart(lineIndex)), | 186 new Cursor(this.node_, this.getLineStart(lineIndex)), |
| 202 new Cursor(this.node_, this.getLineEnd(lineIndex))); | 187 new Cursor(this.node_, this.getLineEnd(lineIndex))); |
| 203 } else { | 188 } else { |
| 204 range = Range.fromNode(this.node_); | 189 range = Range.fromNode(this.node_); |
| 205 } | 190 } |
| 206 if (range) | 191 output.withBraille(range, null, Output.EventType.NAVIGATE); |
| 207 output.withBraille(range, null, Output.EventType.NAVIGATE); | |
| 208 if (isFirstLine) | 192 if (isFirstLine) |
| 209 output.formatForBraille('@tag_textarea'); | 193 output.formatForBraille('@tag_textarea'); |
| 210 output.go(); | 194 output.go(); |
| 211 }, | |
| 212 | |
| 213 /** | |
| 214 * @return {Range} | |
| 215 * @private | |
| 216 */ | |
| 217 getSelectedAutomationLine_: function() { | |
| 218 if (!this.node_.root.anchorObject || !this.node_.root.focusObject) | |
| 219 return null; | |
| 220 | |
| 221 var start = Cursor.fromNode(this.node_.root.anchorObject); | |
| 222 start = start.move(Unit.LINE, Movement.BOUND, Dir.BACKWARD); | |
| 223 var end = Cursor.fromNode(this.node_.root.focusObject); | |
| 224 end = end.move(Unit.LINE, Movement.BOUND, Dir.FORWARD); | |
| 225 return new Range(start, end); | |
| 226 } | 195 } |
| 227 }; | 196 }; |
| 228 | 197 |
| 229 /** | 198 /** |
| 230 * @param {!AutomationNode} node The root editable node, i.e. the root of a | 199 * @param {!AutomationNode} node The root editable node, i.e. the root of a |
| 231 * contenteditable subtree or a text field. | 200 * contenteditable subtree or a text field. |
| 232 * @return {editing.TextEditHandler} | 201 * @return {editing.TextEditHandler} |
| 233 */ | 202 */ |
| 234 editing.TextEditHandler.createForNode = function(node) { | 203 editing.TextEditHandler.createForNode = function(node) { |
| 235 var rootFocusedEditable = null; | 204 var rootFocusedEditable = null; |
| 236 var testNode = node; | 205 var testNode = node; |
| 237 | 206 |
| 238 do { | 207 do { |
| 239 if (testNode.state.focused && testNode.state.editable) | 208 if (testNode.state.focused && testNode.state.editable) |
| 240 rootFocusedEditable = testNode; | 209 rootFocusedEditable = testNode; |
| 241 testNode = testNode.parent; | 210 testNode = testNode.parent; |
| 242 } while (testNode); | 211 } while (testNode); |
| 243 | 212 |
| 244 if (rootFocusedEditable) | 213 if (rootFocusedEditable) |
| 245 return new TextFieldTextEditHandler(rootFocusedEditable); | 214 return new TextFieldTextEditHandler(rootFocusedEditable); |
| 246 | 215 |
| 247 return null; | 216 return null; |
| 248 }; | 217 }; |
| 249 | 218 |
| 250 }); | 219 }); |
| OLD | NEW |