| Left: | ||
| Right: |
| LEFT | RIGHT |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 })(); |
| LEFT | RIGHT |