| LEFT | RIGHT | 
|    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 /* globals require */ |   18 /* globals require */ | 
|   19  |   19  | 
|   20 "use strict"; |   20 "use strict"; | 
|   21  |   21  | 
|   22 (function(global) |   22 (function(global) | 
|   23 { |   23 { | 
|   24   const {port} = require("../lib/messaging"); |   24   const {port} = require("../lib/messaging"); | 
|   25   const {Prefs} = require("../lib/prefs"); |   25   const {Prefs} = require("../lib/prefs"); | 
|   26   const {Utils} = require("../lib/utils"); |   26   const {Utils} = require("../lib/utils"); | 
|   27   const {FilterStorage} = require("../adblockpluscore/lib/filterStorage"); |   27   const {FilterStorage} = require("../adblockpluscore/lib/filterStorage"); | 
|   28   const {FilterNotifier} = require("../adblockpluscore/lib/filterNotifier"); |   28   const {FilterNotifier} = require("../adblockpluscore/lib/filterNotifier"); | 
|   29   const {defaultMatcher} = require("../adblockpluscore/lib/matcher"); |   29   const {defaultMatcher} = require("../adblockpluscore/lib/matcher"); | 
|   30   const {Notification: |   30   const {Notification: | 
|   31          NotificationStorage} = require("../adblockpluscore/lib/notification"); |   31          NotificationStorage} = require("../adblockpluscore/lib/notification"); | 
|   32   const {getActiveNotification, shouldDisplay, |   32   const {getActiveNotification, shouldDisplay, | 
|   33          notificationClicked} = require("../lib/notificationHelper"); |   33          notificationClicked} = require("../lib/notificationHelper"); | 
 |   34   const {HitLogger} = require("../lib/hitLogger"); | 
|   34  |   35  | 
|   35   const { |   36   const { | 
|   36     Filter, ActiveFilter, BlockingFilter, RegExpFilter |   37     Filter, ActiveFilter, BlockingFilter, RegExpFilter | 
|   37   } = require("../adblockpluscore/lib/filterClasses"); |   38   } = require("../adblockpluscore/lib/filterClasses"); | 
|   38   const {Synchronizer} = require("../adblockpluscore/lib/synchronizer"); |   39   const {Synchronizer} = require("../adblockpluscore/lib/synchronizer"); | 
|   39  |   40  | 
|   40   const info = require("info"); |   41   const info = require("info"); | 
|   41   const { |   42   const { | 
|   42     Subscription, |   43     Subscription, | 
|   43     DownloadableSubscription, |   44     DownloadableSubscription, | 
|   44     SpecialSubscription |   45     SpecialSubscription, | 
 |   46     RegularSubscription | 
|   45   } = require("../adblockpluscore/lib/subscriptionClasses"); |   47   } = require("../adblockpluscore/lib/subscriptionClasses"); | 
|   46  |   48  | 
|   47   const {showOptions} = require("../lib/options"); |   49   const {showOptions} = require("../lib/options"); | 
|   48  |   50  | 
|   49   port.on("types.get", (message, sender) => |   51   port.on("types.get", (message, sender) => | 
|   50   { |   52   { | 
|   51     let filterTypes = Array.from(require("requestBlocker").filterTypes); |   53     const filterTypes = Array.from(require("requestBlocker").filterTypes); | 
|   52     filterTypes.push(...filterTypes.splice(filterTypes.indexOf("OTHER"), 1)); |   54     filterTypes.push(...filterTypes.splice(filterTypes.indexOf("OTHER"), 1)); | 
|   53     return filterTypes; |   55     return filterTypes; | 
|   54   }); |   56   }); | 
|   55  |   57  | 
|   56   function convertObject(keys, obj) |   58   function convertObject(keys, obj) | 
|   57   { |   59   { | 
|   58     let result = {}; |   60     const result = {}; | 
|   59     for (let key of keys) |   61     for (const key of keys) | 
|   60     { |   62     { | 
|   61       if (key in obj) |   63       if (key in obj) | 
|   62         result[key] = obj[key]; |   64         result[key] = obj[key]; | 
|   63     } |   65     } | 
|   64     return result; |   66     return result; | 
|   65   } |   67   } | 
|   66  |   68  | 
|   67   function convertSubscription(subscription) |   69   function convertSubscription(subscription) | 
|   68   { |   70   { | 
|   69     let obj = convertObject(["disabled", "downloadStatus", "homepage", |   71     const obj = convertObject(["disabled", "downloadStatus", "homepage", | 
|   70                              "version", "lastDownload", "lastSuccess", |   72                                "version", "lastDownload", "lastSuccess", | 
|   71                              "softExpiration", "expires", "title", |   73                                "softExpiration", "expires", "title", | 
|   72                              "url"], subscription); |   74                                "url"], subscription); | 
|   73     if (subscription instanceof SpecialSubscription) |   75     if (subscription instanceof SpecialSubscription) | 
|   74       obj.filters = subscription.filters.map(convertFilter); |   76       obj.filters = subscription.filters.map(convertFilter); | 
|   75     obj.isDownloading = Synchronizer.isExecuting(subscription.url); |   77     obj.isDownloading = Synchronizer.isExecuting(subscription.url); | 
|   76     return obj; |   78     return obj; | 
|   77   } |   79   } | 
|   78  |   80  | 
|   79   let convertFilter = convertObject.bind(null, ["text"]); |   81   const convertFilter = convertObject.bind(null, ["text"]); | 
|   80  |   82  | 
|   81   let uiPorts = new Map(); |   83   const uiPorts = new Map(); | 
|   82   let listenedPreferences = Object.create(null); |   84   const listenedPreferences = Object.create(null); | 
|   83   let listenedFilterChanges = Object.create(null); |   85   const listenedFilterChanges = Object.create(null); | 
|   84   let messageTypes = new Map([ |   86   const messageTypes = new Map([ | 
|   85     ["app", "app.respond"], |   87     ["app", "app.respond"], | 
|   86     ["filter", "filters.respond"], |   88     ["filter", "filters.respond"], | 
|   87     ["pref", "prefs.respond"], |   89     ["pref", "prefs.respond"], | 
 |   90     ["requests", "requests.respond"], | 
|   88     ["subscription", "subscriptions.respond"] |   91     ["subscription", "subscriptions.respond"] | 
|   89   ]); |   92   ]); | 
|   90  |   93  | 
|   91   function sendMessage(type, action, ...args) |   94   function sendMessage(type, action, ...args) | 
|   92   { |   95   { | 
|   93     if (uiPorts.size == 0) |   96     if (uiPorts.size == 0) | 
|   94       return; |   97       return; | 
|   95  |   98  | 
|   96     let convertedArgs = []; |   99     const convertedArgs = []; | 
|   97     for (let arg of args) |  100     for (const arg of args) | 
|   98     { |  101     { | 
|   99       if (arg instanceof Subscription) |  102       if (arg instanceof Subscription) | 
|  100         convertedArgs.push(convertSubscription(arg)); |  103         convertedArgs.push(convertSubscription(arg)); | 
|  101       else if (arg instanceof Filter) |  104       else if (arg instanceof Filter) | 
|  102         convertedArgs.push(convertFilter(arg)); |  105         convertedArgs.push(convertFilter(arg)); | 
|  103       else |  106       else | 
|  104         convertedArgs.push(arg); |  107         convertedArgs.push(arg); | 
|  105     } |  108     } | 
|  106  |  109  | 
|  107     for (let [uiPort, filters] of uiPorts) |  110     for (const [uiPort, filters] of uiPorts) | 
|  108     { |  111     { | 
|  109       let actions = filters.get(type); |  112       const actions = filters.get(type); | 
|  110       if (actions && actions.indexOf(action) != -1) |  113       if (actions && actions.indexOf(action) != -1) | 
|  111       { |  114       { | 
|  112         uiPort.postMessage({ |  115         uiPort.postMessage({ | 
|  113           type: messageTypes.get(type), |  116           type: messageTypes.get(type), | 
|  114           action, |  117           action, | 
|  115           args: convertedArgs |  118           args: convertedArgs | 
|  116         }); |  119         }); | 
|  117       } |  120       } | 
|  118     } |  121     } | 
|  119   } |  122   } | 
|  120  |  123  | 
 |  124   function includeActiveRemoteSubscriptions(s) | 
 |  125   { | 
 |  126     if (s.disabled || !(s instanceof RegularSubscription)) | 
 |  127       return false; | 
 |  128     if (s instanceof DownloadableSubscription && | 
 |  129         !/^(http|https|ftp):/i.test(s.url)) | 
 |  130       return false; | 
 |  131     return true; | 
 |  132   } | 
 |  133  | 
 |  134   function addRequestListeners(dataCollectionTabId, issueReporterTabId) | 
 |  135   { | 
 |  136     const logRequest = (request, filter) => | 
 |  137     { | 
 |  138       let subscriptions = []; | 
 |  139       if (filter) | 
 |  140       { | 
 |  141         subscriptions = filter.subscriptions. | 
 |  142                         filter(includeActiveRemoteSubscriptions). | 
 |  143                         map(s => s.url); | 
 |  144         filter = convertFilter(filter); | 
 |  145       } | 
 |  146       request = convertObject(["url", "type", "docDomain", "thirdParty"], | 
 |  147                               request); | 
 |  148       sendMessage("requests", "hits", request, filter, subscriptions); | 
 |  149     }; | 
 |  150     const removeTabListeners = (tabId) => | 
 |  151     { | 
 |  152       if (tabId == dataCollectionTabId || tabId == issueReporterTabId) | 
 |  153       { | 
 |  154         HitLogger.removeListener(dataCollectionTabId, logRequest); | 
 |  155         browser.tabs.onRemoved.removeListener(removeTabListeners); | 
 |  156       } | 
 |  157     }; | 
 |  158     HitLogger.addListener(dataCollectionTabId, logRequest); | 
 |  159     browser.tabs.onRemoved.addListener(removeTabListeners); | 
 |  160   } | 
 |  161  | 
|  121   function addFilterListeners(type, actions) |  162   function addFilterListeners(type, actions) | 
|  122   { |  163   { | 
|  123     for (let action of actions) |  164     for (const action of actions) | 
|  124     { |  165     { | 
|  125       let name; |  166       let name; | 
|  126       if (type == "filter" && action == "loaded") |  167       if (type == "filter" && action == "loaded") | 
|  127         name = "load"; |  168         name = "load"; | 
|  128       else |  169       else | 
|  129         name = type + "." + action; |  170         name = type + "." + action; | 
|  130  |  171  | 
|  131       if (!(name in listenedFilterChanges)) |  172       if (!(name in listenedFilterChanges)) | 
|  132       { |  173       { | 
|  133         listenedFilterChanges[name] = null; |  174         listenedFilterChanges[name] = null; | 
| (...skipping 16 matching lines...) Expand all  Loading... | 
|  150     FilterStorage.addSubscription(subscription); |  191     FilterStorage.addSubscription(subscription); | 
|  151     if (subscription instanceof DownloadableSubscription && |  192     if (subscription instanceof DownloadableSubscription && | 
|  152         !subscription.lastDownload) |  193         !subscription.lastDownload) | 
|  153       Synchronizer.execute(subscription); |  194       Synchronizer.execute(subscription); | 
|  154   } |  195   } | 
|  155  |  196  | 
|  156   port.on("app.get", (message, sender) => |  197   port.on("app.get", (message, sender) => | 
|  157   { |  198   { | 
|  158     if (message.what == "issues") |  199     if (message.what == "issues") | 
|  159     { |  200     { | 
|  160       let subscriptionInit = require("../lib/subscriptionInit"); |  201       const subscriptionInit = require("subscriptionInit"); | 
|  161       return { |  202       return { | 
|  162         dataCorrupted: subscriptionInit.isDataCorrupted(), |  203         dataCorrupted: subscriptionInit.isDataCorrupted(), | 
|  163         filterlistsReinitialized: subscriptionInit.isReinitialized() |  204         filterlistsReinitialized: subscriptionInit.isReinitialized() | 
|  164       }; |  205       }; | 
|  165     } |  206     } | 
|  166  |  207  | 
|  167     if (message.what == "doclink") |  208     if (message.what == "doclink") | 
|  168     { |  209     { | 
|  169       let {application} = info; |  210       let {application} = info; | 
|  170       if (info.platform == "chromium" && application != "opera") |  211       if (info.platform == "chromium" && application != "opera") | 
|  171         application = "chrome"; |  212         application = "chrome"; | 
|  172       else if (info.platform == "gecko") |  213       else if (info.platform == "gecko") | 
|  173         application = "firefox"; |  214         application = "firefox"; | 
|  174  |  215  | 
|  175       return Utils.getDocLink(message.link.replace("{browser}", application)); |  216       return Utils.getDocLink(message.link.replace("{browser}", application)); | 
|  176     } |  217     } | 
|  177  |  218  | 
|  178     if (message.what == "localeInfo") |  219     if (message.what == "localeInfo") | 
|  179     { |  220     { | 
|  180       let bidiDir; |  221       let bidiDir; | 
|  181       if ("chromeRegistry" in Utils) |  222       if ("chromeRegistry" in Utils) | 
|  182       { |  223       { | 
|  183         let isRtl = Utils.chromeRegistry.isLocaleRTL("adblockplus"); |  224         const isRtl = Utils.chromeRegistry.isLocaleRTL("adblockplus"); | 
|  184         bidiDir = isRtl ? "rtl" : "ltr"; |  225         bidiDir = isRtl ? "rtl" : "ltr"; | 
|  185       } |  226       } | 
|  186       else |  227       else | 
|  187         bidiDir = Utils.readingDirection; |  228         bidiDir = Utils.readingDirection; | 
|  188  |  229  | 
|  189       return {locale: Utils.appLocale, bidiDir}; |  230       return {locale: Utils.appLocale, bidiDir}; | 
|  190     } |  231     } | 
|  191  |  232  | 
|  192     if (message.what == "features") |  233     if (message.what == "features") | 
|  193     { |  234     { | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
|  213         if (!message.action) |  254         if (!message.action) | 
|  214           return; |  255           return; | 
|  215  |  256  | 
|  216         sendMessage("app", message.action, ...message.args); |  257         sendMessage("app", message.action, ...message.args); | 
|  217       }); |  258       }); | 
|  218     } |  259     } | 
|  219   }); |  260   }); | 
|  220  |  261  | 
|  221   port.on("filters.add", (message, sender) => |  262   port.on("filters.add", (message, sender) => | 
|  222   { |  263   { | 
|  223     let result = require("../lib/filterValidation").parseFilter(message.text); |  264     const result = require("filterValidation").parseFilter(message.text); | 
|  224     let errors = []; |  265     const errors = []; | 
|  225     if (result.error) |  266     if (result.error) | 
|  226       errors.push(result.error.toString()); |  267       errors.push(result.error.toString()); | 
|  227     else if (result.filter) |  268     else if (result.filter) | 
|  228       FilterStorage.addFilter(result.filter); |  269       FilterStorage.addFilter(result.filter); | 
|  229  |  270  | 
|  230     return errors; |  271     return errors; | 
|  231   }); |  272   }); | 
|  232  |  273  | 
|  233   port.on("filters.blocked", (message, sender) => |  274   port.on("filters.blocked", (message, sender) => | 
|  234   { |  275   { | 
|  235     let filter = defaultMatcher.matchesAny(message.url, |  276     const filter = defaultMatcher.matchesAny(message.url, | 
|  236       RegExpFilter.typeMap[message.requestType], message.docDomain, |  277       RegExpFilter.typeMap[message.requestType], message.docDomain, | 
|  237       message.thirdParty); |  278       message.thirdParty); | 
|  238  |  279  | 
|  239     return filter instanceof BlockingFilter; |  280     return filter instanceof BlockingFilter; | 
|  240   }); |  281   }); | 
|  241  |  282  | 
|  242   port.on("filters.get", (message, sender) => |  283   port.on("filters.get", (message, sender) => | 
|  243   { |  284   { | 
|  244     let subscription = Subscription.fromURL(message.subscriptionUrl); |  285     const subscription = Subscription.fromURL(message.subscriptionUrl); | 
|  245     if (!subscription) |  286     if (!subscription) | 
|  246       return []; |  287       return []; | 
|  247  |  288  | 
|  248     return subscription.filters.map(convertFilter); |  289     return subscription.filters.map(convertFilter); | 
|  249   }); |  290   }); | 
|  250  |  291  | 
|  251   port.on("filters.importRaw", (message, sender) => |  292   port.on("filters.importRaw", (message, sender) => | 
|  252   { |  293   { | 
|  253     let result = require("../lib/filterValidation").parseFilters(message.text); |  294     const result = require("filterValidation").parseFilters(message.text); | 
|  254     let errors = []; |  295     const errors = []; | 
|  255     for (let error of result.errors) |  296     for (const error of result.errors) | 
|  256     { |  297     { | 
|  257       if (error.type != "unexpected-filter-list-header") |  298       if (error.type != "unexpected-filter-list-header") | 
|  258         errors.push(error.toString()); |  299         errors.push(error.toString()); | 
|  259     } |  300     } | 
|  260  |  301  | 
|  261     if (errors.length > 0) |  302     if (errors.length > 0) | 
|  262       return errors; |  303       return errors; | 
|  263  |  304  | 
|  264     let seenFilter = Object.create(null); |  305     const seenFilter = Object.create(null); | 
|  265     for (let filter of result.filters) |  306     for (const filter of result.filters) | 
|  266     { |  307     { | 
|  267       FilterStorage.addFilter(filter); |  308       FilterStorage.addFilter(filter); | 
|  268       seenFilter[filter.text] = null; |  309       seenFilter[filter.text] = null; | 
|  269     } |  310     } | 
|  270  |  311  | 
|  271     if (!message.removeExisting) |  312     if (!message.removeExisting) | 
|  272       return errors; |  313       return errors; | 
|  273  |  314  | 
|  274     for (let subscription of FilterStorage.subscriptions) |  315     for (const subscription of FilterStorage.subscriptions) | 
|  275     { |  316     { | 
|  276       if (!(subscription instanceof SpecialSubscription)) |  317       if (!(subscription instanceof SpecialSubscription)) | 
|  277         continue; |  318         continue; | 
|  278  |  319  | 
|  279       for (let j = subscription.filters.length - 1; j >= 0; j--) |  320       for (let j = subscription.filters.length - 1; j >= 0; j--) | 
|  280       { |  321       { | 
|  281         let filter = subscription.filters[j]; |  322         const filter = subscription.filters[j]; | 
|  282         if (/^@@\|\|([^/:]+)\^\$document$/.test(filter.text)) |  323         if (/^@@\|\|([^/:]+)\^\$document$/.test(filter.text)) | 
|  283           continue; |  324           continue; | 
|  284  |  325  | 
|  285         if (!(filter.text in seenFilter)) |  326         if (!(filter.text in seenFilter)) | 
|  286           FilterStorage.removeFilter(filter); |  327           FilterStorage.removeFilter(filter); | 
|  287       } |  328       } | 
|  288     } |  329     } | 
|  289  |  330  | 
|  290     return errors; |  331     return errors; | 
|  291   }); |  332   }); | 
|  292  |  333  | 
|  293   port.on("filters.remove", (message, sender) => |  334   port.on("filters.remove", (message, sender) => | 
|  294   { |  335   { | 
|  295     let filter = Filter.fromText(message.text); |  336     const filter = Filter.fromText(message.text); | 
|  296     let subscription = null; |  337     let subscription = null; | 
|  297     if (message.subscriptionUrl) |  338     if (message.subscriptionUrl) | 
|  298       subscription = Subscription.fromURL(message.subscriptionUrl); |  339       subscription = Subscription.fromURL(message.subscriptionUrl); | 
|  299  |  340  | 
|  300     if (!subscription) |  341     if (!subscription) | 
|  301       FilterStorage.removeFilter(filter); |  342       FilterStorage.removeFilter(filter); | 
|  302     else |  343     else | 
|  303       FilterStorage.removeFilter(filter, subscription, message.index); |  344       FilterStorage.removeFilter(filter, subscription, message.index); | 
|  304   }); |  345   }); | 
|  305  |  346  | 
| (...skipping 13 matching lines...) Expand all  Loading... | 
|  319   port.on("prefs.toggle", (message, sender) => |  360   port.on("prefs.toggle", (message, sender) => | 
|  320   { |  361   { | 
|  321     if (message.key == "notifications_ignoredcategories") |  362     if (message.key == "notifications_ignoredcategories") | 
|  322       return NotificationStorage.toggleIgnoreCategory("*"); |  363       return NotificationStorage.toggleIgnoreCategory("*"); | 
|  323  |  364  | 
|  324     return Prefs[message.key] = !Prefs[message.key]; |  365     return Prefs[message.key] = !Prefs[message.key]; | 
|  325   }); |  366   }); | 
|  326  |  367  | 
|  327   port.on("notifications.get", (message, sender) => |  368   port.on("notifications.get", (message, sender) => | 
|  328   { |  369   { | 
|  329     let notification = getActiveNotification(); |  370     const notification = getActiveNotification(); | 
|  330  |  371  | 
|  331     if (!notification || |  372     if (!notification || | 
|  332         "displayMethod" in message && |  373         "displayMethod" in message && | 
|  333         !shouldDisplay(message.displayMethod, notification.type)) |  374         !shouldDisplay(message.displayMethod, notification.type)) | 
|  334       return; |  375       return; | 
|  335  |  376  | 
|  336     let texts = NotificationStorage.getLocalizedTexts(notification, |  377     const texts = NotificationStorage.getLocalizedTexts(notification, | 
|  337                                                       message.locale); |  378                                                       message.locale); | 
|  338     return Object.assign({texts}, notification); |  379     return Object.assign({texts}, notification); | 
|  339   }); |  380   }); | 
|  340  |  381  | 
|  341   port.on("notifications.clicked", (message, sender) => |  382   port.on("notifications.clicked", (message, sender) => | 
|  342   { |  383   { | 
|  343     notificationClicked(); |  384     notificationClicked(); | 
|  344   }); |  385   }); | 
|  345  |  386  | 
|  346   port.on("subscriptions.add", (message, sender) => |  387   port.on("subscriptions.add", (message, sender) => | 
|  347   { |  388   { | 
|  348     let subscription = Subscription.fromURL(message.url); |  389     const subscription = Subscription.fromURL(message.url); | 
|  349     if (message.confirm) |  390     if (message.confirm) | 
|  350     { |  391     { | 
|  351       if ("title" in message) |  392       if ("title" in message) | 
|  352         subscription.title = message.title; |  393         subscription.title = message.title; | 
|  353       if ("homepage" in message) |  394       if ("homepage" in message) | 
|  354         subscription.homepage = message.homepage; |  395         subscription.homepage = message.homepage; | 
|  355  |  396  | 
|  356       showOptions(() => |  397       showOptions(() => | 
|  357       { |  398       { | 
|  358         sendMessage("app", "addSubscription", subscription); |  399         sendMessage("app", "addSubscription", subscription); | 
|  359       }); |  400       }); | 
|  360     } |  401     } | 
|  361     else |  402     else | 
|  362     { |  403     { | 
|  363       addSubscription(subscription, message); |  404       addSubscription(subscription, message); | 
|  364     } |  405     } | 
|  365   }); |  406   }); | 
|  366  |  407  | 
|  367   port.on("subscriptions.get", (message, sender) => |  408   port.on("subscriptions.get", (message, sender) => | 
|  368   { |  409   { | 
|  369     let subscriptions = FilterStorage.subscriptions.filter((s) => |  410     const subscriptions = FilterStorage.subscriptions.filter((s) => | 
|  370     { |  411     { | 
|  371       if (message.ignoreDisabled && s.disabled) |  412       if (message.ignoreDisabled && s.disabled) | 
|  372         return false; |  413         return false; | 
|  373       if (s instanceof DownloadableSubscription && message.downloadable) |  414       if (s instanceof DownloadableSubscription && message.downloadable) | 
|  374         return true; |  415         return true; | 
|  375       if (s instanceof SpecialSubscription && message.special) |  416       if (s instanceof SpecialSubscription && message.special) | 
|  376         return true; |  417         return true; | 
|  377       return false; |  418       return false; | 
|  378     }); |  419     }); | 
|  379  |  420  | 
|  380     return subscriptions.map((s) => |  421     return subscriptions.map((s) => | 
|  381     { |  422     { | 
|  382       let result = convertSubscription(s); |  423       const result = convertSubscription(s); | 
|  383       if (message.disabledFilters) |  424       if (message.disabledFilters) | 
|  384       { |  425       { | 
|  385         result.disabledFilters = s.filters |  426         result.disabledFilters = s.filters | 
|  386                       .filter((f) => f instanceof ActiveFilter && f.disabled) |  427                       .filter((f) => f instanceof ActiveFilter && f.disabled) | 
|  387                       .map((f) => f.text); |  428                       .map((f) => f.text); | 
|  388       } |  429       } | 
|  389       return result; |  430       return result; | 
|  390     }); |  431     }); | 
|  391   }); |  432   }); | 
|  392  |  433  | 
|  393   port.on("subscriptions.remove", (message, sender) => |  434   port.on("subscriptions.remove", (message, sender) => | 
|  394   { |  435   { | 
|  395     let subscription = Subscription.fromURL(message.url); |  436     const subscription = Subscription.fromURL(message.url); | 
|  396     if (subscription.url in FilterStorage.knownSubscriptions) |  437     if (FilterStorage.knownSubscriptions.has(subscription.url)) | 
|  397       FilterStorage.removeSubscription(subscription); |  438       FilterStorage.removeSubscription(subscription); | 
|  398   }); |  439   }); | 
|  399  |  440  | 
|  400   port.on("subscriptions.toggle", (message, sender) => |  441   port.on("subscriptions.toggle", (message, sender) => | 
|  401   { |  442   { | 
|  402     let subscription = Subscription.fromURL(message.url); |  443     const subscription = Subscription.fromURL(message.url); | 
|  403     if (subscription.url in FilterStorage.knownSubscriptions) |  444     if (FilterStorage.knownSubscriptions.has(subscription.url)) | 
|  404     { |  445     { | 
|  405       if (subscription.disabled || message.keepInstalled) |  446       if (subscription.disabled || message.keepInstalled) | 
|  406         subscription.disabled = !subscription.disabled; |  447         subscription.disabled = !subscription.disabled; | 
|  407       else |  448       else | 
|  408         FilterStorage.removeSubscription(subscription); |  449         FilterStorage.removeSubscription(subscription); | 
|  409     } |  450     } | 
|  410     else |  451     else | 
|  411     { |  452     { | 
|  412       addSubscription(subscription, message); |  453       addSubscription(subscription, message); | 
|  413     } |  454     } | 
|  414   }); |  455   }); | 
|  415  |  456  | 
|  416   port.on("subscriptions.update", (message, sender) => |  457   port.on("subscriptions.update", (message, sender) => | 
|  417   { |  458   { | 
|  418     let {subscriptions} = FilterStorage; |  459     let {subscriptions} = FilterStorage; | 
|  419     if (message.url) |  460     if (message.url) | 
|  420       subscriptions = [Subscription.fromURL(message.url)]; |  461       subscriptions = [Subscription.fromURL(message.url)]; | 
|  421  |  462  | 
|  422     for (let subscription of subscriptions) |  463     for (const subscription of subscriptions) | 
|  423     { |  464     { | 
|  424       if (subscription instanceof DownloadableSubscription) |  465       if (subscription instanceof DownloadableSubscription) | 
|  425         Synchronizer.execute(subscription, true); |  466         Synchronizer.execute(subscription, true); | 
|  426     } |  467     } | 
|  427   }); |  468   }); | 
|  428  |  469  | 
|  429   function listen(type, filters, newFilter) |  470   function listen(type, filters, newFilter, message, senderTabId) | 
|  430   { |  471   { | 
|  431     switch (type) |  472     switch (type) | 
|  432     { |  473     { | 
|  433       case "app": |  474       case "app": | 
|  434         filters.set("app", newFilter); |  475         filters.set("app", newFilter); | 
|  435         break; |  476         break; | 
|  436       case "filters": |  477       case "filters": | 
|  437         filters.set("filter", newFilter); |  478         filters.set("filter", newFilter); | 
|  438         addFilterListeners("filter", newFilter); |  479         addFilterListeners("filter", newFilter); | 
|  439         break; |  480         break; | 
|  440       case "prefs": |  481       case "prefs": | 
|  441         filters.set("pref", newFilter); |  482         filters.set("pref", newFilter); | 
|  442         for (let preference of newFilter) |  483         for (const preference of newFilter) | 
|  443         { |  484         { | 
|  444           if (!(preference in listenedPreferences)) |  485           if (!(preference in listenedPreferences)) | 
|  445           { |  486           { | 
|  446             listenedPreferences[preference] = null; |  487             listenedPreferences[preference] = null; | 
|  447             Prefs.on(preference, () => |  488             Prefs.on(preference, () => | 
|  448             { |  489             { | 
|  449               sendMessage("pref", preference, Prefs[preference]); |  490               sendMessage("pref", preference, Prefs[preference]); | 
|  450             }); |  491             }); | 
|  451           } |  492           } | 
|  452         } |  493         } | 
|  453         break; |  494         break; | 
|  454       case "subscriptions": |  495       case "subscriptions": | 
|  455         filters.set("subscription", newFilter); |  496         filters.set("subscription", newFilter); | 
|  456         addFilterListeners("subscription", newFilter); |  497         addFilterListeners("subscription", newFilter); | 
|  457         break; |  498         break; | 
 |  499       case "requests": | 
 |  500         filters.set("requests", newFilter); | 
 |  501         addRequestListeners(message.tabId, senderTabId); | 
 |  502         break; | 
|  458     } |  503     } | 
|  459   } |  504   } | 
|  460  |  505  | 
|  461   function onConnect(uiPort) |  506   function onConnect(uiPort) | 
|  462   { |  507   { | 
|  463     if (uiPort.name != "ui") |  508     if (uiPort.name != "ui") | 
|  464       return; |  509       return; | 
|  465  |  510  | 
|  466     let filters = new Map(); |  511     const filters = new Map(); | 
|  467     uiPorts.set(uiPort, filters); |  512     uiPorts.set(uiPort, filters); | 
|  468  |  513  | 
|  469     uiPort.onDisconnect.addListener(() => |  514     uiPort.onDisconnect.addListener(() => | 
|  470     { |  515     { | 
|  471       uiPorts.delete(uiPort); |  516       uiPorts.delete(uiPort); | 
|  472     }); |  517     }); | 
|  473  |  518  | 
|  474     uiPort.onMessage.addListener((message) => |  519     uiPort.onMessage.addListener((message) => | 
|  475     { |  520     { | 
|  476       let [type, action] = message.type.split(".", 2); |  521       const [type, action] = message.type.split(".", 2); | 
|  477  |  522  | 
|  478       // For now we're only using long-lived connections for handling |  523       // For now we're only using long-lived connections for handling | 
|  479       // "*.listen" messages to tackle #6440 |  524       // "*.listen" messages to tackle #6440 | 
|  480       if (action == "listen") |  525       if (action == "listen") | 
|  481       { |  526       { | 
|  482         listen(type, filters, message.filter); |  527         listen(type, filters, message.filter, message, uiPort.sender.tab.id); | 
|  483       } |  528       } | 
|  484     }); |  529     }); | 
|  485   } |  530   } | 
|  486  |  531  | 
|  487   browser.runtime.onConnect.addListener(onConnect); |  532   browser.runtime.onConnect.addListener(onConnect); | 
|  488 })(this); |  533 })(this); | 
| LEFT | RIGHT |