Index: chrome/browser/resources/access_chromevox/common/extension_bridge.js |
=================================================================== |
--- chrome/browser/resources/access_chromevox/common/extension_bridge.js (revision 0) |
+++ chrome/browser/resources/access_chromevox/common/extension_bridge.js (revision 0) |
@@ -0,0 +1,273 @@ |
+// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+/** |
+ * @fileoverview Bridge to aid in communication between a Chrome |
+ * background page and scripts injected into a page by a content script. |
+ * |
+ * This is needed when the extension's content script dynamically loads |
+ * most of its code by injecting script tags into the page. To communicate |
+ * with the background page, the page script needs to post a message that |
+ * the content script can listen to and then forward to the background page. |
+ * |
+ * To use cvox.ExtensionBridge, this file must be included in all three |
+ * contexts: |
+ * |
+ * 1. From the background page. |
+ * 2. From the content script (in the manifest.json after all other scripts). |
+ * 3. Inject it into the page from the content script. |
+ * |
+ * It automatically figures out where it's being run and initializes itself |
+ * appropriately. Then just call send() to send a message from the background |
+ * to the page or vice versa, and addMessageListener() to provide a message |
+ * listener. Messages can be any object that can be serialized using JSON. |
+ * |
+ * Messages can be sent to the background page from either the page or the |
+ * content script, and messages sent from the background page are delivered |
+ * to both the content script and the page. |
+ */ |
+ |
+goog.provide('cvox.ExtensionBridge'); |
+ |
+goog.require('cvox.ChromeVoxJSON'); |
+ |
+if (BUILD_TYPE == BUILD_TYPE_CHROME) { |
+ /** |
+ * @constructor |
+ */ |
+ cvox.ExtensionBridge = function() {}; |
+ |
+ /** |
+ * Initialize the extension bridge. Dynamically figure out whether we're in |
+ * the background page, content script, or in a page, and call the |
+ * corresponding function for more specific initialization. |
+ */ |
+ cvox.ExtensionBridge.init = function() { |
+ var self = cvox.ExtensionBridge; |
+ self.listeners = []; |
+ |
+ try { |
+ if (chrome && chrome.windows) { |
+ // This depends on the fact that chrome.windows is only available |
+ // from background pages. |
+ self.json = JSON; |
+ self.context = self.BACKGROUND; |
+ self.initBackground(); |
+ return; |
+ } else { |
+ self.json = cvox.ChromeVoxJSON; |
+ self.context = self.PAGE; |
+ self.initPage(); |
+ return; |
+ } |
+ } catch (e) { |
+ // Ignore exception that might be raised if we try to access |
+ // chrome.windows from a content script. |
+ } |
+ |
+ if (chrome && chrome.extension) { |
+ self.json = JSON; |
+ self.context = self.CONTENT_SCRIPT; |
+ self.initContentScript(); |
+ } |
+ }; |
+ |
+ /** |
+ * Constant indicating we're in a background page. |
+ * @type {number} |
+ * @const |
+ */ |
+ cvox.ExtensionBridge.BACKGROUND = 0; |
+ |
+ /** |
+ * Constant indicating we're in a content script. |
+ * @type {number} |
+ * @const |
+ */ |
+ cvox.ExtensionBridge.CONTENT_SCRIPT = 1; |
+ |
+ /** |
+ * Constant indicating we're in a page. |
+ * @type {number} |
+ * @const |
+ */ |
+ cvox.ExtensionBridge.PAGE = 2; |
+ |
+ /** |
+ * The name of the port between the content script and background page. |
+ * @type {string} |
+ * @const |
+ */ |
+ cvox.ExtensionBridge.PORT_NAME = 'cvox.ExtensionBridge.Port'; |
+ |
+ /** |
+ * The name of the message between the page and content script that sets |
+ * up the bidirectional port between them. |
+ * @type {string} |
+ * @const |
+ */ |
+ cvox.ExtensionBridge.PORT_SETUP_MSG = 'cvox.ExtensionBridge.PortSetup'; |
+ |
+ /** |
+ * Send a message. If the context is a page, sends a message to the |
+ * extension background page. If the context is a background page, sends |
+ * a message to the current active tab (not all tabs). |
+ * |
+ * @param {Object} message The message to be sent. |
+ */ |
+ cvox.ExtensionBridge.send = function(message) { |
+ var self = cvox.ExtensionBridge; |
+ switch (self.context) { |
+ case self.BACKGROUND: |
+ self.sendBackgroundToContentScript(message); |
+ break; |
+ case self.CONTENT_SCRIPT: |
+ self.sendContentScriptToBackground(message); |
+ break; |
+ case self.PAGE: |
+ self.sendPageToContentScript(message); |
+ break; |
+ } |
+ }; |
+ |
+ /** |
+ * Provide a function to listen to messages. In page context, this |
+ * listens to messages from the background. In background context, |
+ * this listens to messages from all pages. |
+ * |
+ * The function gets called with two parameters: the message, and a |
+ * port that can be used to send replies. |
+ * |
+ * @param {function(Object, Port)} listener The message listener. |
+ */ |
+ cvox.ExtensionBridge.addMessageListener = function(listener) { |
+ cvox.ExtensionBridge.listeners.push(listener); |
+ }; |
+ |
+ /** |
+ * Initialize the extension bridge in a background page context by registering |
+ * a listener for connections from the content script. |
+ */ |
+ cvox.ExtensionBridge.initBackground = function() { |
+ var self = cvox.ExtensionBridge; |
+ |
+ chrome.extension.onConnect.addListener(function(port) { |
+ if (port.name != self.PORT_NAME) { |
+ return; |
+ } |
+ port.onMessage.addListener(function(message) { |
+ for (var i = 0; i < self.listeners.length; i++) { |
+ self.listeners[i](message, port); |
+ } |
+ }); |
+ }); |
+ }; |
+ |
+ /** |
+ * Initialize the extension bridge in a content script context, listening |
+ * for messages from the background page and accepting a bidirectional port |
+ * from the page. |
+ */ |
+ cvox.ExtensionBridge.initContentScript = function() { |
+ var self = cvox.ExtensionBridge; |
+ |
+ // Listen to requests from the background that don't come from |
+ // our connection port. |
+ chrome.extension.onRequest.addListener( |
+ function(request, sender, sendResponse) { |
+ for (var i = 0; i < self.listeners.length; i++) { |
+ self.listeners[i](request, self.backgroundPort); |
+ } |
+ if (self.port) { |
+ self.port.postMessage(self.json.stringify(request)); |
+ } |
+ sendResponse({}); |
+ }); |
+ |
+ // Listen to events on the main window and wait for a port setup message |
+ // from the page to continue. |
+ window.addEventListener('message', function(event) { |
+ if (event.data == self.PORT_SETUP_MSG) { |
+ // Now that we have a page connection, connect to background too. |
+ // (Don't do this earlier, otherwise initial messages from the |
+ // background wouldn't make it all the way through to the page.) |
+ self.backgroundPort = chrome.extension.connect({name: self.PORT_NAME}); |
+ self.backgroundPort.onMessage.addListener( |
+ function(message) { |
+ for (var i = 0; i < self.listeners.length; i++) { |
+ self.listeners[i](message, self.backgroundPort); |
+ } |
+ if (self.port) { |
+ self.port.postMessage(self.json.stringify(message)); |
+ } |
+ }); |
+ |
+ self.port = event.ports[0]; |
+ self.port.onmessage = function(event) { |
+ self.backgroundPort.postMessage(self.json.parse(event.data)); |
+ }; |
+ } |
+ }, false); |
+ }; |
+ |
+ /** |
+ * Initialize the extension bridge in a page context, creating a |
+ * MessageChannel and sending one of the ports to the content script |
+ * and then listening for messages on the other port. |
+ */ |
+ cvox.ExtensionBridge.initPage = function() { |
+ var self = cvox.ExtensionBridge; |
+ self.channel = new MessageChannel(); |
+ |
+ // Note: using postMessage.apply rather than just calling postMessage |
+ // directly because the 3-argument form of postMessage is still in the |
+ // HTML5 draft. |
+ window.postMessage.apply( |
+ window, [self.PORT_SETUP_MSG, [self.channel.port2], '*']); |
+ |
+ self.channel.port1.onmessage = function(event) { |
+ for (var i = 0; i < self.listeners.length; i++) { |
+ self.listeners[i](self.json.parse(event.data), self.channel.port1); |
+ } |
+ }; |
+ }; |
+ |
+ /** |
+ * Send a message from the content script to the background page. |
+ * |
+ * @param {Object} message The message to send. |
+ */ |
+ cvox.ExtensionBridge.sendContentScriptToBackground = function(message) { |
+ cvox.ExtensionBridge.backgroundPort.postMessage(message); |
+ }; |
+ |
+ /** |
+ * Send a message from the background page to the content script of the |
+ * current selected tab. |
+ * |
+ * @param {Object} message The message to send. |
+ */ |
+ cvox.ExtensionBridge.sendBackgroundToContentScript = function(message) { |
+ chrome.tabs.getSelected(null, function(tab) { |
+ chrome.tabs.sendRequest(tab.id, message, function() {}); |
+ }); |
+ }; |
+ |
+ /** |
+ * Send a message from the current page to its content script. |
+ * |
+ * @param {Object} message The message to send. |
+ */ |
+ cvox.ExtensionBridge.sendPageToContentScript = function(message) { |
+ cvox.ExtensionBridge.channel.port1.postMessage( |
+ cvox.ExtensionBridge.json.stringify(message)); |
+ }; |
+ |
+ cvox.ExtensionBridge.init(); |
+} else { |
+ if (goog == undefined) { |
+ cvox = {}; |
+ } |
+ cvox.ExtensionBridge = function() {}; |
+} |
Property changes on: chrome/browser/resources/access_chromevox/common/extension_bridge.js |
___________________________________________________________________ |
Added: svn:executable |
+ * |
Added: svn:eol-style |
+ LF |