| 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-2015 Eyeo GmbH | 3  * Copyright (C) 2006-2015 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 with(require("filterClasses")) | 18 with(require("filterClasses")) | 
| 19 { | 19 { | 
| 20   this.Filter = Filter; | 20   this.Filter = Filter; | 
| 21   this.RegExpFilter = RegExpFilter; |  | 
| 22   this.BlockingFilter = BlockingFilter; | 21   this.BlockingFilter = BlockingFilter; | 
| 23   this.WhitelistFilter = WhitelistFilter; | 22   this.WhitelistFilter = WhitelistFilter; | 
|  | 23   this.RegExpFilter = RegExpFilter; | 
| 24 } | 24 } | 
| 25 with(require("subscriptionClasses")) | 25 with(require("subscriptionClasses")) | 
| 26 { | 26 { | 
| 27   this.Subscription = Subscription; | 27   this.Subscription = Subscription; | 
| 28   this.DownloadableSubscription = DownloadableSubscription; | 28   this.DownloadableSubscription = DownloadableSubscription; | 
| 29   this.SpecialSubscription = SpecialSubscription; | 29   this.SpecialSubscription = SpecialSubscription; | 
| 30 } | 30 } | 
| 31 with(require("whitelisting")) | 31 with(require("whitelisting")) | 
| 32 { | 32 { | 
| 33   this.isPageWhitelisted = isPageWhitelisted; | 33   this.isPageWhitelisted = isPageWhitelisted; | 
| 34   this.isFrameWhitelisted = isFrameWhitelisted; | 34   this.isFrameWhitelisted = isFrameWhitelisted; | 
| 35   this.processKey = processKey; | 35   this.processKey = processKey; | 
| 36   this.getKey = getKey; | 36   this.getKey = getKey; | 
| 37 } | 37 } | 
| 38 with(require("url")) | 38 with(require("url")) | 
| 39 { | 39 { | 
| 40   this.stringifyURL = stringifyURL; | 40   this.stringifyURL = stringifyURL; | 
| 41   this.isThirdParty = isThirdParty; | 41   this.isThirdParty = isThirdParty; | 
| 42   this.extractHostFromFrame = extractHostFromFrame; | 42   this.extractHostFromFrame = extractHostFromFrame; | 
| 43 } | 43 } | 
| 44 with(require("icon")) |  | 
| 45 { |  | 
| 46   this.updateIcon = updateIcon; |  | 
| 47   this.startIconAnimation = startIconAnimation; |  | 
| 48   this.stopIconAnimation = stopIconAnimation; |  | 
| 49 } |  | 
| 50 var FilterStorage = require("filterStorage").FilterStorage; | 44 var FilterStorage = require("filterStorage").FilterStorage; | 
|  | 45 var FilterNotifier = require("filterNotifier").FilterNotifier; | 
| 51 var ElemHide = require("elemHide").ElemHide; | 46 var ElemHide = require("elemHide").ElemHide; | 
| 52 var defaultMatcher = require("matcher").defaultMatcher; | 47 var defaultMatcher = require("matcher").defaultMatcher; | 
| 53 var Prefs = require("prefs").Prefs; | 48 var Prefs = require("prefs").Prefs; | 
| 54 var Synchronizer = require("synchronizer").Synchronizer; | 49 var Synchronizer = require("synchronizer").Synchronizer; | 
| 55 var Utils = require("utils").Utils; | 50 var Utils = require("utils").Utils; | 
| 56 var NotificationStorage = require("notification").Notification; |  | 
| 57 var initAntiAdblockNotification = require("antiadblockInit").initAntiAdblockNoti
     fication; |  | 
| 58 var parseFilters = require("filterValidation").parseFilters; | 51 var parseFilters = require("filterValidation").parseFilters; | 
| 59 | 52 var composeFilters = require("filterComposer").composeFilters; | 
| 60 // Some types cannot be distinguished | 53 var updateIcon = require("icon").updateIcon; | 
| 61 RegExpFilter.typeMap.OBJECT_SUBREQUEST = RegExpFilter.typeMap.OBJECT; | 54 var initNotifications = require("notificationHelper").initNotifications; | 
| 62 RegExpFilter.typeMap.MEDIA = RegExpFilter.typeMap.FONT = RegExpFilter.typeMap.OT
     HER; |  | 
| 63 |  | 
| 64 // Chrome on Linux does not fully support chrome.notifications until version 35 |  | 
| 65 // https://code.google.com/p/chromium/issues/detail?id=291485 |  | 
| 66 var canUseChromeNotifications = require("info").platform == "chromium" |  | 
| 67   && "notifications" in chrome |  | 
| 68   && (navigator.platform.indexOf("Linux") == -1 || parseInt(require("info").appl
     icationVersion, 10) > 34); |  | 
| 69 | 55 | 
| 70 var seenDataCorruption = false; | 56 var seenDataCorruption = false; | 
| 71 var filterlistsReinitialized = false; | 57 var filterlistsReinitialized = false; | 
| 72 require("filterNotifier").FilterNotifier.addListener(function(action) | 58 | 
| 73 { | 59 function init() | 
| 74   if (action == "load") | 60 { | 
| 75   { | 61   var filtersLoaded = false; | 
| 76     var addonVersion = require("info").addonVersion; | 62   var prefsLoaded = false; | 
| 77     var prevVersion = ext.storage.currentVersion; | 63 | 
|  | 64   var checkLoaded = function() | 
|  | 65   { | 
|  | 66     if (!filtersLoaded || !prefsLoaded) | 
|  | 67       return; | 
|  | 68 | 
|  | 69     var info = require("info"); | 
|  | 70     var previousVersion = Prefs.currentVersion; | 
| 78 | 71 | 
| 79     // There are no filters stored so we need to reinitialize all filterlists | 72     // There are no filters stored so we need to reinitialize all filterlists | 
| 80     if (!FilterStorage.firstRun && FilterStorage.subscriptions.length === 0) | 73     if (!FilterStorage.firstRun && FilterStorage.subscriptions.length === 0) | 
| 81     { | 74     { | 
| 82       filterlistsReinitialized = true; | 75       filterlistsReinitialized = true; | 
| 83       prevVersion = null; | 76       previousVersion = null; | 
| 84     } | 77     } | 
| 85 | 78 | 
| 86     if (prevVersion != addonVersion || FilterStorage.firstRun) | 79     if (previousVersion != info.addonVersion || FilterStorage.firstRun) | 
| 87     { | 80     { | 
| 88       seenDataCorruption = prevVersion && FilterStorage.firstRun; | 81       seenDataCorruption = previousVersion && FilterStorage.firstRun; | 
| 89       ext.storage.currentVersion = addonVersion; | 82       Prefs.currentVersion = info.addonVersion; | 
| 90       addSubscription(prevVersion); | 83       addSubscription(previousVersion); | 
| 91     } | 84     } | 
| 92 |  | 
| 93     if (canUseChromeNotifications) |  | 
| 94       initChromeNotifications(); |  | 
| 95     initAntiAdblockNotification(); |  | 
| 96 | 85 | 
| 97     // The "Hide placeholders" option has been removed from the UI in 1.8.8.1285 | 86     // The "Hide placeholders" option has been removed from the UI in 1.8.8.1285 | 
| 98     // So we reset the option for users updating from older versions. | 87     // So we reset the option for users updating from older versions. | 
| 99     if (prevVersion && Services.vc.compare(prevVersion, "1.8.8.1285") < 0) | 88     if (previousVersion && Services.vc.compare(previousVersion, "1.8.8.1285") < 
     0) | 
| 100       Prefs.hidePlaceholders = true; | 89       Prefs.hidePlaceholders = true; | 
| 101   } | 90 | 
| 102 | 91     initNotifications(); | 
| 103   // update browser actions when whitelisting might have changed, | 92 | 
| 104   // due to loading filters or saving filter changes | 93     // Update browser actions and context menus when whitelisting might have | 
| 105   if (action == "load" || action == "save") | 94     // changed. That is now when initally loading the filters and later when | 
|  | 95     // importing backups or saving filter changes. | 
|  | 96     FilterNotifier.addListener(function(action) | 
|  | 97     { | 
|  | 98       if (action == "load" || action == "save") | 
|  | 99         refreshIconAndContextMenuForAllPages(); | 
|  | 100     }); | 
| 106     refreshIconAndContextMenuForAllPages(); | 101     refreshIconAndContextMenuForAllPages(); | 
| 107 }); | 102   }; | 
|  | 103 | 
|  | 104   var onFilterAction = function(action) | 
|  | 105   { | 
|  | 106     if (action == "load") | 
|  | 107     { | 
|  | 108       FilterNotifier.removeListener(onFilterAction); | 
|  | 109       filtersLoaded = true; | 
|  | 110       checkLoaded(); | 
|  | 111     } | 
|  | 112   }; | 
|  | 113 | 
|  | 114   var onPrefsLoaded = function() | 
|  | 115   { | 
|  | 116     Prefs.onLoaded.removeListener(onPrefsLoaded); | 
|  | 117     prefsLoaded = true; | 
|  | 118     checkLoaded(); | 
|  | 119   }; | 
|  | 120 | 
|  | 121   FilterNotifier.addListener(onFilterAction); | 
|  | 122   Prefs.onLoaded.addListener(onPrefsLoaded); | 
|  | 123 } | 
|  | 124 init(); | 
| 108 | 125 | 
| 109 // Special-case domains for which we cannot use style-based hiding rules. | 126 // Special-case domains for which we cannot use style-based hiding rules. | 
| 110 // See http://crbug.com/68705. | 127 // See http://crbug.com/68705. | 
| 111 var noStyleRulesHosts = ["mail.google.com", "mail.yahoo.com", "www.google.com"]; | 128 var noStyleRulesHosts = ["mail.google.com", "mail.yahoo.com", "www.google.com"]; | 
| 112 | 129 | 
| 113 var htmlPages = new ext.PageMap(); | 130 var htmlPages = new ext.PageMap(); | 
| 114 |  | 
| 115 function removeDeprecatedOptions() |  | 
| 116 { |  | 
| 117   var deprecatedOptions = ["specialCaseYouTube", "experimental", "disableInlineT
     extAds"]; |  | 
| 118   deprecatedOptions.forEach(function(option) |  | 
| 119   { |  | 
| 120     if (option in ext.storage) |  | 
| 121       delete ext.storage[option]; |  | 
| 122   }); |  | 
| 123 } |  | 
| 124 |  | 
| 125 // Remove deprecated options before we do anything else. |  | 
| 126 removeDeprecatedOptions(); |  | 
| 127 |  | 
| 128 var activeNotification = null; |  | 
| 129 | 131 | 
| 130 var contextMenuItem = { | 132 var contextMenuItem = { | 
| 131   title: ext.i18n.getMessage("block_element"), | 133   title: ext.i18n.getMessage("block_element"), | 
| 132   contexts: ["image", "video", "audio"], | 134   contexts: ["image", "video", "audio"], | 
| 133   onclick: function(page) | 135   onclick: function(page) | 
| 134   { | 136   { | 
| 135     page.sendMessage({type: "clickhide-new-filter"}); | 137     page.sendMessage({type: "clickhide-new-filter"}); | 
| 136   } | 138   } | 
| 137 }; | 139 }; | 
| 138 | 140 | 
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 221       if (subscription instanceof DownloadableSubscription && !subscription.last
     Download) | 223       if (subscription instanceof DownloadableSubscription && !subscription.last
     Download) | 
| 222         Synchronizer.execute(subscription); | 224         Synchronizer.execute(subscription); | 
| 223     } | 225     } | 
| 224   } | 226   } | 
| 225 | 227 | 
| 226   if (!addSubscription && !addAcceptable) | 228   if (!addSubscription && !addAcceptable) | 
| 227     return; | 229     return; | 
| 228 | 230 | 
| 229   function notifyUser() | 231   function notifyUser() | 
| 230   { | 232   { | 
| 231     ext.pages.open(ext.getURL("firstRun.html")); | 233     if (!Prefs.suppress_first_run_page) | 
|  | 234       ext.pages.open(ext.getURL("firstRun.html")); | 
| 232   } | 235   } | 
| 233 | 236 | 
| 234   if (addSubscription) | 237   if (addSubscription) | 
| 235   { | 238   { | 
| 236     // Load subscriptions data | 239     // Load subscriptions data | 
| 237     var request = new XMLHttpRequest(); | 240     var request = new XMLHttpRequest(); | 
| 238     request.open("GET", "subscriptions.xml"); | 241     request.open("GET", "subscriptions.xml"); | 
| 239     request.addEventListener("load", function() | 242     request.addEventListener("load", function() | 
| 240     { | 243     { | 
| 241       var node = Utils.chooseFilterSubscription(request.responseXML.getElementsB
     yTagName("subscription")); | 244       var node = Utils.chooseFilterSubscription(request.responseXML.getElementsB
     yTagName("subscription")); | 
| 242       var subscription = (node ? Subscription.fromURL(node.getAttribute("url")) 
     : null); | 245       var subscription = (node ? Subscription.fromURL(node.getAttribute("url")) 
     : null); | 
| 243       if (subscription) | 246       if (subscription) | 
| 244       { | 247       { | 
| 245         FilterStorage.addSubscription(subscription); | 248         FilterStorage.addSubscription(subscription); | 
| 246         subscription.disabled = false; | 249         subscription.disabled = false; | 
| 247         subscription.title = node.getAttribute("title"); | 250         subscription.title = node.getAttribute("title"); | 
| 248         subscription.homepage = node.getAttribute("homepage"); | 251         subscription.homepage = node.getAttribute("homepage"); | 
| 249         if (subscription instanceof DownloadableSubscription && !subscription.la
     stDownload) | 252         if (subscription instanceof DownloadableSubscription && !subscription.la
     stDownload) | 
| 250           Synchronizer.execute(subscription); | 253           Synchronizer.execute(subscription); | 
| 251 | 254 | 
| 252           notifyUser(); | 255           notifyUser(); | 
| 253       } | 256       } | 
| 254     }, false); | 257     }, false); | 
| 255     request.send(null); | 258     request.send(null); | 
| 256   } | 259   } | 
| 257   else | 260   else | 
| 258     notifyUser(); | 261     notifyUser(); | 
| 259 } | 262 } | 
| 260 | 263 | 
| 261 Prefs.addListener(function(name) | 264 Prefs.onChanged.addListener(function(name) | 
| 262 { | 265 { | 
| 263   if (name == "shouldShowBlockElementMenu") | 266   if (name == "shouldShowBlockElementMenu") | 
| 264     refreshIconAndContextMenuForAllPages(); | 267     refreshIconAndContextMenuForAllPages(); | 
| 265 }); | 268 }); | 
| 266 |  | 
| 267 function prepareNotificationIconAndPopup() |  | 
| 268 { |  | 
| 269   var animateIcon = (activeNotification.type !== "question"); |  | 
| 270   activeNotification.onClicked = function() |  | 
| 271   { |  | 
| 272     if (animateIcon) |  | 
| 273       stopIconAnimation(); |  | 
| 274     notificationClosed(); |  | 
| 275   }; |  | 
| 276   if (animateIcon) |  | 
| 277     startIconAnimation(activeNotification.type); |  | 
| 278 } |  | 
| 279 |  | 
| 280 function openNotificationLinks() |  | 
| 281 { |  | 
| 282   if (activeNotification.links) |  | 
| 283   { |  | 
| 284     activeNotification.links.forEach(function(link) |  | 
| 285     { |  | 
| 286       ext.windows.getLastFocused(function(win) |  | 
| 287       { |  | 
| 288         win.openTab(Utils.getDocLink(link)); |  | 
| 289       }); |  | 
| 290     }); |  | 
| 291   } |  | 
| 292 } |  | 
| 293 |  | 
| 294 function notificationButtonClick(buttonIndex) |  | 
| 295 { |  | 
| 296   if (activeNotification.type === "question") |  | 
| 297   { |  | 
| 298     NotificationStorage.triggerQuestionListeners(activeNotification.id, buttonIn
     dex === 0); |  | 
| 299     NotificationStorage.markAsShown(activeNotification.id); |  | 
| 300     activeNotification.onClicked(); |  | 
| 301   } |  | 
| 302   else if (activeNotification.links && activeNotification.links[buttonIndex]) |  | 
| 303   { |  | 
| 304     ext.windows.getLastFocused(function(win) |  | 
| 305     { |  | 
| 306       win.openTab(Utils.getDocLink(activeNotification.links[buttonIndex])); |  | 
| 307     }); |  | 
| 308   } |  | 
| 309 } |  | 
| 310 |  | 
| 311 function notificationClosed() |  | 
| 312 { |  | 
| 313   activeNotification = null; |  | 
| 314 } |  | 
| 315 |  | 
| 316 function imgToBase64(url, callback) |  | 
| 317 { |  | 
| 318   var canvas = document.createElement("canvas"), |  | 
| 319   ctx = canvas.getContext("2d"), |  | 
| 320   img = new Image; |  | 
| 321   img.src = url; |  | 
| 322   img.onload = function() |  | 
| 323   { |  | 
| 324     canvas.height = img.height; |  | 
| 325     canvas.width = img.width; |  | 
| 326     ctx.drawImage(img, 0, 0); |  | 
| 327     callback(canvas.toDataURL("image/png")); |  | 
| 328     canvas = null; |  | 
| 329   }; |  | 
| 330 } |  | 
| 331 |  | 
| 332 function initChromeNotifications() |  | 
| 333 { |  | 
| 334   // Chrome hides notifications in notification center when clicked so we need t
     o clear them |  | 
| 335   function clearActiveNotification(notificationId) |  | 
| 336   { |  | 
| 337     if (activeNotification && activeNotification.type != "question" && !("links"
      in activeNotification)) |  | 
| 338       return; |  | 
| 339 |  | 
| 340     chrome.notifications.clear(notificationId, function(wasCleared) |  | 
| 341     { |  | 
| 342       if (wasCleared) |  | 
| 343         notificationClosed(); |  | 
| 344     }); |  | 
| 345   } |  | 
| 346 |  | 
| 347   chrome.notifications.onButtonClicked.addListener(function(notificationId, butt
     onIndex) |  | 
| 348   { |  | 
| 349     notificationButtonClick(buttonIndex); |  | 
| 350     clearActiveNotification(notificationId); |  | 
| 351   }); |  | 
| 352   chrome.notifications.onClicked.addListener(clearActiveNotification); |  | 
| 353   chrome.notifications.onClosed.addListener(notificationClosed); |  | 
| 354 } |  | 
| 355 |  | 
| 356 function showNotification(notification) |  | 
| 357 { |  | 
| 358   if (activeNotification && activeNotification.id === notification.id) |  | 
| 359     return; |  | 
| 360 |  | 
| 361   activeNotification = notification; |  | 
| 362   if (activeNotification.type === "critical" || activeNotification.type === "que
     stion") |  | 
| 363   { |  | 
| 364     var texts = NotificationStorage.getLocalizedTexts(notification); |  | 
| 365     var title = texts.title || ""; |  | 
| 366     var message = texts.message ? texts.message.replace(/<\/?(a|strong)>/g, "") 
     : ""; |  | 
| 367     var iconUrl = ext.getURL("icons/abp-128.png"); |  | 
| 368     var hasLinks = activeNotification.links && activeNotification.links.length >
      0; |  | 
| 369 |  | 
| 370     if (canUseChromeNotifications) |  | 
| 371     { |  | 
| 372       var opts = { |  | 
| 373         type: "basic", |  | 
| 374         title: title, |  | 
| 375         message: message, |  | 
| 376         buttons: [], |  | 
| 377         priority: 2 // We use the highest priority to prevent the notification f
     rom closing automatically |  | 
| 378       }; |  | 
| 379       if (activeNotification.type === "question") |  | 
| 380       { |  | 
| 381         opts.buttons.push({title: ext.i18n.getMessage("overlay_notification_butt
     on_yes")}); |  | 
| 382         opts.buttons.push({title: ext.i18n.getMessage("overlay_notification_butt
     on_no")}); |  | 
| 383       } |  | 
| 384       else |  | 
| 385       { |  | 
| 386         var regex = /<a>(.*?)<\/a>/g; |  | 
| 387         var plainMessage = texts.message || ""; |  | 
| 388         var match; |  | 
| 389         while (match = regex.exec(plainMessage)) |  | 
| 390           opts.buttons.push({title: match[1]}); |  | 
| 391       } |  | 
| 392 |  | 
| 393       imgToBase64(iconUrl, function(iconData) |  | 
| 394       { |  | 
| 395         opts["iconUrl"] = iconData; |  | 
| 396         chrome.notifications.create("", opts, function() {}); |  | 
| 397       }); |  | 
| 398     } |  | 
| 399     else if ("Notification" in window && activeNotification.type !== "question") |  | 
| 400     { |  | 
| 401       if (hasLinks) |  | 
| 402         message += " " + ext.i18n.getMessage("notification_without_buttons"); |  | 
| 403 |  | 
| 404       imgToBase64(iconUrl, function(iconData) |  | 
| 405       { |  | 
| 406         var notification = new Notification( |  | 
| 407           title, |  | 
| 408           { |  | 
| 409             lang: Utils.appLocale, |  | 
| 410             dir: ext.i18n.getMessage("@@bidi_dir"), |  | 
| 411             body: message, |  | 
| 412             icon: iconData |  | 
| 413           } |  | 
| 414         ); |  | 
| 415 |  | 
| 416         notification.addEventListener("click", openNotificationLinks); |  | 
| 417         notification.addEventListener("close", notificationClosed); |  | 
| 418       }); |  | 
| 419     } |  | 
| 420     else |  | 
| 421     { |  | 
| 422       var message = title + "\n" + message; |  | 
| 423       if (hasLinks) |  | 
| 424         message += "\n\n" + ext.i18n.getMessage("notification_with_buttons"); |  | 
| 425 |  | 
| 426       var approved = confirm(message); |  | 
| 427       if (activeNotification.type === "question") |  | 
| 428         notificationButtonClick(approved ? 0 : 1); |  | 
| 429       else if (approved) |  | 
| 430         openNotificationLinks(); |  | 
| 431     } |  | 
| 432   } |  | 
| 433   prepareNotificationIconAndPopup(); |  | 
| 434 } |  | 
| 435 | 269 | 
| 436 // This is a hack to speedup loading of the options page on Safari. | 270 // This is a hack to speedup loading of the options page on Safari. | 
| 437 // Once we replaced the background page proxy with message passing | 271 // Once we replaced the background page proxy with message passing | 
| 438 // this global function should removed. | 272 // this global function should removed. | 
| 439 function getUserFilters() | 273 function getUserFilters() | 
| 440 { | 274 { | 
| 441   var filters = []; | 275   var filters = []; | 
| 442   var exceptions = []; | 276   var exceptions = []; | 
| 443 | 277 | 
| 444   for (var i = 0; i < FilterStorage.subscriptions.length; i++) | 278   for (var i = 0; i < FilterStorage.subscriptions.length; i++) | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
| 460   return {filters: filters, exceptions: exceptions}; | 294   return {filters: filters, exceptions: exceptions}; | 
| 461 } | 295 } | 
| 462 | 296 | 
| 463 ext.onMessage.addListener(function (msg, sender, sendResponse) | 297 ext.onMessage.addListener(function (msg, sender, sendResponse) | 
| 464 { | 298 { | 
| 465   switch (msg.type) | 299   switch (msg.type) | 
| 466   { | 300   { | 
| 467     case "get-selectors": | 301     case "get-selectors": | 
| 468       var selectors = []; | 302       var selectors = []; | 
| 469 | 303 | 
| 470       if (!isFrameWhitelisted(sender.page, sender.frame, "DOCUMENT") && | 304       if (!isFrameWhitelisted(sender.page, sender.frame, | 
| 471           !isFrameWhitelisted(sender.page, sender.frame, "ELEMHIDE")) | 305                               RegExpFilter.typeMap.DOCUMENT | RegExpFilter.typeM
     ap.ELEMHIDE)) | 
| 472       { | 306       { | 
| 473         var noStyleRules = false; | 307         var noStyleRules = false; | 
| 474         var specificOnly = isFrameWhitelisted(sender.page, sender.frame, "GENERI
     CHIDE"); | 308         var specificOnly = isFrameWhitelisted(sender.page, sender.frame, | 
|  | 309                                               RegExpFilter.typeMap.GENERICHIDE); | 
| 475         var host = extractHostFromFrame(sender.frame); | 310         var host = extractHostFromFrame(sender.frame); | 
| 476 | 311 | 
| 477         for (var i = 0; i < noStyleRulesHosts.length; i++) | 312         for (var i = 0; i < noStyleRulesHosts.length; i++) | 
| 478         { | 313         { | 
| 479           var noStyleHost = noStyleRulesHosts[i]; | 314           var noStyleHost = noStyleRulesHosts[i]; | 
| 480           if (host == noStyleHost || (host.length > noStyleHost.length && | 315           if (host == noStyleHost || (host.length > noStyleHost.length && | 
| 481                                       host.substr(host.length - noStyleHost.leng
     th - 1) == "." + noStyleHost)) | 316                                       host.substr(host.length - noStyleHost.leng
     th - 1) == "." + noStyleHost)) | 
| 482           { | 317           { | 
| 483             noStyleRules = true; | 318             noStyleRules = true; | 
| 484           } | 319           } | 
| 485         } | 320         } | 
| 486         selectors = ElemHide.getSelectorsForDomain(host, specificOnly); | 321         selectors = ElemHide.getSelectorsForDomain(host, specificOnly); | 
| 487         if (noStyleRules) | 322         if (noStyleRules) | 
| 488         { | 323         { | 
| 489           selectors = selectors.filter(function(s) | 324           selectors = selectors.filter(function(s) | 
| 490           { | 325           { | 
| 491             return !/\[style[\^\$]?=/.test(s); | 326             return !/\[style[\^\$]?=/.test(s); | 
| 492           }); | 327           }); | 
| 493         } | 328         } | 
| 494       } | 329       } | 
| 495 | 330 | 
| 496       sendResponse(selectors); | 331       sendResponse(selectors); | 
| 497       break; | 332       break; | 
| 498     case "should-collapse": | 333     case "should-collapse": | 
| 499       if (isFrameWhitelisted(sender.page, sender.frame, "DOCUMENT")) | 334       if (isFrameWhitelisted(sender.page, sender.frame, RegExpFilter.typeMap.DOC
     UMENT)) | 
| 500       { | 335       { | 
| 501         sendResponse(false); | 336         sendResponse(false); | 
| 502         break; | 337         break; | 
| 503       } | 338       } | 
| 504 | 339 | 
| 505       var url = new URL(msg.url); | 340       var typeMask = RegExpFilter.typeMap[msg.mediatype]; | 
| 506       var documentHost = extractHostFromFrame(sender.frame); | 341       var documentHost = extractHostFromFrame(sender.frame); | 
| 507       var filter = defaultMatcher.matchesAny( | 342       var blocked = false; | 
| 508         stringifyURL(url), msg.mediatype, | 343 | 
| 509         documentHost, isThirdParty(url, documentHost) | 344       for (var i = 0; i < msg.urls.length; i++) | 
| 510       ); | 345       { | 
| 511 | 346         var url = new URL(msg.urls[i], msg.baseURL); | 
| 512       if (filter instanceof BlockingFilter) | 347         var filter = defaultMatcher.matchesAny( | 
| 513       { | 348           stringifyURL(url), typeMask, | 
| 514         var collapse = filter.collapse; | 349           documentHost, isThirdParty(url, documentHost) | 
| 515         if (collapse == null) | 350         ); | 
| 516           collapse = Prefs.hidePlaceholders; | 351 | 
| 517         sendResponse(collapse); | 352         if (filter instanceof BlockingFilter) | 
| 518       } | 353         { | 
| 519       else | 354           if (filter.collapse != null) | 
| 520         sendResponse(false); | 355           { | 
|  | 356             sendResponse(filter.collapse); | 
|  | 357             return; | 
|  | 358           } | 
|  | 359 | 
|  | 360           blocked = true; | 
|  | 361         } | 
|  | 362       } | 
|  | 363 | 
|  | 364       sendResponse(blocked && Prefs.hidePlaceholders); | 
| 521       break; | 365       break; | 
| 522     case "get-domain-enabled-state": | 366     case "get-domain-enabled-state": | 
| 523       // Returns whether this domain is in the exclusion list. | 367       // Returns whether this domain is in the exclusion list. | 
| 524       // The browser action popup asks us this. | 368       // The browser action popup asks us this. | 
| 525       if(sender.page) | 369       if(sender.page) | 
| 526       { | 370       { | 
| 527         sendResponse({enabled: !isPageWhitelisted(sender.page)}); | 371         sendResponse({enabled: !isPageWhitelisted(sender.page)}); | 
| 528         return; | 372         return; | 
| 529       } | 373       } | 
| 530       break; | 374       break; | 
| 531     case "add-filters": | 375     case "add-filters": | 
| 532       var filters; | 376       var result = parseFilters(msg.text); | 
| 533       try | 377 | 
| 534       { | 378       if (result.errors.length > 0) | 
| 535         filters = parseFilters(msg.text); | 379       { | 
| 536       } | 380         sendResponse({status: "invalid", error: result.errors.join("\n")}); | 
| 537       catch (error) |  | 
| 538       { |  | 
| 539         sendResponse({status: "invalid", error: error}); |  | 
| 540         break; | 381         break; | 
| 541       } | 382       } | 
| 542 | 383 | 
| 543       for (var i = 0; i < filters.length; i++) | 384       for (var i = 0; i < result.filters.length; i++) | 
| 544         FilterStorage.addFilter(filters[i]); | 385         FilterStorage.addFilter(result.filters[i]); | 
| 545 | 386 | 
| 546       sendResponse({status: "ok"}); | 387       sendResponse({status: "ok"}); | 
| 547       break; | 388       break; | 
| 548     case "add-subscription": | 389     case "add-subscription": | 
| 549       ext.showOptions(function(page) | 390       ext.showOptions(function(page) | 
| 550       { | 391       { | 
| 551         page.sendMessage(msg); | 392         page.sendMessage(msg); | 
| 552       }); | 393       }); | 
| 553       break; | 394       break; | 
| 554     case "add-sitekey": | 395     case "add-sitekey": | 
| 555       processKey(msg.token, sender.page, sender.frame); | 396       processKey(msg.token, sender.page, sender.frame); | 
| 556       break; | 397       break; | 
| 557     case "report-html-page": | 398     case "report-html-page": | 
| 558       htmlPages.set(sender.page, null); | 399       htmlPages.set(sender.page, null); | 
| 559       refreshIconAndContextMenu(sender.page); | 400       refreshIconAndContextMenu(sender.page); | 
|  | 401       break; | 
|  | 402     case "compose-filters": | 
|  | 403       sendResponse(composeFilters({ | 
|  | 404         tagName: msg.tagName, | 
|  | 405         id: msg.id, | 
|  | 406         src: msg.src, | 
|  | 407         style: msg.style, | 
|  | 408         classes: msg.classes, | 
|  | 409         urls: msg.urls, | 
|  | 410         type: msg.mediatype, | 
|  | 411         baseURL: msg.baseURL, | 
|  | 412         page: sender.page, | 
|  | 413         frame: sender.frame | 
|  | 414       })); | 
| 560       break; | 415       break; | 
| 561     case "forward": | 416     case "forward": | 
| 562       if (sender.page) | 417       if (sender.page) | 
| 563       { | 418       { | 
| 564         if (msg.expectsResponse) | 419         if (msg.expectsResponse) | 
| 565         { | 420         { | 
| 566           sender.page.sendMessage(msg.payload, sendResponse); | 421           sender.page.sendMessage(msg.payload, sendResponse); | 
| 567           return true; | 422           return true; | 
| 568         } | 423         } | 
| 569 | 424 | 
| 570         sender.page.sendMessage(msg.payload); | 425         sender.page.sendMessage(msg.payload); | 
| 571       } | 426       } | 
| 572       break; | 427       break; | 
| 573   } | 428   } | 
| 574 }); | 429 }); | 
| 575 | 430 | 
| 576 // update icon when page changes location | 431 // update icon when page changes location | 
| 577 ext.pages.onLoading.addListener(function(page) | 432 ext.pages.onLoading.addListener(function(page) | 
| 578 { | 433 { | 
| 579   page.sendMessage({type: "clickhide-deactivate"}); | 434   page.sendMessage({type: "clickhide-deactivate"}); | 
| 580   refreshIconAndContextMenu(page); | 435   refreshIconAndContextMenu(page); | 
| 581 }); | 436 }); | 
| 582 |  | 
| 583 setTimeout(function() |  | 
| 584 { |  | 
| 585   var notificationToShow = NotificationStorage.getNextToShow(); |  | 
| 586   if (notificationToShow) |  | 
| 587     showNotification(notificationToShow); |  | 
| 588 }, 3 * 60 * 1000); |  | 
| LEFT | RIGHT | 
|---|