| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 | 5 |
| 6 /** | 6 /** |
| 7 * @fileoverview Uses ChromeVox API to enhance the search experience. | 7 * @fileoverview Uses ChromeVox API to enhance the search experience. |
| 8 */ | 8 */ |
| 9 | 9 |
| 10 goog.provide('cvox.Search'); | 10 goog.provide('cvox.Search'); |
| 11 | 11 |
| 12 goog.require('cvox.ChromeVox'); | 12 goog.require('cvox.ChromeVox'); |
| 13 goog.require('cvox.SearchConstants'); | 13 goog.require('cvox.SearchConstants'); |
| 14 goog.require('cvox.SearchResults'); | 14 goog.require('cvox.SearchResults'); |
| 15 goog.require('cvox.SearchUtil'); | 15 goog.require('cvox.SearchUtil'); |
| 16 goog.require('cvox.UnknownResult'); | 16 goog.require('cvox.UnknownResult'); |
| 17 | 17 |
| 18 /** | 18 /** |
| 19 * @constructor | 19 * @constructor |
| 20 */ | 20 */ |
| 21 cvox.Search = function() { | 21 cvox.Search = function() {}; |
| 22 }; | |
| 23 | 22 |
| 24 /** | 23 /** |
| 25 * Selectors to match results. | 24 * Selectors to match results. |
| 26 * @type {Object<string>} | 25 * @type {Object<string>} |
| 27 */ | 26 */ |
| 28 cvox.Search.selectors = {}; | 27 cvox.Search.selectors = {}; |
| 29 | 28 |
| 30 /** | 29 /** |
| 31 * Selectors for web results. | 30 * Selectors for web results. |
| 32 */ | 31 */ |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 var isSpoken = resultType.speak(result); | 92 var isSpoken = resultType.speak(result); |
| 94 cvox.ChromeVox.syncToNode(resultType.getSyncNode(result), !isSpoken); | 93 cvox.ChromeVox.syncToNode(resultType.getSyncNode(result), !isSpoken); |
| 95 cvox.Search.isPane = false; | 94 cvox.Search.isPane = false; |
| 96 }; | 95 }; |
| 97 | 96 |
| 98 /** | 97 /** |
| 99 * Sync the search result index to ChromeVox. | 98 * Sync the search result index to ChromeVox. |
| 100 */ | 99 */ |
| 101 cvox.Search.syncToIndex = function() { | 100 cvox.Search.syncToIndex = function() { |
| 102 cvox.ChromeVox.tts.stop(); | 101 cvox.ChromeVox.tts.stop(); |
| 103 var prop = { endCallback: cvox.Search.speakSync_ }; | 102 var prop = {endCallback: cvox.Search.speakSync_}; |
| 104 if (cvox.Search.index === 0) { | 103 if (cvox.Search.index === 0) { |
| 105 cvox.ChromeVox.tts.speak('First result', cvox.QueueMode.QUEUE, prop); | 104 cvox.ChromeVox.tts.speak('First result', cvox.QueueMode.QUEUE, prop); |
| 106 } else if (cvox.Search.index === cvox.Search.results.length - 1) { | 105 } else if (cvox.Search.index === cvox.Search.results.length - 1) { |
| 107 cvox.ChromeVox.tts.speak('Last result', cvox.QueueMode.QUEUE, prop); | 106 cvox.ChromeVox.tts.speak('Last result', cvox.QueueMode.QUEUE, prop); |
| 108 } else { | 107 } else { |
| 109 cvox.Search.speakSync_(); | 108 cvox.Search.speakSync_(); |
| 110 } | 109 } |
| 111 }; | 110 }; |
| 112 | 111 |
| 113 /** | 112 /** |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 */ | 161 */ |
| 163 cvox.Search.navigatePage = function(next) { | 162 cvox.Search.navigatePage = function(next) { |
| 164 /* NavEnd contains previous / next page links. */ | 163 /* NavEnd contains previous / next page links. */ |
| 165 var NAV_END_CLASS = 'navend'; | 164 var NAV_END_CLASS = 'navend'; |
| 166 var navEnds = document.getElementsByClassName(NAV_END_CLASS); | 165 var navEnds = document.getElementsByClassName(NAV_END_CLASS); |
| 167 var navEnd = next ? navEnds[1] : navEnds[0]; | 166 var navEnd = next ? navEnds[1] : navEnds[0]; |
| 168 var url = cvox.SearchUtil.extractURL(navEnd); | 167 var url = cvox.SearchUtil.extractURL(navEnd); |
| 169 var navToUrl = function() { | 168 var navToUrl = function() { |
| 170 window.location = url; | 169 window.location = url; |
| 171 }; | 170 }; |
| 172 var prop = { endCallback: navToUrl }; | 171 var prop = {endCallback: navToUrl}; |
| 173 if (url) { | 172 if (url) { |
| 174 var pageNumber = cvox.Search.getPageNumber(url); | 173 var pageNumber = cvox.Search.getPageNumber(url); |
| 175 if (!isNaN(pageNumber)) { | 174 if (!isNaN(pageNumber)) { |
| 176 cvox.ChromeVox.tts.speak('Page ' + pageNumber, cvox.QueueMode.FLUSH, | 175 cvox.ChromeVox.tts.speak( |
| 177 prop); | 176 'Page ' + pageNumber, cvox.QueueMode.FLUSH, prop); |
| 178 } else { | 177 } else { |
| 179 cvox.ChromeVox.tts.speak('Unknown page.', cvox.QueueMode.FLUSH, prop); | 178 cvox.ChromeVox.tts.speak('Unknown page.', cvox.QueueMode.FLUSH, prop); |
| 180 } | 179 } |
| 181 } | 180 } |
| 182 }; | 181 }; |
| 183 | 182 |
| 184 /** | 183 /** |
| 185 * Navigates to the currently synced pane. | 184 * Navigates to the currently synced pane. |
| 186 */ | 185 */ |
| 187 cvox.Search.goToPane = function() { | 186 cvox.Search.goToPane = function() { |
| 188 var pane = cvox.Search.panes[cvox.Search.paneIndex]; | 187 var pane = cvox.Search.panes[cvox.Search.paneIndex]; |
| 189 if (pane.className === cvox.Search.SELECTED_PANE_CLASS) { | 188 if (pane.className === cvox.Search.SELECTED_PANE_CLASS) { |
| 190 cvox.ChromeVox.tts.speak('You are already on that page.', | 189 cvox.ChromeVox.tts.speak( |
| 191 cvox.QueueMode.QUEUE); | 190 'You are already on that page.', cvox.QueueMode.QUEUE); |
| 192 return; | 191 return; |
| 193 } | 192 } |
| 194 var anchor = pane.querySelector('a'); | 193 var anchor = pane.querySelector('a'); |
| 195 cvox.ChromeVox.tts.speak(anchor.textContent, cvox.QueueMode.QUEUE); | 194 cvox.ChromeVox.tts.speak(anchor.textContent, cvox.QueueMode.QUEUE); |
| 196 var url = cvox.SearchUtil.extractURL(pane); | 195 var url = cvox.SearchUtil.extractURL(pane); |
| 197 if (url) { | 196 if (url) { |
| 198 window.location = url; | 197 window.location = url; |
| 199 } | 198 } |
| 200 }; | 199 }; |
| 201 | 200 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 226 if (evt.shiftKey || evt.altKey || evt.ctrlKey) { | 225 if (evt.shiftKey || evt.altKey || evt.ctrlKey) { |
| 227 return false; | 226 return false; |
| 228 } | 227 } |
| 229 | 228 |
| 230 /* Do not handle if search input has focus, or if the search widget | 229 /* Do not handle if search input has focus, or if the search widget |
| 231 * has focus. | 230 * has focus. |
| 232 */ | 231 */ |
| 233 if (document.activeElement !== searchInput && | 232 if (document.activeElement !== searchInput && |
| 234 !cvox.SearchUtil.isSearchWidgetActive()) { | 233 !cvox.SearchUtil.isSearchWidgetActive()) { |
| 235 switch (evt.keyCode) { | 234 switch (evt.keyCode) { |
| 236 case cvox.SearchConstants.KeyCode.UP: | 235 case cvox.SearchConstants.KeyCode.UP: |
| 237 /* Add results.length because JS Modulo is silly. */ | 236 /* Add results.length because JS Modulo is silly. */ |
| 238 cvox.Search.index = cvox.SearchUtil.subOneWrap(cvox.Search.index, | 237 cvox.Search.index = cvox.SearchUtil.subOneWrap( |
| 239 cvox.Search.results.length); | 238 cvox.Search.index, cvox.Search.results.length); |
| 240 if (cvox.Search.index === cvox.Search.results.length - 1) { | 239 if (cvox.Search.index === cvox.Search.results.length - 1) { |
| 241 cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.WRAP); | 240 cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.WRAP); |
| 242 } | 241 } |
| 243 cvox.Search.syncToIndex(); | 242 cvox.Search.syncToIndex(); |
| 244 break; | 243 break; |
| 245 | 244 |
| 246 case cvox.SearchConstants.KeyCode.DOWN: | 245 case cvox.SearchConstants.KeyCode.DOWN: |
| 247 cvox.Search.index = cvox.SearchUtil.addOneWrap(cvox.Search.index, | 246 cvox.Search.index = cvox.SearchUtil.addOneWrap( |
| 248 cvox.Search.results.length); | 247 cvox.Search.index, cvox.Search.results.length); |
| 249 if (cvox.Search.index === 0) { | 248 if (cvox.Search.index === 0) { |
| 250 cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.WRAP); | 249 cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.WRAP); |
| 251 } | 250 } |
| 252 cvox.Search.syncToIndex(); | 251 cvox.Search.syncToIndex(); |
| 253 break; | 252 break; |
| 254 | 253 |
| 255 case cvox.SearchConstants.KeyCode.PAGE_UP: | 254 case cvox.SearchConstants.KeyCode.PAGE_UP: |
| 256 cvox.Search.navigatePage(false); | 255 cvox.Search.navigatePage(false); |
| 257 break; | 256 break; |
| 258 | 257 |
| 259 case cvox.SearchConstants.KeyCode.PAGE_DOWN: | 258 case cvox.SearchConstants.KeyCode.PAGE_DOWN: |
| 260 cvox.Search.navigatePage(true); | 259 cvox.Search.navigatePage(true); |
| 261 break; | 260 break; |
| 262 | 261 |
| 263 case cvox.SearchConstants.KeyCode.LEFT: | 262 case cvox.SearchConstants.KeyCode.LEFT: |
| 264 cvox.Search.paneIndex = cvox.SearchUtil.subOneWrap(cvox.Search.paneIndex, | 263 cvox.Search.paneIndex = cvox.SearchUtil.subOneWrap( |
| 265 cvox.Search.panes.length); | 264 cvox.Search.paneIndex, cvox.Search.panes.length); |
| 266 cvox.Search.syncPaneToIndex(); | 265 cvox.Search.syncPaneToIndex(); |
| 267 break; | 266 break; |
| 268 | 267 |
| 269 case cvox.SearchConstants.KeyCode.RIGHT: | 268 case cvox.SearchConstants.KeyCode.RIGHT: |
| 270 cvox.Search.paneIndex = cvox.SearchUtil.addOneWrap(cvox.Search.paneIndex, | 269 cvox.Search.paneIndex = cvox.SearchUtil.addOneWrap( |
| 271 cvox.Search.panes.length); | 270 cvox.Search.paneIndex, cvox.Search.panes.length); |
| 272 cvox.Search.syncPaneToIndex(); | 271 cvox.Search.syncPaneToIndex(); |
| 273 break; | 272 break; |
| 274 | 273 |
| 275 case cvox.SearchConstants.KeyCode.ENTER: | 274 case cvox.SearchConstants.KeyCode.ENTER: |
| 276 if (cvox.Search.isPane) { | 275 if (cvox.Search.isPane) { |
| 277 cvox.Search.goToPane(); | 276 cvox.Search.goToPane(); |
| 278 } else { | 277 } else { |
| 279 cvox.Search.goToResult(); | 278 cvox.Search.goToResult(); |
| 280 } | 279 } |
| 281 break; | 280 break; |
| 282 | 281 |
| 283 default: | 282 default: |
| 284 return false; | 283 return false; |
| 285 } | 284 } |
| 286 evt.preventDefault(); | 285 evt.preventDefault(); |
| 287 evt.stopPropagation(); | 286 evt.stopPropagation(); |
| 288 return true; | 287 return true; |
| 289 } | 288 } |
| 290 return false; | 289 return false; |
| 291 }; | 290 }; |
| 292 | 291 |
| 293 /** | 292 /** |
| 294 * Adds the elements that match the selector to results. | 293 * Adds the elements that match the selector to results. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 var SEARCH_AREA_SELECT = '#rg_s'; | 341 var SEARCH_AREA_SELECT = '#rg_s'; |
| 343 var target = document.querySelector(SEARCH_AREA_SELECT); | 342 var target = document.querySelector(SEARCH_AREA_SELECT); |
| 344 | 343 |
| 345 var observer = new MutationObserver(function(mutations) { | 344 var observer = new MutationObserver(function(mutations) { |
| 346 cvox.Search.results = []; | 345 cvox.Search.results = []; |
| 347 cvox.Search.populateResults(); | 346 cvox.Search.populateResults(); |
| 348 }); | 347 }); |
| 349 | 348 |
| 350 var config = | 349 var config = |
| 351 /** @type MutationObserverInit */ | 350 /** @type MutationObserverInit */ |
| 352 ({ attributes: true, childList: true, characterData: true }); | 351 ({attributes: true, childList: true, characterData: true}); |
| 353 observer.observe(target, config); | 352 observer.observe(target, config); |
| 354 }; | 353 }; |
| 355 | 354 |
| 356 /** | 355 /** |
| 357 * Get the current selected pane's index. | 356 * Get the current selected pane's index. |
| 358 * @return {number} Index of selected pane. | 357 * @return {number} Index of selected pane. |
| 359 */ | 358 */ |
| 360 cvox.Search.getSelectedPaneIndex = function() { | 359 cvox.Search.getSelectedPaneIndex = function() { |
| 361 var panes = cvox.Search.panes; | 360 var panes = cvox.Search.panes; |
| 362 for (var i = 0; i < panes.length; i++) { | 361 for (var i = 0; i < panes.length; i++) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 | 412 |
| 414 /* Determine the type of search. */ | 413 /* Determine the type of search. */ |
| 415 var SELECTED_CLASS = 'hdtb-msel'; | 414 var SELECTED_CLASS = 'hdtb-msel'; |
| 416 var selected = document.getElementsByClassName(SELECTED_CLASS)[0]; | 415 var selected = document.getElementsByClassName(SELECTED_CLASS)[0]; |
| 417 if (!selected) { | 416 if (!selected) { |
| 418 return; | 417 return; |
| 419 } | 418 } |
| 420 | 419 |
| 421 var selectedHTML = selected.innerHTML; | 420 var selectedHTML = selected.innerHTML; |
| 422 switch (selectedHTML) { | 421 switch (selectedHTML) { |
| 423 case 'Web': | 422 case 'Web': |
| 424 case 'News': | 423 case 'News': |
| 425 cvox.Search.selectors = cvox.Search.webSelectors; | 424 cvox.Search.selectors = cvox.Search.webSelectors; |
| 426 break; | 425 break; |
| 427 case 'Images': | 426 case 'Images': |
| 428 cvox.Search.selectors = cvox.Search.imageSelectors; | 427 cvox.Search.selectors = cvox.Search.imageSelectors; |
| 429 cvox.Search.observeMutation(); | 428 cvox.Search.observeMutation(); |
| 430 break; | 429 break; |
| 431 default: | 430 default: |
| 432 return; | 431 return; |
| 433 } | 432 } |
| 434 | 433 |
| 435 cvox.Search.populateResults(); | 434 cvox.Search.populateResults(); |
| 436 cvox.Search.populatePanes(); | 435 cvox.Search.populatePanes(); |
| 437 cvox.Search.paneIndex = cvox.Search.getSelectedPaneIndex(); | 436 cvox.Search.paneIndex = cvox.Search.getSelectedPaneIndex(); |
| 438 | 437 |
| 439 cvox.Search.initialSync(); | 438 cvox.Search.initialSync(); |
| 440 | 439 |
| 441 }; | 440 }; |
| OLD | NEW |