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

Unified Diff: chrome/browser/resources/access_chromevox/chromevox/injected/navigation_manager.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/chromevox/injected/navigation_manager.js
===================================================================
--- chrome/browser/resources/access_chromevox/chromevox/injected/navigation_manager.js (revision 0)
+++ chrome/browser/resources/access_chromevox/chromevox/injected/navigation_manager.js (revision 0)
@@ -0,0 +1,516 @@
+// 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 Manages navigation within a page.
+ * This unifies navigation by the DOM walker and by WebKit selection.
+ */
+
+goog.provide('cvox.ChromeVoxNavigationManager');
+
+goog.require('cvox.ChromeVoxChoiceWidget');
+goog.require('cvox.DomUtil');
+goog.require('cvox.LinearDomWalker');
+goog.require('cvox.SelectionUtil');
+goog.require('cvox.SelectionWalker');
+
+/**
+ * @constructor
+ */
+cvox.ChromeVoxNavigationManager = function() {
+ this.currentNode = null;
+ this.nodeInformationArray = new Array();
+ this.currentNavStrategy = 2;
+ this.lastUsedNavStrategy = 2;
+ this.linearDomWalker = new cvox.LinearDomWalker();
+ this.selectionWalker = new cvox.SelectionWalker();
+ this.customWalker = null;
+ this.selectionUniqueAncestors = [];
+ this.choiceWidget = new cvox.ChromeVoxChoiceWidget();
+};
+
+/**
+ * @type {Object.<string, number>}
+ */
+cvox.ChromeVoxNavigationManager.STRATEGIES =
+ {'SELECTION' : 0, 'LINEARDOM' : 1, 'SMART' : 2, 'CUSTOM' : 3};
+
+/**
+ * @type {Array.<string>}
+ */
+cvox.ChromeVoxNavigationManager.STRATEGY_NAMES =
+ ['SELECTION', 'OBJECT', 'GROUP', 'CUSTOM'];
+
+/**
+ * Moves forward using the current navigation strategy.
+ */
+cvox.ChromeVoxNavigationManager.prototype.next = function() {
+ switch (this.currentNavStrategy) {
+ default:
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.CUSTOM:
+ this.customWalker.next();
+ break;
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.SMART:
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM:
+ var node = this.linearDomWalker.next();
+ if (node) {
+ cvox.SelectionUtil.selectAllTextInNode(node);
+ this.currentNode = node;
+ }
+ break;
+
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.SELECTION:
+ this.selectionUniqueAncestors = [];
+ var movedOk = this.selectionWalker.next();
+ if (!movedOk) {
+ var selectionNode = this.linearDomWalker.next();
+ this.selectionUniqueAncestors =
+ this.linearDomWalker.getUniqueAncestors();
+ if (selectionNode) {
+ this.currentNode = selectionNode;
+ this.selectionWalker.setCurrentNode(this.currentNode);
+ this.selectionWalker.next();
+ }
+ }
+ break;
+ }
+};
+
+/**
+ * Moves backward using the current navigation strategy.
+ */
+cvox.ChromeVoxNavigationManager.prototype.previous = function() {
+ switch (this.currentNavStrategy) {
+ default:
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.CUSTOM:
+ this.customWalker.previous();
+ break;
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.SMART:
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM:
+ var node = this.linearDomWalker.previous();
+ if (node) {
+ cvox.SelectionUtil.selectAllTextInNode(node);
+ this.currentNode = node;
+ }
+ break;
+
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.SELECTION:
+ this.selectionUniqueAncestors = [];
+ var movedOk = this.selectionWalker.previous();
+ if (!movedOk) {
+ var selectionNode = this.linearDomWalker.previous();
+ this.selectionUniqueAncestors =
+ this.linearDomWalker.getUniqueAncestors();
+ if (selectionNode) {
+ this.currentNode = selectionNode;
+ this.selectionWalker.setCurrentNode(this.currentNode);
+ cvox.SelectionUtil.selectAllTextInNode(this.currentNode);
+ window.getSelection().collapseToEnd();
+ this.selectionWalker.previous();
+ }
+ }
+ break;
+ }
+};
+
+/**
+ * Moves up a level of granularity.
+ */
+cvox.ChromeVoxNavigationManager.prototype.up = function() {
+ switch (this.currentNavStrategy) {
+ default:
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.CUSTOM:
+ break;
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.SMART:
+ if (!!this.customWalker) {
+ this.lastUsedNavStrategy = this.currentNavStrategy;
+ this.currentNavStrategy = 3;
+ this.customWalker.setCurrentNode(this.currentNode);
+ this.customWalker.goToCurrentItem();
+ }
+ break;
+
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM:
+ this.lastUsedNavStrategy = this.currentNavStrategy;
+ this.currentNavStrategy = 2;
+ this.linearDomWalker.setSmartNavEnabled(true);
+ var node = this.currentNode;
+ while (this.linearDomWalker.isLeafNode(node)) {
+ this.currentNode = node;
+ node = node.parentNode;
+ }
+ this.linearDomWalker.setCurrentNode(this.currentNode);
+ if (this.currentNode !== null) {
+ this.previous();
+ }
+ this.next();
+ break;
+
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.SELECTION:
+ var changed = this.selectionWalker.lessGranular();
+ if (!changed) {
+ this.lastUsedNavStrategy = this.currentNavStrategy;
+ this.currentNavStrategy = 1;
+ cvox.SelectionUtil.selectAllTextInNode(this.currentNode);
+ } else {
+ this.selectionWalker.previous();
+ this.selectionWalker.next();
+ }
+ break;
+ }
+};
+
+
+/**
+ * Moves down a level of granularity.
+ */
+cvox.ChromeVoxNavigationManager.prototype.down = function() {
+ switch (this.currentNavStrategy) {
+ default:
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.CUSTOM:
+ this.lastUsedNavStrategy = this.currentNavStrategy;
+ this.currentNavStrategy = 2;
+ this.linearDomWalker.setSmartNavEnabled(true);
+ if (this.customWalker.getCurrentNode() != null) {
+ this.currentNode = this.customWalker.getCurrentNode();
+ this.linearDomWalker.setCurrentNode(this.currentNode);
+ }
+ break;
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.SMART:
+ this.lastUsedNavStrategy = this.currentNavStrategy;
+ this.currentNavStrategy = 1;
+ this.linearDomWalker.setSmartNavEnabled(false);
+ if (this.currentNode !== null) {
+ this.previous();
+ }
+ this.next();
+ break;
+
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM:
+ this.lastUsedNavStrategy = this.currentNavStrategy;
+ this.currentNavStrategy = 0;
+ this.selectionWalker.setCurrentNode(this.currentNode);
+ this.selectionWalker.next();
+ break;
+
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.SELECTION:
+ var changed = this.selectionWalker.moreGranular();
+ if (changed) {
+ this.selectionWalker.previous();
+ this.selectionWalker.next();
+ }
+ break;
+ }
+};
+
+/**
+ * Moves to the next occurrence of a node that matches the given predicate,
+ * if one exists, using the linearDomWalker.
+ * @param {function(Array.<Node>)} predicate A function taking an array
+ * of unique ancestor nodes as a parameter and returning true if it's
+ * what to search for.
+ * @return {boolean} True if a match was found.
+ */
+cvox.ChromeVoxNavigationManager.prototype.findNext = function(predicate) {
+ this.syncPosition();
+ var node = undefined;
+ while (true) {
+ node = this.linearDomWalker.next();
+ if (!node) {
+ break;
+ }
+
+ if (predicate(this.linearDomWalker.getUniqueAncestors())) {
+ break;
+ }
+ }
+
+ if (node) {
+ cvox.SelectionUtil.selectAllTextInNode(node);
+ this.currentNode = node;
+ return true;
+ }
+
+ return false;
+};
+
+/**
+ * Moves to the previous occurrence of a node that matches the given predicate,
+ * if one exists, using the linearDomWalker.
+ * @param {function(Array.<Node>)} predicate A function taking an array
+ * of unique ancestor nodes as a parameter and returning true if it's
+ * what to search for.
+ * @return {boolean} True if a match was found.
+ */
+cvox.ChromeVoxNavigationManager.prototype.findPrevious = function(predicate) {
+ this.syncPosition();
+ var node = undefined;
+ while (true) {
+ node = this.linearDomWalker.previous();
+ if (!node) {
+ break;
+ }
+
+ if (predicate(this.linearDomWalker.getUniqueAncestors())) {
+ break;
+ }
+ }
+
+ if (node) {
+ cvox.SelectionUtil.selectAllTextInNode(node);
+ this.currentNode = node;
+ return true;
+ }
+
+ return false;
+};
+
+/**
+ * Returns the current navigation strategy.
+ *
+ * @return {string} The strategy that is being used.
+ */
+cvox.ChromeVoxNavigationManager.prototype.getStrategy = function() {
+ return cvox.ChromeVoxNavigationManager.STRATEGY_NAMES[
+ this.currentNavStrategy];
+};
+
+/**
+ * Returns the current selection granularity.
+ *
+ * @return {string} The selection granularity that is being used.
+ */
+cvox.ChromeVoxNavigationManager.prototype.getGranularity = function() {
+ return this.selectionWalker.getGranularity();
+};
+
+/**
+ * Synchronizes the current position between the different navigation
+ * strategies.
+ */
+cvox.ChromeVoxNavigationManager.prototype.syncPosition = function() {
+ if (!this.currentNode) {
+ this.currentNode = document.body;
+ }
+ if (this.currentNavStrategy != this.lastUsedNavStrategy) {
+ if ((this.lastUsedNavStrategy ==
+ cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM) ||
+ (this.lastUsedNavStrategy ==
+ cvox.ChromeVoxNavigationManager.STRATEGIES.SMART)) {
+ this.syncToNode(this.currentNode);
+ } else {
+ this.syncToSelection();
+ }
+ }
+ this.lastUsedNavStrategy = this.currentNavStrategy;
+};
+
+/**
+ * Synchronizes the navigation strategies to the current selection.
+ */
+cvox.ChromeVoxNavigationManager.prototype.syncToSelection = function() {
+ if (window.getSelection() && window.getSelection().anchorNode) {
+ this.currentNode = window.getSelection().anchorNode;
+ this.linearDomWalker.setCurrentNode(this.currentNode);
+ }
+};
+
+/**
+ * Synchronizes the navigation strategies to the targetNode.
+ *
+ * @param {Node} targetNode The node that the navigation strategies should be
+ * synced to.
+ */
+cvox.ChromeVoxNavigationManager.prototype.syncToNode = function(targetNode) {
+ if (cvox.DomUtil.isDescendantOfNode(this.currentNode, targetNode)) {
+ // User is already synced at a more specific level than the target;
+ // therefore ignore the sync request.
+ return;
+ }
+ this.currentNode = targetNode;
+ this.linearDomWalker.setCurrentNode(targetNode);
+ var range = document.createRange();
+ range.selectNode(this.currentNode);
+ window.getSelection().removeAllRanges();
+ window.getSelection().addRange(range);
+ window.getSelection().collapseToStart();
+};
+
+/**
+ * Returns only the text content for the current position.
+ *
+ * @return {string} The current text content.
+ */
+cvox.ChromeVoxNavigationManager.prototype.getCurrentContent = function() {
+ switch (this.currentNavStrategy) {
+ default:
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.CUSTOM:
+ return this.customWalker.getCurrentContent();
+ break;
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.SMART:
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM:
+ return cvox.DomUtil.getText(this.currentNode);
+ break;
+
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.SELECTION:
+ return this.selectionWalker.getCurrentContent();
+ break;
+ }
+};
+
+/**
+ * Returns a complete description of the current position, including
+ * the text content and annotations such as "link", "button", etc.
+ *
+ * @return {string} The summary of the current position.
+ */
+cvox.ChromeVoxNavigationManager.prototype.getCurrentDescription = function() {
+ switch (this.currentNavStrategy) {
+ default:
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.CUSTOM:
+ return this.customWalker.getCurrentDescription();
+ break;
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.SMART:
+ // Use a linear DOM walker in non-smart mode to traverse all of the
+ // nodes inside the current smart node and append all of their
+ // descriptions.
+ var description = '';
+ var walker = new cvox.LinearDomWalker();
+ walker.currentNode = this.linearDomWalker.currentNode;
+ walker.useSmartNav = false;
+ walker.previous();
+ walker.next();
+ while (cvox.DomUtil.isDescendantOfNode(
+ walker.currentNode, this.linearDomWalker.currentNode)) {
+ description = description + ' ' +
+ cvox.DomUtil.getText(walker.currentNode) + ' ' +
+ cvox.DomUtil.getInformationFromAncestors(
+ walker.getUniqueAncestors());
+ walker.next();
+ }
+ return description;
+
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM:
+ return this.getCurrentContent() + ' ' +
+ cvox.DomUtil.getInformationFromAncestors(this.getChangedAncestors());
+
+ case cvox.ChromeVoxNavigationManager.STRATEGIES.SELECTION:
+ return this.getCurrentContent() + ' ' +
+ cvox.DomUtil.getInformationFromAncestors(
+ this.selectionUniqueAncestors);
+ }
+};
+
+/**
+ * Returns an array of ancestor nodes that have been changed between the
+ * previous position and the current current position.
+ *
+ * @return {Array.<Node>} The current content.
+ */
+cvox.ChromeVoxNavigationManager.prototype.getChangedAncestors = function() {
+ return this.linearDomWalker.getUniqueAncestors();
+};
+
+/**
+ * Sets the browser's focus to the current node.
+ */
+cvox.ChromeVoxNavigationManager.prototype.setFocus = function() {
+ cvox.DomUtil.setFocus(this.linearDomWalker.getCurrentNode());
+};
+
+/**
+ * Acts on the current item and displays a disambiguation dialog
+ * if more than one action is possible.
+ *
+ * @return {boolean} True if an action was taken.
+ */
+cvox.ChromeVoxNavigationManager.prototype.actOnCurrentItem = function() {
+ if (this.currentNavStrategy ==
+ cvox.ChromeVoxNavigationManager.STRATEGIES.CUSTOM) {
+ return this.customWalker.actOnCurrentItem();
+ } else if (this.currentNavStrategy ==
+ cvox.ChromeVoxNavigationManager.STRATEGIES.SMART) {
+ if (this.currentNode && this.currentNode.tagName &&
+ (this.currentNode.tagName == 'A')) {
+ cvox.DomUtil.clickElem(this.currentNode, false);
+ return true;
+ } else {
+ var aNodes = this.currentNode.getElementsByTagName('A');
+ if (aNodes.length == 1) {
+ cvox.DomUtil.clickElem(aNodes[0], false);
+ return true;
+ } else if (aNodes.length > 1) {
+ var descriptions = new Array();
+ var functions = new Array();
+ for (var i = 0, link; link = aNodes[i]; i++) {
+ if (cvox.DomUtil.hasContent(link)) {
+ descriptions.push(cvox.DomUtil.getText(link));
+ functions.push(cvox.ChromeVoxNavigationManager
+ .createSimpleClickFunction(link));
+ }
+ }
+ this.choiceWidget.show(descriptions, functions,
+ descriptions.toString());
+ return true;
+ }
+ }
+ }
+ return false;
+};
+
+/**
+ * Checks if the navigation manager is able to act on the current item.
+ *
+ * @return {boolean} True if some action is possible.
+ */
+cvox.ChromeVoxNavigationManager.prototype.canActOnCurrentItem = function() {
+ if (this.currentNavStrategy ==
+ cvox.ChromeVoxNavigationManager.STRATEGIES.CUSTOM) {
+ return this.customWalker.canActOnCurrentItem();
+ }
+ if (this.currentNavStrategy ==
+ cvox.ChromeVoxNavigationManager.STRATEGIES.SMART) {
+ if (this.currentNode && this.currentNode.tagName &&
+ (this.currentNode.tagName == 'A')) {
+ return true;
+ } else {
+ var aNodes = this.currentNode.getElementsByTagName('A');
+ if (aNodes.length > 0) {
+ return true;
+ }
+ }
+ }
+ // Anything that is DOM level or lower will always be handled by the browser.
+ return false;
+};
+
+/**
+ * Creates a simple function that will click on the given targetNode when
+ * invoked.
+ * Note that we are using this function because functions created inside a loop
+ * have to be created by another function and not within the loop directly.
+ *
+ * See: http://joust.kano.net/weblog/archive/2005/08/08/
+ * a-huge-gotcha-with-javascript-closures/
+ * @param {Node} targetNode The target node to click on.
+ * @return {function()} A function that will click on the given targetNode.
+ */
+cvox.ChromeVoxNavigationManager.createSimpleClickFunction = function(
+ targetNode) {
+ var target = targetNode.cloneNode(true);
+ return function() { cvox.DomUtil.clickElem(target, false); };
+};
+
+/**
+ * Sets the custom walker to use for the current site.
+ *
+ * @param {Object} customWalkerObj The custom walker to use.
+ */
+cvox.ChromeVoxNavigationManager.prototype.setCustomWalker =
+ function(customWalkerObj) {
+ this.customWalker = customWalkerObj;
+ this.currentNavStrategy = 3;
+ this.lastUsedNavStrategy = 3;
+};
+
Property changes on: chrome/browser/resources/access_chromevox/chromevox/injected/navigation_manager.js
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:eol-style
+ LF

Powered by Google App Engine
This is Rietveld 408576698