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