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

Unified Diff: chrome/browser/resources/access_chromevox/common/linear_dom_walker.js

Issue 6254007: Adding ChromeVox as a component extensions (enabled only for ChromeOS, for no... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 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/access_chromevox/common/linear_dom_walker.js
===================================================================
--- chrome/browser/resources/access_chromevox/common/linear_dom_walker.js (revision 0)
+++ chrome/browser/resources/access_chromevox/common/linear_dom_walker.js (revision 0)
@@ -0,0 +1,317 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview A JavaScript class for walking the DOM.
+ */
+
+
+goog.provide('cvox.LinearDomWalker');
+
+goog.require('cvox.DomUtil');
+goog.require('cvox.XpathUtil');
+
+/**
+ * @constructor
+ */
+cvox.LinearDomWalker = function() {
+ this.currentNode = null;
+ this.currentAncestors = new Array();
+ this.previousNode = null;
+ this.useSmartNav = true;
+};
+
+/**
+ * @type {number}
+ * If a node contains more characters than this, it should not be treated
+ * as a leaf node by the smart navigation algorithm.
+ *
+ * This number was determined by looking at the average number of
+ * characters in a paragraph:
+ * http://www.fullondesign.co.uk/design/usability/
+ * 285-how-many-characters-per-a-page-is-normal.htm
+ * and then trying it out on a few popular websites (CNN, BBC,
+ * Google Search, etc.) and making sure it made sense.
+ */
+cvox.LinearDomWalker.SMARTNAV_MAX_CHARCOUNT = 1500;
+
+/**
+ * @type {string}
+ * If a node contains any of these elements, it should not be treated
+ * as a leaf node by the smart navigation algorithm.
+ */
+cvox.LinearDomWalker.SMARTNAV_BREAKOUT_XPATH = './/blockquote |' +
+ './/button |' +
+ './/code |' +
+ './/form |' +
+ './/frame |' +
+ './/h1 |' +
+ './/h2 |' +
+ './/h3 |' +
+ './/h4 |' +
+ './/h5 |' +
+ './/h6 |' +
+ './/hr |' +
+ './/iframe |' +
+ './/input |' +
+ './/object |' +
+ './/ol |' +
+ './/p |' +
+ './/pre |' +
+ './/select |' +
+ './/table |' +
+ './/tr |' +
+ './/ul |' +
+ // Aria widget roles
+ './/*[@role="alert"] |' +
+ './/*[@role="alertdialog"] |' +
+ './/*[@role="button"] |' +
+ './/*[@role="checkbox"] |' +
+ './/*[@role="combobox"] |' +
+ './/*[@role="dialog"] |' +
+ './/*[@role="log"] |' +
+ './/*[@role="marquee"] |' +
+ './/*[@role="menubar"] |' +
+ './/*[@role="progressbar"] |' +
+ './/*[@role="radio"] |' +
+ './/*[@role="radiogroup"] |' +
+ './/*[@role="scrollbar"] |' +
+ './/*[@role="slider"] |' +
+ './/*[@role="spinbutton"] |' +
+ './/*[@role="status"] |' +
+ './/*[@role="tab"] |' +
+ './/*[@role="tabpanel"] |' +
+ './/*[@role="textbox"] |' +
+ './/*[@role="toolbar"] |' +
+ './/*[@role="tooltip"] |' +
+ './/*[@role="treeitem"] |' +
+ // Aria structure roles
+ './/*[@role="article"] |' +
+ './/*[@role="document"] |' +
+ './/*[@role="group"] |' +
+ './/*[@role="heading"] |' +
+ './/*[@role="img"] |' +
+ './/*[@role="list"] |' +
+ './/*[@role="math"] |' +
+ './/*[@role="region"] |' +
+ './/*[@role="row"] |' +
+ './/*[@role="separator"]';
+
+/**
+ * Gets the currentNode for the cvox.LinearDomWalker.
+ * @return {Node} The the current node.
+ */
+cvox.LinearDomWalker.prototype.getCurrentNode = function() {
+ return this.currentNode;
+};
+
+/**
+ * Sets the currentNode for the cvox.LinearDomWalker.
+ * @param {Node} node The node that should be treated as the current node.
+ */
+cvox.LinearDomWalker.prototype.setCurrentNode = function(node) {
+ this.currentNode = node;
+ this.currentAncestors = new Array();
+ var ancestor = this.currentNode;
+ while (ancestor) {
+ this.currentAncestors.push(ancestor);
+ ancestor = ancestor.parentNode;
+ }
+ this.currentAncestors.reverse();
+};
+
+/**
+ * Moves to the next node.
+ *
+ * @return {Node} The current node.
+ */
+cvox.LinearDomWalker.prototype.next = function() {
+ this.previousNode = this.currentNode;
+
+ /* Make sure the handle to the current element is still valid (attached to the
+ * document); if it isn't, use the cached list of ancestors to find a valid
+ * node, then resume navigation from that point.
+ * The current node can be invalidated by AJAX changing content.
+ */
+ if (this.currentNode &&
+ !cvox.DomUtil.isAttachedToDocument(this.currentNode)) {
+ for (var i = this.currentAncestors.length - 1, ancestor;
+ ancestor = this.currentAncestors[i]; i--) {
+ if (cvox.DomUtil.isAttachedToDocument(ancestor)) {
+ this.setCurrentNode(ancestor);
+ // Previous-Next sequence to put us back at the correct level.
+ this.previous();
+ this.next();
+ break;
+ }
+ }
+ }
+
+ return this.nextContentNode();
+};
+
+/**
+ * Moves to the previous node.
+ *
+ * @return {Node} The current node.
+ */
+cvox.LinearDomWalker.prototype.previous = function() {
+ this.previousNode = this.currentNode;
+
+ /* Make sure the handle to the current element is still valid (attached to the
+ * document); if it isn't, use the cached list of ancestors to find a valid
+ * node, then resume navigation from that point.
+ * The current node can be invalidated by AJAX changing content.
+ */
+ if (this.currentNode &&
+ !cvox.DomUtil.isAttachedToDocument(this.currentNode)) {
+ for (var i = this.currentAncestors.length - 1, ancestor;
+ ancestor = this.currentAncestors[i]; i--) {
+ if (cvox.DomUtil.isAttachedToDocument(ancestor)) {
+ this.setCurrentNode(ancestor);
+ // Next-previous sequence to put us back at the correct level.
+ this.next();
+ this.previous();
+ break;
+ }
+ }
+ }
+
+ return this.prevContentNode();
+};
+
+/**
+ * Moves to the next node.
+ * @return {Node} The current node.
+ */
+cvox.LinearDomWalker.prototype.nextNode = function() {
+ if (!this.currentNode) {
+ this.setCurrentNode(document.body);
+ } else {
+ while (this.currentNode && (!this.currentNode.nextSibling)) {
+ this.setCurrentNode(this.currentNode.parentNode);
+ }
+ if (this.currentNode && this.currentNode.nextSibling) {
+ this.setCurrentNode(this.currentNode.nextSibling);
+ }
+ }
+ if (!this.currentNode) {
+ return null;
+ }
+ while (!this.isLeafNode(this.currentNode)) {
+ this.setCurrentNode(this.currentNode.firstChild);
+ }
+ return this.currentNode;
+};
+
+/**
+ * Moves to the next node that has content.
+ * @return {Node} The current node.
+ */
+cvox.LinearDomWalker.prototype.nextContentNode = function() {
+ this.nextNode();
+ while (this.currentNode && !cvox.DomUtil.hasContent(this.currentNode)) {
+ this.nextNode();
+ }
+ return this.currentNode;
+};
+
+/**
+ * Moves to the previous node.
+ * @return {Node} The current node.
+ */
+cvox.LinearDomWalker.prototype.prevNode = function() {
+ if (!this.currentNode) {
+ this.setCurrentNode(document.body);
+ } else {
+ while (this.currentNode && (!this.currentNode.previousSibling)) {
+ this.setCurrentNode(this.currentNode.parentNode);
+ }
+ if (this.currentNode && this.currentNode.previousSibling) {
+ this.setCurrentNode(this.currentNode.previousSibling);
+ }
+ }
+ if (!this.currentNode) {
+ return null;
+ }
+ while (!this.isLeafNode(this.currentNode)) {
+ this.setCurrentNode(this.currentNode.lastChild);
+ }
+ return this.currentNode;
+};
+
+/**
+ * Moves to the previous node that has content.
+ * @return {Node} The current node.
+ */
+cvox.LinearDomWalker.prototype.prevContentNode = function() {
+ this.prevNode();
+ while (this.currentNode && !cvox.DomUtil.hasContent(this.currentNode)) {
+ this.prevNode();
+ }
+ return this.currentNode;
+};
+
+/**
+ * Returns an array of ancestors that are unique for the current node when
+ * compared to the previous node. Having such an array is useful in generating
+ * the node information (identifying when interesting node boundaries have been
+ * crossed, etc.).
+ *
+ * @return {Array.<Node>} An array of unique ancestors for the current node.
+ */
+cvox.LinearDomWalker.prototype.getUniqueAncestors = function() {
+ return cvox.DomUtil.getUniqueAncestors(this.previousNode,
+ this.currentNode);
+};
+
+/**
+ * Checks if Smart Nav is enabled.
+ * @return {boolean} Whether Smart Nav is enabled.
+ */
+cvox.LinearDomWalker.prototype.getSmartNavEnabled = function() {
+ return this.useSmartNav;
+};
+
+/**
+ * Enables/disables Smart Nav.
+ * @param {boolean} enableSmartNav - Whether Smart Nav should be enabled.
+ */
+cvox.LinearDomWalker.prototype.setSmartNavEnabled = function(enableSmartNav) {
+ this.useSmartNav = enableSmartNav;
+};
+
+
+/**
+ * Determines if the a node should be treated as a leaf node.
+ * Based on DomUtil.isLeafNode - if SmartNav is enabled, then a few additional
+ * heuristics will be applied to determine if a node can be treated as a leaf
+ * node for smoother reading.
+ * @param {Node} targetNode to check.
+ * @return {boolean} True if targetNode can be considered a leaf node.
+ */
+cvox.LinearDomWalker.prototype.isLeafNode = function(targetNode) {
+ if (cvox.DomUtil.isLeafNode(targetNode)) {
+ return true;
+ }
+ if (!this.useSmartNav) {
+ return false;
+ }
+ var content = cvox.DomUtil.getText(targetNode);
+ if (content.length > cvox.LinearDomWalker.SMARTNAV_MAX_CHARCOUNT) {
+ return false;
+ }
+ if (content.replace(/\s/g, '') === '') {
+ // Text only contains whitespace
+ return false;
+ }
+ var breakingNodes = cvox.XpathUtil.evalXPath(
+ cvox.LinearDomWalker.SMARTNAV_BREAKOUT_XPATH, targetNode);
+ for (var i = 0, node; node = breakingNodes[i]; i++) {
+ if (cvox.DomUtil.hasContent(node)) {
+ return false;
+ }
+ }
+ return true;
+};
Property changes on: chrome/browser/resources/access_chromevox/common/linear_dom_walker.js
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:eol-style
+ LF

Powered by Google App Engine
This is Rietveld 408576698