Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(328)

Side by Side Diff: chrome/browser/resources/access_chromevox/common/extension_bridge.js

Issue 6254007: Adding ChromeVox as a component extensions (enabled only for ChromeOS, for no... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:executable
+ *
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6 * @fileoverview Bridge to aid in communication between a Chrome
7 * background page and scripts injected into a page by a content script.
8 *
9 * This is needed when the extension's content script dynamically loads
10 * most of its code by injecting script tags into the page. To communicate
11 * with the background page, the page script needs to post a message that
12 * the content script can listen to and then forward to the background page.
13 *
14 * To use cvox.ExtensionBridge, this file must be included in all three
15 * contexts:
16 *
17 * 1. From the background page.
18 * 2. From the content script (in the manifest.json after all other scripts).
19 * 3. Inject it into the page from the content script.
20 *
21 * It automatically figures out where it's being run and initializes itself
22 * appropriately. Then just call send() to send a message from the background
23 * to the page or vice versa, and addMessageListener() to provide a message
24 * listener. Messages can be any object that can be serialized using JSON.
25 *
26 * Messages can be sent to the background page from either the page or the
27 * content script, and messages sent from the background page are delivered
28 * to both the content script and the page.
29 */
30
31 goog.provide('cvox.ExtensionBridge');
32
33 goog.require('cvox.ChromeVoxJSON');
34
35 if (BUILD_TYPE == BUILD_TYPE_CHROME) {
36 /**
37 * @constructor
38 */
39 cvox.ExtensionBridge = function() {};
40
41 /**
42 * Initialize the extension bridge. Dynamically figure out whether we're in
43 * the background page, content script, or in a page, and call the
44 * corresponding function for more specific initialization.
45 */
46 cvox.ExtensionBridge.init = function() {
47 var self = cvox.ExtensionBridge;
48 self.listeners = [];
49
50 try {
51 if (chrome && chrome.windows) {
52 // This depends on the fact that chrome.windows is only available
53 // from background pages.
54 self.json = JSON;
55 self.context = self.BACKGROUND;
56 self.initBackground();
57 return;
58 } else {
59 self.json = cvox.ChromeVoxJSON;
60 self.context = self.PAGE;
61 self.initPage();
62 return;
63 }
64 } catch (e) {
65 // Ignore exception that might be raised if we try to access
66 // chrome.windows from a content script.
67 }
68
69 if (chrome && chrome.extension) {
70 self.json = JSON;
71 self.context = self.CONTENT_SCRIPT;
72 self.initContentScript();
73 }
74 };
75
76 /**
77 * Constant indicating we're in a background page.
78 * @type {number}
79 * @const
80 */
81 cvox.ExtensionBridge.BACKGROUND = 0;
82
83 /**
84 * Constant indicating we're in a content script.
85 * @type {number}
86 * @const
87 */
88 cvox.ExtensionBridge.CONTENT_SCRIPT = 1;
89
90 /**
91 * Constant indicating we're in a page.
92 * @type {number}
93 * @const
94 */
95 cvox.ExtensionBridge.PAGE = 2;
96
97 /**
98 * The name of the port between the content script and background page.
99 * @type {string}
100 * @const
101 */
102 cvox.ExtensionBridge.PORT_NAME = 'cvox.ExtensionBridge.Port';
103
104 /**
105 * The name of the message between the page and content script that sets
106 * up the bidirectional port between them.
107 * @type {string}
108 * @const
109 */
110 cvox.ExtensionBridge.PORT_SETUP_MSG = 'cvox.ExtensionBridge.PortSetup';
111
112 /**
113 * Send a message. If the context is a page, sends a message to the
114 * extension background page. If the context is a background page, sends
115 * a message to the current active tab (not all tabs).
116 *
117 * @param {Object} message The message to be sent.
118 */
119 cvox.ExtensionBridge.send = function(message) {
120 var self = cvox.ExtensionBridge;
121 switch (self.context) {
122 case self.BACKGROUND:
123 self.sendBackgroundToContentScript(message);
124 break;
125 case self.CONTENT_SCRIPT:
126 self.sendContentScriptToBackground(message);
127 break;
128 case self.PAGE:
129 self.sendPageToContentScript(message);
130 break;
131 }
132 };
133
134 /**
135 * Provide a function to listen to messages. In page context, this
136 * listens to messages from the background. In background context,
137 * this listens to messages from all pages.
138 *
139 * The function gets called with two parameters: the message, and a
140 * port that can be used to send replies.
141 *
142 * @param {function(Object, Port)} listener The message listener.
143 */
144 cvox.ExtensionBridge.addMessageListener = function(listener) {
145 cvox.ExtensionBridge.listeners.push(listener);
146 };
147
148 /**
149 * Initialize the extension bridge in a background page context by registering
150 * a listener for connections from the content script.
151 */
152 cvox.ExtensionBridge.initBackground = function() {
153 var self = cvox.ExtensionBridge;
154
155 chrome.extension.onConnect.addListener(function(port) {
156 if (port.name != self.PORT_NAME) {
157 return;
158 }
159 port.onMessage.addListener(function(message) {
160 for (var i = 0; i < self.listeners.length; i++) {
161 self.listeners[i](message, port);
162 }
163 });
164 });
165 };
166
167 /**
168 * Initialize the extension bridge in a content script context, listening
169 * for messages from the background page and accepting a bidirectional port
170 * from the page.
171 */
172 cvox.ExtensionBridge.initContentScript = function() {
173 var self = cvox.ExtensionBridge;
174
175 // Listen to requests from the background that don't come from
176 // our connection port.
177 chrome.extension.onRequest.addListener(
178 function(request, sender, sendResponse) {
179 for (var i = 0; i < self.listeners.length; i++) {
180 self.listeners[i](request, self.backgroundPort);
181 }
182 if (self.port) {
183 self.port.postMessage(self.json.stringify(request));
184 }
185 sendResponse({});
186 });
187
188 // Listen to events on the main window and wait for a port setup message
189 // from the page to continue.
190 window.addEventListener('message', function(event) {
191 if (event.data == self.PORT_SETUP_MSG) {
192 // Now that we have a page connection, connect to background too.
193 // (Don't do this earlier, otherwise initial messages from the
194 // background wouldn't make it all the way through to the page.)
195 self.backgroundPort = chrome.extension.connect({name: self.PORT_NAME});
196 self.backgroundPort.onMessage.addListener(
197 function(message) {
198 for (var i = 0; i < self.listeners.length; i++) {
199 self.listeners[i](message, self.backgroundPort);
200 }
201 if (self.port) {
202 self.port.postMessage(self.json.stringify(message));
203 }
204 });
205
206 self.port = event.ports[0];
207 self.port.onmessage = function(event) {
208 self.backgroundPort.postMessage(self.json.parse(event.data));
209 };
210 }
211 }, false);
212 };
213
214 /**
215 * Initialize the extension bridge in a page context, creating a
216 * MessageChannel and sending one of the ports to the content script
217 * and then listening for messages on the other port.
218 */
219 cvox.ExtensionBridge.initPage = function() {
220 var self = cvox.ExtensionBridge;
221 self.channel = new MessageChannel();
222
223 // Note: using postMessage.apply rather than just calling postMessage
224 // directly because the 3-argument form of postMessage is still in the
225 // HTML5 draft.
226 window.postMessage.apply(
227 window, [self.PORT_SETUP_MSG, [self.channel.port2], '*']);
228
229 self.channel.port1.onmessage = function(event) {
230 for (var i = 0; i < self.listeners.length; i++) {
231 self.listeners[i](self.json.parse(event.data), self.channel.port1);
232 }
233 };
234 };
235
236 /**
237 * Send a message from the content script to the background page.
238 *
239 * @param {Object} message The message to send.
240 */
241 cvox.ExtensionBridge.sendContentScriptToBackground = function(message) {
242 cvox.ExtensionBridge.backgroundPort.postMessage(message);
243 };
244
245 /**
246 * Send a message from the background page to the content script of the
247 * current selected tab.
248 *
249 * @param {Object} message The message to send.
250 */
251 cvox.ExtensionBridge.sendBackgroundToContentScript = function(message) {
252 chrome.tabs.getSelected(null, function(tab) {
253 chrome.tabs.sendRequest(tab.id, message, function() {});
254 });
255 };
256
257 /**
258 * Send a message from the current page to its content script.
259 *
260 * @param {Object} message The message to send.
261 */
262 cvox.ExtensionBridge.sendPageToContentScript = function(message) {
263 cvox.ExtensionBridge.channel.port1.postMessage(
264 cvox.ExtensionBridge.json.stringify(message));
265 };
266
267 cvox.ExtensionBridge.init();
268 } else {
269 if (goog == undefined) {
270 cvox = {};
271 }
272 cvox.ExtensionBridge = function() {};
273 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698