| LEFT | RIGHT | 
|---|
| 1 /* | 1 /* | 
| 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
| 3  * Copyright (C) 2006-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 let typeMap = { | 18 "use strict"; | 
|  | 19 | 
|  | 20 const 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 }; | 
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 73   } | 75   } | 
| 74 | 76 | 
| 75   return urls; | 77   return urls; | 
| 76 } | 78 } | 
| 77 | 79 | 
| 78 function getURLsFromMediaElement(element) | 80 function getURLsFromMediaElement(element) | 
| 79 { | 81 { | 
| 80   let urls = getURLsFromAttributes(element); | 82   let urls = getURLsFromAttributes(element); | 
| 81 | 83 | 
| 82   for (let child of element.children) | 84   for (let child of element.children) | 
|  | 85   { | 
| 83     if (child.localName == "source" || child.localName == "track") | 86     if (child.localName == "source" || child.localName == "track") | 
| 84       urls.push.apply(urls, getURLsFromAttributes(child)); | 87       urls.push.apply(urls, getURLsFromAttributes(child)); | 
|  | 88   } | 
| 85 | 89 | 
| 86   if (element.poster) | 90   if (element.poster) | 
| 87     urls.push(element.poster); | 91     urls.push(element.poster); | 
| 88 | 92 | 
| 89   return urls; | 93   return urls; | 
| 90 } | 94 } | 
| 91 | 95 | 
| 92 function getURLsFromElement(element) | 96 function getURLsFromElement(element) | 
| 93 { | 97 { | 
| 94   let urls; | 98   let urls; | 
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 196 | 200 | 
| 197   this.observer = new MutationObserver(this.observe.bind(this)); | 201   this.observer = new MutationObserver(this.observe.bind(this)); | 
| 198   this.trace = this.trace.bind(this); | 202   this.trace = this.trace.bind(this); | 
| 199 | 203 | 
| 200   if (document.readyState == "loading") | 204   if (document.readyState == "loading") | 
| 201     document.addEventListener("DOMContentLoaded", this.trace); | 205     document.addEventListener("DOMContentLoaded", this.trace); | 
| 202   else | 206   else | 
| 203     this.trace(); | 207     this.trace(); | 
| 204 } | 208 } | 
| 205 ElementHidingTracer.prototype = { | 209 ElementHidingTracer.prototype = { | 
| 206   checkNodes: nodes => | 210   checkNodes(nodes) | 
| 207   { | 211   { | 
| 208     let matchedSelectors = []; | 212     let matchedSelectors = []; | 
| 209 | 213 | 
| 210     // Find all selectors that match any hidden element inside the given nodes. | 214     // Find all selectors that match any hidden element inside the given nodes. | 
| 211     for (let selector of this.selectors) | 215     for (let selector of this.selectors) | 
| 212     { | 216     { | 
| 213       for (let node of nodes) | 217       for (let node of nodes) | 
| 214       { | 218       { | 
| 215         let elements = node.querySelectorAll(selector); | 219         let elements = node.querySelectorAll(selector); | 
| 216         let matched = false; | 220         let matched = false; | 
| (...skipping 16 matching lines...) Expand all  Loading... | 
| 233       } | 237       } | 
| 234     } | 238     } | 
| 235 | 239 | 
| 236     if (matchedSelectors.length > 0) | 240     if (matchedSelectors.length > 0) | 
| 237       ext.backgroundPage.sendMessage({ | 241       ext.backgroundPage.sendMessage({ | 
| 238         type: "devtools.traceElemHide", | 242         type: "devtools.traceElemHide", | 
| 239         selectors: matchedSelectors | 243         selectors: matchedSelectors | 
| 240       }); | 244       }); | 
| 241   }, | 245   }, | 
| 242 | 246 | 
| 243   onTimeout: function() | 247   onTimeout() | 
| 244   { | 248   { | 
| 245     this.checkNodes(this.changedNodes); | 249     this.checkNodes(this.changedNodes); | 
| 246     this.changedNodes = []; | 250     this.changedNodes = []; | 
| 247     this.timeout = null; | 251     this.timeout = null; | 
| 248   }, | 252   }, | 
| 249 | 253 | 
| 250   observe: function(mutations) | 254   observe(mutations) | 
| 251   { | 255   { | 
| 252     // Forget previously changed nodes that are no longer in the DOM. | 256     // Forget previously changed nodes that are no longer in the DOM. | 
| 253     for (let i = 0; i < this.changedNodes.length; i++) | 257     for (let i = 0; i < this.changedNodes.length; i++) | 
| 254     { | 258     { | 
| 255       if (!document.contains(this.changedNodes[i])) | 259       if (!document.contains(this.changedNodes[i])) | 
| 256         this.changedNodes.splice(i--, 1); | 260         this.changedNodes.splice(i--, 1); | 
| 257     } | 261     } | 
| 258 | 262 | 
| 259     for (let mutation of mutations) | 263     for (let mutation of mutations) | 
| 260     { | 264     { | 
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 295         this.changedNodes.push(node); | 299         this.changedNodes.push(node); | 
| 296     } | 300     } | 
| 297 | 301 | 
| 298     // Check only nodes whose descendants have changed, and not more often | 302     // Check only nodes whose descendants have changed, and not more often | 
| 299     // than once a second. Otherwise large pages with a lot of DOM mutations | 303     // than once a second. Otherwise large pages with a lot of DOM mutations | 
| 300     // (like YouTube) freeze when the devtools panel is active. | 304     // (like YouTube) freeze when the devtools panel is active. | 
| 301     if (this.timeout == null) | 305     if (this.timeout == null) | 
| 302       this.timeout = setTimeout(this.onTimeout.bind(this), 1000); | 306       this.timeout = setTimeout(this.onTimeout.bind(this), 1000); | 
| 303   }, | 307   }, | 
| 304 | 308 | 
| 305   trace: function() | 309   trace() | 
| 306   { | 310   { | 
| 307     this.checkNodes([document]); | 311     this.checkNodes([document]); | 
| 308 | 312 | 
| 309     this.observer.observe( | 313     this.observer.observe( | 
| 310       document, | 314       document, | 
| 311       { | 315       { | 
| 312         childList: true, | 316         childList: true, | 
| 313         attributes: true, | 317         attributes: true, | 
| 314         subtree: true | 318         subtree: true | 
| 315       } | 319       } | 
| 316     ); | 320     ); | 
| 317   }, | 321   }, | 
| 318 | 322 | 
| 319   disconnect: function() | 323   disconnect() | 
| 320   { | 324   { | 
| 321     document.removeEventListener("DOMContentLoaded", this.trace); | 325     document.removeEventListener("DOMContentLoaded", this.trace); | 
| 322     this.observer.disconnect(); | 326     this.observer.disconnect(); | 
| 323     clearTimeout(this.timeout); | 327     clearTimeout(this.timeout); | 
| 324   } | 328   } | 
| 325 }; | 329 }; | 
| 326 | 330 | 
| 327 function runInPageContext(fn, arg) | 331 function runInPageContext(fn, arg) | 
| 328 { | 332 { | 
| 329   let script = document.createElement("script"); | 333   let script = document.createElement("script"); | 
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 430         type: "filters.get", | 434         type: "filters.get", | 
| 431         what: "elemhideemulation" | 435         what: "elemhideemulation" | 
| 432       }, callback); | 436       }, callback); | 
| 433     }, | 437     }, | 
| 434     this.addSelectors.bind(this) | 438     this.addSelectors.bind(this) | 
| 435   ); | 439   ); | 
| 436 } | 440 } | 
| 437 ElemHide.prototype = { | 441 ElemHide.prototype = { | 
| 438   selectorGroupSize: 200, | 442   selectorGroupSize: 200, | 
| 439 | 443 | 
| 440   createShadowTree: () => | 444   createShadowTree() | 
| 441   { | 445   { | 
| 442     // Use Shadow DOM if available as to not mess with with web pages that | 446     // Use Shadow DOM if available as to not mess with with web pages that | 
| 443     // rely on the order of their own <style> tags (#309). However, creating | 447     // rely on the order of their own <style> tags (#309). However, creating | 
| 444     // a shadow root breaks running CSS transitions. So we have to create | 448     // a shadow root breaks running CSS transitions. So we have to create | 
| 445     // the shadow root before transistions might start (#452). | 449     // the shadow root before transistions might start (#452). | 
| 446     if (!("createShadowRoot" in document.documentElement)) | 450     if (!("createShadowRoot" in document.documentElement)) | 
| 447       return null; | 451       return null; | 
| 448 | 452 | 
| 449     // Using shadow DOM causes issues on some Google websites, | 453     // Using shadow DOM causes issues on some Google websites, | 
| 450     // including Google Docs, Gmail and Blogger (#1770, #2602, #2687). | 454     // including Google Docs, Gmail and Blogger (#1770, #2602, #2687). | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 463     { | 467     { | 
| 464       runInPageContext(() => | 468       runInPageContext(() => | 
| 465       { | 469       { | 
| 466         let ourShadowRoot = document.documentElement.shadowRoot; | 470         let ourShadowRoot = document.documentElement.shadowRoot; | 
| 467         if (!ourShadowRoot) | 471         if (!ourShadowRoot) | 
| 468           return; | 472           return; | 
| 469         let desc = Object.getOwnPropertyDescriptor(Element.prototype, "shadowRoo
     t"); | 473         let desc = Object.getOwnPropertyDescriptor(Element.prototype, "shadowRoo
     t"); | 
| 470         let shadowRoot = Function.prototype.call.bind(desc.get); | 474         let shadowRoot = Function.prototype.call.bind(desc.get); | 
| 471 | 475 | 
| 472         Object.defineProperty(Element.prototype, "shadowRoot", { | 476         Object.defineProperty(Element.prototype, "shadowRoot", { | 
| 473           configurable: true, enumerable: true, get: function() | 477           configurable: true, enumerable: true, get() | 
| 474           { | 478           { | 
| 475             let shadow = shadowRoot(this); | 479             let shadow = shadowRoot(this); | 
| 476             return shadow == ourShadowRoot ? null : shadow; | 480             return shadow == ourShadowRoot ? null : shadow; | 
| 477           } | 481           } | 
| 478         }); | 482         }); | 
| 479       }, null); | 483       }, null); | 
| 480     } | 484     } | 
| 481 | 485 | 
| 482     return shadow; | 486     return shadow; | 
| 483   }, | 487   }, | 
| 484 | 488 | 
| 485   addSelectors: function(selectors) | 489   addSelectors(selectors) | 
| 486   { | 490   { | 
| 487     if (selectors.length == 0) | 491     if (selectors.length == 0) | 
| 488       return; | 492       return; | 
| 489 | 493 | 
| 490     if (!this.style) | 494     if (!this.style) | 
| 491     { | 495     { | 
| 492       // Create <style> element lazily, only if we add styles. Add it to | 496       // Create <style> element lazily, only if we add styles. Add it to | 
| 493       // the shadow DOM if possible. Otherwise fallback to the <head> or | 497       // the shadow DOM if possible. Otherwise fallback to the <head> or | 
| 494       // <html> element. If we have injected a style element before that | 498       // <html> element. If we have injected a style element before that | 
| 495       // has been removed (the sheet property is null), create a new one. | 499       // has been removed (the sheet property is null), create a new one. | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
| 526     //  is! Edge apparently has no such limit.) | 530     //  is! Edge apparently has no such limit.) | 
| 527     // [1] - https://github.com/WebKit/webkit/blob/1cb2227f6b2a1035f7bdc46e5ab69
     debb75fc1de/Source/WebCore/css/RuleSet.h#L68 | 531     // [1] - https://github.com/WebKit/webkit/blob/1cb2227f6b2a1035f7bdc46e5ab69
     debb75fc1de/Source/WebCore/css/RuleSet.h#L68 | 
| 528     for (let i = 0; i < selectors.length; i += this.selectorGroupSize) | 532     for (let i = 0; i < selectors.length; i += this.selectorGroupSize) | 
| 529     { | 533     { | 
| 530       let selector = selectors.slice(i, i + this.selectorGroupSize).join(", "); | 534       let selector = selectors.slice(i, i + this.selectorGroupSize).join(", "); | 
| 531       this.style.sheet.insertRule(selector + "{display: none !important;}", | 535       this.style.sheet.insertRule(selector + "{display: none !important;}", | 
| 532                                   this.style.sheet.cssRules.length); | 536                                   this.style.sheet.cssRules.length); | 
| 533     } | 537     } | 
| 534   }, | 538   }, | 
| 535 | 539 | 
| 536   apply: function() | 540   apply() | 
| 537   { | 541   { | 
| 538     let selectors = null; | 542     let selectors = null; | 
| 539     let elemHideEmulationLoaded = false; | 543     let elemHideEmulationLoaded = false; | 
| 540 | 544 | 
| 541     let checkLoaded = function() | 545     let checkLoaded = function() | 
| 542     { | 546     { | 
| 543       if (!selectors || !elemHideEmulationLoaded) | 547       if (!selectors || !elemHideEmulationLoaded) | 
| 544         return; | 548         return; | 
| 545 | 549 | 
| 546       if (this.tracer) | 550       if (this.tracer) | 
| (...skipping 23 matching lines...) Expand all  Loading... | 
| 570       checkLoaded(); | 574       checkLoaded(); | 
| 571     }); | 575     }); | 
| 572   } | 576   } | 
| 573 }; | 577 }; | 
| 574 | 578 | 
| 575 if (document instanceof HTMLDocument) | 579 if (document instanceof HTMLDocument) | 
| 576 { | 580 { | 
| 577   checkSitekey(); | 581   checkSitekey(); | 
| 578   wrapWebSocket(); | 582   wrapWebSocket(); | 
| 579 | 583 | 
| 580   let elemhide = new ElemHide(); | 584   // This variable is also used by our other content scripts, outside of the | 
|  | 585   // current scope. | 
|  | 586   var elemhide = new ElemHide(); | 
| 581   elemhide.apply(); | 587   elemhide.apply(); | 
| 582 | 588 | 
| 583   document.addEventListener("error", event => | 589   document.addEventListener("error", event => | 
| 584   { | 590   { | 
| 585     checkCollapse(event.target); | 591     checkCollapse(event.target); | 
| 586   }, true); | 592   }, true); | 
| 587 | 593 | 
| 588   document.addEventListener("load", event => | 594   document.addEventListener("load", event => | 
| 589   { | 595   { | 
| 590     let element = event.target; | 596     let element = event.target; | 
| 591     if (/^i?frame$/.test(element.localName)) | 597     if (/^i?frame$/.test(element.localName)) | 
| 592       checkCollapse(element); | 598       checkCollapse(element); | 
| 593   }, true); | 599   }, true); | 
| 594 } | 600 } | 
| LEFT | RIGHT | 
|---|