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

Side by Side Diff: chrome/browser/resources/access_chromevox/chromevox/injected/tools/search.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 unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:executable
+ *
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6 * @fileoverview JavaScript for poppup up a search widget and performing
7 * search within a page.
8 */
9
10 goog.provide('cvox.ChromeVoxSearch');
11
12 goog.require('cvox.AbstractEarcons');
13 goog.require('cvox.ChromeVox');
14 goog.require('cvox.SelectionUtil');
15 goog.require('cvox.XpathUtil');
16
17 /**
18 * @type {Object}
19 */
20 cvox.ChromeVoxSearch.txtNode = null;
21
22 /**
23 * @type {boolean}
24 */
25 cvox.ChromeVoxSearch.active = false;
26
27 /**
28 * @type {Array?}
29 */
30 cvox.ChromeVoxSearch.matchNodes = null;
31
32 /**
33 * @type {number?}
34 */
35 cvox.ChromeVoxSearch.matchNodesIndex = null;
36
37 /**
38 * @type {boolean}
39 */
40 cvox.ChromeVoxSearch.caseSensitive = false;
41
42 /**
43 * Initializes the search widget.
44 */
45 cvox.ChromeVoxSearch.init = function() {
46 cvox.ChromeVoxSearch.active = false;
47 cvox.ChromeVoxSearch.caseSensitive = false;
48 window.addEventListener('keypress', cvox.ChromeVoxSearch.processKeyPress,
49 true);
50 window.addEventListener('keydown', cvox.ChromeVoxSearch.processKeyDown,
51 true);
52 window.addEventListener('scroll', cvox.ChromeVoxSearch.scrollHandler,
53 true);
54 };
55
56 /**
57 * Returns whether or not the search widget is active.
58 *
59 * @return {boolean} True if the search widget is active.
60 */
61 cvox.ChromeVoxSearch.isActive = function() {
62 return cvox.ChromeVoxSearch.active;
63 };
64
65 /**
66 * Displays the search widget.
67 */
68 cvox.ChromeVoxSearch.show = function() {
69 cvox.ChromeVoxSearch.txtNode = document.createElement('div');
70 cvox.ChromeVoxSearch.txtNode.style['display'] = 'block';
71 cvox.ChromeVoxSearch.txtNode.style['position'] = 'absolute';
72 cvox.ChromeVoxSearch.txtNode.style['left'] = '2px';
73 cvox.ChromeVoxSearch.txtNode.style['top'] = (window.scrollY + 2) + 'px';
74 cvox.ChromeVoxSearch.txtNode.style['line-height'] = '1.2em';
75 cvox.ChromeVoxSearch.txtNode.style['z-index'] = '10001';
76 cvox.ChromeVoxSearch.txtNode.style['font-size'] = '20px';
77
78 document.body.insertBefore(cvox.ChromeVoxSearch.txtNode,
79 document.body.firstChild);
80 cvox.ChromeVoxSearch.active = true;
81 };
82
83 /**
84 * Keeps the search widget at the upperleft hand corner of the screen when
85 * the page scrolls.
86 */
87 cvox.ChromeVoxSearch.scrollHandler = function() {
88 if (!cvox.ChromeVoxSearch.active) {
89 return;
90 }
91 cvox.ChromeVoxSearch.txtNode.style['top'] = (window.scrollY + 2) + 'px';
92 };
93
94 /**
95 * Handles the keyDown event when the search widget is active.
96 *
97 * @param {Object} evt The keyDown event.
98 * @return {boolean} Whether or not the event was handled.
99 */
100 cvox.ChromeVoxSearch.processKeyDown = function(evt) {
101 if (!cvox.ChromeVoxSearch.active) {
102 return false;
103 }
104 if (evt.keyCode == 8) { // Backspace
105 var searchStr = cvox.ChromeVoxSearch.txtNode.textContent;
106 if (searchStr.length > 0) {
107 searchStr = searchStr.substring(searchStr, searchStr.length - 1);
108 cvox.ChromeVoxSearch.doSearch(searchStr,
109 cvox.ChromeVoxSearch.caseSensitive);
110 }
111 // Don't go to the previous page!
112 evt.preventDefault();
113 return true;
114 } else if (evt.keyCode == 40) { // Down arrow
115 cvox.ChromeVoxSearch.next();
116 return true;
117 } else if (evt.keyCode == 38) { // Up arrow
118 cvox.ChromeVoxSearch.prev();
119 return true;
120 } else if (evt.ctrlKey && evt.keyCode == 67) { // ctrl + c
121 cvox.ChromeVoxSearch.toggleCaseSensitivity();
122 return true;
123 }
124 return false;
125 };
126
127 /**
128 * Adds the letter the user typed to the search string and updates the search.
129 *
130 * @param {Object} evt The keyPress event.
131 * @return {boolean} Whether or not the event was handled.
132 */
133 cvox.ChromeVoxSearch.processKeyPress = function(evt) {
134 if (!cvox.ChromeVoxSearch.active) {
135 return false;
136 }
137 var searchStr = cvox.ChromeVoxSearch.txtNode.textContent +
138 String.fromCharCode(evt.charCode);
139 cvox.ChromeVoxSearch.doSearch(searchStr,
140 cvox.ChromeVoxSearch.caseSensitive);
141 evt.preventDefault();
142 evt.stopPropagation();
143 return true;
144 };
145
146 /**
147 * Toggles whether or not searches are case sensitive.
148 */
149 cvox.ChromeVoxSearch.toggleCaseSensitivity = function() {
150 if (cvox.ChromeVoxSearch.caseSensitive) {
151 cvox.ChromeVoxSearch.caseSensitive = false;
152 cvox.ChromeVox.tts.speak('Ignoring case', 0, null);
153 } else {
154 cvox.ChromeVoxSearch.caseSensitive = true;
155 cvox.ChromeVox.tts.speak('Case sensitive', 0, null);
156 }
157 };
158
159 /**
160 * Performs the search and highlights and speaks the first result.
161 *
162 * @param {String} searchStr The text to search for.
163 * @param {boolean} caseSensitive Whether or not the search is case sensitive.
164 */
165 cvox.ChromeVoxSearch.doSearch = function(searchStr, caseSensitive) {
166 cvox.ChromeVoxSearch.txtNode.textContent = '';
167
168 cvox.ChromeVoxSearch.matchNodes = new Array();
169 var potentialMatchNodes;
170 if (caseSensitive) {
171 potentialMatchNodes = cvox.XpathUtil.evalXPath(
172 './/text()[contains(.,"' + searchStr + '")]',
173 document.body);
174 } else {
175 searchStr = searchStr.toLowerCase();
176 potentialMatchNodes = cvox.XpathUtil.evalXPath(
177 './/text()[contains(translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZ", ' +
178 '"abcdefghijklmnopqrstuvwxyz"), "' + searchStr + '")]',
179 document.body);
180 }
181 // Only accept nodes that are considered to have content.
182 for (var i = 0, node; node = potentialMatchNodes[i]; i++) {
183 if (cvox.DomUtil.hasContent(node)) {
184 cvox.ChromeVoxSearch.matchNodes.push(node);
185 }
186 }
187
188 var firstNode = cvox.ChromeVoxSearch.matchNodes[0];
189
190 if (firstNode) {
191 cvox.ChromeVoxSearch.matchNodesIndex = 0;
192 var startIndex = 0;
193 if (caseSensitive) {
194 startIndex = firstNode.textContent.indexOf(searchStr);
195 } else {
196 startIndex = firstNode.textContent.toLowerCase().indexOf(searchStr);
197 }
198 cvox.SelectionUtil.selectText(firstNode, startIndex,
199 startIndex + searchStr.length);
200 cvox.ChromeVox.traverseContent.moveNext('sentence');
201 var sel = window.getSelection();
202 var range = sel.getRangeAt(0);
203 range.setStart(firstNode, startIndex);
204 sel.removeAllRanges();
205 sel.addRange(range);
206 cvox.SelectionUtil.scrollToSelection(sel);
207 cvox.ChromeVox.tts.speak(window.getSelection() + '', 0, null);
208 } else {
209 // TODO (clchen): Replace this with an error sound once we have one defined.
210 cvox.ChromeVox.tts.stop();
211 cvox.ChromeVox.earcons.playEarcon(cvox.AbstractEarcons.WRAP);
212 }
213 cvox.ChromeVoxSearch.txtNode.textContent = searchStr;
214 };
215
216 /**
217 * Dismisses the search widget
218 */
219 cvox.ChromeVoxSearch.hide = function() {
220 if (cvox.ChromeVoxSearch.active) {
221 cvox.ChromeVoxSearch.txtNode.parentNode.removeChild(
222 cvox.ChromeVoxSearch.txtNode);
223 cvox.ChromeVoxSearch.txtNode = null;
224 cvox.ChromeVoxSearch.active = false;
225 }
226 };
227
228 /**
229 * Goes to the next matching result, highlights it, and speaks it.
230 */
231 cvox.ChromeVoxSearch.next = function() {
232 if (cvox.ChromeVoxSearch.matchNodes &&
233 (cvox.ChromeVoxSearch.matchNodes.length > 0)) {
234 cvox.ChromeVoxSearch.matchNodesIndex++;
235 if (cvox.ChromeVoxSearch.matchNodes.length >
236 cvox.ChromeVoxSearch.matchNodesIndex) {
237 var searchStr = cvox.ChromeVoxSearch.txtNode.textContent;
238 var targetNode = cvox.ChromeVoxSearch.matchNodes[
239 cvox.ChromeVoxSearch.matchNodesIndex];
240 var startIndex = 0;
241 if (cvox.ChromeVoxSearch.caseSensitive) {
242 startIndex = targetNode.textContent.indexOf(searchStr);
243 } else {
244 startIndex = targetNode.textContent.toLowerCase().indexOf(
245 searchStr.toLowerCase());
246 }
247 cvox.SelectionUtil.selectText(targetNode, startIndex,
248 startIndex + searchStr.length);
249 cvox.ChromeVox.traverseContent.moveNext('sentence');
250 var sel = window.getSelection();
251 var range = sel.getRangeAt(0);
252 range.setStart(targetNode, startIndex);
253 sel.removeAllRanges();
254 sel.addRange(range);
255 cvox.SelectionUtil.scrollToSelection(sel);
256 cvox.ChromeVox.tts.speak(window.getSelection() + '', 0, null);
257 } else {
258 cvox.ChromeVox.earcons.playEarcon(cvox.AbstractEarcons.WRAP);
259 cvox.ChromeVoxSearch.matchNodesIndex = -1;
260 cvox.ChromeVoxSearch.next();
261 }
262 }
263 };
264
265 /**
266 * Goes to the previous matching result, highlights it, and speaks it.
267 */
268 cvox.ChromeVoxSearch.prev = function() {
269 if (cvox.ChromeVoxSearch.matchNodes &&
270 (cvox.ChromeVoxSearch.matchNodes.length > 0)) {
271 cvox.ChromeVoxSearch.matchNodesIndex--;
272 if (cvox.ChromeVoxSearch.matchNodesIndex > -1) {
273 var searchStr = cvox.ChromeVoxSearch.txtNode.textContent;
274 var targetNode = cvox.ChromeVoxSearch.matchNodes[
275 cvox.ChromeVoxSearch.matchNodesIndex];
276 var startIndex = 0;
277 if (cvox.ChromeVoxSearch.caseSensitive) {
278 startIndex = targetNode.textContent.indexOf(searchStr);
279 } else {
280 startIndex = targetNode.textContent.toLowerCase().indexOf(
281 searchStr.toLowerCase());
282 }
283 cvox.SelectionUtil.selectText(targetNode, startIndex,
284 startIndex + searchStr.length);
285 cvox.ChromeVox.traverseContent.moveNext('sentence');
286 var sel = window.getSelection();
287 var range = sel.getRangeAt(0);
288 range.setStart(targetNode, startIndex);
289 sel.removeAllRanges();
290 sel.addRange(range);
291 cvox.SelectionUtil.scrollToSelection(sel);
292 cvox.ChromeVox.tts.speak(window.getSelection() + '', 0, null);
293 } else {
294 cvox.ChromeVox.earcons.playEarcon(cvox.AbstractEarcons.WRAP);
295 cvox.ChromeVoxSearch.matchNodesIndex =
296 cvox.ChromeVoxSearch.matchNodes.length;
297 cvox.ChromeVoxSearch.prev();
298 }
299 }
300 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698