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

Unified Diff: chrome/browser/resources/access_chromevox/common/traverse_content.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/traverse_content.js
===================================================================
--- chrome/browser/resources/access_chromevox/common/traverse_content.js (revision 0)
+++ chrome/browser/resources/access_chromevox/common/traverse_content.js (revision 0)
@@ -0,0 +1,381 @@
+// 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 DOM traversal interface for moving a selection around a
+ * webpage. Provides multiple granularities:
+ * 1. Move by paragraph.
+ * 2. Move by sentence.
+ * 3. Move by line.
+ * 4. Move by word.
+ * 5. Move by character.
+ */
+
+goog.provide('cvox.TraverseContent');
+
+goog.require('cvox.SelectionUtil');
+goog.require('cvox.TraverseUtil');
+
+/**
+ * Moves a selection around a document or within a provided DOM object.
+ *
+ * @constructor
+ * @param {Node=} domObj a DOM node (optional).
+ */
+cvox.TraverseContent = function(domObj) {
+ if (domObj != null) {
+ this.currentDomObj = domObj;
+ } else {
+ this.currentDomObj = document.body;
+ }
+};
+
+/**
+ * Whether we should skip whitespace when traversing individual characters.
+ * @type {boolean}
+ */
+cvox.TraverseContent.prototype.skipWhitespace = true;
+
+/**
+ * The maximum number of characters that can be on one line when doing
+ * line-based traversal.
+ * @type {number}
+ */
+cvox.TraverseContent.prototype.lineLength = 40;
+
+/**
+ * If moveNext and movePrev should skip past an invalid selection,
+ * so the user never gets stuck. Ideally the navigation code should never
+ * return a range that's not a valid selection, but this keeps the user from
+ * getting stuck if that code fails. This is set to false for unit testing.
+ * @type {boolean}
+ */
+cvox.TraverseContent.prototype.skipInvalidSelections = true;
+
+/**
+ * If line and sentence navigation should break at <a> links.
+ * @type {boolean}
+ */
+cvox.TraverseContent.prototype.breakAtLinks = false;
+
+/**
+ * The string constant for character granularity.
+ * @type {string}
+ * @const
+ */
+cvox.TraverseContent.kCharacter = 'character';
+
+/**
+ * The string constant for word granularity.
+ * @type {string}
+ * @const
+ */
+cvox.TraverseContent.kWord = 'word';
+
+/**
+ * The string constant for sentence granularity.
+ * @type {string}
+ * @const
+ */
+cvox.TraverseContent.kSentence = 'sentence';
+
+/**
+ * The string constant for line granularity.
+ * @type {string}
+ * @const
+ */
+cvox.TraverseContent.kLine = 'line';
+
+/**
+ * The string constant for paragraph granularity.
+ * @type {string}
+ * @const
+ */
+cvox.TraverseContent.kParagraph = 'paragraph';
+
+/**
+ * A constant array of all granularities.
+ * @type {Array.<string>}
+ * @const
+ */
+cvox.TraverseContent.kAllGrains =
+ [cvox.TraverseContent.kParagraph,
+ cvox.TraverseContent.kSentence,
+ cvox.TraverseContent.kLine,
+ cvox.TraverseContent.kWord,
+ cvox.TraverseContent.kCharacter];
+
+/**
+ * Moves selection forward.
+ *
+ * @param {string} grain specifies "sentence", "word", "character",
+ * or "paragraph" granularity.
+ * @return {Selection} Either:
+ * 1) The fixed-up selection.
+ * 2) null if the end of the domObj has been reached.
+ */
+cvox.TraverseContent.prototype.moveNext = function(grain) {
+ this.normalizeSelection();
+
+ var selection = window.getSelection();
+ var startCursor = new Cursor(
+ selection.anchorNode, selection.anchorOffset,
+ cvox.TraverseUtil.getNodeText(selection.anchorNode));
+ var endCursor = new Cursor(
+ selection.focusNode, selection.focusOffset,
+ cvox.TraverseUtil.getNodeText(selection.focusNode));
+ var breakTags = this.getBreakTags();
+ // As a special case, if the current selection is empty or all
+ // whitespace, ensure that the next returned selection will NOT be
+ // only whitespace - otherwise you can get trapped.
+ var skipWhitespace = this.skipWhitespace;
+ if (!cvox.SelectionUtil.isSelectionValid(selection))
+ skipWhitespace = true;
+
+ var nodesCrossed = [];
+ var str;
+
+ do {
+ if (grain === cvox.TraverseContent.kSentence) {
+ str = cvox.TraverseUtil.getNextSentence(
+ startCursor, endCursor, nodesCrossed, breakTags);
+ } else if (grain === cvox.TraverseContent.kWord) {
+ str = cvox.TraverseUtil.getNextWord(startCursor, endCursor,
+ nodesCrossed);
+ } else if (grain === cvox.TraverseContent.kCharacter) {
+ str = cvox.TraverseUtil.getNextChar(startCursor, endCursor,
+ nodesCrossed, skipWhitespace);
+ } else if (grain === cvox.TraverseContent.kParagraph) {
+ str = cvox.TraverseUtil.getNextParagraph(startCursor, endCursor,
+ nodesCrossed);
+ } else if (grain === cvox.TraverseContent.kLine) {
+ str = cvox.TraverseUtil.getNextLine(
+ startCursor, endCursor, nodesCrossed, this.lineLength, breakTags);
+ } else {
+ // User has provided an invalid string.
+ // Fall through to default: extend by sentence
+ console.log('Invalid selection granularity: "' + grain + '"');
+ grain = cvox.TraverseContent.kSentence;
+ str = cvox.TraverseUtil.getNextSentence(
+ startCursor, endCursor, nodesCrossed, breakTags);
+ }
+
+ // Select the new object.
+ selection = cvox.TraverseUtil.setSelection(startCursor, endCursor);
+
+ if (str == null) {
+ // We reached the end of the document.
+ return null;
+ }
+ } while (this.skipInvalidSelections && selection.isCollapsed);
+
+ if (!cvox.SelectionUtil.isWithinBound(selection.focusNode,
+ this.currentDomObj)) {
+ // Extended outside of specified domObj; trim it back to just the domObj
+ // if we are dealing with a text node.
+ // Return NULL to indicate that we are wrapping to the beginning.
+ if (selection.anchorNode.nodeType == 3) { // NODETYPE 3 == text node
+ cvox.SelectionUtil.selectText(selection.anchorNode,
+ selection.anchorOffset,
+ selection.anchorNode.textContent.length);
+ }
+ return null;
+ }
+ return selection;
+};
+
+
+/**
+ * Moves selection backward.
+ *
+ * @param {string} grain specifies "sentence", "word", "character",
+ * or "paragraph" granularity.
+ * @return {Selection} Either:
+ * 1) The fixed-up selection.
+ * 2) null if the beginning of the domObj has been reached.
+ */
+cvox.TraverseContent.prototype.movePrev = function(grain) {
+ this.normalizeSelection();
+
+ var selection = window.getSelection();
+ var startCursor = new Cursor(
+ selection.anchorNode, selection.anchorOffset,
+ cvox.TraverseUtil.getNodeText(selection.anchorNode));
+ var endCursor = new Cursor(
+ selection.focusNode, selection.focusOffset,
+ cvox.TraverseUtil.getNodeText(selection.focusNode));
+ var breakTags = this.getBreakTags();
+ // As a special case, if the current selection is empty or all
+ // whitespace, ensure that the next returned selection will NOT be
+ // only whitespace - otherwise you can get trapped.
+ var skipWhitespace = this.skipWhitespace;
+ if (!cvox.SelectionUtil.isSelectionValid(selection))
+ skipWhitespace = true;
+
+ var nodesCrossed = [];
+ var str;
+
+ do {
+ if (grain === cvox.TraverseContent.kSentence) {
+ str = cvox.TraverseUtil.getPreviousSentence(
+ startCursor, endCursor, nodesCrossed, breakTags);
+ } else if (grain === cvox.TraverseContent.kWord) {
+ str = cvox.TraverseUtil.getPreviousWord(startCursor, endCursor,
+ nodesCrossed);
+ } else if (grain === cvox.TraverseContent.kCharacter) {
+ var skipWhitespace = this.skipWhitespace;
+ if (!cvox.SelectionUtil.isSelectionValid(selection))
+ skipWhitespace = true;
+ str = cvox.TraverseUtil.getPreviousChar(startCursor, endCursor,
+ nodesCrossed, skipWhitespace);
+ } else if (grain === cvox.TraverseContent.kParagraph) {
+ str = cvox.TraverseUtil.getPreviousParagraph(
+ startCursor, endCursor, nodesCrossed);
+ } else if (grain === cvox.TraverseContent.kLine) {
+ str = cvox.TraverseUtil.getPreviousLine(
+ startCursor, endCursor, nodesCrossed, this.lineLength, breakTags);
+ } else {
+ // User has provided an invalid string.
+ // Fall through to default: extend by sentence
+ console.log('Invalid selection granularity: "' + grain + '"');
+ grain = cvox.TraverseContent.kSentence;
+ str = cvox.TraverseUtil.getPreviousSentence(
+ startCursor, endCursor, nodesCrossed, breakTags);
+ }
+
+ // Select the new object.
+ selection = cvox.TraverseUtil.setSelection(startCursor, endCursor);
+
+ if (str == null) {
+ // We reached the end of the document.
+ return null;
+ }
+
+ } while (this.skipInvalidSelections && selection.isCollapsed);
+
+ if (!cvox.SelectionUtil.isWithinBound(selection.focusNode,
+ this.currentDomObj)) {
+ console.log('not within bound');
+ // Extended outside of specified domObj, nothing more to be done
+ // Return NULL to indicate that we are wrapping to the beginning
+ return null;
+ }
+
+ return selection;
+};
+
+/**
+ * Get the tag names that should break a sentence or line. Currently
+ * just an anchor 'A' should break a sentence or line if the breakAtLinks
+ * flag is true, but in the future we might have other rules for breaking.
+ *
+ * @return {Object} An associative array mapping a tag name to true if
+ * it should break a sentence or line.
+ */
+cvox.TraverseContent.prototype.getBreakTags = function() {
+ return this.breakAtLinks ? {'A': true} : {};
+};
+
+/**
+ * Selects the next element of the document or within the provided DOM object.
+ * Scrolls the window as appropriate.
+ *
+ * @param {string} grain specifies "sentence", "word", "character",
+ * or "paragraph" granularity.
+ * @param {Node=} domObj a DOM node (optional).
+ * @return {Selection} Either:
+ * 1) The current selection.
+ * 2) null if the end of the domObj has been reached.
+ */
+cvox.TraverseContent.prototype.nextElement = function(grain, domObj) {
+
+ if (domObj != null) {
+ this.currentDomObj = domObj;
+ }
+
+ if (! ((grain === 'sentence') || (grain === 'word') ||
+ (grain === 'character') || (grain === 'paragraph'))) {
+ // User has provided an invalid string.
+ // Fall through to default: extend by sentence
+ console.log('Invalid selection granularity: "' + grain + '"');
+ grain = 'sentence';
+ }
+
+ var status = this.moveNext(grain);
+ if (status != null) {
+ // Force window scroll to current selection
+ cvox.SelectionUtil.scrollToSelection(window.getSelection());
+ }
+
+ return status;
+};
+
+
+/**
+ * Selects the previous element of the document or within the provided DOM
+ * object. Scrolls the window as appropriate.
+ *
+ * @param {string} grain specifies "sentence", "word", "character",
+ * or "paragraph" granularity.
+ * @param {Node=} domObj a DOM node (optional).
+ * @return {Selection} Either:
+ * 1) The current selection.
+ * 2) null if the beginning of the domObj has been reached.
+ */
+cvox.TraverseContent.prototype.prevElement = function(grain, domObj) {
+
+ if (domObj != null) {
+ this.currentDomObj = domObj;
+ }
+
+ if (! ((grain === 'sentence') || (grain === 'word') ||
+ (grain === 'character') || (grain === 'paragraph'))) {
+ // User has provided an invalid string.
+ // Fall through to default: extend by sentence
+ console.log('Invalid selection granularity: "' + grain + '"');
+ grain = 'sentence';
+ }
+
+ var status = this.movePrev(grain);
+ if (status != null) {
+ // Force window scroll to current selection
+ cvox.SelectionUtil.scrollToSelection(window.getSelection());
+ }
+
+ return status;
+};
+
+/**
+ * Make sure that exactly one item is selected. If there's no selection,
+ * set the selection to the start of the document.
+ */
+cvox.TraverseContent.prototype.normalizeSelection = function() {
+ var selection = window.getSelection();
+ if (selection.rangeCount < 1) {
+ // Before the user has clicked a freshly-loaded page
+
+ var range = document.createRange();
+ range.setStart(this.currentDomObj, 0);
+ range.setEnd(this.currentDomObj, 0);
+
+ selection.removeAllRanges();
+ selection.addRange(range);
+
+ } else if (selection.rangeCount > 1) {
+ // Multiple ranges exist - remove all ranges but the last one
+ for (var i = 0; i < (selection.rangeCount - 1); i++) {
+ selection.removeRange(selection.getRangeAt(i));
+ }
+ }
+};
+
+/**
+ * Resets the selection.
+ *
+ * @param {Node=} domObj a DOM node. Optional.
+ *
+ */
+cvox.TraverseContent.prototype.reset = function(domObj) {
+ window.getSelection().removeAllRanges();
+};
Property changes on: chrome/browser/resources/access_chromevox/common/traverse_content.js
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:eol-style
+ LF

Powered by Google App Engine
This is Rietveld 408576698