| Index: chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
|
| diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
|
| index 8f83cdab4e8cbce6f19cfafa045c42b5d08b3f5c..82dec9cf54646f73909d11158ed5ceca74dd3fbd 100644
|
| --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
|
| +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
|
| @@ -12,6 +12,7 @@ goog.provide('cursors.Movement');
|
| goog.provide('cursors.Range');
|
| goog.provide('cursors.Unit');
|
|
|
| +goog.require('AutomationPredicate');
|
| goog.require('AutomationUtil');
|
| goog.require('StringUtil');
|
| goog.require('constants');
|
| @@ -71,10 +72,17 @@ var Unit = cursors.Unit;
|
| * is pointed to and covers the case where the accessible text is empty.
|
| */
|
| cursors.Cursor = function(node, index) {
|
| - /** @type {!AutomationNode} @private */
|
| - this.node_ = node;
|
| /** @type {number} @private */
|
| this.index_ = index;
|
| + /** @type {Array<AutomationNode>} @private */
|
| + this.ancestry_ = [];
|
| + var nodeWalker = node;
|
| + while (nodeWalker) {
|
| + this.ancestry_.push(nodeWalker);
|
| + nodeWalker = nodeWalker.parent;
|
| + if (nodeWalker && AutomationPredicate.root(nodeWalker))
|
| + break;
|
| + }
|
| };
|
|
|
| /**
|
| @@ -93,15 +101,26 @@ cursors.Cursor.prototype = {
|
| * @return {boolean}
|
| */
|
| equals: function(rhs) {
|
| - return this.node_ === rhs.node &&
|
| - this.index_ === rhs.index;
|
| + return this.node === rhs.node &&
|
| + this.index === rhs.index;
|
| },
|
|
|
| /**
|
| - * @return {!AutomationNode}
|
| + * Returns the node. If the node is invalid since the last time it
|
| + * was accessed, moves the cursor to the nearest valid ancestor first.
|
| + * @return {AutomationNode}
|
| */
|
| get node() {
|
| - return this.node_;
|
| + for (var i = 0; i < this.ancestry_.length; i++) {
|
| + var firstValidNode = this.ancestry_[i];
|
| + if (firstValidNode != null && firstValidNode.role !== undefined &&
|
| + firstValidNode.root !== undefined) {
|
| + return firstValidNode;
|
| + }
|
| + // If we have to walk up to an ancestor, reset the index to NODE_INDEX.
|
| + this.index_ = cursors.NODE_INDEX;
|
| + }
|
| + return null;
|
| },
|
|
|
| /**
|
| @@ -141,7 +160,7 @@ cursors.Cursor.prototype = {
|
| * @return {string}
|
| */
|
| getText: function(opt_node) {
|
| - var node = opt_node || this.node_;
|
| + var node = opt_node || this.node;
|
| if (node.role === RoleType.textField)
|
| return node.value;
|
| return node.name || '';
|
| @@ -156,7 +175,11 @@ cursors.Cursor.prototype = {
|
| * @return {!cursors.Cursor} The moved cursor.
|
| */
|
| move: function(unit, movement, dir) {
|
| - var newNode = this.node_;
|
| + var originalNode = this.node;
|
| + if (!originalNode)
|
| + return this;
|
| +
|
| + var newNode = originalNode;
|
| var newIndex = this.index_;
|
|
|
| if ((unit != Unit.NODE || unit != Unit.DOM_NODE) &&
|
| @@ -257,7 +280,7 @@ cursors.Cursor.prototype = {
|
| var pred = unit == Unit.NODE ?
|
| AutomationPredicate.leaf : AutomationPredicate.object;
|
| newNode = AutomationUtil.findNextNode(
|
| - newNode, dir, pred) || this.node_;
|
| + newNode, dir, pred) || originalNode;
|
| newIndex = cursors.NODE_INDEX;
|
| break;
|
| }
|
| @@ -268,7 +291,7 @@ cursors.Cursor.prototype = {
|
| case Movement.BOUND:
|
| newNode = AutomationUtil.findNodeUntil(newNode, dir,
|
| AutomationPredicate.linebreak, true);
|
| - newNode = newNode || this.node_;
|
| + newNode = newNode || originalNode;
|
| newIndex =
|
| dir == Dir.FORWARD ? this.getText(newNode).length : 0;
|
| break;
|
| @@ -281,7 +304,7 @@ cursors.Cursor.prototype = {
|
| default:
|
| throw Error('Unrecognized unit: ' + unit);
|
| }
|
| - newNode = newNode || this.node_;
|
| + newNode = newNode || originalNode;
|
| newIndex = goog.isDef(newIndex) ? newIndex : this.index_;
|
| return new cursors.Cursor(newNode, newIndex);
|
| },
|
| @@ -291,7 +314,7 @@ cursors.Cursor.prototype = {
|
| * @return {boolean}
|
| */
|
| isValid: function() {
|
| - return !!this.node.root;
|
| + return !!this.node && !!this.node.root;
|
| }
|
| };
|
|
|
| @@ -324,6 +347,8 @@ cursors.WrappingCursor.prototype = {
|
| /** @override */
|
| move: function(unit, movement, dir) {
|
| var result = this;
|
| + if (!result.node)
|
| + return this;
|
|
|
| // Regular movement.
|
| if (!AutomationPredicate.root(this.node) || dir == Dir.FORWARD)
|
| @@ -340,6 +365,8 @@ cursors.WrappingCursor.prototype = {
|
| var pred = unit == Unit.DOM_NODE ?
|
| AutomationPredicate.object : AutomationPredicate.leaf;
|
| var endpoint = this.node;
|
| + if (!endpoint)
|
| + return this;
|
|
|
| // Case 1: forwards (find the root-like node).
|
| while (!AutomationPredicate.root(endpoint) && endpoint.parent)
|
| @@ -349,7 +376,7 @@ cursors.WrappingCursor.prototype = {
|
| var playEarcon = dir == Dir.FORWARD;
|
|
|
| // Case 2: backward (sync downwards to a leaf), if already on the root.
|
| - if (dir == Dir.BACKWARD && endpoint == this.node_) {
|
| + if (dir == Dir.BACKWARD && endpoint == this.node) {
|
| playEarcon = true;
|
| endpoint = AutomationUtil.findNodePre(endpoint,
|
| dir,
|
| @@ -403,6 +430,10 @@ cursors.Range.getDirection = function(rangeA, rangeB) {
|
| if (!rangeA || !rangeB)
|
| return Dir.FORWARD;
|
|
|
| + if (!rangeA.start.node || !rangeA.end.node ||
|
| + !rangeB.start.node || !rangeB.end.node)
|
| + return Dir.FORWARD;
|
| +
|
| // They are the same range.
|
| if (rangeA.start.node === rangeB.start.node &&
|
| rangeB.end.node === rangeA.end.node)
|
| @@ -482,6 +513,9 @@ cursors.Range.prototype = {
|
| */
|
| move: function(unit, dir) {
|
| var newStart = this.start_;
|
| + if (!newStart.node)
|
| + return this;
|
| +
|
| var newEnd;
|
| switch (unit) {
|
| case Unit.CHARACTER:
|
| @@ -515,6 +549,9 @@ cursors.Range.prototype = {
|
| var start = this.start.node;
|
| var end = this.end.node;
|
|
|
| + if (!start || !end)
|
| + return;
|
| +
|
| // Find the most common root.
|
| var uniqueAncestors = AutomationUtil.getUniqueAncestors(start, end);
|
| var mcr = start.root;
|
|
|