Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: chrome/ext/background.js

Issue 5564089086509056: Issue 1801 - Use URL objects to process URLs in the background page (Closed)
Left Patch Set: Created Jan. 25, 2015, 1:18 p.m.
Right Patch Set: Rebased and addressed comments Created Feb. 11, 2015, 5:06 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « background.js ('k') | lib/basedomain.js » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2015 Eyeo GmbH 3 * Copyright (C) 2006-2015 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 (function() 18 (function()
19 { 19 {
20 /* Pages */ 20 /* Pages */
21 21
22 var Page = ext.Page = function(tab) 22 var Page = ext.Page = function(tab)
23 { 23 {
24 this._id = tab.id; 24 this._id = tab.id;
25 this._url = tab.url && new URL(tab.url);
25 26
26 this.browserAction = new BrowserAction(tab.id); 27 this.browserAction = new BrowserAction(tab.id);
27 this.contextMenus = new ContextMenus(this); 28 this.contextMenus = new ContextMenus(this);
28
29 // Usually Page objects are created from Chrome's Tab objects, which
30 // provide the url. So we can override the fallback implemented below.
31 if (tab.url)
32 Object.defineProperty(this, "url", {value: new URL(tab.url), enumerable: t rue});
Wladimir Palant 2015/02/09 12:54:29 Code that belongs together should really be togeth
Sebastian Noack 2015/02/11 10:55:51 Whatever.
33 }; 29 };
34 Page.prototype = { 30 Page.prototype = {
35 get url() 31 get url()
36 { 32 {
37 // Sometimes we only have the tab id when we create a Page object. 33 // usually our Page objects are created from Chrome's Tab objects, which
38 // In that case we get the url from top frame of the tab, recorded 34 // provide the url. So we can return the url given in the constructor.
39 // by the onBeforeRequest handler. 35 if (this._url)
36 return this._url;
37
38 // but sometimes we only have the tab id when we create a Page object.
39 // In that case we get the url from top frame of the tab, recorded by
40 // the onBeforeRequest handler.
40 var frames = framesOfTabs[this._id]; 41 var frames = framesOfTabs[this._id];
41 if (frames) 42 if (frames)
42 { 43 {
43 var frame = frames[0]; 44 var frame = frames[0];
44 if (frame) 45 if (frame)
45 return frame.url; 46 return frame.url;
46 } 47 }
47 }, 48 },
48 sendMessage: function(message, responseCallback) 49 sendMessage: function(message, responseCallback)
49 { 50 {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 104
104 chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) 105 chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab)
105 { 106 {
106 if (changeInfo.status == "loading") 107 if (changeInfo.status == "loading")
107 ext.pages.onLoading._dispatch(new Page(tab)); 108 ext.pages.onLoading._dispatch(new Page(tab));
108 }); 109 });
109 110
110 chrome.webNavigation.onBeforeNavigate.addListener(function(details) 111 chrome.webNavigation.onBeforeNavigate.addListener(function(details)
111 { 112 {
112 if (details.frameId == 0) 113 if (details.frameId == 0)
114 {
113 ext._removeFromAllPageMaps(details.tabId); 115 ext._removeFromAllPageMaps(details.tabId);
116
117 chrome.tabs.get(details.tabId, function()
118 {
119 // If the tab is prerendered, chrome.tabs.get() sets
120 // chrome.runtime.lastError and we have to dispatch the onLoading event,
121 // since the onUpdated event isn't dispatched for prerendered tabs.
122 // However, we have to keep relying on the unUpdated event for tabs that
123 // are already visible. Otherwise browser action changes get overridden
124 // when Chrome automatically resets them on navigation.
125 if (chrome.runtime.lastError)
126 {
127 ext.pages.onLoading._dispatch(
128 new Page({
129 id: details.tabId,
130 url: details.url
131 })
132 );
133 }
134 });
135 }
114 }); 136 });
115 137
116 chrome.tabs.onRemoved.addListener(function(tabId) 138 function forgetTab(tabId)
117 { 139 {
118 ext._removeFromAllPageMaps(tabId); 140 ext._removeFromAllPageMaps(tabId);
119 delete framesOfTabs[tabId]; 141 delete framesOfTabs[tabId];
142 }
143
144 chrome.tabs.onReplaced.addListener(function(addedTabId, removedTabId)
145 {
146 forgetTab(removedTabId);
120 }); 147 });
121 148
149 chrome.tabs.onRemoved.addListener(forgetTab);
150
122 151
123 /* Browser actions */ 152 /* Browser actions */
124 153
125 var BrowserAction = function(tabId) 154 var BrowserAction = function(tabId)
126 { 155 {
127 this._tabId = tabId; 156 this._tabId = tabId;
157 this._changes = null;
128 }; 158 };
129 BrowserAction.prototype = { 159 BrowserAction.prototype = {
130 setIcon: function(path) 160 _applyChanges: function()
131 { 161 {
132 var paths = {}; 162 if ("iconPath" in this._changes)
133 for (var i = 1; i <= 2; i++) 163 {
134 { 164 chrome.browserAction.setIcon({
135 var size = i * 19; 165 tabId: this._tabId,
136 paths[size] = path.replace("$size", size); 166 path: {
137 } 167 19: this._changes.iconPath.replace("$size", "19"),
138 168 38: this._changes.iconPath.replace("$size", "38")
139 chrome.browserAction.setIcon({tabId: this._tabId, path: paths}); 169 }
140 }, 170 });
141 setBadge: function(badge) 171 }
142 { 172
143 if (!badge) 173 if ("badgeText" in this._changes)
144 { 174 {
145 chrome.browserAction.setBadgeText({ 175 chrome.browserAction.setBadgeText({
146 tabId: this._tabId, 176 tabId: this._tabId,
147 text: "" 177 text: this._changes.badgeText
148 }); 178 });
149 return; 179 }
150 } 180
151 181 if ("badgeColor" in this._changes)
152 if ("color" in badge)
153 { 182 {
154 chrome.browserAction.setBadgeBackgroundColor({ 183 chrome.browserAction.setBadgeBackgroundColor({
155 tabId: this._tabId, 184 tabId: this._tabId,
156 color: badge.color 185 color: this._changes.badgeColor
157 }); 186 });
158 } 187 }
159 188
160 if ("number" in badge) 189 this._changes = null;
161 { 190 },
162 chrome.browserAction.setBadgeText({ 191 _queueChanges: function()
163 tabId: this._tabId, 192 {
164 text: badge.number.toString() 193 chrome.tabs.get(this._tabId, function()
165 }); 194 {
195 // If the tab is prerendered, chrome.tabs.get() sets
196 // chrome.runtime.lastError and we have to delay our changes
197 // until the currently visible tab is replaced with the
198 // prerendered tab. Otherwise chrome.browserAction.set* fails.
199 if (chrome.runtime.lastError)
200 {
201 var onReplaced = function(addedTabId, removedTabId)
202 {
203 if (addedTabId == this._tabId)
204 {
205 chrome.tabs.onReplaced.removeListener(onReplaced);
206 this._applyChanges();
207 }
208 }.bind(this);
209 chrome.tabs.onReplaced.addListener(onReplaced);
210 }
211 else
212 {
213 this._applyChanges();
214 }
215 }.bind(this));
216 },
217 _addChange: function(name, value)
218 {
219 if (!this._changes)
220 {
221 this._changes = {};
222 this._queueChanges();
223 }
224
225 this._changes[name] = value;
226 },
227 setIcon: function(path)
228 {
229 this._addChange("iconPath", path);
230 },
231 setBadge: function(badge)
232 {
233 if (!badge)
234 {
235 this._addChange("badgeText", "");
236 }
237 else
238 {
239 if ("number" in badge)
240 this._addChange("badgeText", badge.number.toString());
241
242 if ("color" in badge)
243 this._addChange("badgeColor", badge.color);
166 } 244 }
167 } 245 }
168 }; 246 };
169 247
170 248
171 /* Context menus */ 249 /* Context menus */
172 250
173 var contextMenuItems = new ext.PageMap(); 251 var contextMenuItems = new ext.PageMap();
174 var contextMenuUpdating = false; 252 var contextMenuUpdating = false;
175 253
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 312
235 chrome.windows.onFocusChanged.addListener(function(windowId) 313 chrome.windows.onFocusChanged.addListener(function(windowId)
236 { 314 {
237 if (windowId != chrome.windows.WINDOW_ID_NONE) 315 if (windowId != chrome.windows.WINDOW_ID_NONE)
238 updateContextMenu(); 316 updateContextMenu();
239 }); 317 });
240 318
241 319
242 /* Web requests */ 320 /* Web requests */
243 321
244 var framesOfTabs = {__proto__: null}; 322 var framesOfTabs = Object.create(null);
245 323
246 ext.getFrame = function(tabId, frameId) 324 ext.getFrame = function(tabId, frameId)
247 { 325 {
248 return (framesOfTabs[tabId] || {})[frameId]; 326 return (framesOfTabs[tabId] || {})[frameId];
249 }; 327 };
250 328
251 ext.webRequest = { 329 ext.webRequest = {
252 onBeforeRequest: new ext._EventTarget(), 330 onBeforeRequest: new ext._EventTarget(),
253 handlerBehaviorChanged: chrome.webRequest.handlerBehaviorChanged 331 handlerBehaviorChanged: chrome.webRequest.handlerBehaviorChanged
254 }; 332 };
255 333
256 chrome.tabs.query({}, function(tabs) 334 chrome.tabs.query({}, function(tabs)
257 { 335 {
258 tabs.forEach(function(tab) 336 tabs.forEach(function(tab)
259 { 337 {
260 chrome.webNavigation.getAllFrames({tabId: tab.id}, function(details) 338 chrome.webNavigation.getAllFrames({tabId: tab.id}, function(details)
261 { 339 {
262 if (details && details.length > 0) 340 if (details && details.length > 0)
263 { 341 {
264 var frames = framesOfTabs[tab.id] = {__proto__: null}; 342 var frames = framesOfTabs[tab.id] = Object.create(null);
265 343
266 for (var i = 0; i < details.length; i++) 344 for (var i = 0; i < details.length; i++)
267 frames[details[i].frameId] = {url: new URL(details[i].url), parent: null}; 345 frames[details[i].frameId] = {url: new URL(details[i].url), parent: null};
268 346
269 for (var i = 0; i < details.length; i++) 347 for (var i = 0; i < details.length; i++)
270 { 348 {
271 var parentFrameId = details[i].parentFrameId; 349 var parentFrameId = details[i].parentFrameId;
272 350
273 if (parentFrameId != -1) 351 if (parentFrameId != -1)
274 frames[details[i].frameId].parent = frames[parentFrameId]; 352 frames[details[i].frameId].parent = frames[parentFrameId];
(...skipping 19 matching lines...) Expand all
294 // assume that the first request belongs to the top frame. Chrome 372 // assume that the first request belongs to the top frame. Chrome
295 // may give the top frame the type "object" instead of "main_frame". 373 // may give the top frame the type "object" instead of "main_frame".
296 // https://code.google.com/p/chromium/issues/detail?id=281711 374 // https://code.google.com/p/chromium/issues/detail?id=281711
297 details.frameId == 0 && !(details.tabId in framesOfTabs) 375 details.frameId == 0 && !(details.tabId in framesOfTabs)
298 ); 376 );
299 377
300 var frames = null; 378 var frames = null;
301 if (!isMainFrame) 379 if (!isMainFrame)
302 frames = framesOfTabs[details.tabId]; 380 frames = framesOfTabs[details.tabId];
303 if (!frames) 381 if (!frames)
304 frames = framesOfTabs[details.tabId] = {__proto__: null}; 382 frames = framesOfTabs[details.tabId] = Object.create(null);
305 383
306 var frame = null; 384 var frame = null;
307 var url = new URL(details.url); 385 var url = new URL(details.url);
308 if (!isMainFrame) 386 if (!isMainFrame)
309 { 387 {
310 // we are looking for the frame that contains the element that 388 // we are looking for the frame that contains the element that
311 // is about to load, however if a frame is loading the surrounding 389 // is about to load, however if a frame is loading the surrounding
312 // frame is indicated by parentFrameId instead of frameId 390 // frame is indicated by parentFrameId instead of frameId
313 var frameId; 391 var frameId;
314 if (requestType == "sub_frame") 392 if (requestType == "sub_frame")
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 } 462 }
385 463
386 return frames[0]; 464 return frames[0];
387 } 465 }
388 } 466 }
389 }; 467 };
390 468
391 return ext.onMessage._dispatch(message, sender, sendResponse).indexOf(true) != -1; 469 return ext.onMessage._dispatch(message, sender, sendResponse).indexOf(true) != -1;
392 }); 470 });
393 471
472 // We have to ensure there is at least one listener for the onConnect event.
473 // Otherwise we can't connect a port later, which we need to do in order to
474 // detect when the extension is reloaded, disabled or uninstalled.
475 chrome.runtime.onConnect.addListener(function() {});
476
394 477
395 /* Storage */ 478 /* Storage */
396 479
397 ext.storage = localStorage; 480 ext.storage = localStorage;
398 481
399 482
400 /* Options */ 483 /* Options */
401 484
402 ext.showOptions = function(callback) 485 ext.showOptions = function(callback)
403 { 486 {
(...skipping 27 matching lines...) Expand all
431 callback(new Page(tab)); 514 callback(new Page(tab));
432 } 515 }
433 else 516 else
434 { 517 {
435 ext.pages.open(optionsUrl, callback); 518 ext.pages.open(optionsUrl, callback);
436 } 519 }
437 }); 520 });
438 }); 521 });
439 }; 522 };
440 })(); 523 })();
LEFTRIGHT

Powered by Google App Engine
This is Rietveld