| OLD | NEW | 
|---|
| 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  * | 
| 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   /* Events */ | 20   /* Pages */ | 
| 21 | 21 | 
| 22   var TabEventTarget = function() | 22   var Page = ext.Page = function(tab) | 
| 23   { | 23   { | 
| 24     WrappedEventTarget.apply(this, arguments); | 24     this._id = tab.id; | 
|  | 25     this._url = tab.url; | 
| 25 | 26 | 
| 26     this._tabs = {}; | 27     this.browserAction = new BrowserAction(tab.id); | 
|  | 28     this.contextMenus = new ContextMenus(this); | 
|  | 29   }; | 
|  | 30   Page.prototype = { | 
|  | 31     get url() | 
|  | 32     { | 
|  | 33       // usually our Page objects are created from Chrome's Tab objects, which | 
|  | 34       // provide the url. So we can return the url given in the constructor. | 
|  | 35       if (this._url != null) | 
|  | 36         return this._url; | 
| 27 | 37 | 
| 28     this._sharedListener = this._sharedListener.bind(this); | 38       // but sometimes we only have the tab id when we create a Page object. | 
| 29     this._removeTab = this._removeTab.bind(this); | 39       // In that case we get the url from top frame of the tab, recorded by | 
| 30   }; | 40       // the onBeforeRequest handler. | 
| 31   TabEventTarget.prototype = { | 41       var frames = framesOfTabs[this._id]; | 
| 32     __proto__: WrappedEventTarget.prototype, | 42       if (frames) | 
| 33     _bindToTab: function(tab) | 43       { | 
|  | 44         var frame = frames[0]; | 
|  | 45         if (frame) | 
|  | 46           return frame.url; | 
|  | 47       } | 
|  | 48     }, | 
|  | 49     activate: function() | 
| 34     { | 50     { | 
| 35       return { | 51       chrome.tabs.update(this._id, {selected: true}); | 
| 36         addListener: function(listener) |  | 
| 37         { |  | 
| 38           var listeners = this._tabs[tab._id]; |  | 
| 39 |  | 
| 40           if (!listeners) |  | 
| 41           { |  | 
| 42             this._tabs[tab._id] = listeners = []; |  | 
| 43 |  | 
| 44             if (Object.keys(this._tabs).length == 1) |  | 
| 45               this.addListener(this._sharedListener); |  | 
| 46 |  | 
| 47             tab.onRemoved.addListener(this._removeTab); |  | 
| 48           } |  | 
| 49 |  | 
| 50           listeners.push(listener); |  | 
| 51         }.bind(this), |  | 
| 52         removeListener: function(listener) |  | 
| 53         { |  | 
| 54           var listeners = this._tabs[tab._id]; |  | 
| 55           if (!listeners) |  | 
| 56             return; |  | 
| 57 |  | 
| 58           var idx = listeners.indexOf(listener); |  | 
| 59           if (idx == -1) |  | 
| 60             return; |  | 
| 61 |  | 
| 62           listeners.splice(idx, 1); |  | 
| 63 |  | 
| 64           if (listeners.length == 0) |  | 
| 65             tab.onRemoved.removeListener(this._removeTab); |  | 
| 66           else |  | 
| 67           { |  | 
| 68             if (listeners.length > 1) |  | 
| 69               return; |  | 
| 70             if (listeners[0] != this._removeTab) |  | 
| 71               return; |  | 
| 72           } |  | 
| 73 |  | 
| 74           this._removeTab(tab); |  | 
| 75         }.bind(this) |  | 
| 76       }; |  | 
| 77     }, | 52     }, | 
| 78     _sharedListener: function(tab) | 53     sendMessage: function(message, responseCallback) | 
| 79     { | 54     { | 
| 80       var listeners = this._tabs[tab._id]; | 55       chrome.tabs.sendMessage(this._id, message, responseCallback); | 
| 81 |  | 
| 82       if (!listeners) |  | 
| 83         return; |  | 
| 84 |  | 
| 85       // copy listeners before calling them, because they might |  | 
| 86       // add or remove other listeners, which must not be taken |  | 
| 87       // into account before the next occurrence of the event |  | 
| 88       listeners = listeners.slice(0); |  | 
| 89 |  | 
| 90       for (var i = 0; i < listeners.length; i++) |  | 
| 91         listeners[i](tab); |  | 
| 92     }, |  | 
| 93     _removeTab: function(tab) |  | 
| 94     { |  | 
| 95       delete this._tabs[tab._id]; |  | 
| 96 |  | 
| 97       if (Object.keys(this._tabs).length == 0) |  | 
| 98         this.removeListener(this._sharedListener); |  | 
| 99     } | 56     } | 
| 100   }; | 57   }; | 
| 101 | 58 | 
| 102   var LoadingTabEventTarget = function() | 59   ext.pages = { | 
| 103   { | 60     open: function(url, callback) | 
| 104     TabEventTarget.call(this, chrome.tabs.onUpdated); |  | 
| 105   }; |  | 
| 106   LoadingTabEventTarget.prototype = { |  | 
| 107     __proto__: TabEventTarget.prototype, |  | 
| 108     _wrapListener: function(listener) |  | 
| 109     { | 61     { | 
| 110       return function(id, info, tab) | 62       if (callback) | 
| 111       { | 63       { | 
| 112         if (info.status == "loading") | 64         chrome.tabs.create({url: url}, function(openedTab) | 
| 113           listener(new Tab(tab)); | 65         { | 
| 114       }; | 66           var onUpdated = function(tabId, changeInfo, tab) | 
| 115     } | 67           { | 
|  | 68             if (tabId == openedTab.id && changeInfo.status == "complete") | 
|  | 69             { | 
|  | 70               chrome.tabs.onUpdated.removeListener(onUpdated); | 
|  | 71               callback(new Page(tab)); | 
|  | 72             } | 
|  | 73           }; | 
|  | 74           chrome.tabs.onUpdated.addListener(onUpdated); | 
|  | 75         }); | 
|  | 76       } | 
|  | 77       else | 
|  | 78         chrome.tabs.create({url: url}); | 
|  | 79     }, | 
|  | 80     query: function(info, callback) | 
|  | 81     { | 
|  | 82       var rawInfo = {}; | 
|  | 83       for (var property in info) | 
|  | 84       { | 
|  | 85         switch (property) | 
|  | 86         { | 
|  | 87           case "active": | 
|  | 88           case "lastFocusedWindow": | 
|  | 89             rawInfo[property] = info[property]; | 
|  | 90         } | 
|  | 91       } | 
|  | 92 | 
|  | 93       chrome.tabs.query(rawInfo, function(tabs) | 
|  | 94       { | 
|  | 95         callback(tabs.map(function(tab) | 
|  | 96         { | 
|  | 97           return new Page(tab); | 
|  | 98         })); | 
|  | 99       }); | 
|  | 100     }, | 
|  | 101     onLoading: new ext._EventTarget() | 
| 116   }; | 102   }; | 
| 117 | 103 | 
| 118   var CompletedTabEventTarget = function() | 104   chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) | 
| 119   { | 105   { | 
| 120     TabEventTarget.call(this, chrome.tabs.onUpdated); | 106     if (changeInfo.status == "loading") | 
| 121   }; | 107       ext.pages.onLoading._dispatch(new Page(tab)); | 
| 122   CompletedTabEventTarget.prototype = { | 108   }); | 
| 123     __proto__: TabEventTarget.prototype, |  | 
| 124     _wrapListener: function(listener) |  | 
| 125     { |  | 
| 126       return function(id, info, tab) |  | 
| 127       { |  | 
| 128         if (info.status == "complete") |  | 
| 129           listener(new Tab(tab)); |  | 
| 130       }; |  | 
| 131     } |  | 
| 132   }; |  | 
| 133 | 109 | 
| 134   var ActivatedTabEventTarget = function() | 110   chrome.webNavigation.onBeforeNavigate.addListener(function(details) | 
| 135   { | 111   { | 
| 136     TabEventTarget.call(this, chrome.tabs.onActivated); | 112     if (details.frameId == 0) | 
| 137   }; | 113       ext._removeFromAllPageMaps(details.tabId); | 
| 138   ActivatedTabEventTarget.prototype = { | 114   }); | 
| 139     __proto__: TabEventTarget.prototype, |  | 
| 140     _wrapListener: function(listener) |  | 
| 141     { |  | 
| 142       return function(info) |  | 
| 143       { |  | 
| 144         chrome.tabs.get(info.tabId, function(tab) |  | 
| 145         { |  | 
| 146           listener(new Tab(tab)); |  | 
| 147         }); |  | 
| 148       }; |  | 
| 149     } |  | 
| 150   } |  | 
| 151 | 115 | 
| 152   var RemovedTabEventTarget = function() | 116   chrome.tabs.onRemoved.addListener(function(tabId) | 
| 153   { | 117   { | 
| 154     TabEventTarget.call(this, chrome.tabs.onRemoved); | 118     ext._removeFromAllPageMaps(tabId); | 
| 155   }; | 119     delete framesOfTabs[tabId]; | 
| 156   RemovedTabEventTarget.prototype = { | 120   }); | 
| 157     __proto__: TabEventTarget.prototype, |  | 
| 158     _wrapListener: function(listener) |  | 
| 159     { |  | 
| 160       return function(id) { listener(new Tab({id: id})); }; |  | 
| 161     } |  | 
| 162   }; |  | 
| 163 |  | 
| 164   var BeforeRequestEventTarget = function() |  | 
| 165   { |  | 
| 166     WrappedEventTarget.call(this, chrome.webRequest.onBeforeRequest); |  | 
| 167   }; |  | 
| 168   BeforeRequestEventTarget.prototype = { |  | 
| 169     __proto__: WrappedEventTarget.prototype, |  | 
| 170     _wrapListener: function(listener) |  | 
| 171     { |  | 
| 172       return function(details) |  | 
| 173       { |  | 
| 174         var tab = null; |  | 
| 175 |  | 
| 176         if (details.tabId != -1) |  | 
| 177           tab = new Tab({id: details.tabId}); |  | 
| 178 |  | 
| 179         return {cancel: listener( |  | 
| 180           details.url, |  | 
| 181           details.type, |  | 
| 182           tab, |  | 
| 183           details.frameId, |  | 
| 184           details.parentFrameId |  | 
| 185         ) === false}; |  | 
| 186       }; |  | 
| 187     }, |  | 
| 188     _prepareExtraArguments: function(urls) |  | 
| 189     { |  | 
| 190       return [urls ? {urls: urls} : {}, ["blocking"]]; |  | 
| 191     } |  | 
| 192   }; |  | 
| 193 | 121 | 
| 194 | 122 | 
| 195   /* Tabs */ | 123   /* Browser actions */ | 
| 196 |  | 
| 197   var sendMessage = chrome.tabs.sendMessage || chrome.tabs.sendRequest; |  | 
| 198 | 124 | 
| 199   var BrowserAction = function(tabId) | 125   var BrowserAction = function(tabId) | 
| 200   { | 126   { | 
| 201     this._tabId = tabId; | 127     this._tabId = tabId; | 
| 202   }; | 128   }; | 
| 203   BrowserAction.prototype = { | 129   BrowserAction.prototype = { | 
| 204     setIcon: function(path) | 130     setIcon: function(path) | 
| 205     { | 131     { | 
| 206       chrome.browserAction.setIcon({tabId: this._tabId, path: path}); | 132       var paths = {}; | 
| 207     }, | 133       for (var i = 1; i <= 2; i++) | 
| 208     setTitle: function(title) | 134       { | 
| 209     { | 135         var size = i * 19; | 
| 210       chrome.browserAction.setTitle({tabId: this._tabId, title: title}); | 136         paths[size] = path.replace("$size", size); | 
|  | 137       } | 
|  | 138 | 
|  | 139       chrome.browserAction.setIcon({tabId: this._tabId, path: paths}); | 
| 211     }, | 140     }, | 
| 212     setBadge: function(badge) | 141     setBadge: function(badge) | 
| 213     { | 142     { | 
| 214       if (!badge) | 143       if (!badge) | 
| 215       { | 144       { | 
| 216         chrome.browserAction.setBadgeText({ | 145         chrome.browserAction.setBadgeText({ | 
| 217           tabId: this._tabId, | 146           tabId: this._tabId, | 
| 218           text: "" | 147           text: "" | 
| 219         }); | 148         }); | 
| 220         return; | 149         return; | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 231       if ("number" in badge) | 160       if ("number" in badge) | 
| 232       { | 161       { | 
| 233         chrome.browserAction.setBadgeText({ | 162         chrome.browserAction.setBadgeText({ | 
| 234           tabId: this._tabId, | 163           tabId: this._tabId, | 
| 235           text: badge.number.toString() | 164           text: badge.number.toString() | 
| 236         }); | 165         }); | 
| 237       } | 166       } | 
| 238     } | 167     } | 
| 239   }; | 168   }; | 
| 240 | 169 | 
| 241   Tab = function(tab) | 170 | 
| 242   { | 171   /* Context menus */ | 
| 243     this._id = tab.id; | 172 | 
| 244 | 173   var contextMenuItems = new ext.PageMap(); | 
| 245     this.url = tab.url; | 174   var contextMenuUpdating = false; | 
| 246     this.browserAction = new BrowserAction(tab.id); | 175 | 
| 247 | 176   var updateContextMenu = function() | 
| 248     this.onLoading = ext.tabs.onLoading._bindToTab(this); | 177   { | 
| 249     this.onCompleted = ext.tabs.onCompleted._bindToTab(this); | 178     if (contextMenuUpdating) | 
| 250     this.onActivated = ext.tabs.onActivated._bindToTab(this); | 179       return; | 
| 251     this.onRemoved = ext.tabs.onRemoved._bindToTab(this); | 180 | 
| 252   }; | 181     contextMenuUpdating = true; | 
| 253   Tab.prototype = { | 182 | 
| 254     close: function() | 183     chrome.tabs.query({active: true, lastFocusedWindow: true}, function(tabs) | 
| 255     { | 184     { | 
| 256       chrome.tabs.remove(this._id); | 185       chrome.contextMenus.removeAll(function() | 
|  | 186       { | 
|  | 187         contextMenuUpdating = false; | 
|  | 188 | 
|  | 189         if (tabs.length == 0) | 
|  | 190           return; | 
|  | 191 | 
|  | 192         var items = contextMenuItems.get({_id: tabs[0].id}); | 
|  | 193 | 
|  | 194         if (!items) | 
|  | 195           return; | 
|  | 196 | 
|  | 197         items.forEach(function(item) | 
|  | 198         { | 
|  | 199           chrome.contextMenus.create({ | 
|  | 200             title: item.title, | 
|  | 201             contexts: item.contexts, | 
|  | 202             onclick: function(info, tab) | 
|  | 203             { | 
|  | 204               item.onclick(info.srcUrl, new Page(tab)); | 
|  | 205             } | 
|  | 206           }); | 
|  | 207         }); | 
|  | 208       }); | 
|  | 209     }); | 
|  | 210   }; | 
|  | 211 | 
|  | 212   var ContextMenus = function(page) | 
|  | 213   { | 
|  | 214     this._page = page; | 
|  | 215   }; | 
|  | 216   ContextMenus.prototype = { | 
|  | 217     create: function(item) | 
|  | 218     { | 
|  | 219       var items = contextMenuItems.get(this._page); | 
|  | 220       if (!items) | 
|  | 221         contextMenuItems.set(this._page, items = []); | 
|  | 222 | 
|  | 223       items.push(item); | 
|  | 224       updateContextMenu(); | 
| 257     }, | 225     }, | 
| 258     activate: function() | 226     removeAll: function() | 
| 259     { | 227     { | 
| 260       chrome.tabs.update(this._id, {selected: true}); | 228       contextMenuItems.delete(this._page); | 
| 261     }, | 229       updateContextMenu(); | 
| 262     sendMessage: function(message, responseCallback) | 230     } | 
| 263     { | 231   }; | 
| 264       sendMessage(this._id, message, responseCallback); | 232 | 
| 265     } | 233   chrome.tabs.onActivated.addListener(updateContextMenu); | 
| 266   }; | 234 | 
| 267 | 235   chrome.windows.onFocusChanged.addListener(function(windowId) | 
| 268   TabMap = function() | 236   { | 
| 269   { | 237     if (windowId != chrome.windows.WINDOW_ID_NONE) | 
| 270     this._map = {}; | 238       updateContextMenu(); | 
| 271     this.delete = this.delete.bind(this); | 239   }); | 
| 272   }; | 240 | 
| 273   TabMap.prototype = { | 241 | 
| 274     get: function(tab) | 242   /* Web requests */ | 
| 275     { | 243 | 
| 276       return (this._map[tab._id] || {}).value; | 244   var framesOfTabs = {__proto__: null}; | 
| 277     }, | 245 | 
| 278     set: function(tab, value) | 246   ext.getFrame = function(tabId, frameId) | 
| 279     { | 247   { | 
| 280       if (!(tab._id in this._map)) | 248     return (framesOfTabs[tabId] || {})[frameId]; | 
| 281         tab.onRemoved.addListener(this.delete); | 249   }; | 
| 282 | 250 | 
| 283       this._map[tab._id] = {tab: tab, value: value}; | 251   ext.webRequest = { | 
| 284     }, | 252     onBeforeRequest: new ext._EventTarget(true), | 
| 285     has: function(tab) | 253     handlerBehaviorChanged: chrome.webRequest.handlerBehaviorChanged | 
| 286     { | 254   }; | 
| 287       return tab._id in this._map; | 255 | 
| 288     }, | 256   chrome.tabs.query({}, function(tabs) | 
| 289     clear: function() | 257   { | 
| 290     { | 258     tabs.forEach(function(tab) | 
| 291       for (var id in this._map) | 259     { | 
| 292         this.delete(this._map[id].tab); | 260       chrome.webNavigation.getAllFrames({tabId: tab.id}, function(details) | 
| 293     } |  | 
| 294   }; |  | 
| 295   TabMap.prototype["delete"] = function(tab) |  | 
| 296   { |  | 
| 297     delete this._map[tab._id]; |  | 
| 298     tab.onRemoved.removeListener(this.delete); |  | 
| 299   }; |  | 
| 300 |  | 
| 301 |  | 
| 302   /* Windows */ |  | 
| 303 |  | 
| 304   Window = function(win) |  | 
| 305   { |  | 
| 306     this._id = win.id; |  | 
| 307     this.visible = win.status != "minimized"; |  | 
| 308   }; |  | 
| 309   Window.prototype = { |  | 
| 310     getAllTabs: function(callback) |  | 
| 311     { |  | 
| 312       chrome.tabs.query({windowId: this._id}, function(tabs) |  | 
| 313       { | 261       { | 
| 314         callback(tabs.map(function(tab) { return new Tab(tab); })); | 262         if (details && details.length > 0) | 
| 315       }); |  | 
| 316     }, |  | 
| 317     getActiveTab: function(callback) |  | 
| 318     { |  | 
| 319       chrome.tabs.query({windowId: this._id, active: true}, function(tabs) |  | 
| 320       { |  | 
| 321         callback(new Tab(tabs[0])); |  | 
| 322       }); |  | 
| 323     }, |  | 
| 324     openTab: function(url, callback) |  | 
| 325     { |  | 
| 326       var props = {windowId: this._id, url: url}; |  | 
| 327 |  | 
| 328       if (!callback) |  | 
| 329         chrome.tabs.create(props); |  | 
| 330       else |  | 
| 331         chrome.tabs.create(props, function(tab) |  | 
| 332         { | 263         { | 
| 333           callback(new Tab(tab)); | 264           var frames = framesOfTabs[tab.id] = {__proto__: null}; | 
| 334         }); | 265 | 
| 335     } | 266           for (var i = 0; i < details.length; i++) | 
| 336   }; | 267             frames[details[i].frameId] = {url: details[i].url, parent: null}; | 
| 337 | 268 | 
| 338 | 269           for (var i = 0; i < details.length; i++) | 
| 339   /* API */ | 270           { | 
| 340 | 271             var parentFrameId = details[i].parentFrameId; | 
| 341   ext.windows = { | 272 | 
| 342     getAll: function(callback) | 273             if (parentFrameId != -1) | 
| 343     { | 274               frames[details[i].frameId].parent = frames[parentFrameId]; | 
| 344       chrome.windows.getAll(function(windows) | 275           } | 
| 345       { |  | 
| 346         callback(windows.map(function(win) |  | 
| 347         { |  | 
| 348           return new Window(win); |  | 
| 349         })); |  | 
| 350       }); |  | 
| 351     }, |  | 
| 352     getLastFocused: function(callback) |  | 
| 353     { |  | 
| 354       chrome.windows.getLastFocused(function(win) |  | 
| 355       { |  | 
| 356         callback(new Window(win)); |  | 
| 357       }); |  | 
| 358     } |  | 
| 359   }; |  | 
| 360 |  | 
| 361   ext.tabs = { |  | 
| 362     onLoading: new LoadingTabEventTarget(), |  | 
| 363     onCompleted: new CompletedTabEventTarget(), |  | 
| 364     onActivated: new ActivatedTabEventTarget(), |  | 
| 365     onRemoved: new RemovedTabEventTarget() |  | 
| 366   }; |  | 
| 367 |  | 
| 368   ext.webRequest = { |  | 
| 369     onBeforeRequest: new BeforeRequestEventTarget(), |  | 
| 370     handlerBehaviorChanged: chrome.webRequest.handlerBehaviorChanged |  | 
| 371   }; |  | 
| 372 |  | 
| 373   ext.contextMenus = { |  | 
| 374     create: function(title, contexts, onclick) |  | 
| 375     { |  | 
| 376       chrome.contextMenus.create({ |  | 
| 377         title: title, |  | 
| 378         contexts: contexts, |  | 
| 379         onclick: function(info, tab) |  | 
| 380         { |  | 
| 381           onclick(info.srcUrl, new Tab(tab)); |  | 
| 382         } | 276         } | 
| 383       }); | 277       }); | 
| 384     }, | 278     }); | 
| 385     removeAll: function(callback) | 279   }); | 
| 386     { | 280 | 
| 387       chrome.contextMenus.removeAll(callback); | 281   chrome.webRequest.onBeforeRequest.addListener(function(details) | 
| 388     } | 282   { | 
| 389   }; | 283     try | 
|  | 284     { | 
|  | 285       // the high-level code isn't interested in requests that aren't related | 
|  | 286       // to a tab and since those can only be handled in Chrome, we ignore | 
|  | 287       // them here instead of in the browser independent high-level code. | 
|  | 288       if (details.tabId == -1) | 
|  | 289         return; | 
|  | 290 | 
|  | 291       var isMainFrame = details.type == "main_frame" || ( | 
|  | 292         // assume that the first request belongs to the top frame. Chrome | 
|  | 293         // may give the top frame the type "object" instead of "main_frame". | 
|  | 294         // https://code.google.com/p/chromium/issues/detail?id=281711 | 
|  | 295         details.frameId == 0 && !(details.tabId in framesOfTabs) | 
|  | 296       ); | 
|  | 297 | 
|  | 298       var frames = null; | 
|  | 299       if (!isMainFrame) | 
|  | 300         frames = framesOfTabs[details.tabId]; | 
|  | 301       if (!frames) | 
|  | 302         frames = framesOfTabs[details.tabId] = {__proto__: null}; | 
|  | 303 | 
|  | 304       var frame = null; | 
|  | 305       if (!isMainFrame) | 
|  | 306       { | 
|  | 307         // we are looking for the frame that contains the element that | 
|  | 308         // is about to load, however if a frame is loading the surrounding | 
|  | 309         // frame is indicated by parentFrameId instead of frameId | 
|  | 310         var frameId; | 
|  | 311         if (details.type == "sub_frame") | 
|  | 312           frameId = details.parentFrameId; | 
|  | 313         else | 
|  | 314           frameId = details.frameId; | 
|  | 315 | 
|  | 316         frame = frames[frameId] || frames[Object.keys(frames)[0]]; | 
|  | 317 | 
|  | 318         if (frame && !ext.webRequest.onBeforeRequest._dispatch(details.url, deta
     ils.type, new Page({id: details.tabId}), frame)) | 
|  | 319           return {cancel: true}; | 
|  | 320       } | 
|  | 321 | 
|  | 322       if (isMainFrame || details.type == "sub_frame") | 
|  | 323         frames[details.frameId] = {url: details.url, parent: frame}; | 
|  | 324     } | 
|  | 325     catch (e) | 
|  | 326     { | 
|  | 327       // recent versions of Chrome cancel the request when an error occurs in | 
|  | 328       // the onBeforeRequest listener. However in our case it is preferred, to | 
|  | 329       // let potentially some ads through, rather than blocking legit requests. | 
|  | 330       console.error(e); | 
|  | 331     } | 
|  | 332   }, {urls: ["<all_urls>"]}, ["blocking"]); | 
|  | 333 | 
|  | 334 | 
|  | 335   /* Message passing */ | 
|  | 336 | 
|  | 337   chrome.runtime.onMessage.addListener(function(message, rawSender, sendResponse
     ) | 
|  | 338   { | 
|  | 339     var sender = { | 
|  | 340       page: new Page(rawSender.tab), | 
|  | 341       frame: { | 
|  | 342         url: rawSender.url, | 
|  | 343         get parent() | 
|  | 344         { | 
|  | 345           var frames = framesOfTabs[rawSender.tab.id]; | 
|  | 346 | 
|  | 347           if (!frames) | 
|  | 348             return null; | 
|  | 349 | 
|  | 350           for (var frameId in frames) | 
|  | 351           { | 
|  | 352             if (frames[frameId].url == rawSender.url) | 
|  | 353               return frames[frameId].parent; | 
|  | 354           } | 
|  | 355 | 
|  | 356           return frames[0]; | 
|  | 357         } | 
|  | 358       } | 
|  | 359     }; | 
|  | 360 | 
|  | 361     return ext.onMessage._dispatch(message, sender, sendResponse); | 
|  | 362   }); | 
|  | 363 | 
|  | 364 | 
|  | 365   /* Storage */ | 
|  | 366 | 
|  | 367   ext.storage = localStorage; | 
| 390 })(); | 368 })(); | 
| OLD | NEW | 
|---|