| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 Classes related to cursors that point to and select parts of | 6 * @fileoverview Classes related to cursors that point to and select parts of |
| 7 * the automation tree. | 7 * the automation tree. |
| 8 */ | 8 */ |
| 9 | 9 |
| 10 goog.provide('cursors.Cursor'); | 10 goog.provide('cursors.Cursor'); |
| 11 goog.provide('cursors.Movement'); | 11 goog.provide('cursors.Movement'); |
| 12 goog.provide('cursors.Range'); | 12 goog.provide('cursors.Range'); |
| 13 goog.provide('cursors.Unit'); | 13 goog.provide('cursors.Unit'); |
| 14 | 14 |
| 15 goog.require('AncestryRecoveryStrategy'); |
| 15 goog.require('AutomationPredicate'); | 16 goog.require('AutomationPredicate'); |
| 16 goog.require('AutomationUtil'); | 17 goog.require('AutomationUtil'); |
| 18 goog.require('RecoveryStrategy'); |
| 17 goog.require('StringUtil'); | 19 goog.require('StringUtil'); |
| 18 goog.require('constants'); | 20 goog.require('constants'); |
| 19 | 21 |
| 20 /** | 22 /** |
| 21 * The special index that represents a cursor pointing to a node without | 23 * The special index that represents a cursor pointing to a node without |
| 22 * pointing to any part of its accessible text. | 24 * pointing to any part of its accessible text. |
| 23 */ | 25 */ |
| 24 cursors.NODE_INDEX = -1; | 26 cursors.NODE_INDEX = -1; |
| 25 | 27 |
| 26 /** | 28 /** |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 cursors.Cursor = function(node, index) { | 79 cursors.Cursor = function(node, index) { |
| 78 // Compensate for specific issues in Blink. | 80 // Compensate for specific issues in Blink. |
| 79 // TODO(dtseng): Pass through affinity; if upstream, skip below. | 81 // TODO(dtseng): Pass through affinity; if upstream, skip below. |
| 80 if (node.role == RoleType.STATIC_TEXT && node.name.length == index) { | 82 if (node.role == RoleType.STATIC_TEXT && node.name.length == index) { |
| 81 // Re-interpret this case as the beginning of the next node. | 83 // Re-interpret this case as the beginning of the next node. |
| 82 var nextNode = AutomationUtil.findNextNode( | 84 var nextNode = AutomationUtil.findNextNode( |
| 83 node, Dir.FORWARD, AutomationPredicate.leafOrStaticText); | 85 node, Dir.FORWARD, AutomationPredicate.leafOrStaticText); |
| 84 | 86 |
| 85 // The exception is when a user types at the end of a line. In that case, | 87 // The exception is when a user types at the end of a line. In that case, |
| 86 // staying on the current node is appropriate. | 88 // staying on the current node is appropriate. |
| 87 if (node && node.nextOnLine && nextNode) { | 89 if (node && node.nextOnLine && node.nextOnLine.role && nextNode) { |
| 88 node = nextNode; | 90 node = nextNode; |
| 89 index = 0; | 91 index = 0; |
| 90 } | 92 } |
| 91 } else if ( | 93 } else if ( |
| 92 node.role == RoleType.GENERIC_CONTAINER && node.state.richlyEditable && | 94 node.role == RoleType.GENERIC_CONTAINER && node.state.richlyEditable && |
| 93 (node.firstChild && | 95 (node.firstChild && |
| 94 (node.firstChild.role == RoleType.LINE_BREAK || | 96 (node.firstChild.role == RoleType.LINE_BREAK || |
| 95 node.firstChild.role == RoleType.STATIC_TEXT))) { | 97 node.firstChild.role == RoleType.STATIC_TEXT))) { |
| 96 // Re-interpret this case as pointing to the text under the div. | 98 // Re-interpret this case as pointing to the text under the div. |
| 97 node = node.find({role: RoleType.INLINE_TEXT_BOX}) || node; | 99 node = node.find({role: RoleType.INLINE_TEXT_BOX}) || node; |
| 98 } | 100 } |
| 99 | 101 |
| 100 /** @type {number} @private */ | 102 /** @type {number} @private */ |
| 101 this.index_ = index; | 103 this.index_ = index; |
| 102 /** @type {Array<AutomationNode>} @private */ | 104 /** @type {RecoveryStrategy} */ |
| 103 this.ancestry_ = []; | 105 this.recovery_ = new AncestryRecoveryStrategy(node); |
| 104 var nodeWalker = node; | |
| 105 while (nodeWalker) { | |
| 106 this.ancestry_.push(nodeWalker); | |
| 107 nodeWalker = nodeWalker.parent; | |
| 108 if (nodeWalker && nodeWalker.role == RoleType.WINDOW) | |
| 109 break; | |
| 110 } | |
| 111 }; | 106 }; |
| 112 | 107 |
| 113 /** | 108 /** |
| 114 * Convenience method to construct a Cursor from a node. | 109 * Convenience method to construct a Cursor from a node. |
| 115 * @param {!AutomationNode} node | 110 * @param {!AutomationNode} node |
| 116 * @return {!cursors.Cursor} | 111 * @return {!cursors.Cursor} |
| 117 */ | 112 */ |
| 118 cursors.Cursor.fromNode = function(node) { | 113 cursors.Cursor.fromNode = function(node) { |
| 119 return new cursors.Cursor(node, cursors.NODE_INDEX); | 114 return new cursors.Cursor(node, cursors.NODE_INDEX); |
| 120 }; | 115 }; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 return rhs.index < this.index ? Dir.BACKWARD : Dir.FORWARD; | 165 return rhs.index < this.index ? Dir.BACKWARD : Dir.FORWARD; |
| 171 return AutomationUtil.getDirection(this.node, rhs.node); | 166 return AutomationUtil.getDirection(this.node, rhs.node); |
| 172 }, | 167 }, |
| 173 | 168 |
| 174 /** | 169 /** |
| 175 * Returns the node. If the node is invalid since the last time it | 170 * Returns the node. If the node is invalid since the last time it |
| 176 * was accessed, moves the cursor to the nearest valid ancestor first. | 171 * was accessed, moves the cursor to the nearest valid ancestor first. |
| 177 * @return {AutomationNode} | 172 * @return {AutomationNode} |
| 178 */ | 173 */ |
| 179 get node() { | 174 get node() { |
| 180 for (var i = 0; i < this.ancestry_.length; i++) { | 175 if (this.recovery_.requiresRecovery()) { |
| 181 var firstValidNode = this.ancestry_[i]; | 176 // If we need to recover, the index is no longer valid. |
| 182 if (firstValidNode != null && firstValidNode.role !== undefined && | |
| 183 firstValidNode.root != undefined) { | |
| 184 return firstValidNode; | |
| 185 } | |
| 186 // If we have to walk up to an ancestor, reset the index to NODE_INDEX. | |
| 187 this.index_ = cursors.NODE_INDEX; | 177 this.index_ = cursors.NODE_INDEX; |
| 188 } | 178 } |
| 189 return null; | 179 return this.recovery_.node; |
| 190 }, | 180 }, |
| 191 | 181 |
| 192 /** | 182 /** |
| 193 * @return {number} | 183 * @return {number} |
| 194 */ | 184 */ |
| 195 get index() { | 185 get index() { |
| 196 return this.index_; | 186 return this.index_; |
| 197 }, | 187 }, |
| 198 | 188 |
| 199 | 189 |
| (...skipping 567 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 767 /** | 757 /** |
| 768 * Returns whether this range has valid start and end cursors. | 758 * Returns whether this range has valid start and end cursors. |
| 769 * @return {boolean} | 759 * @return {boolean} |
| 770 */ | 760 */ |
| 771 isValid: function() { | 761 isValid: function() { |
| 772 return this.start.isValid() && this.end.isValid(); | 762 return this.start.isValid() && this.end.isValid(); |
| 773 } | 763 } |
| 774 }; | 764 }; |
| 775 | 765 |
| 776 }); // goog.scope | 766 }); // goog.scope |
| OLD | NEW |