| 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 MutationObserver = window.MutationObserver || window.WebKitMutationObserver; | 18 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver; | 
| 19 var SELECTOR_GROUP_SIZE = 200; |  | 
| 20 | 19 | 
| 21 var typeMap = { | 20 var typeMap = { | 
| 22   "img": "IMAGE", | 21   "img": "IMAGE", | 
| 23   "input": "IMAGE", | 22   "input": "IMAGE", | 
| 24   "picture": "IMAGE", | 23   "picture": "IMAGE", | 
| 25   "audio": "MEDIA", | 24   "audio": "MEDIA", | 
| 26   "video": "MEDIA", | 25   "video": "MEDIA", | 
| 27   "frame": "SUBDOCUMENT", | 26   "frame": "SUBDOCUMENT", | 
| 28   "iframe": "SUBDOCUMENT", | 27   "iframe": "SUBDOCUMENT", | 
| 29   "object": "OBJECT", | 28   "object": "OBJECT", | 
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 189   try | 188   try | 
| 190   { | 189   { | 
| 191     return element.contentDocument; | 190     return element.contentDocument; | 
| 192   } | 191   } | 
| 193   catch (e) | 192   catch (e) | 
| 194   { | 193   { | 
| 195     return null; | 194     return null; | 
| 196   } | 195   } | 
| 197 } | 196 } | 
| 198 | 197 | 
| 199 function ElementHidingTracer(document, selectors) | 198 function ElementHidingTracer(selectors) | 
| 200 { | 199 { | 
| 201   this.document = document; |  | 
| 202   this.selectors = selectors; | 200   this.selectors = selectors; | 
| 203 | 201 | 
| 204   this.changedNodes = []; | 202   this.changedNodes = []; | 
| 205   this.timeout = null; | 203   this.timeout = null; | 
| 206 | 204 | 
| 207   this.observer = new MutationObserver(this.observe.bind(this)); | 205   this.observer = new MutationObserver(this.observe.bind(this)); | 
| 208   this.trace = this.trace.bind(this); | 206   this.trace = this.trace.bind(this); | 
| 209 | 207 | 
| 210   if (document.readyState == "loading") | 208   if (document.readyState == "loading") | 
| 211     document.addEventListener("DOMContentLoaded", this.trace); | 209     document.addEventListener("DOMContentLoaded", this.trace); | 
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 257     this.checkNodes(this.changedNodes); | 255     this.checkNodes(this.changedNodes); | 
| 258     this.changedNodes = []; | 256     this.changedNodes = []; | 
| 259     this.timeout = null; | 257     this.timeout = null; | 
| 260   }, | 258   }, | 
| 261 | 259 | 
| 262   observe: function(mutations) | 260   observe: function(mutations) | 
| 263   { | 261   { | 
| 264     // Forget previously changed nodes that are no longer in the DOM. | 262     // Forget previously changed nodes that are no longer in the DOM. | 
| 265     for (var i = 0; i < this.changedNodes.length; i++) | 263     for (var i = 0; i < this.changedNodes.length; i++) | 
| 266     { | 264     { | 
| 267       if (!this.document.contains(this.changedNodes[i])) | 265       if (!document.contains(this.changedNodes[i])) | 
| 268         this.changedNodes.splice(i--, 1); | 266         this.changedNodes.splice(i--, 1); | 
| 269     } | 267     } | 
| 270 | 268 | 
| 271     for (var j = 0; j < mutations.length; j++) | 269     for (var j = 0; j < mutations.length; j++) | 
| 272     { | 270     { | 
| 273       var mutation = mutations[j]; | 271       var mutation = mutations[j]; | 
| 274       var node = mutation.target; | 272       var node = mutation.target; | 
| 275 | 273 | 
| 276       // Ignore mutations of nodes that aren't in the DOM anymore. | 274       // Ignore mutations of nodes that aren't in the DOM anymore. | 
| 277       if (!this.document.contains(node)) | 275       if (!document.contains(node)) | 
| 278         continue; | 276         continue; | 
| 279 | 277 | 
| 280       // Since querySelectorAll() doesn't consider the root itself | 278       // Since querySelectorAll() doesn't consider the root itself | 
| 281       // and since CSS selectors can also match siblings, we have | 279       // and since CSS selectors can also match siblings, we have | 
| 282       // to consider the parent node for attribute mutations. | 280       // to consider the parent node for attribute mutations. | 
| 283       if (mutation.type == "attributes") | 281       if (mutation.type == "attributes") | 
| 284         node = node.parentNode; | 282         node = node.parentNode; | 
| 285 | 283 | 
| 286       var addNode = true; | 284       var addNode = true; | 
| 287       for (var k = 0; k < this.changedNodes.length; k++) | 285       for (var k = 0; k < this.changedNodes.length; k++) | 
| (...skipping 22 matching lines...) Expand all  Loading... | 
| 310 | 308 | 
| 311     // Check only nodes whose descendants have changed, and not more often | 309     // Check only nodes whose descendants have changed, and not more often | 
| 312     // than once a second. Otherwise large pages with a lot of DOM mutations | 310     // than once a second. Otherwise large pages with a lot of DOM mutations | 
| 313     // (like YouTube) freeze when the devtools panel is active. | 311     // (like YouTube) freeze when the devtools panel is active. | 
| 314     if (this.timeout == null) | 312     if (this.timeout == null) | 
| 315       this.timeout = setTimeout(this.onTimeout.bind(this), 1000); | 313       this.timeout = setTimeout(this.onTimeout.bind(this), 1000); | 
| 316   }, | 314   }, | 
| 317 | 315 | 
| 318   trace: function() | 316   trace: function() | 
| 319   { | 317   { | 
| 320     this.checkNodes([this.document]); | 318     this.checkNodes([document]); | 
| 321 | 319 | 
| 322     this.observer.observe( | 320     this.observer.observe( | 
| 323       this.document, | 321       document, | 
| 324       { | 322       { | 
| 325         childList: true, | 323         childList: true, | 
| 326         attributes: true, | 324         attributes: true, | 
| 327         subtree: true | 325         subtree: true | 
| 328       } | 326       } | 
| 329     ); | 327     ); | 
| 330   }, | 328   }, | 
| 331 | 329 | 
| 332   disconnect: function() | 330   disconnect: function() | 
| 333   { | 331   { | 
| 334     this.document.removeEventListener("DOMContentLoaded", this.trace); | 332     document.removeEventListener("DOMContentLoaded", this.trace); | 
| 335     this.observer.disconnect(); | 333     this.observer.disconnect(); | 
| 336     clearTimeout(this.timeout); | 334     clearTimeout(this.timeout); | 
| 337   } | 335   } | 
| 338 }; | 336 }; | 
| 339 | 337 | 
| 340 function runInDocument(document, fn, arg) | 338 function runInPageContext(fn, arg) | 
| 341 { | 339 { | 
| 342   var script = document.createElement("script"); | 340   var script = document.createElement("script"); | 
| 343   script.type = "application/javascript"; | 341   script.type = "application/javascript"; | 
| 344   script.async = false; | 342   script.async = false; | 
| 345   script.textContent = "(" + fn + ")(" + JSON.stringify(arg) + ");"; | 343   script.textContent = "(" + fn + ")(" + JSON.stringify(arg) + ");"; | 
| 346   document.documentElement.appendChild(script); | 344   document.documentElement.appendChild(script); | 
| 347   document.documentElement.removeChild(script); | 345   document.documentElement.removeChild(script); | 
| 348 } | 346 } | 
| 349 | 347 | 
| 350 // Neither Chrome[1] nor Safari allow us to intercept WebSockets, and therefore | 348 // Neither Chrome[1] nor Safari allow us to intercept WebSockets, and therefore | 
| 351 // some ad networks are misusing them as a way to serve adverts and circumvent | 349 // some ad networks are misusing them as a way to serve adverts and circumvent | 
| 352 // us. As a workaround we wrap WebSocket, preventing blocked WebSocket | 350 // us. As a workaround we wrap WebSocket, preventing blocked WebSocket | 
| 353 // connections from being opened. | 351 // connections from being opened. | 
| 354 // [1] - https://bugs.chromium.org/p/chromium/issues/detail?id=129353 | 352 // [1] - https://bugs.chromium.org/p/chromium/issues/detail?id=129353 | 
| 355 function wrapWebSocket(document) | 353 function wrapWebSocket() | 
| 356 { | 354 { | 
| 357   if (typeof WebSocket == "undefined") | 355   if (typeof WebSocket == "undefined") | 
| 358     return; | 356     return; | 
| 359 | 357 | 
| 360   var eventName = "abpws-" + Math.random().toString(36).substr(2); | 358   var eventName = "abpws-" + Math.random().toString(36).substr(2); | 
| 361 | 359 | 
| 362   document.addEventListener(eventName, function(event) | 360   document.addEventListener(eventName, function(event) | 
| 363   { | 361   { | 
| 364     ext.backgroundPage.sendMessage({ | 362     ext.backgroundPage.sendMessage({ | 
| 365       type: "request.websocket", | 363       type: "request.websocket", | 
| 366       url: event.detail.url | 364       url: event.detail.url | 
| 367     }, function (block) | 365     }, function (block) | 
| 368     { | 366     { | 
| 369       document.dispatchEvent( | 367       document.dispatchEvent( | 
| 370         new CustomEvent(eventName + "-" + event.detail.url, {detail: block}) | 368         new CustomEvent(eventName + "-" + event.detail.url, {detail: block}) | 
| 371       ); | 369       ); | 
| 372     }); | 370     }); | 
| 373   }); | 371   }); | 
| 374 | 372 | 
| 375   runInDocument(document, function(eventName) | 373   runInPageContext(function(eventName) | 
| 376   { | 374   { | 
| 377     // As far as possible we must track everything we use that could be | 375     // As far as possible we must track everything we use that could be | 
| 378     // sabotaged by the website later in order to circumvent us. | 376     // sabotaged by the website later in order to circumvent us. | 
| 379     var RealWebSocket = WebSocket; | 377     var RealWebSocket = WebSocket; | 
| 380     var closeWebSocket = Function.prototype.call.bind(RealWebSocket.prototype.cl
     ose); | 378     var closeWebSocket = Function.prototype.call.bind(RealWebSocket.prototype.cl
     ose); | 
| 381     var addEventListener = document.addEventListener.bind(document); | 379     var addEventListener = document.addEventListener.bind(document); | 
| 382     var removeEventListener = document.removeEventListener.bind(document); | 380     var removeEventListener = document.removeEventListener.bind(document); | 
| 383     var dispatchEvent = document.dispatchEvent.bind(document); | 381     var dispatchEvent = document.dispatchEvent.bind(document); | 
| 384     var CustomEvent = window.CustomEvent; | 382     var CustomEvent = window.CustomEvent; | 
| 385 | 383 | 
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 425       OPEN: {value: RealWebSocket.OPEN, enumerable: true}, | 423       OPEN: {value: RealWebSocket.OPEN, enumerable: true}, | 
| 426       CLOSING: {value: RealWebSocket.CLOSING, enumerable: true}, | 424       CLOSING: {value: RealWebSocket.CLOSING, enumerable: true}, | 
| 427       CLOSED: {value: RealWebSocket.CLOSED, enumerable: true}, | 425       CLOSED: {value: RealWebSocket.CLOSED, enumerable: true}, | 
| 428       prototype: {value: RealWebSocket.prototype} | 426       prototype: {value: RealWebSocket.prototype} | 
| 429     }); | 427     }); | 
| 430 | 428 | 
| 431     RealWebSocket.prototype.constructor = WebSocket; | 429     RealWebSocket.prototype.constructor = WebSocket; | 
| 432   }, eventName); | 430   }, eventName); | 
| 433 } | 431 } | 
| 434 | 432 | 
| 435 function init(document) | 433 function ElemHide() | 
| 436 { | 434 { | 
| 437   var shadow = null; | 435   this.shadow = this.createShadowTree(); | 
| 438   var style = null; | 436   this.style = null; | 
| 439   var observer = null; | 437   this.tracer = null; | 
| 440   var tracer = null; |  | 
| 441 | 438 | 
| 442   wrapWebSocket(document); | 439   this.propertyFilters = new CSSPropertyFilters( | 
|  | 440     window, | 
|  | 441     function(callback) | 
|  | 442     { | 
|  | 443       ext.backgroundPage.sendMessage({ | 
|  | 444         type: "filters.get", | 
|  | 445         what: "cssproperties" | 
|  | 446       }, callback); | 
|  | 447     }, | 
|  | 448     this.addSelectors.bind(this) | 
|  | 449   ); | 
|  | 450 } | 
|  | 451 ElemHide.prototype = { | 
|  | 452   selectorGroupSize: 200, | 
| 443 | 453 | 
| 444   function getPropertyFilters(callback) | 454   createShadowTree: function() | 
| 445   { | 455   { | 
| 446     ext.backgroundPage.sendMessage({ | 456     // Use Shadow DOM if available as to not mess with with web pages that | 
| 447       type: "filters.get", | 457     // rely on the order of their own <style> tags (#309). However, creating | 
| 448       what: "cssproperties" | 458     // a shadow root breaks running CSS transitions. So we have to create | 
| 449     }, callback); | 459     // the shadow root before transistions might start (#452). | 
| 450   } | 460     if (!("createShadowRoot" in document.documentElement)) | 
| 451   var propertyFilters = new CSSPropertyFilters(window, getPropertyFilters, | 461       return null; | 
| 452                                                addElemHideSelectors); |  | 
| 453 | 462 | 
| 454   // Use Shadow DOM if available to don't mess with web pages that rely on | 463     // Using shadow DOM causes issues on some Google websites, | 
| 455   // the order of their own <style> tags (#309). | 464     // including Google Docs, Gmail and Blogger (#1770, #2602, #2687). | 
| 456   // | 465     if (/\.(?:google|blogger)\.com$/.test(document.domain)) | 
| 457   // However, creating a shadow root breaks running CSS transitions. So we | 466       return null; | 
| 458   // have to create the shadow root before transistions might start (#452). | 467 | 
| 459   // | 468     var shadow = document.documentElement.createShadowRoot(); | 
| 460   // Also, using shadow DOM causes issues on some Google websites, |  | 
| 461   // including Google Docs, Gmail and Blogger (#1770, #2602, #2687). |  | 
| 462   if ("createShadowRoot" in document.documentElement && |  | 
| 463       !/\.(?:google|blogger)\.com$/.test(document.domain)) |  | 
| 464   { |  | 
| 465     shadow = document.documentElement.createShadowRoot(); |  | 
| 466     shadow.appendChild(document.createElement("shadow")); | 469     shadow.appendChild(document.createElement("shadow")); | 
| 467 | 470 | 
| 468     // Stop the website from messing with our shadowRoot | 471     // Stop the website from messing with our shadow root (#4191, #4298). | 
| 469     if ("shadowRoot" in Element.prototype) | 472     if ("shadowRoot" in Element.prototype) | 
| 470     { | 473     { | 
| 471       runInDocument(document, function() | 474       runInPageContext(function() | 
| 472       { | 475       { | 
| 473         var ourShadowRoot = document.documentElement.shadowRoot; | 476         var ourShadowRoot = document.documentElement.shadowRoot; | 
| 474         var desc = Object.getOwnPropertyDescriptor(Element.prototype, "shadowRoo
     t"); | 477         var desc = Object.getOwnPropertyDescriptor(Element.prototype, "shadowRoo
     t"); | 
| 475         var shadowRoot = Function.prototype.call.bind(desc.get); | 478         var shadowRoot = Function.prototype.call.bind(desc.get); | 
| 476 | 479 | 
| 477         Object.defineProperty(Element.prototype, "shadowRoot", { | 480         Object.defineProperty(Element.prototype, "shadowRoot", { | 
| 478           configurable: true, enumerable: true, get: function() | 481           configurable: true, enumerable: true, get: function() | 
| 479           { | 482           { | 
| 480             var shadow = shadowRoot(this); | 483             var shadow = shadowRoot(this); | 
| 481             return shadow == ourShadowRoot ? null : shadow; | 484             return shadow == ourShadowRoot ? null : shadow; | 
| 482           } | 485           } | 
| 483         }); | 486         }); | 
| 484       }, null); | 487       }, null); | 
| 485     } | 488     } | 
| 486   } |  | 
| 487 | 489 | 
| 488   function addElemHideSelectors(selectors) | 490     return shadow; | 
|  | 491   }, | 
|  | 492 | 
|  | 493   addSelectors: function(selectors) | 
| 489   { | 494   { | 
| 490     if (selectors.length == 0) | 495     if (selectors.length == 0) | 
| 491       return; | 496       return; | 
| 492 | 497 | 
| 493     if (!style) | 498     if (!this.style) | 
| 494     { | 499     { | 
| 495       // Create <style> element lazily, only if we add styles. Add it to | 500       // Create <style> element lazily, only if we add styles. Add it to | 
| 496       // the shadow DOM if possible. Otherwise fallback to the <head> or | 501       // the shadow DOM if possible. Otherwise fallback to the <head> or | 
| 497       // <html> element. If we have injected a style element before that | 502       // <html> element. If we have injected a style element before that | 
| 498       // has been removed (the sheet property is null), create a new one. | 503       // has been removed (the sheet property is null), create a new one. | 
| 499       style = document.createElement("style"); | 504       this.style = document.createElement("style"); | 
| 500       (shadow || document.head || document.documentElement).appendChild(style); | 505       (this.shadow || document.head | 
|  | 506                    || document.documentElement).appendChild(this.style); | 
| 501 | 507 | 
| 502       // It can happen that the frame already navigated to a different | 508       // It can happen that the frame already navigated to a different | 
| 503       // document while we were waiting for the background page to respond. | 509       // document while we were waiting for the background page to respond. | 
| 504       // In that case the sheet property will stay null, after addind the | 510       // In that case the sheet property will stay null, after addind the | 
| 505       // <style> element to the shadow DOM. | 511       // <style> element to the shadow DOM. | 
| 506       if (!style.sheet) | 512       if (!this.style.sheet) | 
| 507         return; | 513         return; | 
| 508     } | 514     } | 
| 509 | 515 | 
| 510     // If using shadow DOM, we have to add the ::content pseudo-element | 516     // If using shadow DOM, we have to add the ::content pseudo-element | 
| 511     // before each selector, in order to match elements within the | 517     // before each selector, in order to match elements within the | 
| 512     // insertion point. | 518     // insertion point. | 
| 513     if (shadow) | 519     if (this.shadow) | 
| 514     { | 520     { | 
| 515       var preparedSelectors = []; | 521       var preparedSelectors = []; | 
| 516       for (var i = 0; i < selectors.length; i++) | 522       for (var i = 0; i < selectors.length; i++) | 
| 517       { | 523       { | 
| 518         var subSelectors = splitSelector(selectors[i]); | 524         var subSelectors = splitSelector(selectors[i]); | 
| 519         for (var j = 0; j < subSelectors.length; j++) | 525         for (var j = 0; j < subSelectors.length; j++) | 
| 520           preparedSelectors.push("::content " + subSelectors[j]); | 526           preparedSelectors.push("::content " + subSelectors[j]); | 
| 521       } | 527       } | 
| 522       selectors = preparedSelectors; | 528       selectors = preparedSelectors; | 
| 523     } | 529     } | 
| 524 | 530 | 
| 525     // Safari only allows 8192 primitive selectors to be injected at once[1], we | 531     // Safari only allows 8192 primitive selectors to be injected at once[1], we | 
| 526     // therefore chunk the inserted selectors into groups of 200 to be safe. | 532     // therefore chunk the inserted selectors into groups of 200 to be safe. | 
| 527     // (Chrome also has a limit, larger... but we're not certain exactly what it | 533     // (Chrome also has a limit, larger... but we're not certain exactly what it | 
| 528     //  is! Edge apparently has no such limit.) | 534     //  is! Edge apparently has no such limit.) | 
| 529     // [1] - https://github.com/WebKit/webkit/blob/1cb2227f6b2a1035f7bdc46e5ab69
     debb75fc1de/Source/WebCore/css/RuleSet.h#L68 | 535     // [1] - https://github.com/WebKit/webkit/blob/1cb2227f6b2a1035f7bdc46e5ab69
     debb75fc1de/Source/WebCore/css/RuleSet.h#L68 | 
| 530     for (var i = 0; i < selectors.length; i += SELECTOR_GROUP_SIZE) | 536     for (var i = 0; i < selectors.length; i += this.selectorGroupSize) | 
| 531     { | 537     { | 
| 532       var selector = selectors.slice(i, i + SELECTOR_GROUP_SIZE).join(", "); | 538       var selector = selectors.slice(i, i + this.selectorGroupSize).join(", "); | 
| 533       style.sheet.addRule(selector, "display: none !important;"); | 539       this.style.sheet.addRule(selector, "display: none !important;"); | 
| 534     } | 540     } | 
| 535   }; | 541   }, | 
| 536 | 542 | 
| 537   var updateStylesheet = function() | 543   apply: function() | 
| 538   { | 544   { | 
| 539     var selectors = null; | 545     var selectors = null; | 
| 540     var CSSPropertyFiltersLoaded = false; | 546     var propertyFiltersLoaded = false; | 
| 541 | 547 | 
| 542     var checkLoaded = function() | 548     var checkLoaded = function() | 
| 543     { | 549     { | 
| 544       if (!selectors || !CSSPropertyFiltersLoaded) | 550       if (!selectors || !propertyFiltersLoaded) | 
| 545         return; | 551         return; | 
| 546 | 552 | 
| 547       if (observer) | 553       if (this.tracer) | 
| 548         observer.disconnect(); | 554         this.tracer.disconnect(); | 
| 549       observer = null; | 555       this.tracer = null; | 
| 550 | 556 | 
| 551       if (tracer) | 557       if (this.style && this.style.parentElement) | 
| 552         tracer.disconnect(); | 558         this.style.parentElement.removeChild(this.style); | 
| 553       tracer = null; | 559       this.style = null; | 
| 554 | 560 | 
| 555       if (style && style.parentElement) | 561       this.addSelectors(selectors.selectors); | 
| 556         style.parentElement.removeChild(style); | 562       this.propertyFilters.apply(); | 
| 557       style = null; |  | 
| 558 |  | 
| 559       addElemHideSelectors(selectors.selectors); |  | 
| 560       propertyFilters.apply(); |  | 
| 561 | 563 | 
| 562       if (selectors.trace) | 564       if (selectors.trace) | 
| 563         tracer = new ElementHidingTracer(document, selectors.selectors); | 565         this.tracer = new ElementHidingTracer(selectors.selectors); | 
| 564     }; | 566     }.bind(this); | 
| 565 | 567 | 
| 566     ext.backgroundPage.sendMessage({type: "get-selectors"}, function(response) | 568     ext.backgroundPage.sendMessage({type: "get-selectors"}, function(response) | 
| 567     { | 569     { | 
| 568       selectors = response; | 570       selectors = response; | 
| 569       checkLoaded(); | 571       checkLoaded(); | 
| 570     }); | 572     }); | 
| 571 | 573 | 
| 572     propertyFilters.load(function() | 574     this.propertyFilters.load(function() | 
| 573     { | 575     { | 
| 574       CSSPropertyFiltersLoaded = true; | 576       propertyFiltersLoaded = true; | 
| 575       checkLoaded(); | 577       checkLoaded(); | 
| 576     }); | 578     }); | 
| 577   }; | 579   } | 
|  | 580 }; | 
| 578 | 581 | 
| 579   updateStylesheet(); | 582 if (document instanceof HTMLDocument) | 
|  | 583 { | 
|  | 584   checkSitekey(); | 
|  | 585   wrapWebSocket(); | 
|  | 586 | 
|  | 587   var elemhide = new ElemHide(); | 
|  | 588   elemhide.apply(); | 
| 580 | 589 | 
| 581   document.addEventListener("error", function(event) | 590   document.addEventListener("error", function(event) | 
| 582   { | 591   { | 
| 583     checkCollapse(event.target); | 592     checkCollapse(event.target); | 
| 584   }, true); | 593   }, true); | 
| 585 | 594 | 
| 586   document.addEventListener("load", function(event) | 595   document.addEventListener("load", function(event) | 
| 587   { | 596   { | 
| 588     var element = event.target; | 597     var element = event.target; | 
| 589 |  | 
| 590     if (/^i?frame$/.test(element.localName)) | 598     if (/^i?frame$/.test(element.localName)) | 
| 591       checkCollapse(element); | 599       checkCollapse(element); | 
| 592 |  | 
| 593     if (/\bChrome\//.test(navigator.userAgent)) |  | 
| 594     { |  | 
| 595       var contentDocument = getContentDocument(element); |  | 
| 596       if (contentDocument) |  | 
| 597       { |  | 
| 598         var contentWindow = contentDocument.defaultView; |  | 
| 599         if (contentDocument instanceof contentWindow.HTMLDocument) |  | 
| 600         { |  | 
| 601           // Prior to Chrome 37, content scripts cannot run in |  | 
| 602           // dynamically created frames. Also on Chrome 37-40 |  | 
| 603           // document_start content scripts (like this one) don't |  | 
| 604           // run either in those frames due to https://crbug.com/416907. |  | 
| 605           // So we have to apply element hiding from the parent frame. |  | 
| 606           if (!("init" in contentWindow)) |  | 
| 607             init(contentDocument); |  | 
| 608         } |  | 
| 609       } |  | 
| 610     } |  | 
| 611   }, true); | 600   }, true); | 
| 612 |  | 
| 613   return updateStylesheet; |  | 
| 614 } | 601 } | 
| 615 |  | 
| 616 if (document instanceof HTMLDocument) |  | 
| 617 { |  | 
| 618   checkSitekey(); |  | 
| 619   window.updateStylesheet = init(document); |  | 
| 620 } |  | 
| OLD | NEW | 
|---|