| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2  * This file is part of Adblock Plus <http://adblockplus.org/>, | 2  * This file is part of Adblock Plus <http://adblockplus.org/>, | 
| 3  * Copyright (C) 2006-2013 Eyeo GmbH | 3  * Copyright (C) 2006-2014 Eyeo GmbH | 
| 4  * | 4  * | 
| 5  * Adblock Plus is free software: you can redistribute it and/or modify | 5  * Adblock Plus is free software: you can redistribute it and/or modify | 
| 6  * it under the terms of the GNU General Public License version 3 as | 6  * it under the terms of the GNU General Public License version 3 as | 
| 7  * published by the Free Software Foundation. | 7  * published by the Free Software Foundation. | 
| 8  * | 8  * | 
| 9  * Adblock Plus is distributed in the hope that it will be useful, | 9  * Adblock Plus is distributed in the hope that it will be useful, | 
| 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| 12  * GNU General Public License for more details. | 12  * GNU General Public License for more details. | 
| 13  * | 13  * | 
| 14  * You should have received a copy of the GNU General Public License | 14  * You should have received a copy of the GNU General Public License | 
| 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
| 16  */ | 16  */ | 
| 17 | 17 | 
| 18 with(require("filterClasses")) | 18 with(require("filterClasses")) | 
| 19 { | 19 { | 
| 20   this.Filter = Filter; | 20   this.Filter = Filter; | 
| 21   this.RegExpFilter = RegExpFilter; | 21   this.RegExpFilter = RegExpFilter; | 
| 22   this.BlockingFilter = BlockingFilter; | 22   this.BlockingFilter = BlockingFilter; | 
| 23   this.WhitelistFilter = WhitelistFilter; | 23   this.WhitelistFilter = WhitelistFilter; | 
| 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; | 
|  | 30 } | 
|  | 31 with(require("whitelisting")) | 
|  | 32 { | 
|  | 33   this.isWhitelisted = isWhitelisted; | 
|  | 34   this.isFrameWhitelisted = isFrameWhitelisted; | 
|  | 35   this.processKeyException = processKeyException; | 
| 29 } | 36 } | 
| 30 var FilterStorage = require("filterStorage").FilterStorage; | 37 var FilterStorage = require("filterStorage").FilterStorage; | 
| 31 var ElemHide = require("elemHide").ElemHide; | 38 var ElemHide = require("elemHide").ElemHide; | 
| 32 var defaultMatcher = require("matcher").defaultMatcher; | 39 var defaultMatcher = require("matcher").defaultMatcher; | 
| 33 var Prefs = require("prefs").Prefs; | 40 var Prefs = require("prefs").Prefs; | 
| 34 var Synchronizer = require("synchronizer").Synchronizer; | 41 var Synchronizer = require("synchronizer").Synchronizer; | 
| 35 var Utils = require("utils").Utils; | 42 var Utils = require("utils").Utils; | 
| 36 var Notification = require("notification").Notification; | 43 var Notification = require("notification").Notification; | 
|  | 44 var initAntiAdblockNotification = require("antiadblockInit").initAntiAdblockNoti
     fication; | 
| 37 | 45 | 
| 38 // Some types cannot be distinguished | 46 // Some types cannot be distinguished | 
| 39 RegExpFilter.typeMap.OBJECT_SUBREQUEST = RegExpFilter.typeMap.OBJECT; | 47 RegExpFilter.typeMap.OBJECT_SUBREQUEST = RegExpFilter.typeMap.OBJECT; | 
| 40 RegExpFilter.typeMap.MEDIA = RegExpFilter.typeMap.FONT = RegExpFilter.typeMap.OT
     HER; | 48 RegExpFilter.typeMap.MEDIA = RegExpFilter.typeMap.FONT = RegExpFilter.typeMap.OT
     HER; | 
| 41 | 49 | 
| 42 var isFirstRun = false; | 50 // Chrome on Linux does not fully support chrome.notifications until version 35 | 
|  | 51 // https://code.google.com/p/chromium/issues/detail?id=291485 | 
|  | 52 var canUseChromeNotifications = require("info").platform == "chromium" | 
|  | 53   && "notifications" in chrome | 
|  | 54   && (navigator.platform.indexOf("Linux") == -1 || parseInt(require("info").appl
     icationVersion) > 34); | 
|  | 55 | 
| 43 var seenDataCorruption = false; | 56 var seenDataCorruption = false; | 
|  | 57 var filterlistsReinitialized = false; | 
| 44 require("filterNotifier").FilterNotifier.addListener(function(action) | 58 require("filterNotifier").FilterNotifier.addListener(function(action) | 
| 45 { | 59 { | 
| 46   if (action == "load") | 60   if (action == "load") | 
| 47   { | 61   { | 
| 48     var importingOldData = importOldData(); | 62     var importingOldData = importOldData(); | 
| 49 | 63 | 
| 50     var addonVersion = require("info").addonVersion; | 64     var addonVersion = require("info").addonVersion; | 
| 51     var prevVersion = localStorage.currentVersion; | 65     var prevVersion = ext.storage.currentVersion; | 
| 52     if (prevVersion != addonVersion) | 66 | 
|  | 67     // There are no filters stored so we need to reinitialize all filterlists | 
|  | 68     if (!FilterStorage.firstRun && FilterStorage.subscriptions.length === 0) | 
| 53     { | 69     { | 
| 54       isFirstRun = !prevVersion; | 70       filterlistsReinitialized = true; | 
| 55       localStorage.currentVersion = addonVersion; | 71       prevVersion = null; | 
|  | 72     } | 
|  | 73 | 
|  | 74     if (prevVersion != addonVersion || FilterStorage.firstRun) | 
|  | 75     { | 
|  | 76       seenDataCorruption = prevVersion && FilterStorage.firstRun; | 
|  | 77       ext.storage.currentVersion = addonVersion; | 
| 56       if (!importingOldData) | 78       if (!importingOldData) | 
| 57         addSubscription(prevVersion); | 79         addSubscription(prevVersion); | 
| 58     } | 80     } | 
|  | 81 | 
|  | 82     if (canUseChromeNotifications) | 
|  | 83       initChromeNotifications(); | 
|  | 84     initAntiAdblockNotification(); | 
| 59   } | 85   } | 
|  | 86 | 
|  | 87   // update browser actions when whitelisting might have changed, | 
|  | 88   // due to loading filters or saving filter changes | 
|  | 89   if (action == "load" || action == "save") | 
|  | 90     refreshIconAndContextMenuForAllPages(); | 
| 60 }); | 91 }); | 
| 61 | 92 | 
| 62 // Special-case domains for which we cannot use style-based hiding rules. | 93 // Special-case domains for which we cannot use style-based hiding rules. | 
| 63 // See http://crbug.com/68705. | 94 // See http://crbug.com/68705. | 
| 64 var noStyleRulesHosts = ["mail.google.com", "mail.yahoo.com", "www.google.com"]; | 95 var noStyleRulesHosts = ["mail.google.com", "mail.yahoo.com", "www.google.com"]; | 
| 65 | 96 | 
| 66 function removeDeprecatedOptions() | 97 function removeDeprecatedOptions() | 
| 67 { | 98 { | 
| 68   var deprecatedOptions = ["specialCaseYouTube", "experimental", "disableInlineT
     extAds"]; | 99   var deprecatedOptions = ["specialCaseYouTube", "experimental", "disableInlineT
     extAds"]; | 
| 69   deprecatedOptions.forEach(function(option) | 100   deprecatedOptions.forEach(function(option) | 
| 70   { | 101   { | 
| 71     if (option in localStorage) | 102     if (option in ext.storage) | 
| 72       delete localStorage[option]; | 103       delete ext.storage[option]; | 
| 73   }); | 104   }); | 
| 74 } | 105 } | 
| 75 | 106 | 
| 76 // Sets options to defaults, upgrading old options from previous versions as nec
     essary | 107 // Remove deprecated options before we do anything else. | 
| 77 function setDefaultOptions() | 108 removeDeprecatedOptions(); | 
| 78 { |  | 
| 79   function defaultOptionValue(opt, val) |  | 
| 80   { |  | 
| 81     if(!(opt in localStorage)) |  | 
| 82       localStorage[opt] = val; |  | 
| 83   } |  | 
| 84 |  | 
| 85   defaultOptionValue("shouldShowBlockElementMenu", "true"); |  | 
| 86 |  | 
| 87   removeDeprecatedOptions(); |  | 
| 88 } |  | 
| 89 |  | 
| 90 // Upgrade options before we do anything else. |  | 
| 91 setDefaultOptions(); |  | 
| 92 |  | 
| 93 /** |  | 
| 94  * Checks whether a page is whitelisted. |  | 
| 95  * @param {String} url |  | 
| 96  * @param {String} [parentUrl] URL of the parent frame |  | 
| 97  * @param {String} [type] content type to be checked, default is "DOCUMENT" |  | 
| 98  * @return {Filter} filter that matched the URL or null if not whitelisted |  | 
| 99  */ |  | 
| 100 function isWhitelisted(url, parentUrl, type) |  | 
| 101 { |  | 
| 102   // Ignore fragment identifier |  | 
| 103   var index = url.indexOf("#"); |  | 
| 104   if (index >= 0) |  | 
| 105     url = url.substring(0, index); |  | 
| 106 |  | 
| 107   var result = defaultMatcher.matchesAny(url, type || "DOCUMENT", extractHostFro
     mURL(parentUrl || url), false); |  | 
| 108   return (result instanceof WhitelistFilter ? result : null); |  | 
| 109 } |  | 
| 110 | 109 | 
| 111 var activeNotification = null; | 110 var activeNotification = null; | 
| 112 | 111 | 
|  | 112 var contextMenuItem = { | 
|  | 113   title: ext.i18n.getMessage("block_element"), | 
|  | 114   contexts: ["image", "video", "audio"], | 
|  | 115   onclick: function(srcUrl, page) | 
|  | 116   { | 
|  | 117     if (srcUrl) | 
|  | 118       page.sendMessage({type: "clickhide-new-filter", filter: srcUrl}); | 
|  | 119   } | 
|  | 120 }; | 
|  | 121 | 
| 113 // Adds or removes browser action icon according to options. | 122 // Adds or removes browser action icon according to options. | 
| 114 function refreshIconAndContextMenu(tab) | 123 function refreshIconAndContextMenu(page) | 
| 115 { | 124 { | 
| 116   if(!/^https?:/.test(tab.url)) | 125   var whitelisted = isWhitelisted(page.url); | 
| 117     return; |  | 
| 118 | 126 | 
| 119   var iconFilename; | 127   var iconFilename; | 
| 120   if (require("info").platform == "safari") | 128   if (whitelisted && require("info").platform != "safari") | 
| 121     // There is no grayscale version of the icon for whitelisted tabs | 129     // There is no grayscale version of the icon for whitelisted pages | 
| 122     // when using Safari, because icons are grayscale already and icons | 130     // when using Safari, because icons are grayscale already and icons | 
| 123     // aren't per tab in Safari. | 131     // aren't per page in Safari. | 
| 124     iconFilename = "icons/abp-16.png" | 132     iconFilename = "icons/abp-$size-whitelisted.png"; | 
| 125   else | 133   else | 
|  | 134     iconFilename = "icons/abp-$size.png"; | 
|  | 135 | 
|  | 136   page.browserAction.setIcon(iconFilename); | 
|  | 137   iconAnimation.registerPage(page, iconFilename); | 
|  | 138 | 
|  | 139   // show or hide the context menu entry dependent on whether | 
|  | 140   // adblocking is active on that page | 
|  | 141   page.contextMenus.removeAll(); | 
|  | 142 | 
|  | 143   if (Prefs.shouldShowBlockElementMenu && !whitelisted && /^https?:/.test(page.u
     rl)) | 
|  | 144     page.contextMenus.create(contextMenuItem); | 
|  | 145 } | 
|  | 146 | 
|  | 147 function refreshIconAndContextMenuForAllPages() | 
|  | 148 { | 
|  | 149   ext.pages.query({}, function(pages) | 
| 126   { | 150   { | 
| 127     var excluded = isWhitelisted(tab.url); | 151     pages.forEach(refreshIconAndContextMenu); | 
| 128     iconFilename = excluded ? "icons/abp-19-whitelisted.png" : "icons/abp-19.png
     "; | 152   }); | 
| 129   } |  | 
| 130 |  | 
| 131   tab.browserAction.setIcon(iconFilename); |  | 
| 132   tab.browserAction.setTitle(ext.i18n.getMessage("name")); |  | 
| 133 |  | 
| 134   iconAnimation.registerTab(tab, iconFilename); |  | 
| 135 |  | 
| 136   // Set context menu status according to whether current tab has whitelisted do
     main |  | 
| 137   if (excluded) |  | 
| 138     chrome.contextMenus.removeAll(); |  | 
| 139   else |  | 
| 140     showContextMenu(); |  | 
| 141 } | 153 } | 
| 142 | 154 | 
| 143 /** | 155 /** | 
| 144  * Old versions for Opera stored patterns.ini in the localStorage object, this | 156  * Old versions for Opera stored patterns.ini in the localStorage object, this | 
| 145  * will import it into FilterStorage properly. | 157  * will import it into FilterStorage properly. | 
| 146  * @return {Boolean} true if data import is in progress | 158  * @return {Boolean} true if data import is in progress | 
| 147  */ | 159  */ | 
| 148 function importOldData() | 160 function importOldData() | 
| 149 { | 161 { | 
| 150   if ("patterns.ini" in localStorage) | 162   if ("patterns.ini" in localStorage) | 
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 210     { | 222     { | 
| 211       subscription.title = "Allow non-intrusive advertising"; | 223       subscription.title = "Allow non-intrusive advertising"; | 
| 212       FilterStorage.addSubscription(subscription); | 224       FilterStorage.addSubscription(subscription); | 
| 213       if (subscription instanceof DownloadableSubscription && !subscription.last
     Download) | 225       if (subscription instanceof DownloadableSubscription && !subscription.last
     Download) | 
| 214         Synchronizer.execute(subscription); | 226         Synchronizer.execute(subscription); | 
| 215     } | 227     } | 
| 216     else | 228     else | 
| 217       addAcceptable = false; | 229       addAcceptable = false; | 
| 218   } | 230   } | 
| 219 | 231 | 
|  | 232   // Add "anti-adblock messages" subscription for new users and users updating f
     rom old ABP versions | 
|  | 233   if (!prevVersion || Services.vc.compare(prevVersion, "1.8") < 0) | 
|  | 234   { | 
|  | 235     var subscription = Subscription.fromURL(Prefs.subscriptions_antiadblockurl); | 
|  | 236     if (subscription && !(subscription.url in FilterStorage.knownSubscriptions)) | 
|  | 237     { | 
|  | 238       subscription.disabled = true; | 
|  | 239       FilterStorage.addSubscription(subscription); | 
|  | 240       if (subscription instanceof DownloadableSubscription && !subscription.last
     Download) | 
|  | 241         Synchronizer.execute(subscription); | 
|  | 242     } | 
|  | 243   } | 
|  | 244 | 
| 220   if (!addSubscription && !addAcceptable) | 245   if (!addSubscription && !addAcceptable) | 
| 221     return; | 246     return; | 
| 222 | 247 | 
| 223   function notifyUser() | 248   function notifyUser() | 
| 224   { | 249   { | 
| 225     ext.windows.getLastFocused(function(win) | 250     ext.pages.open(ext.getURL("firstRun.html")); | 
| 226     { |  | 
| 227       win.openTab(ext.getURL("firstRun.html")); |  | 
| 228     }); |  | 
| 229   } | 251   } | 
| 230 | 252 | 
| 231   if (addSubscription) | 253   if (addSubscription) | 
| 232   { | 254   { | 
| 233     // Load subscriptions data | 255     // Load subscriptions data | 
| 234     var request = new XMLHttpRequest(); | 256     var request = new XMLHttpRequest(); | 
| 235     request.open("GET", "subscriptions.xml"); | 257     request.open("GET", "subscriptions.xml"); | 
| 236     request.addEventListener("load", function() | 258     request.addEventListener("load", function() | 
| 237     { | 259     { | 
| 238       var node = Utils.chooseFilterSubscription(request.responseXML.getElementsB
     yTagName("subscription")); | 260       var node = Utils.chooseFilterSubscription(request.responseXML.getElementsB
     yTagName("subscription")); | 
| 239       var subscription = (node ? Subscription.fromURL(node.getAttribute("url")) 
     : null); | 261       var subscription = (node ? Subscription.fromURL(node.getAttribute("url")) 
     : null); | 
| 240       if (subscription) | 262       if (subscription) | 
| 241       { | 263       { | 
| 242         FilterStorage.addSubscription(subscription); | 264         FilterStorage.addSubscription(subscription); | 
| 243         subscription.disabled = false; | 265         subscription.disabled = false; | 
| 244         subscription.title = node.getAttribute("title"); | 266         subscription.title = node.getAttribute("title"); | 
| 245         subscription.homepage = node.getAttribute("homepage"); | 267         subscription.homepage = node.getAttribute("homepage"); | 
| 246         if (subscription instanceof DownloadableSubscription && !subscription.la
     stDownload) | 268         if (subscription instanceof DownloadableSubscription && !subscription.la
     stDownload) | 
| 247           Synchronizer.execute(subscription); | 269           Synchronizer.execute(subscription); | 
| 248 | 270 | 
| 249           notifyUser(); | 271           notifyUser(); | 
| 250       } | 272       } | 
| 251     }, false); | 273     }, false); | 
| 252     request.send(null); | 274     request.send(null); | 
| 253   } | 275   } | 
| 254   else | 276   else | 
| 255     notifyUser(); | 277     notifyUser(); | 
| 256 } | 278 } | 
| 257 | 279 | 
| 258 // Set up context menu for user selection of elements to block | 280 Prefs.addListener(function(name) | 
| 259 function showContextMenu() | 281 { | 
| 260 { | 282   if (name == "shouldShowBlockElementMenu") | 
| 261   ext.contextMenus.removeAll(function() | 283     refreshIconAndContextMenuForAllPages(); | 
| 262   { | 284 }); | 
| 263     if(typeof localStorage["shouldShowBlockElementMenu"] == "string" && localSto
     rage["shouldShowBlockElementMenu"] == "true") |  | 
| 264     { |  | 
| 265       ext.contextMenus.create(ext.i18n.getMessage("block_element"), ["image", "v
     ideo", "audio"], function(srcUrl, tab) |  | 
| 266       { |  | 
| 267         if(srcUrl) |  | 
| 268           tab.sendMessage({type: "clickhide-new-filter", filter: srcUrl}); |  | 
| 269       }); |  | 
| 270     } |  | 
| 271   }); |  | 
| 272 } |  | 
| 273 | 285 | 
| 274 /** | 286 /** | 
| 275   * Opens options tab or focuses an existing one, within the last focused window
     . | 287   * Opens options page or focuses an existing one, within the last focused windo
     w. | 
| 276   * @param {Function} callback  function to be called with the | 288   * @param {Function} callback  function to be called with the | 
| 277                                 Tab object of the options tab | 289                                 Page object of the options page | 
| 278   */ | 290   */ | 
| 279 function openOptions(callback) | 291 function openOptions(callback) | 
| 280 { | 292 { | 
| 281   ext.windows.getLastFocused(function(win) | 293   ext.pages.query({lastFocusedWindow: true}, function(pages) | 
| 282   { | 294   { | 
| 283     win.getAllTabs(function(tabs) | 295     var optionsUrl = ext.getURL("options.html"); | 
| 284     { | 296 | 
| 285       var optionsUrl = ext.getURL("options.html"); | 297     for (var i = 0; i < pages.length; i++) | 
| 286 | 298     { | 
| 287       for (var i = 0; i < tabs.length; i++) | 299       var page = pages[i]; | 
| 288       { | 300       if (page.url == optionsUrl) | 
| 289         if (tabs[i].url == optionsUrl) | 301       { | 
| 290         { | 302         page.activate(); | 
| 291           tabs[i].activate(); | 303         if (callback) | 
| 292           if (callback) | 304           callback(page); | 
| 293             callback(tabs[i]); | 305         return; | 
| 294           return; |  | 
| 295         } |  | 
| 296       } | 306       } | 
| 297 | 307     } | 
| 298       win.openTab(optionsUrl, callback && function(tab) | 308 | 
| 299       { | 309     ext.pages.open(optionsUrl, callback); | 
| 300         tab.onCompleted.addListener(callback); | 310   }); | 
|  | 311 } | 
|  | 312 | 
|  | 313 function prepareNotificationIconAndPopup() | 
|  | 314 { | 
|  | 315   var animateIcon = (activeNotification.type !== "question"); | 
|  | 316   activeNotification.onClicked = function() | 
|  | 317   { | 
|  | 318     if (animateIcon) | 
|  | 319       iconAnimation.stop(); | 
|  | 320     notificationClosed(); | 
|  | 321   }; | 
|  | 322   if (animateIcon) | 
|  | 323     iconAnimation.update(activeNotification.type); | 
|  | 324 } | 
|  | 325 | 
|  | 326 function openNotificationLinks() | 
|  | 327 { | 
|  | 328   if (activeNotification.links) | 
|  | 329   { | 
|  | 330     activeNotification.links.forEach(function(link) | 
|  | 331     { | 
|  | 332       ext.windows.getLastFocused(function(win) | 
|  | 333       { | 
|  | 334         win.openTab(Utils.getDocLink(link)); | 
| 301       }); | 335       }); | 
| 302     }); | 336     }); | 
|  | 337   } | 
|  | 338 } | 
|  | 339 | 
|  | 340 function notificationButtonClick(buttonIndex) | 
|  | 341 { | 
|  | 342   if (activeNotification.type === "question") | 
|  | 343   { | 
|  | 344     Notification.triggerQuestionListeners(activeNotification.id, buttonIndex ===
      0); | 
|  | 345     Notification.markAsShown(activeNotification.id); | 
|  | 346     activeNotification.onClicked(); | 
|  | 347   } | 
|  | 348   else if (activeNotification.links && activeNotification.links[buttonIndex]) | 
|  | 349   { | 
|  | 350     ext.windows.getLastFocused(function(win) | 
|  | 351     { | 
|  | 352       win.openTab(Utils.getDocLink(activeNotification.links[buttonIndex])); | 
|  | 353     }); | 
|  | 354   } | 
|  | 355 } | 
|  | 356 | 
|  | 357 function notificationClosed() | 
|  | 358 { | 
|  | 359   activeNotification = null; | 
|  | 360 } | 
|  | 361 | 
|  | 362 function imgToBase64(url, callback) | 
|  | 363 { | 
|  | 364   var canvas = document.createElement("canvas"), | 
|  | 365   ctx = canvas.getContext("2d"), | 
|  | 366   img = new Image; | 
|  | 367   img.src = url; | 
|  | 368   img.onload = function() | 
|  | 369   { | 
|  | 370     canvas.height = img.height; | 
|  | 371     canvas.width = img.width; | 
|  | 372     ctx.drawImage(img, 0, 0); | 
|  | 373     callback(canvas.toDataURL("image/png")); | 
|  | 374     canvas = null; | 
|  | 375   }; | 
|  | 376 } | 
|  | 377 | 
|  | 378 function initChromeNotifications() | 
|  | 379 { | 
|  | 380   // Chrome hides notifications in notification center when clicked so we need t
     o clear them | 
|  | 381   function clearActiveNotification(notificationId) | 
|  | 382   { | 
|  | 383     if (activeNotification && activeNotification.type != "question" && !("links"
      in activeNotification)) | 
|  | 384       return; | 
|  | 385 | 
|  | 386     chrome.notifications.clear(notificationId, function(wasCleared) | 
|  | 387     { | 
|  | 388       if (wasCleared) | 
|  | 389         notificationClosed(); | 
|  | 390     }); | 
|  | 391   } | 
|  | 392 | 
|  | 393   chrome.notifications.onButtonClicked.addListener(function(notificationId, butt
     onIndex) | 
|  | 394   { | 
|  | 395     notificationButtonClick(buttonIndex); | 
|  | 396     clearActiveNotification(notificationId); | 
| 303   }); | 397   }); | 
| 304 } | 398   chrome.notifications.onClicked.addListener(clearActiveNotification); | 
| 305 | 399   chrome.notifications.onClosed.addListener(notificationClosed); | 
| 306 function prepareNotificationIconAndPopup() |  | 
| 307 { |  | 
| 308   activeNotification.onClicked = function() |  | 
| 309   { |  | 
| 310     iconAnimation.stop(); |  | 
| 311     activeNotification = null; |  | 
| 312   }; |  | 
| 313 |  | 
| 314   iconAnimation.update(activeNotification.severity); |  | 
| 315 } | 400 } | 
| 316 | 401 | 
| 317 function showNotification(notification) | 402 function showNotification(notification) | 
| 318 { | 403 { | 
|  | 404   if (activeNotification && activeNotification.id === notification.id) | 
|  | 405     return; | 
|  | 406 | 
| 319   activeNotification = notification; | 407   activeNotification = notification; | 
| 320 | 408   if (activeNotification.type === "critical" || activeNotification.type === "que
     stion") | 
| 321   if (activeNotification.severity === "critical" | 409   { | 
| 322       && typeof webkitNotifications !== "undefined") | 410     var hasWebkitNotifications = typeof webkitNotifications !== "undefined"; | 
| 323   { | 411     if (hasWebkitNotifications && "createHTMLNotification" in webkitNotification
     s) | 
| 324     var notification = webkitNotifications.createHTMLNotification("notification.
     html"); | 412     { | 
| 325     notification.show(); | 413       var notification = webkitNotifications.createHTMLNotification("notificatio
     n.html"); | 
| 326     notification.addEventListener("close", prepareNotificationIconAndPopup); | 414       notification.show(); | 
| 327   } | 415       prepareNotificationIconAndPopup(); | 
| 328   else | 416       return; | 
| 329     prepareNotificationIconAndPopup(); | 417     } | 
| 330 } | 418 | 
| 331 | 419     var texts = Notification.getLocalizedTexts(notification); | 
| 332 /** | 420     var title = texts.title || ""; | 
| 333  * This function is a hack - we only know the tabId and document URL for a | 421     var message = texts.message ? texts.message.replace(/<\/?(a|strong)>/g, "") 
     : ""; | 
| 334  * message but we need to know the frame ID. Try to find it in webRequest"s | 422     var iconUrl = ext.getURL("icons/abp-128.png"); | 
| 335  * frame data. | 423     var hasLinks = activeNotification.links && activeNotification.links.length >
      0; | 
| 336  */ | 424 | 
| 337 function getFrameId(tab, url) | 425     if (canUseChromeNotifications) | 
| 338 { | 426     { | 
| 339   for (var frameId in frames.get(tab)) | 427       var opts = { | 
| 340     if (getFrameUrl(tab, frameId) == url) | 428         type: "basic", | 
| 341       return frameId; | 429         title: title, | 
| 342   return -1; | 430         message: message, | 
|  | 431         buttons: [], | 
|  | 432         priority: 2 // We use the highest priority to prevent the notification f
     rom closing automatically | 
|  | 433       }; | 
|  | 434       if (activeNotification.type === "question") | 
|  | 435       { | 
|  | 436         opts.buttons.push({title: ext.i18n.getMessage("overlay_notification_butt
     on_yes")}); | 
|  | 437         opts.buttons.push({title: ext.i18n.getMessage("overlay_notification_butt
     on_no")}); | 
|  | 438       } | 
|  | 439       else | 
|  | 440       { | 
|  | 441         var regex = /<a>(.*?)<\/a>/g; | 
|  | 442         var plainMessage = texts.message || ""; | 
|  | 443         var match; | 
|  | 444         while (match = regex.exec(plainMessage)) | 
|  | 445           opts.buttons.push({title: match[1]}); | 
|  | 446       } | 
|  | 447 | 
|  | 448       imgToBase64(iconUrl, function(iconData) | 
|  | 449       { | 
|  | 450         opts["iconUrl"] = iconData; | 
|  | 451         chrome.notifications.create("", opts, function() {}); | 
|  | 452       }); | 
|  | 453     } | 
|  | 454     else if (hasWebkitNotifications && "createNotification" in webkitNotificatio
     ns && activeNotification.type !== "question") | 
|  | 455     { | 
|  | 456       if (hasLinks) | 
|  | 457         message += " " + ext.i18n.getMessage("notification_without_buttons"); | 
|  | 458 | 
|  | 459       imgToBase64(iconUrl, function(iconData) | 
|  | 460       { | 
|  | 461         var notification = webkitNotifications.createNotification(iconData, titl
     e, message); | 
|  | 462         notification.show(); | 
|  | 463         notification.addEventListener("click", openNotificationLinks, false); | 
|  | 464         notification.addEventListener("close", notificationClosed, false); | 
|  | 465       }); | 
|  | 466     } | 
|  | 467     else | 
|  | 468     { | 
|  | 469       var message = title + "\n" + message; | 
|  | 470       if (hasLinks) | 
|  | 471         message += "\n\n" + ext.i18n.getMessage("notification_with_buttons"); | 
|  | 472 | 
|  | 473       var approved = confirm(message); | 
|  | 474       if (activeNotification.type === "question") | 
|  | 475         notificationButtonClick(approved ? 0 : 1); | 
|  | 476       else if (approved) | 
|  | 477         openNotificationLinks(); | 
|  | 478     } | 
|  | 479   } | 
|  | 480   prepareNotificationIconAndPopup(); | 
|  | 481 } | 
|  | 482 | 
|  | 483 // This is a hack to speedup loading of the options page on Safari. | 
|  | 484 // Once we replaced the background page proxy with message passing | 
|  | 485 // this global function should removed. | 
|  | 486 function getUserFilters() | 
|  | 487 { | 
|  | 488   var filters = []; | 
|  | 489   var exceptions = []; | 
|  | 490 | 
|  | 491   for (var i = 0; i < FilterStorage.subscriptions.length; i++) | 
|  | 492   { | 
|  | 493     var subscription = FilterStorage.subscriptions[i]; | 
|  | 494     if (!(subscription instanceof SpecialSubscription)) | 
|  | 495       continue; | 
|  | 496 | 
|  | 497     for (var j = 0; j < subscription.filters.length; j++) | 
|  | 498     { | 
|  | 499       var filter = subscription.filters[j]; | 
|  | 500       if (filter instanceof WhitelistFilter &&  /^@@\|\|([^\/:]+)\^\$document$/.
     test(filter.text)) | 
|  | 501         exceptions.push(RegExp.$1); | 
|  | 502       else | 
|  | 503         filters.push(filter.text); | 
|  | 504     } | 
|  | 505   } | 
|  | 506 | 
|  | 507   return {filters: filters, exceptions: exceptions}; | 
| 343 } | 508 } | 
| 344 | 509 | 
| 345 ext.onMessage.addListener(function (msg, sender, sendResponse) | 510 ext.onMessage.addListener(function (msg, sender, sendResponse) | 
| 346 { | 511 { | 
| 347   switch (msg.type) | 512   switch (msg.type) | 
| 348   { | 513   { | 
| 349     case "get-selectors": | 514     case "get-selectors": | 
| 350       var selectors = null; | 515       var selectors = []; | 
| 351       var frameId = sender.tab ? getFrameId(sender.tab, msg.frameUrl) : -1; |  | 
| 352 | 516 | 
| 353       if (!isFrameWhitelisted(sender.tab, frameId, "DOCUMENT") && | 517       if (!isFrameWhitelisted(sender.page, sender.frame, "DOCUMENT") && | 
| 354           !isFrameWhitelisted(sender.tab, frameId, "ELEMHIDE")) | 518           !isFrameWhitelisted(sender.page, sender.frame, "ELEMHIDE")) | 
| 355       { | 519       { | 
| 356         var noStyleRules = false; | 520         var noStyleRules = false; | 
| 357         var host = extractHostFromURL(msg.frameUrl); | 521         var host = extractHostFromFrame(sender.frame); | 
| 358         for (var i = 0; i < noStyleRulesHosts.length; i++) | 522         for (var i = 0; i < noStyleRulesHosts.length; i++) | 
| 359         { | 523         { | 
| 360           var noStyleHost = noStyleRulesHosts[i]; | 524           var noStyleHost = noStyleRulesHosts[i]; | 
| 361           if (host == noStyleHost || (host.length > noStyleHost.length && | 525           if (host == noStyleHost || (host.length > noStyleHost.length && | 
| 362                                       host.substr(host.length - noStyleHost.leng
     th - 1) == "." + noStyleHost)) | 526                                       host.substr(host.length - noStyleHost.leng
     th - 1) == "." + noStyleHost)) | 
| 363           { | 527           { | 
| 364             noStyleRules = true; | 528             noStyleRules = true; | 
| 365           } | 529           } | 
| 366         } | 530         } | 
| 367         selectors = ElemHide.getSelectorsForDomain(host, false); | 531         selectors = ElemHide.getSelectorsForDomain(host, false); | 
| 368         if (noStyleRules) | 532         if (noStyleRules) | 
| 369         { | 533         { | 
| 370           selectors = selectors.filter(function(s) | 534           selectors = selectors.filter(function(s) | 
| 371           { | 535           { | 
| 372             return !/\[style[\^\$]?=/.test(s); | 536             return !/\[style[\^\$]?=/.test(s); | 
| 373           }); | 537           }); | 
| 374         } | 538         } | 
| 375       } | 539       } | 
| 376 | 540 | 
| 377       sendResponse(selectors); | 541       sendResponse(selectors); | 
| 378       break; | 542       break; | 
| 379     case "should-collapse": | 543     case "should-collapse": | 
| 380       var frameId = sender.tab ? getFrameId(sender.tab, msg.documentUrl) : -1; | 544       if (isFrameWhitelisted(sender.page, sender.frame, "DOCUMENT")) | 
| 381 |  | 
| 382       if (isFrameWhitelisted(sender.tab, frameId, "DOCUMENT")) |  | 
| 383       { | 545       { | 
| 384         sendResponse(false); | 546         sendResponse(false); | 
| 385         break; | 547         break; | 
| 386       } | 548       } | 
| 387 | 549 | 
| 388       var requestHost = extractHostFromURL(msg.url); | 550       var requestHost = extractHostFromURL(msg.url); | 
| 389       var documentHost = extractHostFromURL(msg.documentUrl); | 551       var documentHost = extractHostFromFrame(sender.frame); | 
| 390       var thirdParty = isThirdParty(requestHost, documentHost); | 552       var thirdParty = isThirdParty(requestHost, documentHost); | 
| 391       var filter = defaultMatcher.matchesAny(msg.url, msg.mediatype, documentHos
     t, thirdParty); | 553       var filter = defaultMatcher.matchesAny(msg.url, msg.mediatype, documentHos
     t, thirdParty); | 
| 392       if (filter instanceof BlockingFilter) | 554       if (filter instanceof BlockingFilter) | 
| 393       { | 555       { | 
| 394         var collapse = filter.collapse; | 556         var collapse = filter.collapse; | 
| 395         if (collapse == null) | 557         if (collapse == null) | 
| 396           collapse = (localStorage.hidePlaceholders != "false"); | 558           collapse = Prefs.hidePlaceholders; | 
| 397         sendResponse(collapse); | 559         sendResponse(collapse); | 
| 398       } | 560       } | 
| 399       else | 561       else | 
| 400         sendResponse(false); | 562         sendResponse(false); | 
| 401       break; | 563       break; | 
| 402     case "get-domain-enabled-state": | 564     case "get-domain-enabled-state": | 
| 403       // Returns whether this domain is in the exclusion list. | 565       // Returns whether this domain is in the exclusion list. | 
| 404       // The browser action popup asks us this. | 566       // The browser action popup asks us this. | 
| 405       if(sender.tab) | 567       if(sender.page) | 
| 406       { | 568       { | 
| 407         sendResponse({enabled: !isWhitelisted(sender.tab.url)}); | 569         sendResponse({enabled: !isWhitelisted(sender.page.url)}); | 
| 408         return; | 570         return; | 
| 409       } | 571       } | 
| 410       break; | 572       break; | 
| 411     case "add-filters": | 573     case "add-filters": | 
| 412       if (msg.filters && msg.filters.length) | 574       if (msg.filters && msg.filters.length) | 
| 413       { | 575       { | 
| 414         for (var i = 0; i < msg.filters.length; i++) | 576         for (var i = 0; i < msg.filters.length; i++) | 
| 415           FilterStorage.addFilter(Filter.fromText(msg.filters[i])); | 577           FilterStorage.addFilter(Filter.fromText(msg.filters[i])); | 
| 416       } | 578       } | 
| 417       break; | 579       break; | 
| 418     case "add-subscription": | 580     case "add-subscription": | 
| 419       openOptions(function(tab) | 581       openOptions(function(page) | 
| 420       { | 582       { | 
| 421         tab.sendMessage(msg); | 583         page.sendMessage(msg); | 
| 422       }); | 584       }); | 
| 423       break; | 585       break; | 
|  | 586     case "add-key-exception": | 
|  | 587       processKeyException(msg.token, sender.page, sender.frame); | 
|  | 588       break; | 
| 424     case "forward": | 589     case "forward": | 
| 425       if (sender.tab) | 590       if (sender.page) | 
| 426       { | 591       { | 
| 427         sender.tab.sendMessage(msg.payload, sendResponse); | 592         sender.page.sendMessage(msg.payload, sendResponse); | 
| 428         // Return true to indicate that we want to call | 593         // Return true to indicate that we want to call | 
| 429         // sendResponse asynchronously | 594         // sendResponse asynchronously | 
| 430         return true; | 595         return true; | 
| 431       } | 596       } | 
| 432       break; | 597       break; | 
| 433     default: | 598     default: | 
| 434       sendResponse({}); | 599       sendResponse({}); | 
| 435       break; | 600       break; | 
| 436   } | 601   } | 
| 437 }); | 602 }); | 
| 438 | 603 | 
| 439 // Show icon as browser action for all tabs that already exist | 604 // update icon when page changes location | 
| 440 ext.windows.getAll(function(windows) | 605 ext.pages.onLoading.addListener(function(page) | 
| 441 { | 606 { | 
| 442   for (var i = 0; i < windows.length; i++) | 607   page.sendMessage({type: "clickhide-deactivate"}); | 
| 443   { | 608   refreshIconAndContextMenu(page); | 
| 444     windows[i].getAllTabs(function(tabs) |  | 
| 445     { |  | 
| 446       tabs.forEach(refreshIconAndContextMenu); |  | 
| 447     }); |  | 
| 448   } |  | 
| 449 }); |  | 
| 450 |  | 
| 451 // Update icon if a tab changes location |  | 
| 452 ext.tabs.onLoading.addListener(function(tab) |  | 
| 453 { |  | 
| 454   tab.sendMessage({type: "clickhide-deactivate"}); |  | 
| 455   refreshIconAndContextMenu(tab); |  | 
| 456 }); | 609 }); | 
| 457 | 610 | 
| 458 setTimeout(function() | 611 setTimeout(function() | 
| 459 { | 612 { | 
| 460   var notificationToShow = Notification.getNextToShow(); | 613   var notificationToShow = Notification.getNextToShow(); | 
| 461   if (notificationToShow) | 614   if (notificationToShow) | 
| 462     showNotification(notificationToShow); | 615     showNotification(notificationToShow); | 
| 463 }, 3 * 60 * 1000); | 616 }, 3 * 60 * 1000); | 
| OLD | NEW | 
|---|