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