Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(493)

Unified Diff: chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js

Issue 637223006: Initial support for Ranges over automation nodes (used to track ChromeVox focus). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add tests for range. Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 c8b65e50d1d17e82be781b78f637347c875ec219..d80085bd790c4626d51cdac162a3a145ccafdcc1 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
@@ -66,19 +66,44 @@ var Unit = cursors.Unit;
* pointed to and covers the case where the accessible text is empty.
*/
cursors.Cursor = function(node, index) {
- /** @type {!AutomationNode} */
- this.node = node;
- /** @type {number} */
- this.index = index;
+ /** @type {!AutomationNode} @private */
+ this.node_ = node;
+ /** @type {number} @private */
+ this.index_ = index;
+};
+
+/**
+ * Convenience method to construct a Cursor from a node.
+ * @param {!AutomationNode} node
+ * @return {!cursors.Cursor}
+ */
+cursors.Cursor.fromNode = function(node) {
+ return new cursors.Cursor(node, cursors.NODE_INDEX);
};
cursors.Cursor.prototype = {
/**
- * Returns a copy of this cursor.
- * @return {cursors.Cursor}
+ * Returns true if |rhs| is equal to this cursor.
+ * @param {!cursors.Cursor} rhs
+ * @return {boolean}
+ */
+ equals: function(rhs) {
+ return this.node_ === rhs.getNode() &&
+ this.index_ === rhs.getIndex();
+ },
+
+ /**
+ * @return {!AutomationNode}
*/
- clone: function() {
- return new cursors.Cursor(this.node, this.index);
+ getNode: function() {
+ return this.node_;
+ },
+
+ /**
+ * @return {number}
+ */
+ getIndex: function() {
+ return this.index_;
},
/**
@@ -92,23 +117,25 @@ cursors.Cursor.prototype = {
* @return {string}
*/
getText: function(opt_node) {
- var node = opt_node || this.node;
+ var node = opt_node || this.node_;
return node.attributes.name || node.attributes.value || '';
},
/**
- * Moves this cursor by the unit in the given direction using the given
- * movement type.
+ * Makes a Cursor which has been moved from this cursor by the unit in the
+ * given direction using the given movement type.
* @param {Unit} unit
* @param {Movement} movement
* @param {Dir} dir
+ * @return {!cursors.Cursor} The moved cursor.
*/
move: function(unit, movement, dir) {
+ var newNode, newIndex;
switch (unit) {
case Unit.CHARACTER:
// BOUND and DIRECTIONAL are the same for characters.
- var node = this.node;
- var nextIndex = dir == Dir.FORWARD ? this.index + 1 : this.index - 1;
+ var node = this.node_;
+ var nextIndex = dir == Dir.FORWARD ? this.index_ + 1 : this.index_ - 1;
if (nextIndex < 0 || nextIndex >= this.getText().length) {
node = AutomationUtil.findNextNode(
node, dir, AutomationPredicate.leaf);
@@ -116,57 +143,65 @@ cursors.Cursor.prototype = {
nextIndex =
dir == Dir.FORWARD ? 0 : this.getText(node).length - 1;
} else {
- node = this.node;
- nextIndex = this.index;
+ node = this.node_;
+ nextIndex = this.index_;
}
}
- this.node = node;
- this.index = nextIndex;
+ newNode = node;
+ newIndex = nextIndex;
break;
case Unit.WORD:
switch (movement) {
case Movement.BOUND:
- if (this.node.role == Role.inlineTextBox) {
+ if (this.node_.role == Role.inlineTextBox) {
var start, end;
- for (var i = 0; i < this.node.attributes.wordStarts.length; i++) {
- if (this.index >= this.node.attributes.wordStarts[i] &&
- this.index <= this.node.attributes.wordEnds[i]) {
- start = this.node.attributes.wordStarts[i];
- end = this.node.attributes.wordEnds[i];
+ for (
+ var i = 0; i < this.node_.attributes.wordStarts.length; i++) {
dmazzoni 2014/10/24 16:13:30 funny indentation?
+ if (this.index_ >= this.node_.attributes.wordStarts[i] &&
+ this.index_ <= this.node_.attributes.wordEnds[i]) {
+ start = this.node_.attributes.wordStarts[i];
+ end = this.node_.attributes.wordEnds[i];
break;
}
}
if (goog.isDef(start) && goog.isDef(end))
- this.index = dir == Dir.FORWARD ? end : start;
+ newIndex = dir == Dir.FORWARD ? end : start;
} else {
// TODO(dtseng): Figure out what to do in this case.
}
break;
case Movement.DIRECTIONAL:
- if (this.node.role == Role.inlineTextBox) {
+ if (this.node_.role == Role.inlineTextBox) {
var start, end;
- for (var i = 0; i < this.node.attributes.wordStarts.length; i++) {
- if (this.index >= this.node.attributes.wordStarts[i] &&
- this.index <= this.node.attributes.wordEnds[i]) {
+ for (
+ var i = 0; i < this.node_.attributes.wordStarts.length; i++) {
+ if (this.index_ >= this.node_.attributes.wordStarts[i] &&
+ this.index_ <= this.node_.attributes.wordEnds[i]) {
var nextIndex = dir == Dir.FORWARD ? i + 1 : i - 1;
- start = this.node.attributes.wordStarts[nextIndex];
- end = this.node.attributes.wordEnds[nextIndex];
+ start = this.node_.attributes.wordStarts[nextIndex];
+ end = this.node_.attributes.wordEnds[nextIndex];
break;
}
}
if (goog.isDef(start)) {
- this.index = start;
+ newIndex = start;
} else {
- var node = AutomationUtil.findNextNode(this.node, dir,
- AutomationPredicate.leaf);
- if (node) {
- this.node = node;
- this.index = 0;
- if (dir == Dir.BACKWARD && node.role == Role.inlineTextBox) {
- var starts = node.attributes.wordStarts;
- this.index = starts[starts.length - 1] || 0;
- } else {
- // TODO(dtseng): Figure out what to do for general nodes.
+ // The backward case is special at the beginning of nodes.
+ if (dir == Dir.BACKWARD && this.index_ != 0) {
+ this.index_ = 0;
+ } else {
+ var node = AutomationUtil.findNextNode(this.node_, dir,
+ AutomationPredicate.leaf);
+ if (node) {
+ newNode = node;
+ newIndex = 0;
+ if (dir == Dir.BACKWARD &&
+ node.role == Role.inlineTextBox) {
+ var starts = node.attributes.wordStarts;
+ newIndex = starts[starts.length - 1] || 0;
+ } else {
+ // TODO(dtseng): Figure out what to do for general nodes.
+ }
}
}
}
@@ -178,39 +213,132 @@ cursors.Cursor.prototype = {
case Unit.NODE:
switch (movement) {
case Movement.BOUND:
- this.index = dir == Dir.FORWARD ? this.getText().length - 1 : 0;
+ newIndex = dir == Dir.FORWARD ? this.getText().length - 1 : 0;
break;
case Movement.DIRECTIONAL:
- this.node = AutomationUtil.findNextNode(
- this.node, dir, AutomationPredicate.leaf) || this.node;
- this.index = cursors.NODE_INDEX;
+ newNode = AutomationUtil.findNextNode(
+ this.node_, dir, AutomationPredicate.leaf) || this.node_;
+ newIndex = cursors.NODE_INDEX;
break;
}
break;
case Unit.LINE:
- this.index = 0;
+ newIndex = 0;
switch (movement) {
case Movement.BOUND:
- var node = this.node;
- node = AutomationUtil.findNodeUntil(node, dir,
+ newNode = AutomationUtil.findNodeUntil(this.node_, dir,
AutomationPredicate.linebreak, {before: true});
- this.node = node || this.node;
+ newNode = newNode || this.node_;
+ newIndex =
+ dir == Dir.FORWARD ? this.getText(newNode).length - 1 : 0;
break;
case Movement.DIRECTIONAL:
- var node = this.node;
- node = AutomationUtil.findNodeUntil(
- node, dir, AutomationPredicate.linebreak);
+ newNode = AutomationUtil.findNodeUntil(
+ this.node_, dir, AutomationPredicate.linebreak);
// We stick to the beginning of lines out of convention.
- if (node && dir == Dir.BACKWARD) {
- node = AutomationUtil.findNodeUntil(node, dir,
+ if (newNode && dir == Dir.BACKWARD) {
+ newNode = AutomationUtil.findNodeUntil(newNode, dir,
AutomationPredicate.linebreak, {before: true}) || node;
}
- this.node = node || this.node;
break;
}
+ break;
+ default:
+ throw 'Unrecognized unit: ' + unit;
+ }
+ newNode = newNode || this.node_;
+ newIndex = goog.isDef(newIndex) ? newIndex : this.index_;
+ return new cursors.Cursor(newNode, newIndex);
+ }
+};
+
+/**
+ * Represents a range in the automation tree. There is no visible selection on
+ * the page caused by usage of this object.
+ * @param {!cursors.Cursor} start
+ * @param {!cursors.Cursor} end
+ * @constructor
+ */
+cursors.Range = function(start, end) {
+ /** @type {!cursors.Cursor} @private */
+ this.start_ = start;
+ /** @type {!cursors.Cursor} @private */
+ this.end_ = end;
+};
+
+/**
+ * Convenience method to construct a Range surrounding one node.
+ * @param {!AutomationNode} node
+ * @return {!cursors.Range}
+ */
+cursors.Range.fromNode = function(node) {
+ return new cursors.Range(cursors.Cursor.fromNode(node),
+ cursors.Cursor.fromNode(node));
+};
+
+cursors.Range.prototype = {
+ /**
+ * Returns true if |rhs| is equal to this range.
+ * @param {!cursors.Range} rhs
+ * @return {boolean}
+ */
+ equals: function(rhs) {
+ return this.start_.equals(rhs.getStart()) &&
+ this.end_.equals(rhs.getEnd());
+ },
+
+ /**
+ * Gets a cursor bounding this range.
+ * @param {Dir} dir Which endpoint cursor to return; Dir.FORWARD for end,
+ * Dir.BACKWARD for start.
+ * @return {!cursors.Cursor}
+ */
+ getBound: function(dir) {
+ return dir == Dir.FORWARD ? this.end_ : this.start_;
+ },
+
+ /**
+ * @return {!cursors.Cursor}
+ */
+ getStart: function() {
+ return this.start_;
+ },
+
+ /**
+ * @return {!cursors.Cursor}
+ */
+ getEnd: function() {
+ return this.end_;
+ },
+
+ /**
+ * Makes a Range which has been moved from this range by the given unit and
+ * direction.
+ * @param {Unit} unit
+ * @param {Dir} dir
+ * @return {cursors.Range}
+ */
+ move: function(unit, dir) {
+ var newStart = this.start_;
+ var newEnd = newStart;
+ switch (unit) {
+ case Unit.CHARACTER:
+ newStart = newStart.move(unit, Movement.BOUND, dir);
+ newEnd = newStart.move(unit, Movement.BOUND, Dir.FORWARD);
+ // Character crossed a node; collapses to the end of the node.
+ if (newStart.getNode() !== newEnd.getNode())
+ newEnd = newStart;
+ break;
+ case Unit.WORD:
+ case Unit.LINE:
+ case Unit.NODE:
+ newEnd = newEnd.move(unit, Movement.DIRECTIONAL, dir);
+ newStart = newEnd;
+ newEnd = newEnd.move(unit, Movement.BOUND, Dir.FORWARD);
break;
}
+ return new cursors.Range(newStart, newEnd);
}
};

Powered by Google App Engine
This is Rietveld 408576698