| 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
|
|
|
|
|