PageRenderTime 24ms CodeModel.GetById 2ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 1ms

/WebVox/res/raw/basic.user.js

http://eyes-free.googlecode.com/
JavaScript | 363 lines | 323 code | 23 blank | 17 comment | 122 complexity | 3ba988c3877b79cc1269747bd8c05a6f MD5 | raw file
  1// ==UserScript==
  2// @name          CVOX
  3// @description   Generic CVOX Script
  4// @author        Charles L. Chen
  5// @include       http://*
  6// ==/UserScript==
  7
  8var currentElem = null;
  9var prevElem = null;
 10var inputFocused = false;
 11
 12function getNextLeafNode(){
 13  prevElem = currentElem;
 14  if (currentElem == null){
 15    currentElem = document.body;
 16  } else {
 17    while (!currentElem.nextSibling){
 18    currentElem = currentElem.parentNode;
 19    if (currentElem == document.body){
 20      currentElem = null;
 21      return currentElem;
 22    }
 23  }
 24  currentElem = currentElem.nextSibling;
 25  }
 26  while (currentElem.firstChild){
 27    currentElem = currentElem.firstChild;
 28  }
 29  return currentElem;  
 30}
 31
 32function getPrevLeafNode(){
 33  prevElem = currentElem;
 34  if (currentElem == null){
 35    currentElem = document.body;
 36  } else {
 37    while (!currentElem.previousSibling){
 38    currentElem = currentElem.parentNode;
 39    if (currentElem == document.body){
 40      currentElem = null;
 41      return currentElem;
 42    }
 43  }
 44  currentElem = currentElem.previousSibling;
 45  }
 46  while (currentElem.lastChild){
 47    currentElem = currentElem.lastChild;
 48  }
 49  return currentElem;  
 50}
 51
 52function containsText(textStr){
 53  if (textStr === null){
 54    return false;
 55  }
 56  if (textStr.length < 1){
 57    return false;
 58  }
 59  var myregexp = new RegExp("[a-zA-Z0-9]");
 60  return myregexp.test(textStr);
 61}
 62
 63function getLineage(targetNode){
 64  var lineage = new Array();
 65  while (targetNode){
 66    lineage.push(targetNode);      
 67    targetNode = targetNode.parentNode;
 68  }
 69  lineage.reverse();
 70  while(lineage.length && !lineage[0].tagName && !lineage[0].nodeValue){
 71    lineage.shift();
 72  }
 73  return lineage;
 74}
 75
 76//Compares Lineage A with Lineage B and returns
 77//the index value in B at which B diverges from A.
 78//If there is no divergence, the result will be -1.
 79//Note that if B is the same as A except B has more nodes
 80//even after A has ended, that is considered a divergence.
 81//The first node that B has which A does not have will
 82//be treated as the divergence point.
 83//
 84function compareLineages(lina, linb){
 85  var i = 0;
 86  while( lina[i] && linb[i] && (lina[i] == linb[i]) ){
 87    i++;
 88  }
 89  if ( !lina[i] && !linb[i] ){
 90    i = -1;
 91  }
 92  return i;
 93}
 94
 95function hasTagInLineage(elem, tag){
 96  var node = elem;
 97  while(node){
 98    if (node.tagName && node.tagName == tag){
 99      return true;
100    }
101    node = node.parentNode;
102  }
103  return false;
104}
105
106function getText(elem){
107  if (elem.tagName && elem.tagName == 'IMG'){
108    return elem.alt;
109  }
110  return elem.textContent;
111}
112
113var readingMode = 1; // 0 = detailed, 1 = skim, 2 = headings only
114
115function isSkippable(elem){
116  if (hasTagInLineage(elem, 'SCRIPT')){
117    return true;
118  }
119  if (readingMode === 0){
120    return false;
121  } else if (readingMode == 1){
122    if (hasTagInLineage(elem, 'P')){
123      return false;
124    }
125    if (hasTagInLineage(elem, 'H1')){
126      return false;
127    }
128    if (hasTagInLineage(elem, 'H2')){
129      return false;
130    }
131    if (hasTagInLineage(elem, 'H3')){
132      return false;
133    }
134    if (hasTagInLineage(elem, 'H4')){
135      return false;
136    }
137    if (hasTagInLineage(elem, 'H5')){
138      return false;
139    }
140    if (hasTagInLineage(elem, 'H6')){
141      return false;
142    }
143    if (hasTagInLineage(elem, 'OL')){
144      return false;
145    }
146    if (hasTagInLineage(elem, 'UL')){
147      return false;
148    }
149    if (hasTagInLineage(elem, 'DL')){
150      return false;
151    }
152    if (hasTagInLineage(elem, 'BLOCKQUOTE')){
153      return false;
154    }
155    if (hasTagInLineage(elem, 'DIV')){
156      return false;
157    }
158    return true;
159  } else if (readingMode == 2) {
160    if (hasTagInLineage(elem, 'H1')){
161      return false;
162    }
163    if (hasTagInLineage(elem, 'H2')){
164      return false;
165    }
166    if (hasTagInLineage(elem, 'H3')){
167      return false;
168    }
169    if (hasTagInLineage(elem, 'H4')){
170      return false;
171    }
172    if (hasTagInLineage(elem, 'H5')){
173      return false;
174    }
175    if (hasTagInLineage(elem, 'H6')){
176      return false;
177    }
178    return true;
179  }  
180}
181
182function getInfoOnCurrentElem(){
183  var currentLineage = getLineage(currentElem);
184  var divergence = compareLineages(getLineage(prevElem), currentLineage);
185  var infoStr = "";
186  for (var i=divergence, elem; elem = currentLineage[i]; i++){
187    if (elem.tagName){
188    if (elem.tagName == 'H1'){
189      infoStr = infoStr + 'H 1. ';
190    } else if (elem.tagName == 'H2'){
191      infoStr = infoStr + 'H 2. ';
192    } else if (elem.tagName == 'H3'){
193      infoStr = infoStr + 'H 3. ';
194    } else if (elem.tagName == 'H4'){
195      infoStr = infoStr + 'H 4. ';
196    } else if (elem.tagName == 'H5'){
197      infoStr = infoStr + 'H 5. ';
198    } else if (elem.tagName == 'H6'){
199      infoStr = infoStr + 'H 6. ';
200    } else if (elem.tagName == 'A'){
201      infoStr = infoStr + 'Link. ';
202    }
203  }
204  }
205  return infoStr;
206}
207
208function readNext(){
209  getNextLeafNode();
210  var textContent = getText(currentElem);
211  while (!containsText(textContent)){
212    getNextLeafNode();
213    if (currentElem === null){
214      speak("End of document", 0, null);
215      return false;
216    }
217    textContent = getText(currentElem);
218  }
219  if (isSkippable(currentElem)){
220    return readNext();
221  } else {
222    speak(getInfoOnCurrentElem() + ' ' + textContent, 0, null);
223    scrollToElem(currentElem);
224    return true;
225  }
226}
227
228function readPrev(){
229  getPrevLeafNode();
230  var textContent = getText(currentElem);
231  while (!containsText(textContent)){
232    getPrevLeafNode();
233    if (currentElem === null){
234      speak("Beginning of document", 0, null);
235      return false;
236    }
237    textContent = getText(currentElem);
238  }
239  if (isSkippable(currentElem)){
240    return readPrev();
241  } else {
242    speak(getInfoOnCurrentElem() + ' ' + textContent, 0, null);
243    scrollToElem(currentElem);
244    return true;
245  }
246}
247
248function scrollToElem(targetNode){
249  while (!targetNode.offsetParent){
250    targetNode = targetNode.parentNode;
251  }
252  var left = 0;
253  var top = 0;
254  while (targetNode.offsetParent) { 
255    left += targetNode.offsetLeft;
256    top += targetNode.offsetTop; 
257    targetNode = targetNode.offsetParent;
258  }
259  left += targetNode.offsetLeft;
260  top += targetNode.offsetTop;
261  window.scrollTo(left, top);
262}
263
264function speak(textStr, queueMode, paramsArray){
265  window.ttsHelper.speak(textStr, queueMode);
266  //alert(textStr);
267}
268
269function isSpeaking(){
270  return window.ttsHelper.isSpeaking();
271}
272
273var keepGoing = true;
274
275function autoRead(){  
276  if (!isSpeaking()){
277    keepGoing = readNext();
278  }
279  if (keepGoing){
280    window.setTimeout(autoRead, 1000);
281  }
282}
283
284//TODO: Come up with a working escape sequence!
285function keyPressHandler(evt){
286  var keyCode = evt.keyCode;
287  if (inputFocused){
288    return true;
289  }
290  if (keyCode == 97) { // a
291    keepGoing = true;
292    autoRead();
293    return false;
294  }  
295  if (keyCode == 106) { // j
296    readNext();
297    return false;
298  }
299  if (keyCode == 107) { // k
300    readPrev();
301    return false;
302  } 
303  if (keyCode == 104) { // h
304    readingMode++;
305    if (readingMode > 2){
306      readingMode = 0;
307    }
308    if (readingMode == 0){
309      speak("All", 0, null);
310    } else if (readingMode == 1){
311      speak("Quick", 0, null);
312    } else if (readingMode == 2){
313      speak("Headings", 0, null);
314    } 
315    return false;
316  }   
317  return true;
318}
319
320function keyDownHandler(evt){
321  keepGoing = false;
322  window.ttsHelper.stop();
323  var keyCode = evt.keyCode;
324  if (inputFocused){
325    return true;
326  }
327  if ((keyCode == 32) || (keyCode == 13)) { // space or Enter (G1 enter key does not work)
328    var targetElem = currentElem;
329    while (targetElem){
330	  if (targetElem.tagName == 'A'){
331	    document.location = targetElem.href;
332      return false;
333	  }
334	  targetElem = targetElem.parentNode;
335	}
336    return true;
337  }
338  return true;
339}
340
341function focusHandler(evt){
342  if (evt.target.tagName && 
343      evt.target.tagName == 'INPUT'){
344      inputFocused = true;
345      }
346  return true;
347}
348
349function blurHandler(evt){
350  inputFocused = false;
351  return true;
352}
353
354if (document.location.toString().indexOf('http://www.google.com/m?') === 0){
355  // Do nothing, rely on mgws script
356} else 
357if (document.location.toString().indexOf('http://www.google.com/search?') != 0){
358  document.addEventListener('keypress', keyPressHandler, true);
359  document.addEventListener('keydown', keyDownHandler, true);
360  document.addEventListener('focus', focusHandler, true);
361  document.addEventListener('blur', blurHandler, true);
362  speak(document.title, 0, null);
363}