| OLD | NEW | 
|---|
| 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-present eyeo GmbH | 3  * Copyright (C) 2006-present 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 /* global internal, defineNamespace */ | 
|  | 19 | 
| 18 "use strict"; | 20 "use strict"; | 
| 19 | 21 | 
| 20 { | 22 { | 
| 21   let nonEmptyPageMaps = new Set(); | 23   let nonEmptyPageMaps = new Set(); | 
| 22 | 24 | 
| 23   let PageMap = ext.PageMap = function() | 25   let PageMap = ext.PageMap = function() | 
| 24   { | 26   { | 
| 25     this._map = new Map(); | 27     defineNamespace(this, internal); | 
|  | 28 | 
|  | 29     this[internal].map = new Map(); | 
| 26   }; | 30   }; | 
| 27   PageMap.prototype = { | 31   PageMap.prototype = { | 
| 28     _delete(id) |  | 
| 29     { |  | 
| 30       this._map.delete(id); |  | 
| 31 |  | 
| 32       if (this._map.size == 0) |  | 
| 33         nonEmptyPageMaps.delete(this); |  | 
| 34     }, |  | 
| 35     keys() | 32     keys() | 
| 36     { | 33     { | 
| 37       return Array.from(this._map.keys()).map(ext.getPage); | 34       return Array.from(this[internal].map.keys()).map(ext.getPage); | 
| 38     }, | 35     }, | 
| 39     get(page) | 36     get(page) | 
| 40     { | 37     { | 
| 41       return this._map.get(page.id); | 38       return this[internal].map.get(page.id); | 
| 42     }, | 39     }, | 
| 43     set(page, value) | 40     set(page, value) | 
| 44     { | 41     { | 
| 45       this._map.set(page.id, value); | 42       this[internal].map.set(page.id, value); | 
| 46       nonEmptyPageMaps.add(this); | 43       nonEmptyPageMaps.add(this); | 
| 47     }, | 44     }, | 
| 48     has(page) | 45     has(page) | 
| 49     { | 46     { | 
| 50       return this._map.has(page.id); | 47       return this[internal].map.has(page.id); | 
| 51     }, | 48     }, | 
| 52     clear() | 49     clear() | 
| 53     { | 50     { | 
| 54       this._map.clear(); | 51       this[internal].map.clear(); | 
| 55       nonEmptyPageMaps.delete(this); | 52       nonEmptyPageMaps.delete(this); | 
| 56     }, | 53     }, | 
| 57     delete(page) | 54     delete(page) | 
| 58     { | 55     { | 
| 59       this._delete(page.id); | 56       deletePage(this, page.id); | 
| 60     } | 57     } | 
| 61   }; | 58   }; | 
| 62 | 59 | 
| 63   ext._removeFromAllPageMaps = pageId => | 60   function deletePage(pageMap, pageId) | 
|  | 61   { | 
|  | 62     pageMap[internal].map.delete(pageId); | 
|  | 63 | 
|  | 64     if (pageMap[internal].map.size == 0) | 
|  | 65       nonEmptyPageMaps.delete(pageMap); | 
|  | 66   } | 
|  | 67 | 
|  | 68   ext[internal].removeFromAllPageMaps = pageId => | 
| 64   { | 69   { | 
| 65     for (let pageMap of nonEmptyPageMaps) | 70     for (let pageMap of nonEmptyPageMaps) | 
| 66       pageMap._delete(pageId); | 71       deletePage(pageMap, pageId); | 
| 67   }; | 72   }; | 
| 68 | 73 | 
| 69   /* Pages */ | 74   /* Pages */ | 
| 70 | 75 | 
| 71   let Page = ext.Page = function(tab) | 76   let Page = ext.Page = function(tab) | 
| 72   { | 77   { | 
|  | 78     defineNamespace(this, internal); | 
|  | 79 | 
| 73     this.id = tab.id; | 80     this.id = tab.id; | 
| 74     this._url = tab.url && new URL(tab.url); | 81 | 
|  | 82     this[internal].url = tab.url && new URL(tab.url); | 
| 75 | 83 | 
| 76     this.browserAction = new BrowserAction(tab.id); | 84     this.browserAction = new BrowserAction(tab.id); | 
| 77     this.contextMenus = new ContextMenus(this); | 85     this.contextMenus = new ContextMenus(this); | 
| 78   }; | 86   }; | 
| 79   Page.prototype = { | 87   Page.prototype = { | 
| 80     get url() | 88     get url() | 
| 81     { | 89     { | 
| 82       // usually our Page objects are created from Chrome's Tab objects, which | 90       // usually our Page objects are created from Chrome's Tab objects, which | 
| 83       // provide the url. So we can return the url given in the constructor. | 91       // provide the url. So we can return the url given in the constructor. | 
| 84       if (this._url) | 92       if (this[internal].url) | 
| 85         return this._url; | 93         return this[internal].url; | 
| 86 | 94 | 
| 87       // but sometimes we only have the tab id when we create a Page object. | 95       // but sometimes we only have the tab id when we create a Page object. | 
| 88       // In that case we get the url from top frame of the tab, recorded by | 96       // In that case we get the url from top frame of the tab, recorded by | 
| 89       // the onBeforeRequest handler. | 97       // the onBeforeRequest handler. | 
| 90       let frames = framesOfTabs.get(this.id); | 98       let frames = framesOfTabs.get(this.id); | 
| 91       if (frames) | 99       if (frames) | 
| 92       { | 100       { | 
| 93         let frame = frames.get(0); | 101         let frame = frames.get(0); | 
| 94         if (frame) | 102         if (frame) | 
| 95           return frame.url; | 103           return frame.url; | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
| 113         { | 121         { | 
| 114           browser.tabs.onUpdated.removeListener(onUpdated); | 122           browser.tabs.onUpdated.removeListener(onUpdated); | 
| 115           callback(new Page(openedTab)); | 123           callback(new Page(openedTab)); | 
| 116         } | 124         } | 
| 117       }; | 125       }; | 
| 118       browser.tabs.onUpdated.addListener(onUpdated); | 126       browser.tabs.onUpdated.addListener(onUpdated); | 
| 119     }; | 127     }; | 
| 120   } | 128   } | 
| 121 | 129 | 
| 122   ext.pages = { | 130   ext.pages = { | 
| 123     onLoading: new ext._EventTarget(), | 131     onLoading: new ext[internal].EventTarget(), | 
| 124     onActivated: new ext._EventTarget(), | 132     onActivated: new ext[internal].EventTarget(), | 
| 125     onRemoved: new ext._EventTarget() | 133     onRemoved: new ext[internal].EventTarget() | 
| 126   }; | 134   }; | 
| 127 | 135 | 
| 128   browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => | 136   browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => | 
| 129   { | 137   { | 
| 130     if (changeInfo.status == "loading") | 138     if (changeInfo.status == "loading") | 
| 131       ext.pages.onLoading._dispatch(new Page(tab)); | 139       ext[internal].dispatchEvent(ext.pages.onLoading, new Page(tab)); | 
| 132   }); | 140   }); | 
| 133 | 141 | 
| 134   function createFrame(tabId, frameId) | 142   function createFrame(tabId, frameId) | 
| 135   { | 143   { | 
| 136     let frames = framesOfTabs.get(tabId); | 144     let frames = framesOfTabs.get(tabId); | 
| 137     if (!frames) | 145     if (!frames) | 
| 138     { | 146     { | 
| 139       frames = new Map(); | 147       frames = new Map(); | 
| 140       framesOfTabs.set(tabId, frames); | 148       framesOfTabs.set(tabId, frames); | 
| 141     } | 149     } | 
| 142 | 150 | 
| 143     let frame = frames.get(frameId); | 151     let frame = frames.get(frameId); | 
| 144     if (!frame) | 152     if (!frame) | 
| 145     { | 153     { | 
| 146       frame = {}; | 154       frame = {}; | 
| 147       frames.set(frameId, frame); | 155       frames.set(frameId, frame); | 
| 148     } | 156     } | 
| 149 | 157 | 
| 150     return frame; | 158     return frame; | 
| 151   } | 159   } | 
| 152 | 160 | 
| 153   function updatePageFrameStructure(frameId, tabId, url, parentFrameId) | 161   function updatePageFrameStructure(frameId, tabId, url, parentFrameId) | 
| 154   { | 162   { | 
| 155     if (frameId == 0) | 163     if (frameId == 0) | 
| 156     { | 164     { | 
| 157       let page = new Page({id: tabId, url}); | 165       let page = new Page({id: tabId, url}); | 
| 158 | 166 | 
| 159       ext._removeFromAllPageMaps(tabId); | 167       ext[internal].removeFromAllPageMaps(tabId); | 
| 160 | 168 | 
| 161       browser.tabs.get(tabId, () => | 169       browser.tabs.get(tabId, () => | 
| 162       { | 170       { | 
| 163         // If the tab is prerendered, browser.tabs.get() sets | 171         // If the tab is prerendered, browser.tabs.get() sets | 
| 164         // browser.runtime.lastError and we have to dispatch the onLoading | 172         // browser.runtime.lastError and we have to dispatch the onLoading | 
| 165         // event, since the onUpdated event isn't dispatched for prerendered | 173         // event, since the onUpdated event isn't dispatched for prerendered | 
| 166         // tabs. However, we have to keep relying on the onUpdated event for | 174         // tabs. However, we have to keep relying on the onUpdated event for | 
| 167         // tabs that are already visible. Otherwise browser action changes get | 175         // tabs that are already visible. Otherwise browser action changes get | 
| 168         // overridden when Chrome automatically resets them on navigation. | 176         // overridden when Chrome automatically resets them on navigation. | 
| 169         if (browser.runtime.lastError) | 177         if (browser.runtime.lastError) | 
| 170           ext.pages.onLoading._dispatch(page); | 178           ext[internal].dispatchEvent(ext.pages.onLoading, page); | 
| 171       }); | 179       }); | 
| 172     } | 180     } | 
| 173 | 181 | 
| 174     // Update frame URL and parent in frame structure | 182     // Update frame URL and parent in frame structure | 
| 175     let frame = createFrame(tabId, frameId); | 183     let frame = createFrame(tabId, frameId); | 
| 176     frame.url = new URL(url); | 184     frame.url = new URL(url); | 
| 177 | 185 | 
| 178     let parentFrame = framesOfTabs.get(tabId).get(parentFrameId); | 186     let parentFrame = framesOfTabs.get(tabId).get(parentFrameId); | 
| 179     if (parentFrame) | 187     if (parentFrame) | 
| 180       frame.parent = parentFrame; | 188       frame.parent = parentFrame; | 
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 270           // for Web Store URLs. | 278           // for Web Store URLs. | 
| 271           !url.startsWith("https://chrome.google.com/webstore/"))) | 279           !url.startsWith("https://chrome.google.com/webstore/"))) | 
| 272     { | 280     { | 
| 273       updatePageFrameStructure(details.frameId, details.tabId, url, | 281       updatePageFrameStructure(details.frameId, details.tabId, url, | 
| 274                                details.parentFrameId); | 282                                details.parentFrameId); | 
| 275     } | 283     } | 
| 276   }); | 284   }); | 
| 277 | 285 | 
| 278   function forgetTab(tabId) | 286   function forgetTab(tabId) | 
| 279   { | 287   { | 
| 280     ext.pages.onRemoved._dispatch(tabId); | 288     ext[internal].dispatchEvent(ext.pages.onRemoved, tabId); | 
| 281 | 289 | 
| 282     ext._removeFromAllPageMaps(tabId); | 290     ext[internal].removeFromAllPageMaps(tabId); | 
| 283     framesOfTabs.delete(tabId); | 291     framesOfTabs.delete(tabId); | 
| 284   } | 292   } | 
| 285 | 293 | 
| 286   browser.tabs.onReplaced.addListener((addedTabId, removedTabId) => | 294   browser.tabs.onReplaced.addListener((addedTabId, removedTabId) => | 
| 287   { | 295   { | 
| 288     forgetTab(removedTabId); | 296     forgetTab(removedTabId); | 
| 289   }); | 297   }); | 
| 290 | 298 | 
| 291   browser.tabs.onRemoved.addListener(forgetTab); | 299   browser.tabs.onRemoved.addListener(forgetTab); | 
| 292 | 300 | 
| 293   browser.tabs.onActivated.addListener(details => | 301   browser.tabs.onActivated.addListener(details => | 
| 294   { | 302   { | 
| 295     ext.pages.onActivated._dispatch(new Page({id: details.tabId})); | 303     ext[internal].dispatchEvent(ext.pages.onActivated, | 
|  | 304                                 new Page({id: details.tabId})); | 
| 296   }); | 305   }); | 
| 297 | 306 | 
| 298 | 307 | 
| 299   /* Browser actions */ | 308   /* Browser actions */ | 
| 300 | 309 | 
| 301   let BrowserAction = function(tabId) | 310   let BrowserAction = function(tabId) | 
| 302   { | 311   { | 
| 303     this._tabId = tabId; | 312     defineNamespace(this, internal); | 
| 304     this._changes = null; | 313 | 
|  | 314     this[internal].tabId = tabId; | 
|  | 315     this[internal].changes = null; | 
| 305   }; | 316   }; | 
| 306   BrowserAction.prototype = { | 317   BrowserAction.prototype = { | 
| 307     _applyChanges() |  | 
| 308     { |  | 
| 309       if ("iconPath" in this._changes) |  | 
| 310       { |  | 
| 311         // Firefox for Android displays the browser action not as an icon but |  | 
| 312         // as a menu item. There is no icon, but such an option may be added in |  | 
| 313         // the future. |  | 
| 314         // https://bugzilla.mozilla.org/show_bug.cgi?id=1331746 |  | 
| 315         if ("setIcon" in browser.browserAction) |  | 
| 316         { |  | 
| 317           let path = { |  | 
| 318             16: this._changes.iconPath.replace("$size", "16"), |  | 
| 319             19: this._changes.iconPath.replace("$size", "19"), |  | 
| 320             20: this._changes.iconPath.replace("$size", "20"), |  | 
| 321             32: this._changes.iconPath.replace("$size", "32"), |  | 
| 322             38: this._changes.iconPath.replace("$size", "38"), |  | 
| 323             40: this._changes.iconPath.replace("$size", "40") |  | 
| 324           }; |  | 
| 325           try |  | 
| 326           { |  | 
| 327             browser.browserAction.setIcon({tabId: this._tabId, path}); |  | 
| 328           } |  | 
| 329           catch (e) |  | 
| 330           { |  | 
| 331             // Edge throws if passed icon sizes different than 19,20,38,40px. |  | 
| 332             delete path[16]; |  | 
| 333             delete path[32]; |  | 
| 334             browser.browserAction.setIcon({tabId: this._tabId, path}); |  | 
| 335           } |  | 
| 336         } |  | 
| 337       } |  | 
| 338 |  | 
| 339       if ("badgeText" in this._changes) |  | 
| 340       { |  | 
| 341         // There is no badge on Firefox for Android; the browser action is |  | 
| 342         // simply a menu item. |  | 
| 343         if ("setBadgeText" in browser.browserAction) |  | 
| 344         { |  | 
| 345           browser.browserAction.setBadgeText({ |  | 
| 346             tabId: this._tabId, |  | 
| 347             text: this._changes.badgeText |  | 
| 348           }); |  | 
| 349         } |  | 
| 350       } |  | 
| 351 |  | 
| 352       if ("badgeColor" in this._changes) |  | 
| 353       { |  | 
| 354         // There is no badge on Firefox for Android; the browser action is |  | 
| 355         // simply a menu item. |  | 
| 356         if ("setBadgeBackgroundColor" in browser.browserAction) |  | 
| 357         { |  | 
| 358           browser.browserAction.setBadgeBackgroundColor({ |  | 
| 359             tabId: this._tabId, |  | 
| 360             color: this._changes.badgeColor |  | 
| 361           }); |  | 
| 362         } |  | 
| 363       } |  | 
| 364 |  | 
| 365       this._changes = null; |  | 
| 366     }, |  | 
| 367     _queueChanges() |  | 
| 368     { |  | 
| 369       browser.tabs.get(this._tabId, () => |  | 
| 370       { |  | 
| 371         // If the tab is prerendered, browser.tabs.get() sets |  | 
| 372         // browser.runtime.lastError and we have to delay our changes |  | 
| 373         // until the currently visible tab is replaced with the |  | 
| 374         // prerendered tab. Otherwise browser.browserAction.set* fails. |  | 
| 375         if (browser.runtime.lastError) |  | 
| 376         { |  | 
| 377           let onReplaced = (addedTabId, removedTabId) => |  | 
| 378           { |  | 
| 379             if (addedTabId == this._tabId) |  | 
| 380             { |  | 
| 381               browser.tabs.onReplaced.removeListener(onReplaced); |  | 
| 382               this._applyChanges(); |  | 
| 383             } |  | 
| 384           }; |  | 
| 385           browser.tabs.onReplaced.addListener(onReplaced); |  | 
| 386         } |  | 
| 387         else |  | 
| 388         { |  | 
| 389           this._applyChanges(); |  | 
| 390         } |  | 
| 391       }); |  | 
| 392     }, |  | 
| 393     _addChange(name, value) |  | 
| 394     { |  | 
| 395       if (!this._changes) |  | 
| 396       { |  | 
| 397         this._changes = {}; |  | 
| 398         this._queueChanges(); |  | 
| 399       } |  | 
| 400 |  | 
| 401       this._changes[name] = value; |  | 
| 402     }, |  | 
| 403     setIcon(path) | 318     setIcon(path) | 
| 404     { | 319     { | 
| 405       this._addChange("iconPath", path); | 320       addBrowserActionChange(this, "iconPath", path); | 
| 406     }, | 321     }, | 
| 407     setBadge(badge) | 322     setBadge(badge) | 
| 408     { | 323     { | 
| 409       if (!badge) | 324       if (!badge) | 
| 410       { | 325       { | 
| 411         this._addChange("badgeText", ""); | 326         addBrowserActionChange(this, "badgeText", ""); | 
| 412       } | 327       } | 
| 413       else | 328       else | 
| 414       { | 329       { | 
| 415         if ("number" in badge) | 330         if ("number" in badge) | 
| 416           this._addChange("badgeText", badge.number.toString()); | 331           addBrowserActionChange(this, "badgeText", badge.number.toString()); | 
| 417 | 332 | 
| 418         if ("color" in badge) | 333         if ("color" in badge) | 
| 419           this._addChange("badgeColor", badge.color); | 334           addBrowserActionChange(this, "badgeColor", badge.color); | 
| 420       } | 335       } | 
| 421     } | 336     } | 
| 422   }; | 337   }; | 
| 423 | 338 | 
|  | 339   function queueBrowserActionChanges(browserAction) | 
|  | 340   { | 
|  | 341     browser.tabs.get(browserAction[internal].tabId, () => | 
|  | 342     { | 
|  | 343       // If the tab is prerendered, browser.tabs.get() sets | 
|  | 344       // browser.runtime.lastError and we have to delay our changes | 
|  | 345       // until the currently visible tab is replaced with the | 
|  | 346       // prerendered tab. Otherwise browser.browserAction.set* fails. | 
|  | 347       if (browser.runtime.lastError) | 
|  | 348       { | 
|  | 349         let onReplaced = (addedTabId, removedTabId) => | 
|  | 350         { | 
|  | 351           if (addedTabId == browserAction[internal].tabId) | 
|  | 352           { | 
|  | 353             browser.tabs.onReplaced.removeListener(onReplaced); | 
|  | 354             applyBrowserActionChanges(browserAction); | 
|  | 355           } | 
|  | 356         }; | 
|  | 357         browser.tabs.onReplaced.addListener(onReplaced); | 
|  | 358       } | 
|  | 359       else | 
|  | 360       { | 
|  | 361         applyBrowserActionChanges(browserAction); | 
|  | 362       } | 
|  | 363     }); | 
|  | 364   } | 
|  | 365 | 
|  | 366   function applyBrowserActionChanges(browserAction) | 
|  | 367   { | 
|  | 368     if ("iconPath" in browserAction[internal].changes) | 
|  | 369     { | 
|  | 370       // Firefox for Android displays the browser action not as an icon but | 
|  | 371       // as a menu item. There is no icon, but such an option may be added in | 
|  | 372       // the future. | 
|  | 373       // https://bugzilla.mozilla.org/show_bug.cgi?id=1331746 | 
|  | 374       if ("setIcon" in browser.browserAction) | 
|  | 375       { | 
|  | 376         let path = { | 
|  | 377           16: browserAction[internal].changes.iconPath.replace("$size", "16"), | 
|  | 378           19: browserAction[internal].changes.iconPath.replace("$size", "19"), | 
|  | 379           20: browserAction[internal].changes.iconPath.replace("$size", "20"), | 
|  | 380           32: browserAction[internal].changes.iconPath.replace("$size", "32"), | 
|  | 381           38: browserAction[internal].changes.iconPath.replace("$size", "38"), | 
|  | 382           40: browserAction[internal].changes.iconPath.replace("$size", "40") | 
|  | 383         }; | 
|  | 384         try | 
|  | 385         { | 
|  | 386           browser.browserAction.setIcon({ | 
|  | 387             tabId: browserAction[internal].tabId, | 
|  | 388             path | 
|  | 389           }); | 
|  | 390         } | 
|  | 391         catch (e) | 
|  | 392         { | 
|  | 393           // Edge throws if passed icon sizes different than 19,20,38,40px. | 
|  | 394           delete path[16]; | 
|  | 395           delete path[32]; | 
|  | 396           browser.browserAction.setIcon({ | 
|  | 397             tabId: browserAction[internal].tabId, | 
|  | 398             path | 
|  | 399           }); | 
|  | 400         } | 
|  | 401       } | 
|  | 402     } | 
|  | 403 | 
|  | 404     if ("badgeText" in browserAction[internal].changes) | 
|  | 405     { | 
|  | 406       // There is no badge on Firefox for Android; the browser action is | 
|  | 407       // simply a menu item. | 
|  | 408       if ("setBadgeText" in browser.browserAction) | 
|  | 409       { | 
|  | 410         browser.browserAction.setBadgeText({ | 
|  | 411           tabId: browserAction[internal].tabId, | 
|  | 412           text: browserAction[internal].changes.badgeText | 
|  | 413         }); | 
|  | 414       } | 
|  | 415     } | 
|  | 416 | 
|  | 417     if ("badgeColor" in browserAction[internal].changes) | 
|  | 418     { | 
|  | 419       // There is no badge on Firefox for Android; the browser action is | 
|  | 420       // simply a menu item. | 
|  | 421       if ("setBadgeBackgroundColor" in browser.browserAction) | 
|  | 422       { | 
|  | 423         browser.browserAction.setBadgeBackgroundColor({ | 
|  | 424           tabId: browserAction[internal].tabId, | 
|  | 425           color: browserAction[internal].changes.badgeColor | 
|  | 426         }); | 
|  | 427       } | 
|  | 428     } | 
|  | 429 | 
|  | 430     browserAction[internal].changes = null; | 
|  | 431   } | 
|  | 432 | 
|  | 433   function addBrowserActionChange(browserAction, name, value) | 
|  | 434   { | 
|  | 435     if (!browserAction[internal].changes) | 
|  | 436     { | 
|  | 437       browserAction[internal].changes = {}; | 
|  | 438       queueBrowserActionChanges(browserAction); | 
|  | 439     } | 
|  | 440 | 
|  | 441     browserAction[internal].changes[name] = value; | 
|  | 442   } | 
|  | 443 | 
| 424 | 444 | 
| 425   /* Context menus */ | 445   /* Context menus */ | 
| 426 | 446 | 
| 427   let contextMenuItems = new ext.PageMap(); | 447   let contextMenuItems = new ext.PageMap(); | 
| 428   let contextMenuUpdating = false; | 448   let contextMenuUpdating = false; | 
| 429 | 449 | 
| 430   let updateContextMenu = () => | 450   let updateContextMenu = () => | 
| 431   { | 451   { | 
| 432     // Firefox for Android does not support context menus. | 452     // Firefox for Android does not support context menus. | 
| 433     // https://bugzilla.mozilla.org/show_bug.cgi?id=1269062 | 453     // https://bugzilla.mozilla.org/show_bug.cgi?id=1269062 | 
| (...skipping 26 matching lines...) Expand all  Loading... | 
| 460               item.onclick(new Page(tab)); | 480               item.onclick(new Page(tab)); | 
| 461             } | 481             } | 
| 462           }); | 482           }); | 
| 463         }); | 483         }); | 
| 464       }); | 484       }); | 
| 465     }); | 485     }); | 
| 466   }; | 486   }; | 
| 467 | 487 | 
| 468   let ContextMenus = function(page) | 488   let ContextMenus = function(page) | 
| 469   { | 489   { | 
| 470     this._page = page; | 490     defineNamespace(this, internal); | 
|  | 491 | 
|  | 492     this[internal].page = page; | 
| 471   }; | 493   }; | 
| 472   ContextMenus.prototype = { | 494   ContextMenus.prototype = { | 
| 473     create(item) | 495     create(item) | 
| 474     { | 496     { | 
| 475       let items = contextMenuItems.get(this._page); | 497       let items = contextMenuItems.get(this[internal].page); | 
| 476       if (!items) | 498       if (!items) | 
| 477         contextMenuItems.set(this._page, items = []); | 499         contextMenuItems.set(this[internal].page, items = []); | 
| 478 | 500 | 
| 479       items.push(item); | 501       items.push(item); | 
| 480       updateContextMenu(); | 502       updateContextMenu(); | 
| 481     }, | 503     }, | 
| 482     remove(item) | 504     remove(item) | 
| 483     { | 505     { | 
| 484       let items = contextMenuItems.get(this._page); | 506       let items = contextMenuItems.get(this[internal].page); | 
| 485       if (items) | 507       if (items) | 
| 486       { | 508       { | 
| 487         let index = items.indexOf(item); | 509         let index = items.indexOf(item); | 
| 488         if (index != -1) | 510         if (index != -1) | 
| 489         { | 511         { | 
| 490           items.splice(index, 1); | 512           items.splice(index, 1); | 
| 491           updateContextMenu(); | 513           updateContextMenu(); | 
| 492         } | 514         } | 
| 493       } | 515       } | 
| 494     } | 516     } | 
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 530         propagateHandlerBehaviorChange | 552         propagateHandlerBehaviorChange | 
| 531       ); | 553       ); | 
| 532       browser.webRequest.handlerBehaviorChanged(); | 554       browser.webRequest.handlerBehaviorChanged(); | 
| 533 | 555 | 
| 534       handlerBehaviorChangedQuota--; | 556       handlerBehaviorChangedQuota--; | 
| 535       setTimeout(() => { handlerBehaviorChangedQuota++; }, 600000); | 557       setTimeout(() => { handlerBehaviorChangedQuota++; }, 600000); | 
| 536     } | 558     } | 
| 537   } | 559   } | 
| 538 | 560 | 
| 539   ext.webRequest = { | 561   ext.webRequest = { | 
| 540     onBeforeRequest: new ext._EventTarget(), | 562     onBeforeRequest: new ext[internal].EventTarget(), | 
| 541     handlerBehaviorChanged() | 563     handlerBehaviorChanged() | 
| 542     { | 564     { | 
| 543       // Defer handlerBehaviorChanged() until navigation occurs. | 565       // Defer handlerBehaviorChanged() until navigation occurs. | 
| 544       // There wouldn't be any visible effect when calling it earlier, | 566       // There wouldn't be any visible effect when calling it earlier, | 
| 545       // but it's an expensive operation and that way we avoid to call | 567       // but it's an expensive operation and that way we avoid to call | 
| 546       // it multiple times, if multiple filters are added/removed. | 568       // it multiple times, if multiple filters are added/removed. | 
| 547       let {onBeforeNavigate} = browser.webNavigation; | 569       let {onBeforeNavigate} = browser.webNavigation; | 
| 548       if (!onBeforeNavigate.hasListener(propagateHandlerBehaviorChange)) | 570       if (!onBeforeNavigate.hasListener(propagateHandlerBehaviorChange)) | 
| 549         onBeforeNavigate.addListener(propagateHandlerBehaviorChange); | 571         onBeforeNavigate.addListener(propagateHandlerBehaviorChange); | 
| 550     } | 572     } | 
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 615     // Sometimes requests are not associated with a browser tab and | 637     // Sometimes requests are not associated with a browser tab and | 
| 616     // in this case we want to still be able to view the url being called. | 638     // in this case we want to still be able to view the url being called. | 
| 617     let frame = null; | 639     let frame = null; | 
| 618     let page = null; | 640     let page = null; | 
| 619     if (details.tabId != -1) | 641     if (details.tabId != -1) | 
| 620     { | 642     { | 
| 621       frame = ext.getFrame(details.tabId, frameId); | 643       frame = ext.getFrame(details.tabId, frameId); | 
| 622       page = new Page({id: details.tabId}); | 644       page = new Page({id: details.tabId}); | 
| 623     } | 645     } | 
| 624 | 646 | 
| 625     if (ext.webRequest.onBeforeRequest._dispatch( | 647     if (ext[internal].dispatchEvent(ext.webRequest.onBeforeRequest, | 
| 626         url, type, page, frame).includes(false)) | 648                                     url, type, page, frame).includes(false)) | 
|  | 649     { | 
| 627       return {cancel: true}; | 650       return {cancel: true}; | 
|  | 651     } | 
| 628   }, {urls: ["<all_urls>"]}, ["blocking"]); | 652   }, {urls: ["<all_urls>"]}, ["blocking"]); | 
| 629 | 653 | 
| 630 | 654 | 
| 631   /* Message passing */ | 655   /* Message passing */ | 
| 632 | 656 | 
| 633   browser.runtime.onMessage.addListener((message, rawSender, sendResponse) => | 657   browser.runtime.onMessage.addListener((message, rawSender, sendResponse) => | 
| 634   { | 658   { | 
| 635     let sender = {}; | 659     let sender = {}; | 
| 636 | 660 | 
| 637     // Add "page" and "frame" if the message was sent by a content script. | 661     // Add "page" and "frame" if the message was sent by a content script. | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
| 653 | 677 | 
| 654           let frame = frames.get(rawSender.frameId); | 678           let frame = frames.get(rawSender.frameId); | 
| 655           if (frame) | 679           if (frame) | 
| 656             return frame.parent || null; | 680             return frame.parent || null; | 
| 657 | 681 | 
| 658           return frames.get(0) || null; | 682           return frames.get(0) || null; | 
| 659         } | 683         } | 
| 660       }; | 684       }; | 
| 661     } | 685     } | 
| 662 | 686 | 
| 663     return ext.onMessage._dispatch( | 687     return ext[internal].dispatchEvent( | 
|  | 688       ext.onMessage, | 
| 664       message, sender, sendResponse | 689       message, sender, sendResponse | 
| 665     ).includes(true); | 690     ).includes(true); | 
| 666   }); | 691   }); | 
| 667 | 692 | 
| 668 | 693 | 
| 669   /* Storage */ | 694   /* Storage */ | 
| 670 | 695 | 
| 671   ext.storage = { | 696   ext.storage = { | 
| 672     get(keys, callback) | 697     get(keys, callback) | 
| 673     { | 698     { | 
| (...skipping 16 matching lines...) Expand all  Loading... | 
| 690   ext.windows = { | 715   ext.windows = { | 
| 691     create(createData, callback) | 716     create(createData, callback) | 
| 692     { | 717     { | 
| 693       browser.windows.create(createData, createdWindow => | 718       browser.windows.create(createData, createdWindow => | 
| 694       { | 719       { | 
| 695         afterTabLoaded(callback)(createdWindow.tabs[0]); | 720         afterTabLoaded(callback)(createdWindow.tabs[0]); | 
| 696       }); | 721       }); | 
| 697     } | 722     } | 
| 698   }; | 723   }; | 
| 699 } | 724 } | 
| OLD | NEW | 
|---|