| 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 var SELECTOR_GROUP_SIZE = 20; | 18 var SELECTOR_GROUP_SIZE = 20; | 
| 19 | 19 | 
| 20 var elemhideElt = null; |  | 
| 21 |  | 
| 22 // Sets the currently used CSS rules for elemhide filters |  | 
| 23 function setElemhideCSSRules(selectors) |  | 
| 24 { |  | 
| 25   if (elemhideElt && elemhideElt.parentNode) |  | 
| 26     elemhideElt.parentNode.removeChild(elemhideElt); |  | 
| 27 |  | 
| 28   if (!selectors) |  | 
| 29     return; |  | 
| 30 |  | 
| 31   elemhideElt = document.createElement("style"); |  | 
| 32   elemhideElt.setAttribute("type", "text/css"); |  | 
| 33 |  | 
| 34   // Try to insert the style into the <head> tag, inserting directly under the |  | 
| 35   // document root breaks dev tools functionality: |  | 
| 36   // http://code.google.com/p/chromium/issues/detail?id=178109 |  | 
| 37   (document.head || document.documentElement).appendChild(elemhideElt); |  | 
| 38 |  | 
| 39   var elt = elemhideElt;  // Use a local variable to avoid racing conditions |  | 
| 40   function setRules() |  | 
| 41   { |  | 
| 42     if (!elt.sheet) |  | 
| 43     { |  | 
| 44       // Stylesheet didn't initialize yet, wait a little longer |  | 
| 45       window.setTimeout(setRules, 0); |  | 
| 46       return; |  | 
| 47     } |  | 
| 48 |  | 
| 49     // WebKit apparently chokes when the selector list in a CSS rule is huge. |  | 
| 50     // So we split the elemhide selectors into groups. |  | 
| 51     for (var i = 0, j = 0; i < selectors.length; i += SELECTOR_GROUP_SIZE, j++) |  | 
| 52     { |  | 
| 53       var selector = selectors.slice(i, i + SELECTOR_GROUP_SIZE).join(", "); |  | 
| 54       elt.sheet.insertRule(selector + " { display: none !important; }", j); |  | 
| 55     } |  | 
| 56   } |  | 
| 57   setRules(); |  | 
| 58 } |  | 
| 59 |  | 
| 60 var typeMap = { | 20 var typeMap = { | 
| 61   "img": "IMAGE", | 21   "img": "IMAGE", | 
| 62   "input": "IMAGE", | 22   "input": "IMAGE", | 
| 63   "audio": "MEDIA", | 23   "audio": "MEDIA", | 
| 64   "video": "MEDIA", | 24   "video": "MEDIA", | 
| 65   "frame": "SUBDOCUMENT", | 25   "frame": "SUBDOCUMENT", | 
| 66   "iframe": "SUBDOCUMENT" | 26   "iframe": "SUBDOCUMENT" | 
| 67 }; | 27 }; | 
| 68 | 28 | 
| 69 function checkCollapse(event) | 29 function checkCollapse(element) | 
| 70 { | 30 { | 
| 71   var target = event.target; | 31   var tag = element.localName; | 
| 72   var tag = target.localName; | 32   if (tag in typeMap) | 
| 73   var expectedEvent = (tag == "iframe" || tag == "frame" ? "load" : "error"); |  | 
| 74   if (tag in typeMap && event.type == expectedEvent) |  | 
| 75   { | 33   { | 
| 76     // This element failed loading, did we block it? | 34     // This element failed loading, did we block it? | 
| 77     var url = target.src; | 35     var url = element.src; | 
| 78     if (!url) | 36     if (!url) | 
| 79       return; | 37       return; | 
| 80 | 38 | 
| 81     ext.backgroundPage.sendMessage( | 39     ext.backgroundPage.sendMessage( | 
| 82       { | 40       { | 
| 83         type: "should-collapse", | 41         type: "should-collapse", | 
| 84         url: url, | 42         url: url, | 
| 85         documentUrl: document.URL, |  | 
| 86         mediatype: typeMap[tag] | 43         mediatype: typeMap[tag] | 
| 87       }, | 44       }, | 
| 88 | 45 | 
| 89       function(response) | 46       function(response) | 
| 90       { | 47       { | 
| 91         if (response && target.parentNode) | 48         if (response && element.parentNode) | 
| 92         { | 49         { | 
| 93           // <frame> cannot be removed, doing that will mess up the frameset | 50           // <frame> cannot be removed, doing that will mess up the frameset | 
| 94           if (tag == "frame") | 51           if (tag == "frame") | 
| 95             target.style.setProperty("visibility", "hidden", "!important"); | 52             element.style.setProperty("visibility", "hidden", "important"); | 
| 96           else | 53           else | 
| 97             target.parentNode.removeChild(target); | 54             element.style.setProperty("display", "none", "important"); | 
| 98         } | 55         } | 
| 99       } | 56       } | 
| 100     ); | 57     ); | 
| 101   } | 58   } | 
| 102 } | 59 } | 
| 103 | 60 | 
| 104 function init() | 61 function checkExceptionKey() | 
| 105 { | 62 { | 
| 106   // Make sure this is really an HTML page, as Chrome runs these scripts on just
      about everything | 63   var attr = document.documentElement.getAttribute("data-adblockkey"); | 
| 107   if (!(document.documentElement instanceof HTMLElement)) | 64   if (attr) | 
| 108     return; | 65     ext.backgroundPage.sendMessage({type: "add-key-exception", token: attr}); | 
| 109 |  | 
| 110   document.addEventListener("error", checkCollapse, true); |  | 
| 111   document.addEventListener("load", checkCollapse, true); |  | 
| 112 |  | 
| 113   ext.backgroundPage.sendMessage( |  | 
| 114     { |  | 
| 115       type: "get-selectors", |  | 
| 116       frameUrl: window.location.href |  | 
| 117     }, |  | 
| 118     setElemhideCSSRules |  | 
| 119   ); |  | 
| 120 } | 66 } | 
| 121 | 67 | 
| 122 // In Chrome 18 the document might not be initialized yet | 68 function hasInlineURL(element, attribute) | 
| 123 if (document.documentElement) | 69 { | 
| 124   init(); | 70   var value = element.getAttribute(attribute); | 
| 125 else | 71   return value == null || /^\s*(javascript:|about:|$)/i.test(value); | 
| 126   window.setTimeout(init, 0); | 72 } | 
|  | 73 | 
|  | 74 function isInlineFrame(element) | 
|  | 75 { | 
|  | 76   switch (element.localName) | 
|  | 77   { | 
|  | 78     case "iframe": | 
|  | 79       return hasInlineURL(element, "src") || element.hasAttribute("srcdoc"); | 
|  | 80     case "frame": | 
|  | 81       return hasInlineURL(element, "src"); | 
|  | 82     case "object": | 
|  | 83       return hasInlineURL(element, "data") && element.contentDocument; | 
|  | 84     default: | 
|  | 85       return false; | 
|  | 86   } | 
|  | 87 } | 
|  | 88 | 
|  | 89 // Converts relative to absolute URL | 
|  | 90 // e.g.: foo.swf on http://example.com/whatever/bar.html | 
|  | 91 //  -> http://example.com/whatever/foo.swf | 
|  | 92 function relativeToAbsoluteUrl(url) | 
|  | 93 { | 
|  | 94   // If URL is already absolute, don't mess with it | 
|  | 95   if (!url || /^[\w\-]+:/i.test(url)) | 
|  | 96     return url; | 
|  | 97 | 
|  | 98   // Leading / means absolute path | 
|  | 99   // Leading // means network path | 
|  | 100   if (url[0] == '/') | 
|  | 101   { | 
|  | 102     if (url[1] == '/') | 
|  | 103       return document.location.protocol + url; | 
|  | 104     else | 
|  | 105       return document.location.protocol + "//" + document.location.host + url; | 
|  | 106   } | 
|  | 107 | 
|  | 108   // Remove filename and add relative URL to it | 
|  | 109   var base = document.baseURI.match(/.+\//); | 
|  | 110   if (!base) | 
|  | 111     return document.baseURI + "/" + url; | 
|  | 112   return base[0] + url; | 
|  | 113 } | 
|  | 114 | 
|  | 115 function init(document) | 
|  | 116 { | 
|  | 117   var canUseShadow = "webkitCreateShadowRoot" in document.documentElement; | 
|  | 118   var fixInlineFrames = false; | 
|  | 119 | 
|  | 120   var match = navigator.userAgent.match(/\bChrome\/(\d+)/); | 
|  | 121   if (match) | 
|  | 122   { | 
|  | 123     var chromeVersion = parseInt(match[1]); | 
|  | 124 | 
|  | 125     // the <shadow> element is ignored in Chrome 32 (#309). Also Chrome 31-33 | 
|  | 126     // crashes in some situations on some pages when using shadow DOM (#498). | 
|  | 127     // So we must not use Shadow DOM on those versions of Chrome. | 
|  | 128     if (chromeVersion >= 31 && chromeVersion <= 33) | 
|  | 129       canUseShadow = false; | 
|  | 130 | 
|  | 131     // prior to Chrome 37, content scripts don't run on about:blank | 
|  | 132     // and about:srcdoc. So we have to apply element hiding and collapsing | 
|  | 133     // from the parent frame, when inline frames are loaded. | 
|  | 134     if (chromeVersion < 37) | 
|  | 135       fixInlineFrames = true; | 
|  | 136   } | 
|  | 137 | 
|  | 138   // use Shadow DOM if available to don't mess with web pages that | 
|  | 139   // rely on the order of their own <style> tags (#309). However we | 
|  | 140   // must not create the shadow root in the response callback passed | 
|  | 141   // to sendMessage(), otherwise Chrome breaks some websites (#450). | 
|  | 142   if (canUseShadow) | 
|  | 143   { | 
|  | 144     var shadow = document.documentElement.webkitCreateShadowRoot(); | 
|  | 145     shadow.appendChild(document.createElement("shadow")); | 
|  | 146   } | 
|  | 147 | 
|  | 148   // Sets the currently used CSS rules for elemhide filters | 
|  | 149   var setElemhideCSSRules = function(selectors) | 
|  | 150   { | 
|  | 151     if (selectors.length == 0) | 
|  | 152       return; | 
|  | 153 | 
|  | 154     var style = document.createElement("style"); | 
|  | 155     style.setAttribute("type", "text/css"); | 
|  | 156 | 
|  | 157     if (canUseShadow) | 
|  | 158     { | 
|  | 159       shadow.appendChild(style); | 
|  | 160 | 
|  | 161       try | 
|  | 162       { | 
|  | 163         document.querySelector("::content"); | 
|  | 164 | 
|  | 165         for (var i = 0; i < selectors.length; i++) | 
|  | 166           selectors[i] = "::content " + selectors[i]; | 
|  | 167       } | 
|  | 168       catch (e) | 
|  | 169       { | 
|  | 170         for (var i = 0; i < selectors.length; i++) | 
|  | 171           selectors[i] = "::-webkit-distributed(" + selectors[i] + ")"; | 
|  | 172       } | 
|  | 173     } | 
|  | 174     else | 
|  | 175     { | 
|  | 176       // Try to insert the style into the <head> tag, inserting directly under t
     he | 
|  | 177       // document root breaks dev tools functionality: | 
|  | 178       // http://code.google.com/p/chromium/issues/detail?id=178109 | 
|  | 179       (document.head || document.documentElement).appendChild(style); | 
|  | 180     } | 
|  | 181 | 
|  | 182     var setRules = function() | 
|  | 183     { | 
|  | 184       // The sheet property might not exist yet if the | 
|  | 185       // <style> element was created for a sub frame | 
|  | 186       if (!style.sheet) | 
|  | 187       { | 
|  | 188         setTimeout(setRules, 0); | 
|  | 189         return; | 
|  | 190       } | 
|  | 191 | 
|  | 192       // WebKit apparently chokes when the selector list in a CSS rule is huge. | 
|  | 193       // So we split the elemhide selectors into groups. | 
|  | 194       for (var i = 0; selectors.length > 0; i++) | 
|  | 195       { | 
|  | 196         var selector = selectors.splice(0, SELECTOR_GROUP_SIZE).join(", "); | 
|  | 197         style.sheet.insertRule(selector + " { display: none !important; }", i); | 
|  | 198       } | 
|  | 199     }; | 
|  | 200 | 
|  | 201     setRules(); | 
|  | 202   }; | 
|  | 203 | 
|  | 204   document.addEventListener("error", function(event) | 
|  | 205   { | 
|  | 206     checkCollapse(event.target); | 
|  | 207   }, true); | 
|  | 208 | 
|  | 209   document.addEventListener("load", function(event) | 
|  | 210   { | 
|  | 211     var element = event.target; | 
|  | 212 | 
|  | 213     if (/^i?frame$/.test(element.localName)) | 
|  | 214       checkCollapse(element); | 
|  | 215 | 
|  | 216     if (fixInlineFrames && isInlineFrame(element)) | 
|  | 217     { | 
|  | 218       init(element.contentDocument); | 
|  | 219 | 
|  | 220       for (var tagName in typeMap) | 
|  | 221         Array.prototype.forEach.call(element.contentDocument.getElementsByTagNam
     e(tagName), checkCollapse); | 
|  | 222     } | 
|  | 223   }, true); | 
|  | 224 | 
|  | 225   ext.backgroundPage.sendMessage({type: "get-selectors"}, setElemhideCSSRules); | 
|  | 226 } | 
|  | 227 | 
|  | 228 if (document instanceof HTMLDocument) | 
|  | 229 { | 
|  | 230   checkExceptionKey(); | 
|  | 231   init(document); | 
|  | 232 } | 
| OLD | NEW | 
|---|