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'); |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
127 while (rNode && (rNode.role == RoleType.INLINE_TEXT_BOX || | 127 while (rNode && (rNode.role == RoleType.INLINE_TEXT_BOX || |
128 rNode.role == RoleType.STATIC_TEXT)) | 128 rNode.role == RoleType.STATIC_TEXT)) |
129 rNode = rNode.parent; | 129 rNode = rNode.parent; |
130 | 130 |
131 // Ignore indicies for now. | 131 // Ignore indicies for now. |
132 | 132 |
133 return lNode === rNode && lNode != undefined; | 133 return lNode === rNode && lNode != undefined; |
134 }, | 134 }, |
135 | 135 |
136 /** | 136 /** |
137 * Compares this cursor with |rhs|. | |
138 * @param {cursors.Cursor} rhs | |
139 * @return Dir.BACKWARD if |rhs| comes before this cursor in | |
140 * document order. Forward otherwise. | |
141 */ | |
142 compare: function(rhs) { | |
143 if (!this.node || !rhs.node) | |
144 return Dir.FORWARD; | |
145 | |
146 if (rhs.node == this.node) | |
147 return rhs.index < this.index ? Dir.BACKWARD : Dir.FORWARD; | |
148 return AutomationUtil.getDirection(this.node, rhs.node); | |
149 }, | |
150 | |
151 /** | |
137 * Returns the node. If the node is invalid since the last time it | 152 * Returns the node. If the node is invalid since the last time it |
138 * was accessed, moves the cursor to the nearest valid ancestor first. | 153 * was accessed, moves the cursor to the nearest valid ancestor first. |
139 * @return {AutomationNode} | 154 * @return {AutomationNode} |
140 */ | 155 */ |
141 get node() { | 156 get node() { |
142 for (var i = 0; i < this.ancestry_.length; i++) { | 157 for (var i = 0; i < this.ancestry_.length; i++) { |
143 var firstValidNode = this.ancestry_[i]; | 158 var firstValidNode = this.ancestry_[i]; |
144 if (firstValidNode != null && firstValidNode.role !== undefined && | 159 if (firstValidNode != null && firstValidNode.role !== undefined && |
145 firstValidNode.root != undefined) { | 160 firstValidNode.root != undefined) { |
146 return firstValidNode; | 161 return firstValidNode; |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
357 case Movement.DIRECTIONAL: | 372 case Movement.DIRECTIONAL: |
358 var pred = unit == Unit.TEXT ? | 373 var pred = unit == Unit.TEXT ? |
359 AutomationPredicate.leaf : AutomationPredicate.object; | 374 AutomationPredicate.leaf : AutomationPredicate.object; |
360 newNode = AutomationUtil.findNextNode(newNode, dir, pred) || | 375 newNode = AutomationUtil.findNextNode(newNode, dir, pred) || |
361 originalNode; | 376 originalNode; |
362 newIndex = cursors.NODE_INDEX; | 377 newIndex = cursors.NODE_INDEX; |
363 break; | 378 break; |
364 } | 379 } |
365 break; | 380 break; |
366 case Unit.LINE: | 381 case Unit.LINE: |
367 newIndex = 0; | 382 var deepEquivalent = this.deepEquivalent; |
383 newNode = deepEquivalent.node || newNode; | |
384 newIndex = deepEquivalent.index || 0; | |
385 | |
368 switch (movement) { | 386 switch (movement) { |
369 case Movement.BOUND: | 387 case Movement.BOUND: |
370 newNode = AutomationUtil.findNodeUntil(newNode, dir, | 388 newNode = AutomationUtil.findNodeUntil(newNode, dir, |
371 AutomationPredicate.linebreak, true); | 389 AutomationPredicate.linebreak, true); |
372 newNode = newNode || originalNode; | 390 newNode = newNode || originalNode; |
373 newIndex = | 391 newIndex = |
374 dir == Dir.FORWARD ? AutomationUtil.getText(newNode).length : 0; | 392 dir == Dir.FORWARD ? AutomationUtil.getText(newNode).length : 0; |
375 break; | 393 break; |
376 case Movement.DIRECTIONAL: | 394 case Movement.DIRECTIONAL: |
377 newNode = AutomationUtil.findNodeUntil( | 395 newNode = AutomationUtil.findNodeUntil( |
378 newNode, dir, AutomationPredicate.linebreak); | 396 newNode, dir, AutomationPredicate.linebreak); |
379 break; | 397 break; |
380 } | 398 } |
381 break; | 399 break; |
382 default: | 400 default: |
383 throw Error('Unrecognized unit: ' + unit); | 401 throw Error('Unrecognized unit: ' + unit); |
384 } | 402 } |
385 newNode = newNode || originalNode; | 403 newNode = newNode || originalNode; |
386 newIndex = goog.isDef(newIndex) ? newIndex : this.index_; | 404 newIndex = goog.isDef(newIndex) ? newIndex : this.index_; |
387 return new cursors.Cursor(newNode, newIndex); | 405 return new cursors.Cursor(newNode, newIndex); |
388 }, | 406 }, |
389 | 407 |
390 /** | 408 /** |
409 * Returns the deepest equivalent cursor. | |
410 * @return {cursors.Cursor} | |
411 */ | |
412 get deepEquivalent() { | |
dmazzoni
2017/05/09 04:49:46
Might be nice to have a unit test for this?
David Tseng
2017/05/09 23:22:51
Before we get there, do you have any comments on w
dmazzoni
2017/05/10 06:02:52
I think so. Note that Nektarios has already implem
| |
413 var newNode = this.node; | |
414 var newIndex = this.index_; | |
415 while (newNode.firstChild) { | |
416 if (newNode.role == RoleType.STATIC_TEXT) { | |
417 // Text offset. | |
418 // Re-interpret the index as an offset into an inlineTextBox. | |
419 var target = newNode.firstChild; | |
420 var length = 0; | |
421 while (target && length < newIndex) { | |
422 if (length <= newIndex && newIndex < (length + target.name.length)) | |
423 break; | |
dmazzoni
2017/05/09 04:49:46
nit: indent
David Tseng
2017/05/09 23:22:51
Done.
| |
424 length += target.name.length; | |
425 target = target.nextSibling; | |
426 } | |
427 if (target) { | |
428 newNode = target; | |
429 newIndex = newIndex - length; | |
430 } | |
431 break; | |
432 } else if (newNode.role != RoleType.INLINE_TEXT_BOX && | |
433 newNode.children[newIndex]) { | |
434 // Valid node offset. | |
435 newNode = newNode.children[newIndex]; | |
436 newIndex = 0; | |
437 } else { | |
438 // Invalid offset. | |
439 break; | |
440 } | |
441 } | |
442 | |
443 return new cursors.Cursor(newNode, newIndex); | |
444 }, | |
445 | |
446 /** | |
391 * Returns whether this cursor points to a valid position. | 447 * Returns whether this cursor points to a valid position. |
392 * @return {boolean} | 448 * @return {boolean} |
393 */ | 449 */ |
394 isValid: function() { | 450 isValid: function() { |
395 return this.node != null; | 451 return this.node != null; |
396 } | 452 } |
397 }; | 453 }; |
398 | 454 |
399 /** | 455 /** |
400 * A cursors.Cursor that wraps from beginning to end and vice versa when moved. | 456 * A cursors.Cursor that wraps from beginning to end and vice versa when moved. |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
687 /** | 743 /** |
688 * Returns whether this range has valid start and end cursors. | 744 * Returns whether this range has valid start and end cursors. |
689 * @return {boolean} | 745 * @return {boolean} |
690 */ | 746 */ |
691 isValid: function() { | 747 isValid: function() { |
692 return this.start.isValid() && this.end.isValid(); | 748 return this.start.isValid() && this.end.isValid(); |
693 } | 749 } |
694 }; | 750 }; |
695 | 751 |
696 }); // goog.scope | 752 }); // goog.scope |
OLD | NEW |