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