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

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

Issue 5464830253203456: Refactored the abstraction layer to address prerendered pages on Safari caused by leaky abstraction (Closed)
Left Patch Set: Created Feb. 22, 2014, 10:45 a.m.
Right Patch Set: Addressed comments Created April 11, 2014, 2:47 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') | chrome/ext/common.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 <http://adblockplus.org/>, 2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2013 Eyeo GmbH 3 * Copyright (C) 2006-2014 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 *
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 sendMessage: function(message, responseCallback) 54 sendMessage: function(message, responseCallback)
55 { 55 {
56 sendMessage(this._id, message, responseCallback); 56 sendMessage(this._id, message, responseCallback);
57 } 57 }
58 }; 58 };
59 59
60 ext.pages = { 60 ext.pages = {
61 open: function(url, callback) 61 open: function(url, callback)
62 { 62 {
63 if (callback) 63 if (callback)
64 chrome.tabs.create({url: url}, function(tab) { callback(new Page(tab)); }); 64 {
65 chrome.tabs.create({url: url}, function(openedTab)
66 {
67 var onUpdated = function(tabId, changeInfo, tab)
68 {
69 if (tabId == openedTab.id && changeInfo.status == "complete")
70 {
71 chrome.tabs.onUpdated.removeListener(onUpdated);
72 callback(new Page(tab));
73 }
74 };
75 chrome.tabs.onUpdated.addListener(onUpdated);
76 });
77 }
65 else 78 else
66 chrome.tabs.create({url: url}); 79 chrome.tabs.create({url: url});
67 }, 80 },
68 query: function(info, callback) 81 query: function(info, callback)
69 { 82 {
70 var rawInfo = {}; 83 var rawInfo = {};
71 var visibleWindow = null;
72
73 for (var property in info) 84 for (var property in info)
74 { 85 {
75 switch (property) 86 switch (property)
76 { 87 {
77 case "active": 88 case "active":
78 case "lastFocusedWindow": 89 case "lastFocusedWindow":
79 rawInfo[property] = info[property]; 90 rawInfo[property] = info[property];
80 break;
81 case "visibleWindow":
82 visibleWindow = info[property];
83 break;
84 } 91 }
85 } 92 }
86 93
87 chrome.tabs.query(rawInfo, function(tabs) 94 chrome.tabs.query(rawInfo, function(tabs)
88 { 95 {
89 if (visibleWindow != null && tabs.length > 0) 96 callback(tabs.map(function(tab)
90 { 97 {
91 var windows = {__proto__: null}; 98 return new Page(tab);
92 var pending = 0; 99 }));
93
94 for (var i = 0; i < tabs.length; i++)
95 {
96 var windowId = tabs[i].windowId;
97 if (!(windowId in windows))
98 {
99 windows[windowId] = null;
100 pending++;
101
102 chrome.windows.get(windowId, null, function(win)
103 {
104 if (visibleWindow != (win.state != "minimized"))
Wladimir Palant 2014/04/04 14:00:35 That's quite a bit of code just to exclude minimiz
Sebastian Noack 2014/04/07 13:15:25 We need that for the icon animation, in order to a
Wladimir Palant 2014/04/11 13:02:35 It seems that the original code was only animating
Sebastian Noack 2014/04/11 14:47:45 Done.
105 {
106 for (var j = 0; j < tabs.length; j++)
107 {
108 if (tabs[j].windowId == win.id)
109 tabs.splice(j--, 1);
110 }
111 }
112
113 if (--pending == 0)
114 callback(tabs.map(function(tab)
115 {
116 return new Page(tab);
117 }));
118 });
119 }
120 }
121 }
122 else
123 {
124 callback(tabs.map(function(tab)
125 {
126 return new Page(tab);
127 }));
128 }
129 }); 100 });
130 }, 101 },
131 onLoading: new ext._EventTarget() 102 onLoading: new ext._EventTarget()
132 }; 103 };
133 104
134 chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) 105 chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab)
135 { 106 {
136 if (changeInfo.status == "loading") 107 if (changeInfo.status == "loading")
137 ext.pages.onLoading._dispatch(new Page(tab)); 108 ext.pages.onLoading._dispatch(new Page(tab));
138 }); 109 });
139 110
140 chrome.webNavigation.onBeforeNavigate.addListener(function(details) 111 chrome.webNavigation.onBeforeNavigate.addListener(function(details)
141 { 112 {
142 if (details.frameId == 0) 113 if (details.frameId == 0)
143 ext._removeFromAllPageMaps(details.tabId); 114 ext._removeFromAllPageMaps(details.tabId);
144 }); 115 });
Wladimir Palant 2014/04/04 14:00:35 Just wondering: will this also be triggered for na
Sebastian Noack 2014/04/07 13:15:25 It isn't triggered for javascript: URLs entered in
Wladimir Palant 2014/04/11 13:02:35 I did some testing and it seems that using onBefor
145 116
146 chrome.tabs.onRemoved.addListener(function(tabId) 117 chrome.tabs.onRemoved.addListener(function(tabId)
147 { 118 {
148 ext._removeFromAllPageMaps(tabId); 119 ext._removeFromAllPageMaps(tabId);
149 delete framesOfTabs[tabId]; 120 delete framesOfTabs[tabId];
150 }); 121 });
151 122
152 123
153 /* Browser actions */ 124 /* Browser actions */
154 125
155 var BrowserAction = function(tabId) 126 var BrowserAction = function(tabId)
156 { 127 {
157 this._tabId = tabId; 128 this._tabId = tabId;
158 }; 129 };
159 BrowserAction.prototype = { 130 BrowserAction.prototype = {
160 setIcon: function(path) 131 setIcon: function(path)
161 { 132 {
162 chrome.browserAction.setIcon({tabId: this._tabId, path: path}); 133 var paths = {};
134 for (var i = 1; i <= 2; i++)
135 {
136 var size = i * 19;
137 paths[size] = path.replace("$size", size);
138 }
139
140 chrome.browserAction.setIcon({tabId: this._tabId, path: paths});
163 }, 141 },
164 setBadge: function(badge) 142 setBadge: function(badge)
165 { 143 {
166 if (!badge) 144 if (!badge)
167 { 145 {
168 chrome.browserAction.setBadgeText({ 146 chrome.browserAction.setBadgeText({
169 tabId: this._tabId, 147 tabId: this._tabId,
170 text: "" 148 text: ""
171 }); 149 });
172 return; 150 return;
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 227
250 /* Web requests */ 228 /* Web requests */
251 229
252 ext.webRequest = { 230 ext.webRequest = {
253 onBeforeRequest: new ext._EventTarget(true), 231 onBeforeRequest: new ext._EventTarget(true),
254 handlerBehaviorChanged: chrome.webRequest.handlerBehaviorChanged 232 handlerBehaviorChanged: chrome.webRequest.handlerBehaviorChanged
255 }; 233 };
256 234
257 chrome.webRequest.onBeforeRequest.addListener(function(details) 235 chrome.webRequest.onBeforeRequest.addListener(function(details)
258 { 236 {
259 // the high-level code isn't interested in requests that aren't related 237 try
260 // to a tab and since those can only be handled in Chrome, we ignore 238 {
261 // them here instead of in the browser independent high-level code. 239 // the high-level code isn't interested in requests that aren't related
262 if (details.tabId == -1) 240 // to a tab and since those can only be handled in Chrome, we ignore
263 return; 241 // them here instead of in the browser independent high-level code.
264 242 if (details.tabId == -1)
265 var page = new Page({id: details.tabId});
266 var frames = framesOfTabs[details.tabId];
267
268 if (!frames)
269 {
270 frames = framesOfTabs[details.tabId] = [];
271
272 // assume that the first request belongs to the top frame. Chrome
273 // may give the top frame the type "object" instead of "main_frame".
274 // https://code.google.com/p/chromium/issues/detail?id=281711
275 if (frameId == 0)
276 details.type = "main_frame";
277 }
278
279 var frameId;
280 if (details.type == "main_frame" || details.type == "sub_frame")
281 {
282 frameId = details.parentFrameId;
283 frames[details.frameId] = {url: details.url, parent: frameId};
284
285 // the high-level code isn't interested in top frame requests and
286 // since those can only be handled in Chrome, we ignore them here
287 // instead of in the browser independent high-level code.
288 if (details.type == "main_frame")
289 return; 243 return;
290 } 244
291 else 245 var page = new Tab({id: details.tabId});
292 frameId = details.frameId; 246 var frames = framesOfTabs[details.tabId];
293 247
294 if (!(frameId in frames)) 248 if (!frames)
295 { 249 {
296 // the high-level code relies on the frame. So ignore the request if we 250 frames = framesOfTabs[details.tabId] = [];
297 // don't even know the top-level frame. That can happen for example when 251
298 // the extension was just (re)loaded. 252 // assume that the first request belongs to the top frame. Chrome
299 if (!(0 in frames)) 253 // may give the top frame the type "object" instead of "main_frame".
300 return; 254 // https://code.google.com/p/chromium/issues/detail?id=281711
301 255 if (frameId == 0)
302 // however when the src of the frame is a javascript: or data: URL, we 256 details.type = "main_frame";
303 // don't know the frame either. But since we know the top-level frame we 257 }
304 // can just pretend that we are in the top-level frame, in order to have 258
305 // at least most domain-based filter rules working. 259 var frameId;
306 frameId = 0; 260 if (details.type == "main_frame" || details.type == "sub_frame")
307 if (details.type == "sub_frame") 261 {
308 frames[details.frameId].parent = frameId; 262 frameId = details.parentFrameId;
309 } 263 frames[details.frameId] = {url: details.url, parent: frameId};
310 264
311 var frame = new Frame({frameId: frameId, tabId: details.tabId}); 265 // the high-level code isn't interested in top frame requests and
312 266 // since those can only be handled in Chrome, we ignore them here
313 if (!ext.webRequest.onBeforeRequest._dispatch(details.url, details.type, pag e, frame)) 267 // instead of in the browser independent high-level code.
314 return {cancel: true}; 268 if (details.type == "main_frame")
269 return;
270 }
271 else
272 frameId = details.frameId;
273
274 if (!(frameId in frames))
275 {
276 // the high-level code relies on the frame. So ignore the request if we
277 // don't even know the top-level frame. That can happen for example when
278 // the extension was just (re)loaded.
279 if (!(0 in frames))
280 return;
281
282 // however when the src of the frame is a javascript: or data: URL, we
283 // don't know the frame either. But since we know the top-level frame we
284 // can just pretend that we are in the top-level frame, in order to have
285 // at least most domain-based filter rules working.
286 frameId = 0;
287 if (details.type == "sub_frame")
288 frames[details.frameId].parent = frameId;
289 }
290
291 var frame = new Frame({id: frameId, tabId: details.tabId});
292
293 if (!ext.webRequest.onBeforeRequest._dispatch(details.url, details.type, p age, frame))
294 return {cancel: true};
295 }
296 catch (e)
297 {
298 // recent versions of Chrome cancel the request when an error occurs in
299 // the onBeforeRequest listener. However in our case it is preferred, to
300 // let potentially some ads through, rather than blocking legit requests.
301 console.error(e);
302 }
315 }, {urls: ["<all_urls>"]}, ["blocking"]); 303 }, {urls: ["<all_urls>"]}, ["blocking"]);
316 304
317 305
318 /* Context menus */ 306 /* Context menus */
319 307
320 var contextMenuItems = []; 308 var contextMenuItems = [];
321 var isContextMenuHidden = true; 309 var isContextMenuHidden = true;
322 310
323 ext.contextMenus = { 311 ext.contextMenus = {
324 addMenuItem: function(title, contexts, onclick) 312 addMenuItem: function(title, contexts, onclick)
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 358
371 /* Message passing */ 359 /* Message passing */
372 360
373 ext._setupMessageListener(function(sender) 361 ext._setupMessageListener(function(sender)
374 { 362 {
375 return { 363 return {
376 page: new Page(sender.tab), 364 page: new Page(sender.tab),
377 frame: new Frame({url: sender.url, tabId: sender.tab.id}) 365 frame: new Frame({url: sender.url, tabId: sender.tab.id})
378 }; 366 };
379 }); 367 });
368
369
370 /* Storage */
371
372 ext.storage = localStorage;
380 })(); 373 })();
LEFTRIGHT

Powered by Google App Engine
This is Rietveld