| 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 * @fileoverview The entry point for all ChromeVox2 related code for the | 6 * @fileoverview The entry point for all ChromeVox2 related code for the |
| 7 * background page. | 7 * background page. |
| 8 */ | 8 */ |
| 9 | 9 |
| 10 goog.provide('Background'); | 10 goog.provide('Background'); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 this[func] = this[func].bind(this); | 79 this[func] = this[func].bind(this); |
| 80 } | 80 } |
| 81 | 81 |
| 82 /** | 82 /** |
| 83 * Maps an automation event to its listener. | 83 * Maps an automation event to its listener. |
| 84 * @type {!Object.<EventType, function(Object) : void>} | 84 * @type {!Object.<EventType, function(Object) : void>} |
| 85 */ | 85 */ |
| 86 this.listeners_ = { | 86 this.listeners_ = { |
| 87 alert: this.onEventDefault, | 87 alert: this.onEventDefault, |
| 88 focus: this.onEventDefault, | 88 focus: this.onEventDefault, |
| 89 hover: this.onEventDefault, | |
| 90 menuStart: this.onEventDefault, | 89 menuStart: this.onEventDefault, |
| 91 menuEnd: this.onEventDefault, | 90 menuEnd: this.onEventDefault, |
| 92 loadComplete: this.onLoadComplete, | 91 loadComplete: this.onLoadComplete, |
| 93 textChanged: this.onTextOrTextSelectionChanged, | 92 textSelectionChanged: this.onTextSelectionChanged |
| 94 textSelectionChanged: this.onTextOrTextSelectionChanged, | |
| 95 valueChanged: this.onEventDefault | |
| 96 }; | 93 }; |
| 97 | 94 |
| 98 // Register listeners for ... | 95 // Register listeners for ... |
| 99 // Desktop. | 96 // Desktop. |
| 100 chrome.automation.getDesktop(this.onGotTree); | 97 chrome.automation.getDesktop(this.onGotTree); |
| 101 | 98 |
| 102 // Tabs. | 99 // Tabs. |
| 103 chrome.tabs.onUpdated.addListener(this.onTabUpdated); | 100 chrome.tabs.onUpdated.addListener(this.onTabUpdated); |
| 101 |
| 102 // Commands. |
| 103 chrome.commands.onCommand.addListener(this.onGotCommand); |
| 104 }; | 104 }; |
| 105 | 105 |
| 106 Background.prototype = { | 106 Background.prototype = { |
| 107 /** | 107 /** |
| 108 * Handles chrome.tabs.onUpdated. | 108 * Handles chrome.tabs.onUpdated. |
| 109 * @param {number} tabId | 109 * @param {number} tabId |
| 110 * @param {Object} changeInfo | 110 * @param {Object} changeInfo |
| 111 */ | 111 */ |
| 112 onTabUpdated: function(tabId, changeInfo) { | 112 onTabUpdated: function(tabId, changeInfo) { |
| 113 if (changeInfo.status != 'complete') | 113 if (changeInfo.status != 'complete') |
| 114 return; | 114 return; |
| 115 chrome.tabs.get(tabId, function(tab) { | 115 chrome.tabs.get(tabId, function(tab) { |
| 116 if (!tab.url) | 116 if (!tab.url) |
| 117 return; | 117 return; |
| 118 | 118 |
| 119 var next = this.isWhitelisted_(tab.url); | 119 var next = this.isWhitelisted_(tab.url); |
| 120 | |
| 121 // Only care about Next for now. | |
| 122 if (!next) | |
| 123 return; | |
| 124 | |
| 125 this.toggleChromeVoxVersion({next: next, classic: !next}); | 120 this.toggleChromeVoxVersion({next: next, classic: !next}); |
| 126 }.bind(this)); | 121 }.bind(this)); |
| 127 }, | 122 }, |
| 128 | 123 |
| 129 /** | 124 /** |
| 130 * Handles all setup once a new automation tree appears. | 125 * Handles all setup once a new automation tree appears. |
| 131 * @param {chrome.automation.AutomationNode} root | 126 * @param {chrome.automation.AutomationNode} root |
| 132 */ | 127 */ |
| 133 onGotTree: function(root) { | 128 onGotTree: function(root) { |
| 134 // Register all automation event listeners. | 129 // Register all automation event listeners. |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 new Output(this.currentRange_, prevRange, Output.EventType.NAVIGATE); | 232 new Output(this.currentRange_, prevRange, Output.EventType.NAVIGATE); |
| 238 } | 233 } |
| 239 }, | 234 }, |
| 240 | 235 |
| 241 /** | 236 /** |
| 242 * Provides all feedback once ChromeVox's focus changes. | 237 * Provides all feedback once ChromeVox's focus changes. |
| 243 * @param {Object} evt | 238 * @param {Object} evt |
| 244 */ | 239 */ |
| 245 onEventDefault: function(evt) { | 240 onEventDefault: function(evt) { |
| 246 var node = evt.target; | 241 var node = evt.target; |
| 247 | |
| 248 if (!node) | 242 if (!node) |
| 249 return; | 243 return; |
| 250 | 244 |
| 251 var prevRange = this.currentRange_; | 245 var prevRange = this.currentRange_; |
| 252 this.currentRange_ = cursors.Range.fromNode(node); | 246 this.currentRange_ = cursors.Range.fromNode(node); |
| 253 | |
| 254 // Don't process nodes inside of web content if ChromeVox Next is inactive. | |
| 255 if (node.root.role != chrome.automation.RoleType.desktop && !this.active_) | |
| 256 return; | |
| 257 | |
| 258 new Output(this.currentRange_, prevRange, evt.type); | 247 new Output(this.currentRange_, prevRange, evt.type); |
| 259 }, | 248 }, |
| 260 | 249 |
| 261 /** | 250 /** |
| 262 * Provides all feedback once a load complete event fires. | 251 * Provides all feedback once a load complete event fires. |
| 263 * @param {Object} evt | 252 * @param {Object} evt |
| 264 */ | 253 */ |
| 265 onLoadComplete: function(evt) { | 254 onLoadComplete: function(evt) { |
| 266 var node = AutomationUtil.findNodePost(evt.target, | 255 var node = AutomationUtil.findNodePost(evt.target, |
| 267 Dir.FORWARD, | 256 Dir.FORWARD, |
| 268 AutomationPredicate.leaf); | 257 AutomationPredicate.leaf); |
| 269 if (node) | 258 if (node) |
| 270 this.currentRange_ = cursors.Range.fromNode(node); | 259 this.currentRange_ = cursors.Range.fromNode(node); |
| 271 | 260 |
| 272 if (this.currentRange_) | 261 if (this.currentRange_) |
| 273 new Output(this.currentRange_, null, evt.type); | 262 new Output(this.currentRange_, null, evt.type); |
| 274 }, | 263 }, |
| 275 | 264 |
| 276 /** | 265 /** |
| 277 * Provides all feedback once a text selection change event fires. | 266 * Provides all feedback once a text selection change event fires. |
| 278 * @param {Object} evt | 267 * @param {Object} evt |
| 279 */ | 268 */ |
| 280 onTextOrTextSelectionChanged: function(evt) { | 269 onTextSelectionChanged: function(evt) { |
| 281 if (!this.currentRange_) { | 270 if (!this.currentRange_) |
| 282 if (!evt.target.state.focused) | |
| 283 return; | |
| 284 | |
| 285 this.onEventDefault(evt); | |
| 286 this.currentRange_ = cursors.Range.fromNode(evt.target); | 271 this.currentRange_ = cursors.Range.fromNode(evt.target); |
| 287 } | |
| 288 | 272 |
| 289 var textChangeEvent = new cvox.TextChangeEvent( | 273 var textChangeEvent = new cvox.TextChangeEvent( |
| 290 evt.target.attributes.value, | 274 evt.target.attributes.value, |
| 291 evt.target.attributes.textSelStart, | 275 evt.target.attributes.textSelStart, |
| 292 evt.target.attributes.textSelEnd, | 276 evt.target.attributes.textSelEnd, |
| 293 true); // triggered by user | 277 true); // triggered by user |
| 294 if (!this.editableTextHandler || | 278 if (!this.editableTextHandler || |
| 295 evt.target != this.currentRange_.getStart().getNode()) { | 279 evt.target != this.currentRange_.getStart().getNode()) { |
| 296 this.editableTextHandler = | 280 this.editableTextHandler = |
| 297 new cvox.ChromeVoxEditableTextBase( | 281 new cvox.ChromeVoxEditableTextBase( |
| 298 textChangeEvent.value, | 282 textChangeEvent.value, |
| 299 textChangeEvent.start, | 283 textChangeEvent.start, |
| 300 textChangeEvent.end, | 284 textChangeEvent.end, |
| 301 evt.target.state['protected'], | 285 evt.target.state['protected'], |
| 302 cvox.ChromeVox.tts); | 286 cvox.ChromeVox.tts); |
| 303 } | 287 } |
| 304 | 288 |
| 305 this.editableTextHandler.changed(textChangeEvent); | 289 this.editableTextHandler.changed(textChangeEvent); |
| 306 new Output(this.currentRange_, null, evt.type, {braille: true}); | |
| 307 }, | 290 }, |
| 308 | 291 |
| 309 /** | 292 /** |
| 310 * @private | 293 * @private |
| 311 * @param {string} url | 294 * @param {string} url |
| 312 * @return {boolean} Whether the given |url| is whitelisted. | 295 * @return {boolean} Whether the given |url| is whitelisted. |
| 313 */ | 296 */ |
| 314 isWhitelisted_: function(url) { | 297 isWhitelisted_: function(url) { |
| 315 return this.whitelist_.some(function(item) { | 298 return this.whitelist_.some(function(item) { |
| 316 return url.indexOf(item) != -1; | 299 return url.indexOf(item) != -1; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 333 * @param {{classic: boolean, next: boolean}=} opt_options Forceably set. | 316 * @param {{classic: boolean, next: boolean}=} opt_options Forceably set. |
| 334 */ | 317 */ |
| 335 toggleChromeVoxVersion: function(opt_options) { | 318 toggleChromeVoxVersion: function(opt_options) { |
| 336 if (!opt_options) { | 319 if (!opt_options) { |
| 337 opt_options = {}; | 320 opt_options = {}; |
| 338 opt_options.next = !this.active_; | 321 opt_options.next = !this.active_; |
| 339 opt_options.classic = !opt_options.next; | 322 opt_options.classic = !opt_options.next; |
| 340 } | 323 } |
| 341 | 324 |
| 342 if (opt_options.next) { | 325 if (opt_options.next) { |
| 343 if (!chrome.commands.onCommand.hasListener(this.onGotCommand)) | 326 chrome.automation.getTree(this.onGotTree); |
| 344 chrome.commands.onCommand.addListener(this.onGotCommand); | |
| 345 | |
| 346 if (!this.active_) | |
| 347 chrome.automation.getTree(this.onGotTree); | |
| 348 this.active_ = true; | 327 this.active_ = true; |
| 349 } else { | 328 } else { |
| 350 if (chrome.commands.onCommand.hasListener(this.onGotCommand)) | |
| 351 chrome.commands.onCommand.removeListener(this.onGotCommand); | |
| 352 | |
| 353 if (this.active_) { | 329 if (this.active_) { |
| 354 for (var eventType in this.listeners_) { | 330 for (var eventType in this.listeners_) { |
| 355 this.currentRange_.getStart().getNode().root.removeEventListener( | 331 this.currentRange_.getStart().getNode().root.removeEventListener( |
| 356 eventType, this.listeners_[eventType], true); | 332 eventType, this.listeners_[eventType], true); |
| 357 } | 333 } |
| 358 } | 334 } |
| 359 this.active_ = false; | 335 this.active_ = false; |
| 360 } | 336 } |
| 361 | 337 |
| 362 chrome.tabs.query({active: true}, function(tabs) { | 338 chrome.tabs.query({active: true}, function(tabs) { |
| 363 if (opt_options.classic) { | 339 if (opt_options.classic) { |
| 364 cvox.ChromeVox.injectChromeVoxIntoTabs(tabs); | 340 cvox.ChromeVox.injectChromeVoxIntoTabs(tabs); |
| 365 } else { | 341 } else { |
| 366 tabs.forEach(function(tab) { | 342 tabs.forEach(function(tab) { |
| 367 this.disableClassicChromeVox_(tab.id); | 343 this.disableClassicChromeVox_(tab.id); |
| 368 }.bind(this)); | 344 }.bind(this)); |
| 369 } | 345 } |
| 370 }.bind(this)); | 346 }.bind(this)); |
| 371 } | 347 } |
| 372 }; | 348 }; |
| 373 | 349 |
| 374 /** @type {Background} */ | 350 /** @type {Background} */ |
| 375 global.backgroundObj = new Background(); | 351 global.backgroundObj = new Background(); |
| 376 | 352 |
| 377 }); // goog.scope | 353 }); // goog.scope |
| OLD | NEW |