| 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 | 
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 183   try | 183   try | 
| 184   { | 184   { | 
| 185     return element.contentDocument; | 185     return element.contentDocument; | 
| 186   } | 186   } | 
| 187   catch (e) | 187   catch (e) | 
| 188   { | 188   { | 
| 189     return null; | 189     return null; | 
| 190   } | 190   } | 
| 191 } | 191 } | 
| 192 | 192 | 
|  | 193 function ElementHidingTracer(document, selectors) | 
|  | 194 { | 
|  | 195   this.document = document; | 
|  | 196   this.selectors = selectors; | 
|  | 197 | 
|  | 198   this.changedNodes = []; | 
|  | 199   this.timeout = null; | 
|  | 200 | 
|  | 201   this.observer = new MutationObserver(this.observe.bind(this)); | 
|  | 202   this.trace = this.trace.bind(this); | 
|  | 203 | 
|  | 204   if (document.readyState == "loading") | 
|  | 205     document.addEventListener("DOMContentLoaded", this.trace); | 
|  | 206   else | 
|  | 207     this.trace(); | 
|  | 208 } | 
|  | 209 ElementHidingTracer.prototype = { | 
|  | 210   checkNodes: function(nodes) | 
|  | 211   { | 
|  | 212     var matchedSelectors = []; | 
|  | 213 | 
|  | 214     // Find all selectors that match any hidden element inside the given nodes. | 
|  | 215     for (var i = 0; i < this.selectors.length; i++) | 
|  | 216     { | 
|  | 217       var selector = this.selectors[i]; | 
|  | 218 | 
|  | 219       for (var j = 0; j < nodes.length; j++) | 
|  | 220       { | 
|  | 221         var elements = nodes[j].querySelectorAll(selector); | 
|  | 222         var matched = false; | 
|  | 223 | 
|  | 224         for (var k = 0; k < elements.length; k++) | 
|  | 225         { | 
|  | 226           // Only consider selectors that actually have an effect on the | 
|  | 227           // computed styles, and aren't overridden by rules with higher | 
|  | 228           // priority, or haven't been circumvented in a different way. | 
|  | 229           if (getComputedStyle(elements[k]).display == "none") | 
|  | 230           { | 
|  | 231             matchedSelectors.push(selector); | 
|  | 232             matched = true; | 
|  | 233             break; | 
|  | 234           } | 
|  | 235         } | 
|  | 236 | 
|  | 237         if (matched) | 
|  | 238           break; | 
|  | 239       } | 
|  | 240     } | 
|  | 241 | 
|  | 242     if (matchedSelectors.length > 0) | 
|  | 243       ext.backgroundPage.sendMessage({ | 
|  | 244         type: "trace-elemhide", | 
|  | 245         selectors: matchedSelectors | 
|  | 246       }); | 
|  | 247   }, | 
|  | 248 | 
|  | 249   onTimeout: function() | 
|  | 250   { | 
|  | 251     this.checkNodes(this.changedNodes); | 
|  | 252     this.changedNodes = []; | 
|  | 253     this.timeout = null; | 
|  | 254   }, | 
|  | 255 | 
|  | 256   observe: function(mutations) | 
|  | 257   { | 
|  | 258     // Forget previously changed nodes that are no longer in the DOM. | 
|  | 259     for (var i = 0; i < this.changedNodes.length; i++) | 
|  | 260     { | 
|  | 261       if (!this.document.contains(this.changedNodes[i])) | 
|  | 262         this.changedNodes.splice(i--, 1); | 
|  | 263     } | 
|  | 264 | 
|  | 265     for (var j = 0; j < mutations.length; j++) | 
|  | 266     { | 
|  | 267       var mutation = mutations[j]; | 
|  | 268       var node = mutation.target; | 
|  | 269 | 
|  | 270       // Ignore mutations of nodes that aren't in the DOM anymore. | 
|  | 271       if (!this.document.contains(node)) | 
|  | 272         continue; | 
|  | 273 | 
|  | 274       // Since querySelectorAll() doesn't consider the root itself | 
|  | 275       // and since CSS selectors can also match siblings, we have | 
|  | 276       // to consider the parent node for attribute mutations. | 
|  | 277       if (mutation.type == "attributes") | 
|  | 278         node = node.parentNode; | 
|  | 279 | 
|  | 280       var addNode = true; | 
|  | 281       for (var k = 0; k < this.changedNodes.length; k++) | 
|  | 282       { | 
|  | 283         var previouslyChangedNode = this.changedNodes[k]; | 
|  | 284 | 
|  | 285         // If we are already going to check an ancestor of this node, | 
|  | 286         // we can ignore this node, since it will be considered anyway | 
|  | 287         // when checking one of its ancestors. | 
|  | 288         if (previouslyChangedNode.contains(node)) | 
|  | 289         { | 
|  | 290           addNode = false; | 
|  | 291           break; | 
|  | 292         } | 
|  | 293 | 
|  | 294         // If this node is an ancestor of a node that previously changed, | 
|  | 295         // we can ignore that node, since it will be considered anyway | 
|  | 296         // when checking one of its ancestors. | 
|  | 297         if (node.contains(previouslyChangedNode)) | 
|  | 298           this.changedNodes.splice(k--, 1); | 
|  | 299       } | 
|  | 300 | 
|  | 301       if (addNode) | 
|  | 302         this.changedNodes.push(node); | 
|  | 303     } | 
|  | 304 | 
|  | 305     // Check only nodes whose descendants have changed, and not more often | 
|  | 306     // than once a second. Otherwise large pages with a lot of DOM mutations | 
|  | 307     // (like YouTube) freeze when the devtools panel is active. | 
|  | 308     if (this.timeout == null) | 
|  | 309       this.timeout = setTimeout(this.onTimeout.bind(this), 1000); | 
|  | 310   }, | 
|  | 311 | 
|  | 312   trace: function() | 
|  | 313   { | 
|  | 314     this.checkNodes([this.document]); | 
|  | 315 | 
|  | 316     this.observer.observe( | 
|  | 317       this.document, | 
|  | 318       { | 
|  | 319         childList: true, | 
|  | 320         attributes: true, | 
|  | 321         subtree: true | 
|  | 322       } | 
|  | 323     ); | 
|  | 324   }, | 
|  | 325 | 
|  | 326   disconnect: function() | 
|  | 327   { | 
|  | 328     this.document.removeEventListener("DOMContentLoaded", this.trace); | 
|  | 329     this.observer.disconnect(); | 
|  | 330     clearTimeout(this.timeout); | 
|  | 331   } | 
|  | 332 }; | 
|  | 333 | 
| 193 function reinjectRulesWhenRemoved(document, style) | 334 function reinjectRulesWhenRemoved(document, style) | 
| 194 { | 335 { | 
| 195   var MutationObserver = window.MutationObserver || window.WebKitMutationObserve
     r; | 336   var MutationObserver = window.MutationObserver || window.WebKitMutationObserve
     r; | 
| 196   if (!MutationObserver) | 337   if (!MutationObserver) | 
| 197     return; | 338     return; | 
| 198 | 339 | 
| 199   var observer = new MutationObserver(function(mutations) | 340   var observer = new MutationObserver(function(mutations) | 
| 200   { | 341   { | 
| 201     var isStyleRemoved = false; | 342     var isStyleRemoved = false; | 
| 202     for (var i = 0; i < mutations.length; i++) | 343     for (var i = 0; i < mutations.length; i++) | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 213     observer.disconnect(); | 354     observer.disconnect(); | 
| 214 | 355 | 
| 215     var n = document.styleSheets.length; | 356     var n = document.styleSheets.length; | 
| 216     if (n == 0) | 357     if (n == 0) | 
| 217       return; | 358       return; | 
| 218 | 359 | 
| 219     var stylesheet = document.styleSheets[n - 1]; | 360     var stylesheet = document.styleSheets[n - 1]; | 
| 220     ext.backgroundPage.sendMessage( | 361     ext.backgroundPage.sendMessage( | 
| 221       {type: "get-selectors"}, | 362       {type: "get-selectors"}, | 
| 222 | 363 | 
| 223       function(selectors) | 364       function(response) | 
| 224       { | 365       { | 
|  | 366         var selectors = response.selectors; | 
| 225         while (selectors.length > 0) | 367         while (selectors.length > 0) | 
| 226         { | 368         { | 
| 227           var selector = selectors.splice(0, SELECTOR_GROUP_SIZE).join(", "); | 369           var selector = selectors.splice(0, SELECTOR_GROUP_SIZE).join(", "); | 
| 228 | 370 | 
| 229           // Using non-standard addRule() here. This is the only way | 371           // Using non-standard addRule() here. This is the only way | 
| 230           // to add rules at the end of a cross-origin stylesheet | 372           // to add rules at the end of a cross-origin stylesheet | 
| 231           // because we don't know how many rules are already in there | 373           // because we don't know how many rules are already in there | 
| 232           stylesheet.addRule(selector, "display: none !important;"); | 374           stylesheet.addRule(selector, "display: none !important;"); | 
| 233         } | 375         } | 
| 234       } | 376       } | 
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 278   } | 420   } | 
| 279 | 421 | 
| 280   return result; | 422   return result; | 
| 281 } | 423 } | 
| 282 | 424 | 
| 283 function init(document) | 425 function init(document) | 
| 284 { | 426 { | 
| 285   var shadow = null; | 427   var shadow = null; | 
| 286   var style = null; | 428   var style = null; | 
| 287   var observer = null; | 429   var observer = null; | 
|  | 430   var tracer = null; | 
| 288   var propertyFilters = new CSSPropertyFilters(window, addElemHideSelectors); | 431   var propertyFilters = new CSSPropertyFilters(window, addElemHideSelectors); | 
| 289 | 432 | 
| 290   // Use Shadow DOM if available to don't mess with web pages that rely on | 433   // Use Shadow DOM if available to don't mess with web pages that rely on | 
| 291   // the order of their own <style> tags (#309). | 434   // the order of their own <style> tags (#309). | 
| 292   // | 435   // | 
| 293   // However, creating a shadow root breaks running CSS transitions. So we | 436   // However, creating a shadow root breaks running CSS transitions. So we | 
| 294   // have to create the shadow root before transistions might start (#452). | 437   // have to create the shadow root before transistions might start (#452). | 
| 295   // | 438   // | 
| 296   // Also, using shadow DOM causes issues on some Google websites, | 439   // Also, using shadow DOM causes issues on some Google websites, | 
| 297   // including Google Docs and Gmail (#1770, #2602). | 440   // including Google Docs and Gmail (#1770, #2602). | 
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 347 | 490 | 
| 348     var checkLoaded = function() | 491     var checkLoaded = function() | 
| 349     { | 492     { | 
| 350       if (!selectors || !CSSPropertyFiltersLoaded) | 493       if (!selectors || !CSSPropertyFiltersLoaded) | 
| 351         return; | 494         return; | 
| 352 | 495 | 
| 353       if (observer) | 496       if (observer) | 
| 354         observer.disconnect(); | 497         observer.disconnect(); | 
| 355       observer = null; | 498       observer = null; | 
| 356 | 499 | 
|  | 500       if (tracer) | 
|  | 501         tracer.disconnect(); | 
|  | 502       tracer = null; | 
|  | 503 | 
| 357       if (style && style.parentElement) | 504       if (style && style.parentElement) | 
| 358         style.parentElement.removeChild(style); | 505         style.parentElement.removeChild(style); | 
| 359       style = null; | 506       style = null; | 
| 360 | 507 | 
| 361       addElemHideSelectors(selectors); | 508       addElemHideSelectors(selectors.selectors); | 
| 362       propertyFilters.apply(); | 509       propertyFilters.apply(); | 
|  | 510 | 
|  | 511       if (selectors.trace) | 
|  | 512         tracer = new ElementHidingTracer(document, selectors.selectors); | 
| 363     }; | 513     }; | 
| 364 | 514 | 
| 365     ext.backgroundPage.sendMessage({type: "get-selectors"}, function(response) | 515     ext.backgroundPage.sendMessage({type: "get-selectors"}, function(response) | 
| 366     { | 516     { | 
| 367       selectors = response; | 517       selectors = response; | 
| 368       checkLoaded(); | 518       checkLoaded(); | 
| 369     }); | 519     }); | 
| 370 | 520 | 
| 371     propertyFilters.load(function() | 521     propertyFilters.load(function() | 
| 372     { | 522     { | 
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 416   }, true); | 566   }, true); | 
| 417 | 567 | 
| 418   return updateStylesheet; | 568   return updateStylesheet; | 
| 419 } | 569 } | 
| 420 | 570 | 
| 421 if (document instanceof HTMLDocument) | 571 if (document instanceof HTMLDocument) | 
| 422 { | 572 { | 
| 423   checkSitekey(); | 573   checkSitekey(); | 
| 424   window.updateStylesheet = init(document); | 574   window.updateStylesheet = init(document); | 
| 425 } | 575 } | 
| OLD | NEW | 
|---|