| Index: chrome/browser/resources/access_chromevox/chromevox/injected/tools/search.js
|
| ===================================================================
|
| --- chrome/browser/resources/access_chromevox/chromevox/injected/tools/search.js (revision 0)
|
| +++ chrome/browser/resources/access_chromevox/chromevox/injected/tools/search.js (revision 0)
|
| @@ -0,0 +1,300 @@
|
| +// 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 JavaScript for poppup up a search widget and performing
|
| + * search within a page.
|
| + */
|
| +
|
| +goog.provide('cvox.ChromeVoxSearch');
|
| +
|
| +goog.require('cvox.AbstractEarcons');
|
| +goog.require('cvox.ChromeVox');
|
| +goog.require('cvox.SelectionUtil');
|
| +goog.require('cvox.XpathUtil');
|
| +
|
| +/**
|
| + * @type {Object}
|
| + */
|
| +cvox.ChromeVoxSearch.txtNode = null;
|
| +
|
| +/**
|
| + * @type {boolean}
|
| + */
|
| +cvox.ChromeVoxSearch.active = false;
|
| +
|
| +/**
|
| + * @type {Array?}
|
| + */
|
| +cvox.ChromeVoxSearch.matchNodes = null;
|
| +
|
| +/**
|
| + * @type {number?}
|
| + */
|
| +cvox.ChromeVoxSearch.matchNodesIndex = null;
|
| +
|
| +/**
|
| + * @type {boolean}
|
| + */
|
| +cvox.ChromeVoxSearch.caseSensitive = false;
|
| +
|
| +/**
|
| + * Initializes the search widget.
|
| + */
|
| +cvox.ChromeVoxSearch.init = function() {
|
| + cvox.ChromeVoxSearch.active = false;
|
| + cvox.ChromeVoxSearch.caseSensitive = false;
|
| + window.addEventListener('keypress', cvox.ChromeVoxSearch.processKeyPress,
|
| + true);
|
| + window.addEventListener('keydown', cvox.ChromeVoxSearch.processKeyDown,
|
| + true);
|
| + window.addEventListener('scroll', cvox.ChromeVoxSearch.scrollHandler,
|
| + true);
|
| +};
|
| +
|
| +/**
|
| + * Returns whether or not the search widget is active.
|
| + *
|
| + * @return {boolean} True if the search widget is active.
|
| + */
|
| +cvox.ChromeVoxSearch.isActive = function() {
|
| + return cvox.ChromeVoxSearch.active;
|
| +};
|
| +
|
| +/**
|
| + * Displays the search widget.
|
| + */
|
| +cvox.ChromeVoxSearch.show = function() {
|
| + cvox.ChromeVoxSearch.txtNode = document.createElement('div');
|
| + cvox.ChromeVoxSearch.txtNode.style['display'] = 'block';
|
| + cvox.ChromeVoxSearch.txtNode.style['position'] = 'absolute';
|
| + cvox.ChromeVoxSearch.txtNode.style['left'] = '2px';
|
| + cvox.ChromeVoxSearch.txtNode.style['top'] = (window.scrollY + 2) + 'px';
|
| + cvox.ChromeVoxSearch.txtNode.style['line-height'] = '1.2em';
|
| + cvox.ChromeVoxSearch.txtNode.style['z-index'] = '10001';
|
| + cvox.ChromeVoxSearch.txtNode.style['font-size'] = '20px';
|
| +
|
| + document.body.insertBefore(cvox.ChromeVoxSearch.txtNode,
|
| + document.body.firstChild);
|
| + cvox.ChromeVoxSearch.active = true;
|
| +};
|
| +
|
| +/**
|
| + * Keeps the search widget at the upperleft hand corner of the screen when
|
| + * the page scrolls.
|
| + */
|
| +cvox.ChromeVoxSearch.scrollHandler = function() {
|
| + if (!cvox.ChromeVoxSearch.active) {
|
| + return;
|
| + }
|
| + cvox.ChromeVoxSearch.txtNode.style['top'] = (window.scrollY + 2) + 'px';
|
| +};
|
| +
|
| +/**
|
| + * Handles the keyDown event when the search widget is active.
|
| + *
|
| + * @param {Object} evt The keyDown event.
|
| + * @return {boolean} Whether or not the event was handled.
|
| + */
|
| +cvox.ChromeVoxSearch.processKeyDown = function(evt) {
|
| + if (!cvox.ChromeVoxSearch.active) {
|
| + return false;
|
| + }
|
| + if (evt.keyCode == 8) { // Backspace
|
| + var searchStr = cvox.ChromeVoxSearch.txtNode.textContent;
|
| + if (searchStr.length > 0) {
|
| + searchStr = searchStr.substring(searchStr, searchStr.length - 1);
|
| + cvox.ChromeVoxSearch.doSearch(searchStr,
|
| + cvox.ChromeVoxSearch.caseSensitive);
|
| + }
|
| + // Don't go to the previous page!
|
| + evt.preventDefault();
|
| + return true;
|
| + } else if (evt.keyCode == 40) { // Down arrow
|
| + cvox.ChromeVoxSearch.next();
|
| + return true;
|
| + } else if (evt.keyCode == 38) { // Up arrow
|
| + cvox.ChromeVoxSearch.prev();
|
| + return true;
|
| + } else if (evt.ctrlKey && evt.keyCode == 67) { // ctrl + c
|
| + cvox.ChromeVoxSearch.toggleCaseSensitivity();
|
| + return true;
|
| + }
|
| + return false;
|
| +};
|
| +
|
| +/**
|
| + * Adds the letter the user typed to the search string and updates the search.
|
| + *
|
| + * @param {Object} evt The keyPress event.
|
| + * @return {boolean} Whether or not the event was handled.
|
| + */
|
| +cvox.ChromeVoxSearch.processKeyPress = function(evt) {
|
| + if (!cvox.ChromeVoxSearch.active) {
|
| + return false;
|
| + }
|
| + var searchStr = cvox.ChromeVoxSearch.txtNode.textContent +
|
| + String.fromCharCode(evt.charCode);
|
| + cvox.ChromeVoxSearch.doSearch(searchStr,
|
| + cvox.ChromeVoxSearch.caseSensitive);
|
| + evt.preventDefault();
|
| + evt.stopPropagation();
|
| + return true;
|
| +};
|
| +
|
| +/**
|
| + * Toggles whether or not searches are case sensitive.
|
| + */
|
| +cvox.ChromeVoxSearch.toggleCaseSensitivity = function() {
|
| + if (cvox.ChromeVoxSearch.caseSensitive) {
|
| + cvox.ChromeVoxSearch.caseSensitive = false;
|
| + cvox.ChromeVox.tts.speak('Ignoring case', 0, null);
|
| + } else {
|
| + cvox.ChromeVoxSearch.caseSensitive = true;
|
| + cvox.ChromeVox.tts.speak('Case sensitive', 0, null);
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * Performs the search and highlights and speaks the first result.
|
| + *
|
| + * @param {String} searchStr The text to search for.
|
| + * @param {boolean} caseSensitive Whether or not the search is case sensitive.
|
| + */
|
| +cvox.ChromeVoxSearch.doSearch = function(searchStr, caseSensitive) {
|
| + cvox.ChromeVoxSearch.txtNode.textContent = '';
|
| +
|
| + cvox.ChromeVoxSearch.matchNodes = new Array();
|
| + var potentialMatchNodes;
|
| + if (caseSensitive) {
|
| + potentialMatchNodes = cvox.XpathUtil.evalXPath(
|
| + './/text()[contains(.,"' + searchStr + '")]',
|
| + document.body);
|
| + } else {
|
| + searchStr = searchStr.toLowerCase();
|
| + potentialMatchNodes = cvox.XpathUtil.evalXPath(
|
| + './/text()[contains(translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZ", ' +
|
| + '"abcdefghijklmnopqrstuvwxyz"), "' + searchStr + '")]',
|
| + document.body);
|
| + }
|
| + // Only accept nodes that are considered to have content.
|
| + for (var i = 0, node; node = potentialMatchNodes[i]; i++) {
|
| + if (cvox.DomUtil.hasContent(node)) {
|
| + cvox.ChromeVoxSearch.matchNodes.push(node);
|
| + }
|
| + }
|
| +
|
| + var firstNode = cvox.ChromeVoxSearch.matchNodes[0];
|
| +
|
| + if (firstNode) {
|
| + cvox.ChromeVoxSearch.matchNodesIndex = 0;
|
| + var startIndex = 0;
|
| + if (caseSensitive) {
|
| + startIndex = firstNode.textContent.indexOf(searchStr);
|
| + } else {
|
| + startIndex = firstNode.textContent.toLowerCase().indexOf(searchStr);
|
| + }
|
| + cvox.SelectionUtil.selectText(firstNode, startIndex,
|
| + startIndex + searchStr.length);
|
| + cvox.ChromeVox.traverseContent.moveNext('sentence');
|
| + var sel = window.getSelection();
|
| + var range = sel.getRangeAt(0);
|
| + range.setStart(firstNode, startIndex);
|
| + sel.removeAllRanges();
|
| + sel.addRange(range);
|
| + cvox.SelectionUtil.scrollToSelection(sel);
|
| + cvox.ChromeVox.tts.speak(window.getSelection() + '', 0, null);
|
| + } else {
|
| + // TODO (clchen): Replace this with an error sound once we have one defined.
|
| + cvox.ChromeVox.tts.stop();
|
| + cvox.ChromeVox.earcons.playEarcon(cvox.AbstractEarcons.WRAP);
|
| + }
|
| + cvox.ChromeVoxSearch.txtNode.textContent = searchStr;
|
| +};
|
| +
|
| +/**
|
| + * Dismisses the search widget
|
| + */
|
| +cvox.ChromeVoxSearch.hide = function() {
|
| + if (cvox.ChromeVoxSearch.active) {
|
| + cvox.ChromeVoxSearch.txtNode.parentNode.removeChild(
|
| + cvox.ChromeVoxSearch.txtNode);
|
| + cvox.ChromeVoxSearch.txtNode = null;
|
| + cvox.ChromeVoxSearch.active = false;
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * Goes to the next matching result, highlights it, and speaks it.
|
| + */
|
| +cvox.ChromeVoxSearch.next = function() {
|
| + if (cvox.ChromeVoxSearch.matchNodes &&
|
| + (cvox.ChromeVoxSearch.matchNodes.length > 0)) {
|
| + cvox.ChromeVoxSearch.matchNodesIndex++;
|
| + if (cvox.ChromeVoxSearch.matchNodes.length >
|
| + cvox.ChromeVoxSearch.matchNodesIndex) {
|
| + var searchStr = cvox.ChromeVoxSearch.txtNode.textContent;
|
| + var targetNode = cvox.ChromeVoxSearch.matchNodes[
|
| + cvox.ChromeVoxSearch.matchNodesIndex];
|
| + var startIndex = 0;
|
| + if (cvox.ChromeVoxSearch.caseSensitive) {
|
| + startIndex = targetNode.textContent.indexOf(searchStr);
|
| + } else {
|
| + startIndex = targetNode.textContent.toLowerCase().indexOf(
|
| + searchStr.toLowerCase());
|
| + }
|
| + cvox.SelectionUtil.selectText(targetNode, startIndex,
|
| + startIndex + searchStr.length);
|
| + cvox.ChromeVox.traverseContent.moveNext('sentence');
|
| + var sel = window.getSelection();
|
| + var range = sel.getRangeAt(0);
|
| + range.setStart(targetNode, startIndex);
|
| + sel.removeAllRanges();
|
| + sel.addRange(range);
|
| + cvox.SelectionUtil.scrollToSelection(sel);
|
| + cvox.ChromeVox.tts.speak(window.getSelection() + '', 0, null);
|
| + } else {
|
| + cvox.ChromeVox.earcons.playEarcon(cvox.AbstractEarcons.WRAP);
|
| + cvox.ChromeVoxSearch.matchNodesIndex = -1;
|
| + cvox.ChromeVoxSearch.next();
|
| + }
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * Goes to the previous matching result, highlights it, and speaks it.
|
| + */
|
| +cvox.ChromeVoxSearch.prev = function() {
|
| + if (cvox.ChromeVoxSearch.matchNodes &&
|
| + (cvox.ChromeVoxSearch.matchNodes.length > 0)) {
|
| + cvox.ChromeVoxSearch.matchNodesIndex--;
|
| + if (cvox.ChromeVoxSearch.matchNodesIndex > -1) {
|
| + var searchStr = cvox.ChromeVoxSearch.txtNode.textContent;
|
| + var targetNode = cvox.ChromeVoxSearch.matchNodes[
|
| + cvox.ChromeVoxSearch.matchNodesIndex];
|
| + var startIndex = 0;
|
| + if (cvox.ChromeVoxSearch.caseSensitive) {
|
| + startIndex = targetNode.textContent.indexOf(searchStr);
|
| + } else {
|
| + startIndex = targetNode.textContent.toLowerCase().indexOf(
|
| + searchStr.toLowerCase());
|
| + }
|
| + cvox.SelectionUtil.selectText(targetNode, startIndex,
|
| + startIndex + searchStr.length);
|
| + cvox.ChromeVox.traverseContent.moveNext('sentence');
|
| + var sel = window.getSelection();
|
| + var range = sel.getRangeAt(0);
|
| + range.setStart(targetNode, startIndex);
|
| + sel.removeAllRanges();
|
| + sel.addRange(range);
|
| + cvox.SelectionUtil.scrollToSelection(sel);
|
| + cvox.ChromeVox.tts.speak(window.getSelection() + '', 0, null);
|
| + } else {
|
| + cvox.ChromeVox.earcons.playEarcon(cvox.AbstractEarcons.WRAP);
|
| + cvox.ChromeVoxSearch.matchNodesIndex =
|
| + cvox.ChromeVoxSearch.matchNodes.length;
|
| + cvox.ChromeVoxSearch.prev();
|
| + }
|
| + }
|
| +};
|
|
|
| Property changes on: chrome/browser/resources/access_chromevox/chromevox/injected/tools/search.js
|
| ___________________________________________________________________
|
| Added: svn:executable
|
| + *
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|