| OLD | NEW | 
|---|
| 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-2016 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 var typeMap = { | 18 "use strict"; | 
|  | 19 | 
|  | 20 let typeMap = { | 
| 19   "img": "IMAGE", | 21   "img": "IMAGE", | 
| 20   "input": "IMAGE", | 22   "input": "IMAGE", | 
| 21   "picture": "IMAGE", | 23   "picture": "IMAGE", | 
| 22   "audio": "MEDIA", | 24   "audio": "MEDIA", | 
| 23   "video": "MEDIA", | 25   "video": "MEDIA", | 
| 24   "frame": "SUBDOCUMENT", | 26   "frame": "SUBDOCUMENT", | 
| 25   "iframe": "SUBDOCUMENT", | 27   "iframe": "SUBDOCUMENT", | 
| 26   "object": "OBJECT", | 28   "object": "OBJECT", | 
| 27   "embed": "OBJECT" | 29   "embed": "OBJECT" | 
| 28 }; | 30 }; | 
| 29 | 31 | 
| 30 function getURLsFromObjectElement(element) | 32 function getURLsFromObjectElement(element) | 
| 31 { | 33 { | 
| 32   var url = element.getAttribute("data"); | 34   let url = element.getAttribute("data"); | 
| 33   if (url) | 35   if (url) | 
| 34     return [url]; | 36     return [url]; | 
| 35 | 37 | 
| 36   for (var i = 0; i < element.children.length; i++) | 38   for (let child of element.children) | 
| 37   { | 39   { | 
| 38     var child = element.children[i]; |  | 
| 39     if (child.localName != "param") | 40     if (child.localName != "param") | 
| 40       continue; | 41       continue; | 
| 41 | 42 | 
| 42     var name = child.getAttribute("name"); | 43     let name = child.getAttribute("name"); | 
| 43     if (name != "movie"  && // Adobe Flash | 44     if (name != "movie"  && // Adobe Flash | 
| 44         name != "source" && // Silverlight | 45         name != "source" && // Silverlight | 
| 45         name != "src"    && // Real Media + Quicktime | 46         name != "src"    && // Real Media + Quicktime | 
| 46         name != "FileName") // Windows Media | 47         name != "FileName") // Windows Media | 
| 47       continue; | 48       continue; | 
| 48 | 49 | 
| 49     var value = child.getAttribute("value"); | 50     let value = child.getAttribute("value"); | 
| 50     if (!value) | 51     if (!value) | 
| 51       continue; | 52       continue; | 
| 52 | 53 | 
| 53     return [value]; | 54     return [value]; | 
| 54   } | 55   } | 
| 55 | 56 | 
| 56   return []; | 57   return []; | 
| 57 } | 58 } | 
| 58 | 59 | 
| 59 function getURLsFromAttributes(element) | 60 function getURLsFromAttributes(element) | 
| 60 { | 61 { | 
| 61   var urls = []; | 62   let urls = []; | 
| 62 | 63 | 
| 63   if (element.src) | 64   if (element.src) | 
| 64     urls.push(element.src); | 65     urls.push(element.src); | 
| 65 | 66 | 
| 66   if (element.srcset) | 67   if (element.srcset) | 
| 67   { | 68   { | 
| 68     var candidates = element.srcset.split(","); | 69     for (let candidate of element.srcset.split(",")) | 
| 69     for (var i = 0; i < candidates.length; i++) |  | 
| 70     { | 70     { | 
| 71       var url = candidates[i].trim().replace(/\s+\S+$/, ""); | 71       let url = candidate.trim().replace(/\s+\S+$/, ""); | 
| 72       if (url) | 72       if (url) | 
| 73         urls.push(url); | 73         urls.push(url); | 
| 74     } | 74     } | 
| 75   } | 75   } | 
| 76 | 76 | 
| 77   return urls; | 77   return urls; | 
| 78 } | 78 } | 
| 79 | 79 | 
| 80 function getURLsFromMediaElement(element) | 80 function getURLsFromMediaElement(element) | 
| 81 { | 81 { | 
| 82   var urls = getURLsFromAttributes(element); | 82   let urls = getURLsFromAttributes(element); | 
| 83 | 83 | 
| 84   for (var i = 0; i < element.children.length; i++) | 84   for (let child of element.children) | 
| 85   { |  | 
| 86     var child = element.children[i]; |  | 
| 87     if (child.localName == "source" || child.localName == "track") | 85     if (child.localName == "source" || child.localName == "track") | 
| 88       urls.push.apply(urls, getURLsFromAttributes(child)); | 86       urls.push.apply(urls, getURLsFromAttributes(child)); | 
| 89   } |  | 
| 90 | 87 | 
| 91   if (element.poster) | 88   if (element.poster) | 
| 92     urls.push(element.poster); | 89     urls.push(element.poster); | 
| 93 | 90 | 
| 94   return urls; | 91   return urls; | 
| 95 } | 92 } | 
| 96 | 93 | 
| 97 function getURLsFromElement(element) | 94 function getURLsFromElement(element) | 
| 98 { | 95 { | 
| 99   var urls; | 96   let urls; | 
| 100   switch (element.localName) | 97   switch (element.localName) | 
| 101   { | 98   { | 
| 102     case "object": | 99     case "object": | 
| 103       urls = getURLsFromObjectElement(element); | 100       urls = getURLsFromObjectElement(element); | 
| 104       break; | 101       break; | 
| 105 | 102 | 
| 106     case "video": | 103     case "video": | 
| 107     case "audio": | 104     case "audio": | 
| 108     case "picture": | 105     case "picture": | 
| 109       urls = getURLsFromMediaElement(element); | 106       urls = getURLsFromMediaElement(element); | 
| 110       break; | 107       break; | 
| 111 | 108 | 
| 112     default: | 109     default: | 
| 113       urls = getURLsFromAttributes(element); | 110       urls = getURLsFromAttributes(element); | 
| 114       break; | 111       break; | 
| 115   } | 112   } | 
| 116 | 113 | 
| 117   for (var i = 0; i < urls.length; i++) | 114   for (let i = 0; i < urls.length; i++) | 
| 118   { | 115   { | 
| 119     if (/^(?!https?:)[\w-]+:/i.test(urls[i])) | 116     if (/^(?!https?:)[\w-]+:/i.test(urls[i])) | 
| 120       urls.splice(i--, 1); | 117       urls.splice(i--, 1); | 
| 121   } | 118   } | 
| 122 | 119 | 
| 123   return urls; | 120   return urls; | 
| 124 } | 121 } | 
| 125 | 122 | 
| 126 function checkCollapse(element) | 123 function checkCollapse(element) | 
| 127 { | 124 { | 
| 128   var mediatype = typeMap[element.localName]; | 125   let mediatype = typeMap[element.localName]; | 
| 129   if (!mediatype) | 126   if (!mediatype) | 
| 130     return; | 127     return; | 
| 131 | 128 | 
| 132   var urls = getURLsFromElement(element); | 129   let urls = getURLsFromElement(element); | 
| 133   if (urls.length == 0) | 130   if (urls.length == 0) | 
| 134     return; | 131     return; | 
| 135 | 132 | 
| 136   ext.backgroundPage.sendMessage( | 133   ext.backgroundPage.sendMessage( | 
| 137     { | 134     { | 
| 138       type: "filters.collapse", | 135       type: "filters.collapse", | 
| 139       urls: urls, | 136       urls: urls, | 
| 140       mediatype: mediatype, | 137       mediatype: mediatype, | 
| 141       baseURL: document.location.href | 138       baseURL: document.location.href | 
| 142     }, | 139     }, | 
| 143 | 140 | 
| 144     function(collapse) | 141     collapse => | 
| 145     { | 142     { | 
| 146       function collapseElement() | 143       function collapseElement() | 
| 147       { | 144       { | 
| 148         var propertyName = "display"; | 145         let propertyName = "display"; | 
| 149         var propertyValue = "none"; | 146         let propertyValue = "none"; | 
| 150         if (element.localName == "frame") | 147         if (element.localName == "frame") | 
| 151         { | 148         { | 
| 152           propertyName = "visibility"; | 149           propertyName = "visibility"; | 
| 153           propertyValue = "hidden"; | 150           propertyValue = "hidden"; | 
| 154         } | 151         } | 
| 155 | 152 | 
| 156         if (element.style.getPropertyValue(propertyName) != propertyValue || | 153         if (element.style.getPropertyValue(propertyName) != propertyValue || | 
| 157             element.style.getPropertyPriority(propertyName) != "important") | 154             element.style.getPropertyPriority(propertyName) != "important") | 
| 158           element.style.setProperty(propertyName, propertyValue, "important"); | 155           element.style.setProperty(propertyName, propertyValue, "important"); | 
| 159       } | 156       } | 
| 160 | 157 | 
| 161       if (collapse) | 158       if (collapse) | 
| 162       { | 159       { | 
| 163         collapseElement(); | 160         collapseElement(); | 
| 164 | 161 | 
| 165         new MutationObserver(collapseElement).observe( | 162         new MutationObserver(collapseElement).observe( | 
| 166           element, { | 163           element, { | 
| 167             attributes: true, | 164             attributes: true, | 
| 168             attributeFilter: ["style"] | 165             attributeFilter: ["style"] | 
| 169           } | 166           } | 
| 170         ); | 167         ); | 
| 171       } | 168       } | 
| 172     } | 169     } | 
| 173   ); | 170   ); | 
| 174 } | 171 } | 
| 175 | 172 | 
| 176 function checkSitekey() | 173 function checkSitekey() | 
| 177 { | 174 { | 
| 178   var attr = document.documentElement.getAttribute("data-adblockkey"); | 175   let attr = document.documentElement.getAttribute("data-adblockkey"); | 
| 179   if (attr) | 176   if (attr) | 
| 180     ext.backgroundPage.sendMessage({type: "filters.addKey", token: attr}); | 177     ext.backgroundPage.sendMessage({type: "filters.addKey", token: attr}); | 
| 181 } | 178 } | 
| 182 | 179 | 
| 183 function getContentDocument(element) | 180 function getContentDocument(element) | 
| 184 { | 181 { | 
| 185   try | 182   try | 
| 186   { | 183   { | 
| 187     return element.contentDocument; | 184     return element.contentDocument; | 
| 188   } | 185   } | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 201 | 198 | 
| 202   this.observer = new MutationObserver(this.observe.bind(this)); | 199   this.observer = new MutationObserver(this.observe.bind(this)); | 
| 203   this.trace = this.trace.bind(this); | 200   this.trace = this.trace.bind(this); | 
| 204 | 201 | 
| 205   if (document.readyState == "loading") | 202   if (document.readyState == "loading") | 
| 206     document.addEventListener("DOMContentLoaded", this.trace); | 203     document.addEventListener("DOMContentLoaded", this.trace); | 
| 207   else | 204   else | 
| 208     this.trace(); | 205     this.trace(); | 
| 209 } | 206 } | 
| 210 ElementHidingTracer.prototype = { | 207 ElementHidingTracer.prototype = { | 
| 211   checkNodes: function(nodes) | 208   checkNodes: nodes => | 
| 212   { | 209   { | 
| 213     var matchedSelectors = []; | 210     let matchedSelectors = []; | 
| 214 | 211 | 
| 215     // Find all selectors that match any hidden element inside the given nodes. | 212     // Find all selectors that match any hidden element inside the given nodes. | 
| 216     for (var i = 0; i < this.selectors.length; i++) | 213     for (let selector of this.selectors) | 
| 217     { | 214     { | 
| 218       var selector = this.selectors[i]; | 215       for (let node of nodes) | 
|  | 216       { | 
|  | 217         let elements = node.querySelectorAll(selector); | 
|  | 218         let matched = false; | 
| 219 | 219 | 
| 220       for (var j = 0; j < nodes.length; j++) | 220         for (let element of elements) | 
| 221       { |  | 
| 222         var elements = nodes[j].querySelectorAll(selector); |  | 
| 223         var matched = false; |  | 
| 224 |  | 
| 225         for (var k = 0; k < elements.length; k++) |  | 
| 226         { | 221         { | 
| 227           // Only consider selectors that actually have an effect on the | 222           // Only consider selectors that actually have an effect on the | 
| 228           // computed styles, and aren't overridden by rules with higher | 223           // computed styles, and aren't overridden by rules with higher | 
| 229           // priority, or haven't been circumvented in a different way. | 224           // priority, or haven't been circumvented in a different way. | 
| 230           if (getComputedStyle(elements[k]).display == "none") | 225           if (getComputedStyle(element).display == "none") | 
| 231           { | 226           { | 
| 232             matchedSelectors.push(selector); | 227             matchedSelectors.push(selector); | 
| 233             matched = true; | 228             matched = true; | 
| 234             break; | 229             break; | 
| 235           } | 230           } | 
| 236         } | 231         } | 
| 237 | 232 | 
| 238         if (matched) | 233         if (matched) | 
| 239           break; | 234           break; | 
| 240       } | 235       } | 
| 241     } | 236     } | 
| 242 | 237 | 
| 243     if (matchedSelectors.length > 0) | 238     if (matchedSelectors.length > 0) | 
| 244       ext.backgroundPage.sendMessage({ | 239       ext.backgroundPage.sendMessage({ | 
| 245         type: "devtools.traceElemHide", | 240         type: "devtools.traceElemHide", | 
| 246         selectors: matchedSelectors | 241         selectors: matchedSelectors | 
| 247       }); | 242       }); | 
| 248   }, | 243   }, | 
| 249 | 244 | 
| 250   onTimeout: function() | 245   onTimeout: function() | 
| 251   { | 246   { | 
| 252     this.checkNodes(this.changedNodes); | 247     this.checkNodes(this.changedNodes); | 
| 253     this.changedNodes = []; | 248     this.changedNodes = []; | 
| 254     this.timeout = null; | 249     this.timeout = null; | 
| 255   }, | 250   }, | 
| 256 | 251 | 
| 257   observe: function(mutations) | 252   observe: function(mutations) | 
| 258   { | 253   { | 
| 259     // Forget previously changed nodes that are no longer in the DOM. | 254     // Forget previously changed nodes that are no longer in the DOM. | 
| 260     for (var i = 0; i < this.changedNodes.length; i++) | 255     for (let i = 0; i < this.changedNodes.length; i++) | 
| 261     { | 256     { | 
| 262       if (!document.contains(this.changedNodes[i])) | 257       if (!document.contains(this.changedNodes[i])) | 
| 263         this.changedNodes.splice(i--, 1); | 258         this.changedNodes.splice(i--, 1); | 
| 264     } | 259     } | 
| 265 | 260 | 
| 266     for (var j = 0; j < mutations.length; j++) | 261     for (let mutation of mutations) | 
| 267     { | 262     { | 
| 268       var mutation = mutations[j]; | 263       let node = mutation.target; | 
| 269       var node = mutation.target; |  | 
| 270 | 264 | 
| 271       // Ignore mutations of nodes that aren't in the DOM anymore. | 265       // Ignore mutations of nodes that aren't in the DOM anymore. | 
| 272       if (!document.contains(node)) | 266       if (!document.contains(node)) | 
| 273         continue; | 267         continue; | 
| 274 | 268 | 
| 275       // Since querySelectorAll() doesn't consider the root itself | 269       // Since querySelectorAll() doesn't consider the root itself | 
| 276       // and since CSS selectors can also match siblings, we have | 270       // and since CSS selectors can also match siblings, we have | 
| 277       // to consider the parent node for attribute mutations. | 271       // to consider the parent node for attribute mutations. | 
| 278       if (mutation.type == "attributes") | 272       if (mutation.type == "attributes") | 
| 279         node = node.parentNode; | 273         node = node.parentNode; | 
| 280 | 274 | 
| 281       var addNode = true; | 275       let addNode = true; | 
| 282       for (var k = 0; k < this.changedNodes.length; k++) | 276       for (let i = 0; i < this.changedNodes.length; i++) | 
| 283       { | 277       { | 
| 284         var previouslyChangedNode = this.changedNodes[k]; | 278         let previouslyChangedNode = this.changedNodes[i]; | 
| 285 | 279 | 
| 286         // If we are already going to check an ancestor of this node, | 280         // If we are already going to check an ancestor of this node, | 
| 287         // we can ignore this node, since it will be considered anyway | 281         // we can ignore this node, since it will be considered anyway | 
| 288         // when checking one of its ancestors. | 282         // when checking one of its ancestors. | 
| 289         if (previouslyChangedNode.contains(node)) | 283         if (previouslyChangedNode.contains(node)) | 
| 290         { | 284         { | 
| 291           addNode = false; | 285           addNode = false; | 
| 292           break; | 286           break; | 
| 293         } | 287         } | 
| 294 | 288 | 
| 295         // If this node is an ancestor of a node that previously changed, | 289         // If this node is an ancestor of a node that previously changed, | 
| 296         // we can ignore that node, since it will be considered anyway | 290         // we can ignore that node, since it will be considered anyway | 
| 297         // when checking one of its ancestors. | 291         // when checking one of its ancestors. | 
| 298         if (node.contains(previouslyChangedNode)) | 292         if (node.contains(previouslyChangedNode)) | 
| 299           this.changedNodes.splice(k--, 1); | 293           this.changedNodes.splice(i--, 1); | 
| 300       } | 294       } | 
| 301 | 295 | 
| 302       if (addNode) | 296       if (addNode) | 
| 303         this.changedNodes.push(node); | 297         this.changedNodes.push(node); | 
| 304     } | 298     } | 
| 305 | 299 | 
| 306     // Check only nodes whose descendants have changed, and not more often | 300     // Check only nodes whose descendants have changed, and not more often | 
| 307     // than once a second. Otherwise large pages with a lot of DOM mutations | 301     // than once a second. Otherwise large pages with a lot of DOM mutations | 
| 308     // (like YouTube) freeze when the devtools panel is active. | 302     // (like YouTube) freeze when the devtools panel is active. | 
| 309     if (this.timeout == null) | 303     if (this.timeout == null) | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
| 327   disconnect: function() | 321   disconnect: function() | 
| 328   { | 322   { | 
| 329     document.removeEventListener("DOMContentLoaded", this.trace); | 323     document.removeEventListener("DOMContentLoaded", this.trace); | 
| 330     this.observer.disconnect(); | 324     this.observer.disconnect(); | 
| 331     clearTimeout(this.timeout); | 325     clearTimeout(this.timeout); | 
| 332   } | 326   } | 
| 333 }; | 327 }; | 
| 334 | 328 | 
| 335 function runInPageContext(fn, arg) | 329 function runInPageContext(fn, arg) | 
| 336 { | 330 { | 
| 337   var script = document.createElement("script"); | 331   let script = document.createElement("script"); | 
| 338   script.type = "application/javascript"; | 332   script.type = "application/javascript"; | 
| 339   script.async = false; | 333   script.async = false; | 
| 340   script.textContent = "(" + fn + ")(" + JSON.stringify(arg) + ");"; | 334   script.textContent = "(" + fn + ")(" + JSON.stringify(arg) + ");"; | 
| 341   document.documentElement.appendChild(script); | 335   document.documentElement.appendChild(script); | 
| 342   document.documentElement.removeChild(script); | 336   document.documentElement.removeChild(script); | 
| 343 } | 337 } | 
| 344 | 338 | 
| 345 // Chrome doesn't allow us to intercept WebSockets[1], and therefore | 339 // Chrome doesn't allow us to intercept WebSockets[1], and therefore | 
| 346 // some ad networks are misusing them as a way to serve adverts and circumvent | 340 // some ad networks are misusing them as a way to serve adverts and circumvent | 
| 347 // us. As a workaround we wrap WebSocket, preventing blocked WebSocket | 341 // us. As a workaround we wrap WebSocket, preventing blocked WebSocket | 
| 348 // connections from being opened. | 342 // connections from being opened. | 
| 349 // [1] - https://bugs.chromium.org/p/chromium/issues/detail?id=129353 | 343 // [1] - https://bugs.chromium.org/p/chromium/issues/detail?id=129353 | 
| 350 function wrapWebSocket() | 344 function wrapWebSocket() | 
| 351 { | 345 { | 
| 352   var eventName = "abpws-" + Math.random().toString(36).substr(2); | 346   let eventName = "abpws-" + Math.random().toString(36).substr(2); | 
| 353 | 347 | 
| 354   document.addEventListener(eventName, function(event) | 348   document.addEventListener(eventName, event => | 
| 355   { | 349   { | 
| 356     ext.backgroundPage.sendMessage({ | 350     ext.backgroundPage.sendMessage({ | 
| 357       type: "request.websocket", | 351       type: "request.websocket", | 
| 358       url: event.detail.url | 352       url: event.detail.url | 
| 359     }, function (block) | 353     }, block => | 
| 360     { | 354     { | 
| 361       document.dispatchEvent( | 355       document.dispatchEvent( | 
| 362         new CustomEvent(eventName + "-" + event.detail.url, {detail: block}) | 356         new CustomEvent(eventName + "-" + event.detail.url, {detail: block}) | 
| 363       ); | 357       ); | 
| 364     }); | 358     }); | 
| 365   }); | 359   }); | 
| 366 | 360 | 
| 367   runInPageContext(function(eventName) | 361   runInPageContext(eventName => | 
| 368   { | 362   { | 
| 369     // As far as possible we must track everything we use that could be | 363     // As far as possible we must track everything we use that could be | 
| 370     // sabotaged by the website later in order to circumvent us. | 364     // sabotaged by the website later in order to circumvent us. | 
| 371     var RealWebSocket = WebSocket; | 365     let RealWebSocket = WebSocket; | 
| 372     var closeWebSocket = Function.prototype.call.bind(RealWebSocket.prototype.cl
     ose); | 366     let closeWebSocket = Function.prototype.call.bind(RealWebSocket.prototype.cl
     ose); | 
| 373     var addEventListener = document.addEventListener.bind(document); | 367     let addEventListener = document.addEventListener.bind(document); | 
| 374     var removeEventListener = document.removeEventListener.bind(document); | 368     let removeEventListener = document.removeEventListener.bind(document); | 
| 375     var dispatchEvent = document.dispatchEvent.bind(document); | 369     let dispatchEvent = document.dispatchEvent.bind(document); | 
| 376     var CustomEvent = window.CustomEvent; | 370     let CustomEvent = window.CustomEvent; | 
| 377 | 371 | 
| 378     function checkRequest(url, callback) | 372     function checkRequest(url, callback) | 
| 379     { | 373     { | 
| 380       var incomingEventName = eventName + "-" + url; | 374       let incomingEventName = eventName + "-" + url; | 
| 381       function listener(event) | 375       function listener(event) | 
| 382       { | 376       { | 
| 383         callback(event.detail); | 377         callback(event.detail); | 
| 384         removeEventListener(incomingEventName, listener); | 378         removeEventListener(incomingEventName, listener); | 
| 385       } | 379       } | 
| 386       addEventListener(incomingEventName, listener); | 380       addEventListener(incomingEventName, listener); | 
| 387 | 381 | 
| 388       dispatchEvent(new CustomEvent(eventName, { | 382       dispatchEvent(new CustomEvent(eventName, { | 
| 389         detail: {url: url} | 383         detail: {url: url} | 
| 390       })); | 384       })); | 
| 391     } | 385     } | 
| 392 | 386 | 
| 393     function WrappedWebSocket(url) | 387     function WrappedWebSocket(url) | 
| 394     { | 388     { | 
| 395       // Throw correct exceptions if the constructor is used improperly. | 389       // Throw correct exceptions if the constructor is used improperly. | 
| 396       if (!(this instanceof WrappedWebSocket)) return RealWebSocket(); | 390       if (!(this instanceof WrappedWebSocket)) return RealWebSocket(); | 
| 397       if (arguments.length < 1) return new RealWebSocket(); | 391       if (arguments.length < 1) return new RealWebSocket(); | 
| 398 | 392 | 
| 399       var websocket; | 393       let websocket; | 
| 400       if (arguments.length == 1) | 394       if (arguments.length == 1) | 
| 401         websocket = new RealWebSocket(url); | 395         websocket = new RealWebSocket(url); | 
| 402       else | 396       else | 
| 403         websocket = new RealWebSocket(url, arguments[1]); | 397         websocket = new RealWebSocket(url, arguments[1]); | 
| 404 | 398 | 
| 405       checkRequest(websocket.url, function(blocked) | 399       checkRequest(websocket.url, blocked => | 
| 406       { | 400       { | 
| 407         if (blocked) | 401         if (blocked) | 
| 408           closeWebSocket(websocket); | 402           closeWebSocket(websocket); | 
| 409       }); | 403       }); | 
| 410 | 404 | 
| 411       return websocket; | 405       return websocket; | 
| 412     } | 406     } | 
| 413     WrappedWebSocket.prototype = RealWebSocket.prototype; | 407     WrappedWebSocket.prototype = RealWebSocket.prototype; | 
| 414     WebSocket = WrappedWebSocket.bind(); | 408     WebSocket = WrappedWebSocket.bind(); | 
| 415     Object.defineProperties(WebSocket, { | 409     Object.defineProperties(WebSocket, { | 
| 416       CONNECTING: {value: RealWebSocket.CONNECTING, enumerable: true}, | 410       CONNECTING: {value: RealWebSocket.CONNECTING, enumerable: true}, | 
| 417       OPEN: {value: RealWebSocket.OPEN, enumerable: true}, | 411       OPEN: {value: RealWebSocket.OPEN, enumerable: true}, | 
| 418       CLOSING: {value: RealWebSocket.CLOSING, enumerable: true}, | 412       CLOSING: {value: RealWebSocket.CLOSING, enumerable: true}, | 
| 419       CLOSED: {value: RealWebSocket.CLOSED, enumerable: true}, | 413       CLOSED: {value: RealWebSocket.CLOSED, enumerable: true}, | 
| 420       prototype: {value: RealWebSocket.prototype} | 414       prototype: {value: RealWebSocket.prototype} | 
| 421     }); | 415     }); | 
| 422 | 416 | 
| 423     RealWebSocket.prototype.constructor = WebSocket; | 417     RealWebSocket.prototype.constructor = WebSocket; | 
| 424   }, eventName); | 418   }, eventName); | 
| 425 } | 419 } | 
| 426 | 420 | 
| 427 function ElemHide() | 421 function ElemHide() | 
| 428 { | 422 { | 
| 429   this.shadow = this.createShadowTree(); | 423   this.shadow = this.createShadowTree(); | 
| 430   this.style = null; | 424   this.style = null; | 
| 431   this.tracer = null; | 425   this.tracer = null; | 
| 432 | 426 | 
| 433   this.elemHideEmulation = new ElemHideEmulation( | 427   this.elemHideEmulation = new ElemHideEmulation( | 
| 434     window, | 428     window, | 
| 435     function(callback) | 429     callback => | 
| 436     { | 430     { | 
| 437       ext.backgroundPage.sendMessage({ | 431       ext.backgroundPage.sendMessage({ | 
| 438         type: "filters.get", | 432         type: "filters.get", | 
| 439         what: "elemhideemulation" | 433         what: "elemhideemulation" | 
| 440       }, callback); | 434       }, callback); | 
| 441     }, | 435     }, | 
| 442     this.addSelectors.bind(this) | 436     this.addSelectors.bind(this) | 
| 443   ); | 437   ); | 
| 444 } | 438 } | 
| 445 ElemHide.prototype = { | 439 ElemHide.prototype = { | 
| 446   selectorGroupSize: 200, | 440   selectorGroupSize: 200, | 
| 447 | 441 | 
| 448   createShadowTree: function() | 442   createShadowTree: () => | 
| 449   { | 443   { | 
| 450     // Use Shadow DOM if available as to not mess with with web pages that | 444     // Use Shadow DOM if available as to not mess with with web pages that | 
| 451     // rely on the order of their own <style> tags (#309). However, creating | 445     // rely on the order of their own <style> tags (#309). However, creating | 
| 452     // a shadow root breaks running CSS transitions. So we have to create | 446     // a shadow root breaks running CSS transitions. So we have to create | 
| 453     // the shadow root before transistions might start (#452). | 447     // the shadow root before transistions might start (#452). | 
| 454     if (!("createShadowRoot" in document.documentElement)) | 448     if (!("createShadowRoot" in document.documentElement)) | 
| 455       return null; | 449       return null; | 
| 456 | 450 | 
| 457     // Using shadow DOM causes issues on some Google websites, | 451     // Using shadow DOM causes issues on some Google websites, | 
| 458     // including Google Docs, Gmail and Blogger (#1770, #2602, #2687). | 452     // including Google Docs, Gmail and Blogger (#1770, #2602, #2687). | 
| 459     if (/\.(?:google|blogger)\.com$/.test(document.domain)) | 453     if (/\.(?:google|blogger)\.com$/.test(document.domain)) | 
| 460       return null; | 454       return null; | 
| 461 | 455 | 
| 462     // Finally since some users have both AdBlock and Adblock Plus installed we | 456     // Finally since some users have both AdBlock and Adblock Plus installed we | 
| 463     // have to consider how the two extensions interact. For example we want to | 457     // have to consider how the two extensions interact. For example we want to | 
| 464     // avoid creating the shadowRoot twice. | 458     // avoid creating the shadowRoot twice. | 
| 465     var shadow = document.documentElement.shadowRoot || | 459     let shadow = document.documentElement.shadowRoot || | 
| 466                  document.documentElement.createShadowRoot(); | 460                  document.documentElement.createShadowRoot(); | 
| 467     shadow.appendChild(document.createElement("shadow")); | 461     shadow.appendChild(document.createElement("shadow")); | 
| 468 | 462 | 
| 469     // Stop the website from messing with our shadow root (#4191, #4298). | 463     // Stop the website from messing with our shadow root (#4191, #4298). | 
| 470     if ("shadowRoot" in Element.prototype) | 464     if ("shadowRoot" in Element.prototype) | 
| 471     { | 465     { | 
| 472       runInPageContext(function() | 466       runInPageContext(() => | 
| 473       { | 467       { | 
| 474         var ourShadowRoot = document.documentElement.shadowRoot; | 468         let ourShadowRoot = document.documentElement.shadowRoot; | 
| 475         if (!ourShadowRoot) | 469         if (!ourShadowRoot) | 
| 476           return; | 470           return; | 
| 477         var desc = Object.getOwnPropertyDescriptor(Element.prototype, "shadowRoo
     t"); | 471         let desc = Object.getOwnPropertyDescriptor(Element.prototype, "shadowRoo
     t"); | 
| 478         var shadowRoot = Function.prototype.call.bind(desc.get); | 472         let shadowRoot = Function.prototype.call.bind(desc.get); | 
| 479 | 473 | 
| 480         Object.defineProperty(Element.prototype, "shadowRoot", { | 474         Object.defineProperty(Element.prototype, "shadowRoot", { | 
| 481           configurable: true, enumerable: true, get: function() | 475           configurable: true, enumerable: true, get: function() | 
| 482           { | 476           { | 
| 483             var shadow = shadowRoot(this); | 477             let shadow = shadowRoot(this); | 
| 484             return shadow == ourShadowRoot ? null : shadow; | 478             return shadow == ourShadowRoot ? null : shadow; | 
| 485           } | 479           } | 
| 486         }); | 480         }); | 
| 487       }, null); | 481       }, null); | 
| 488     } | 482     } | 
| 489 | 483 | 
| 490     return shadow; | 484     return shadow; | 
| 491   }, | 485   }, | 
| 492 | 486 | 
| 493   addSelectors: function(selectors) | 487   addSelectors: function(selectors) | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
| 511       // <style> element to the shadow DOM. | 505       // <style> element to the shadow DOM. | 
| 512       if (!this.style.sheet) | 506       if (!this.style.sheet) | 
| 513         return; | 507         return; | 
| 514     } | 508     } | 
| 515 | 509 | 
| 516     // If using shadow DOM, we have to add the ::content pseudo-element | 510     // If using shadow DOM, we have to add the ::content pseudo-element | 
| 517     // before each selector, in order to match elements within the | 511     // before each selector, in order to match elements within the | 
| 518     // insertion point. | 512     // insertion point. | 
| 519     if (this.shadow) | 513     if (this.shadow) | 
| 520     { | 514     { | 
| 521       var preparedSelectors = []; | 515       let preparedSelectors = []; | 
| 522       for (var i = 0; i < selectors.length; i++) | 516       for (let selector of selectors) | 
| 523       { | 517       { | 
| 524         var subSelectors = splitSelector(selectors[i]); | 518         let subSelectors = splitSelector(selector); | 
| 525         for (var j = 0; j < subSelectors.length; j++) | 519         for (let subSelector of subSelectors) | 
| 526           preparedSelectors.push("::content " + subSelectors[j]); | 520           preparedSelectors.push("::content " + subSelector); | 
| 527       } | 521       } | 
| 528       selectors = preparedSelectors; | 522       selectors = preparedSelectors; | 
| 529     } | 523     } | 
| 530 | 524 | 
| 531     // Safari only allows 8192 primitive selectors to be injected at once[1], we | 525     // Safari only allows 8192 primitive selectors to be injected at once[1], we | 
| 532     // therefore chunk the inserted selectors into groups of 200 to be safe. | 526     // therefore chunk the inserted selectors into groups of 200 to be safe. | 
| 533     // (Chrome also has a limit, larger... but we're not certain exactly what it | 527     // (Chrome also has a limit, larger... but we're not certain exactly what it | 
| 534     //  is! Edge apparently has no such limit.) | 528     //  is! Edge apparently has no such limit.) | 
| 535     // [1] - https://github.com/WebKit/webkit/blob/1cb2227f6b2a1035f7bdc46e5ab69
     debb75fc1de/Source/WebCore/css/RuleSet.h#L68 | 529     // [1] - https://github.com/WebKit/webkit/blob/1cb2227f6b2a1035f7bdc46e5ab69
     debb75fc1de/Source/WebCore/css/RuleSet.h#L68 | 
| 536     for (var i = 0; i < selectors.length; i += this.selectorGroupSize) | 530     for (let i = 0; i < selectors.length; i += this.selectorGroupSize) | 
| 537     { | 531     { | 
| 538       var selector = selectors.slice(i, i + this.selectorGroupSize).join(", "); | 532       let selector = selectors.slice(i, i + this.selectorGroupSize).join(", "); | 
| 539       this.style.sheet.insertRule(selector + "{display: none !important;}", | 533       this.style.sheet.insertRule(selector + "{display: none !important;}", | 
| 540                                   this.style.sheet.cssRules.length); | 534                                   this.style.sheet.cssRules.length); | 
| 541     } | 535     } | 
| 542   }, | 536   }, | 
| 543 | 537 | 
| 544   apply: function() | 538   apply: function() | 
| 545   { | 539   { | 
| 546     var selectors = null; | 540     let selectors = null; | 
| 547     var elemHideEmulationLoaded = false; | 541     let elemHideEmulationLoaded = false; | 
| 548 | 542 | 
| 549     var checkLoaded = function() | 543     let checkLoaded = function() | 
| 550     { | 544     { | 
| 551       if (!selectors || !elemHideEmulationLoaded) | 545       if (!selectors || !elemHideEmulationLoaded) | 
| 552         return; | 546         return; | 
| 553 | 547 | 
| 554       if (this.tracer) | 548       if (this.tracer) | 
| 555         this.tracer.disconnect(); | 549         this.tracer.disconnect(); | 
| 556       this.tracer = null; | 550       this.tracer = null; | 
| 557 | 551 | 
| 558       if (this.style && this.style.parentElement) | 552       if (this.style && this.style.parentElement) | 
| 559         this.style.parentElement.removeChild(this.style); | 553         this.style.parentElement.removeChild(this.style); | 
| 560       this.style = null; | 554       this.style = null; | 
| 561 | 555 | 
| 562       this.addSelectors(selectors.selectors); | 556       this.addSelectors(selectors.selectors); | 
| 563       this.elemHideEmulation.apply(); | 557       this.elemHideEmulation.apply(); | 
| 564 | 558 | 
| 565       if (selectors.trace) | 559       if (selectors.trace) | 
| 566         this.tracer = new ElementHidingTracer(selectors.selectors); | 560         this.tracer = new ElementHidingTracer(selectors.selectors); | 
| 567     }.bind(this); | 561     }.bind(this); | 
| 568 | 562 | 
| 569     ext.backgroundPage.sendMessage({type: "get-selectors"}, function(response) | 563     ext.backgroundPage.sendMessage({type: "get-selectors"}, response => | 
| 570     { | 564     { | 
| 571       selectors = response; | 565       selectors = response; | 
| 572       checkLoaded(); | 566       checkLoaded(); | 
| 573     }); | 567     }); | 
| 574 | 568 | 
| 575     this.elemHideEmulation.load(function() | 569     this.elemHideEmulation.load(() => | 
| 576     { | 570     { | 
| 577       elemHideEmulationLoaded = true; | 571       elemHideEmulationLoaded = true; | 
| 578       checkLoaded(); | 572       checkLoaded(); | 
| 579     }); | 573     }); | 
| 580   } | 574   } | 
| 581 }; | 575 }; | 
| 582 | 576 | 
| 583 if (document instanceof HTMLDocument) | 577 if (document instanceof HTMLDocument) | 
| 584 { | 578 { | 
| 585   checkSitekey(); | 579   checkSitekey(); | 
| 586   wrapWebSocket(); | 580   wrapWebSocket(); | 
| 587 | 581 | 
| 588   var elemhide = new ElemHide(); | 582   let elemhide = new ElemHide(); | 
| 589   elemhide.apply(); | 583   elemhide.apply(); | 
| 590 | 584 | 
| 591   document.addEventListener("error", function(event) | 585   document.addEventListener("error", event => | 
| 592   { | 586   { | 
| 593     checkCollapse(event.target); | 587     checkCollapse(event.target); | 
| 594   }, true); | 588   }, true); | 
| 595 | 589 | 
| 596   document.addEventListener("load", function(event) | 590   document.addEventListener("load", event => | 
| 597   { | 591   { | 
| 598     var element = event.target; | 592     let element = event.target; | 
| 599     if (/^i?frame$/.test(element.localName)) | 593     if (/^i?frame$/.test(element.localName)) | 
| 600       checkCollapse(element); | 594       checkCollapse(element); | 
| 601   }, true); | 595   }, true); | 
| 602 } | 596 } | 
| OLD | NEW | 
|---|