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 |