| 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 /* globals ElemHideEmulation, splitSelector */ | 
|  | 19 | 
| 18 "use strict"; | 20 "use strict"; | 
| 19 | 21 | 
| 20 const typeMap = { | 22 // This variable is also used by our other content scripts. | 
| 21   "img": "IMAGE", | 23 let elemhide; | 
| 22   "input": "IMAGE", | 24 | 
| 23   "picture": "IMAGE", | 25 const typeMap = new Map([ | 
| 24   "audio": "MEDIA", | 26   ["img", "IMAGE"], | 
| 25   "video": "MEDIA", | 27   ["input", "IMAGE"], | 
| 26   "frame": "SUBDOCUMENT", | 28   ["picture", "IMAGE"], | 
| 27   "iframe": "SUBDOCUMENT", | 29   ["audio", "MEDIA"], | 
| 28   "object": "OBJECT", | 30   ["video", "MEDIA"], | 
| 29   "embed": "OBJECT" | 31   ["frame", "SUBDOCUMENT"], | 
| 30 }; | 32   ["iframe", "SUBDOCUMENT"], | 
|  | 33   ["object", "OBJECT"], | 
|  | 34   ["embed", "OBJECT"] | 
|  | 35 ]); | 
| 31 | 36 | 
| 32 function getURLsFromObjectElement(element) | 37 function getURLsFromObjectElement(element) | 
| 33 { | 38 { | 
| 34   let url = element.getAttribute("data"); | 39   let url = element.getAttribute("data"); | 
| 35   if (url) | 40   if (url) | 
| 36     return [url]; | 41     return [url]; | 
| 37 | 42 | 
| 38   for (let child of element.children) | 43   for (let child of element.children) | 
| 39   { | 44   { | 
| 40     if (child.localName != "param") | 45     if (child.localName != "param") | 
| 41       continue; | 46       continue; | 
| 42 | 47 | 
| 43     let name = child.getAttribute("name"); | 48     let name = child.getAttribute("name"); | 
| 44     if (name != "movie"  && // Adobe Flash | 49     if (name != "movie" &&  // Adobe Flash | 
| 45         name != "source" && // Silverlight | 50         name != "source" && // Silverlight | 
| 46         name != "src"    && // Real Media + Quicktime | 51         name != "src" &&    // Real Media + Quicktime | 
| 47         name != "FileName") // Windows Media | 52         name != "FileName") // Windows Media | 
| 48       continue; | 53       continue; | 
| 49 | 54 | 
| 50     let value = child.getAttribute("value"); | 55     let value = child.getAttribute("value"); | 
| 51     if (!value) | 56     if (!value) | 
| 52       continue; | 57       continue; | 
| 53 | 58 | 
| 54     return [value]; | 59     return [value]; | 
| 55   } | 60   } | 
| 56 | 61 | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
| 77   return urls; | 82   return urls; | 
| 78 } | 83 } | 
| 79 | 84 | 
| 80 function getURLsFromMediaElement(element) | 85 function getURLsFromMediaElement(element) | 
| 81 { | 86 { | 
| 82   let urls = getURLsFromAttributes(element); | 87   let urls = getURLsFromAttributes(element); | 
| 83 | 88 | 
| 84   for (let child of element.children) | 89   for (let child of element.children) | 
| 85   { | 90   { | 
| 86     if (child.localName == "source" || child.localName == "track") | 91     if (child.localName == "source" || child.localName == "track") | 
| 87       urls.push.apply(urls, getURLsFromAttributes(child)); | 92       urls.push(...getURLsFromAttributes(child)); | 
| 88   } | 93   } | 
| 89 | 94 | 
| 90   if (element.poster) | 95   if (element.poster) | 
| 91     urls.push(element.poster); | 96     urls.push(element.poster); | 
| 92 | 97 | 
| 93   return urls; | 98   return urls; | 
| 94 } | 99 } | 
| 95 | 100 | 
| 96 function getURLsFromElement(element) | 101 function getURLsFromElement(element) | 
| 97 { | 102 { | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
| 117   { | 122   { | 
| 118     if (/^(?!https?:)[\w-]+:/i.test(urls[i])) | 123     if (/^(?!https?:)[\w-]+:/i.test(urls[i])) | 
| 119       urls.splice(i--, 1); | 124       urls.splice(i--, 1); | 
| 120   } | 125   } | 
| 121 | 126 | 
| 122   return urls; | 127   return urls; | 
| 123 } | 128 } | 
| 124 | 129 | 
| 125 function checkCollapse(element) | 130 function checkCollapse(element) | 
| 126 { | 131 { | 
| 127   let mediatype = typeMap[element.localName]; | 132   let mediatype = typeMap.get(element.localName); | 
| 128   if (!mediatype) | 133   if (!mediatype) | 
| 129     return; | 134     return; | 
| 130 | 135 | 
| 131   let urls = getURLsFromElement(element); | 136   let urls = getURLsFromElement(element); | 
| 132   if (urls.length == 0) | 137   if (urls.length == 0) | 
| 133     return; | 138     return; | 
| 134 | 139 | 
| 135   ext.backgroundPage.sendMessage( | 140   ext.backgroundPage.sendMessage( | 
| 136     { | 141     { | 
| 137       type: "filters.collapse", | 142       type: "filters.collapse", | 
| 138       urls: urls, | 143       urls, | 
| 139       mediatype: mediatype, | 144       mediatype, | 
| 140       baseURL: document.location.href | 145       baseURL: document.location.href | 
| 141     }, | 146     }, | 
| 142 | 147 | 
| 143     collapse => | 148     collapse => | 
| 144     { | 149     { | 
| 145       function collapseElement() | 150       function collapseElement() | 
| 146       { | 151       { | 
| 147         let propertyName = "display"; | 152         let propertyName = "display"; | 
| 148         let propertyValue = "none"; | 153         let propertyValue = "none"; | 
| 149         if (element.localName == "frame") | 154         if (element.localName == "frame") | 
| (...skipping 22 matching lines...) Expand all  Loading... | 
| 172   ); | 177   ); | 
| 173 } | 178 } | 
| 174 | 179 | 
| 175 function checkSitekey() | 180 function checkSitekey() | 
| 176 { | 181 { | 
| 177   let attr = document.documentElement.getAttribute("data-adblockkey"); | 182   let attr = document.documentElement.getAttribute("data-adblockkey"); | 
| 178   if (attr) | 183   if (attr) | 
| 179     ext.backgroundPage.sendMessage({type: "filters.addKey", token: attr}); | 184     ext.backgroundPage.sendMessage({type: "filters.addKey", token: attr}); | 
| 180 } | 185 } | 
| 181 | 186 | 
| 182 function getContentDocument(element) |  | 
| 183 { |  | 
| 184   try |  | 
| 185   { |  | 
| 186     return element.contentDocument; |  | 
| 187   } |  | 
| 188   catch (e) |  | 
| 189   { |  | 
| 190     return null; |  | 
| 191   } |  | 
| 192 } |  | 
| 193 |  | 
| 194 function ElementHidingTracer() | 187 function ElementHidingTracer() | 
| 195 { | 188 { | 
| 196   this.selectors = []; | 189   this.selectors = []; | 
| 197   this.filters = []; | 190   this.filters = []; | 
| 198 | 191 | 
| 199   this.changedNodes = []; | 192   this.changedNodes = []; | 
| 200   this.timeout = null; | 193   this.timeout = null; | 
| 201 | 194 | 
| 202   this.observer = new MutationObserver(this.observe.bind(this)); | 195   this.observer = new MutationObserver(this.observe.bind(this)); | 
| 203   this.trace = this.trace.bind(this); | 196   this.trace = this.trace.bind(this); | 
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 235           if (getComputedStyle(element).display == "none") | 228           if (getComputedStyle(element).display == "none") | 
| 236           { | 229           { | 
| 237             matchedSelectors.push(filters[i].replace(/^.*?##/, "")); | 230             matchedSelectors.push(filters[i].replace(/^.*?##/, "")); | 
| 238             break nodes; | 231             break nodes; | 
| 239           } | 232           } | 
| 240         } | 233         } | 
| 241       } | 234       } | 
| 242     } | 235     } | 
| 243 | 236 | 
| 244     if (matchedSelectors.length > 0) | 237     if (matchedSelectors.length > 0) | 
|  | 238     { | 
| 245       ext.backgroundPage.sendMessage({ | 239       ext.backgroundPage.sendMessage({ | 
| 246         type: "devtools.traceElemHide", | 240         type: "devtools.traceElemHide", | 
| 247         selectors: matchedSelectors | 241         selectors: matchedSelectors | 
| 248       }); | 242       }); | 
|  | 243     } | 
| 249   }, | 244   }, | 
| 250 | 245 | 
| 251   onTimeout() | 246   onTimeout() | 
| 252   { | 247   { | 
| 253     this.checkNodes(this.changedNodes, this.selectors, this.filters); | 248     this.checkNodes(this.changedNodes, this.selectors, this.filters); | 
| 254     this.changedNodes = []; | 249     this.changedNodes = []; | 
| 255     this.timeout = null; | 250     this.timeout = null; | 
| 256   }, | 251   }, | 
| 257 | 252 | 
| 258   observe(mutations) | 253   observe(mutations) | 
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 342   document.documentElement.removeChild(script); | 337   document.documentElement.removeChild(script); | 
| 343 } | 338 } | 
| 344 | 339 | 
| 345 // Chrome doesn't allow us to intercept WebSockets[1], and therefore | 340 // 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 | 341 // 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 | 342 // us. As a workaround we wrap WebSocket, preventing blocked WebSocket | 
| 348 // connections from being opened. | 343 // connections from being opened. | 
| 349 // [1] - https://bugs.chromium.org/p/chromium/issues/detail?id=129353 | 344 // [1] - https://bugs.chromium.org/p/chromium/issues/detail?id=129353 | 
| 350 function wrapWebSocket() | 345 function wrapWebSocket() | 
| 351 { | 346 { | 
| 352   let eventName = "abpws-" + Math.random().toString(36).substr(2); | 347   let randomEventName = "abpws-" + Math.random().toString(36).substr(2); | 
| 353 | 348 | 
| 354   document.addEventListener(eventName, event => | 349   document.addEventListener(randomEventName, event => | 
| 355   { | 350   { | 
| 356     ext.backgroundPage.sendMessage({ | 351     ext.backgroundPage.sendMessage({ | 
| 357       type: "request.websocket", | 352       type: "request.websocket", | 
| 358       url: event.detail.url | 353       url: event.detail.url | 
| 359     }, block => | 354     }, block => | 
| 360     { | 355     { | 
| 361       document.dispatchEvent( | 356       document.dispatchEvent(new CustomEvent( | 
| 362         new CustomEvent(eventName + "-" + event.detail.url, {detail: block}) | 357         randomEventName + "-" + event.detail.url, {detail: block} | 
| 363       ); | 358       )); | 
| 364     }); | 359     }); | 
| 365   }); | 360   }); | 
| 366 | 361 | 
| 367   runInPageContext(eventName => | 362   runInPageContext(eventName => | 
| 368   { | 363   { | 
| 369     // As far as possible we must track everything we use that could be | 364     // As far as possible we must track everything we use that could be | 
| 370     // sabotaged by the website later in order to circumvent us. | 365     // sabotaged by the website later in order to circumvent us. | 
| 371     let RealWebSocket = WebSocket; | 366     let RealWebSocket = WebSocket; | 
| 372     let closeWebSocket = Function.prototype.call.bind(RealWebSocket.prototype.cl
     ose); | 367     let RealCustomEvent = window.CustomEvent; | 
|  | 368     let closeWebSocket = Function.prototype.call.bind( | 
|  | 369       RealWebSocket.prototype.close | 
|  | 370     ); | 
| 373     let addEventListener = document.addEventListener.bind(document); | 371     let addEventListener = document.addEventListener.bind(document); | 
| 374     let removeEventListener = document.removeEventListener.bind(document); | 372     let removeEventListener = document.removeEventListener.bind(document); | 
| 375     let dispatchEvent = document.dispatchEvent.bind(document); | 373     let dispatchEvent = document.dispatchEvent.bind(document); | 
| 376     let CustomEvent = window.CustomEvent; |  | 
| 377 | 374 | 
| 378     function checkRequest(url, callback) | 375     function checkRequest(url, callback) | 
| 379     { | 376     { | 
| 380       let incomingEventName = eventName + "-" + url; | 377       let incomingEventName = eventName + "-" + url; | 
| 381       function listener(event) | 378       function listener(event) | 
| 382       { | 379       { | 
| 383         callback(event.detail); | 380         callback(event.detail); | 
| 384         removeEventListener(incomingEventName, listener); | 381         removeEventListener(incomingEventName, listener); | 
| 385       } | 382       } | 
| 386       addEventListener(incomingEventName, listener); | 383       addEventListener(incomingEventName, listener); | 
| 387 | 384 | 
| 388       dispatchEvent(new CustomEvent(eventName, { | 385       dispatchEvent(new RealCustomEvent(eventName, {detail: {url}})); | 
| 389         detail: {url: url} |  | 
| 390       })); |  | 
| 391     } | 386     } | 
| 392 | 387 | 
| 393     function WrappedWebSocket(url) | 388     function WrappedWebSocket(url, ...args) | 
| 394     { | 389     { | 
| 395       // Throw correct exceptions if the constructor is used improperly. | 390       // Throw correct exceptions if the constructor is used improperly. | 
| 396       if (!(this instanceof WrappedWebSocket)) return RealWebSocket(); | 391       if (!(this instanceof WrappedWebSocket)) return RealWebSocket(); | 
| 397       if (arguments.length < 1) return new RealWebSocket(); | 392       if (arguments.length < 1) return new RealWebSocket(); | 
| 398 | 393 | 
| 399       let websocket; | 394       let websocket = new RealWebSocket(url, ...args); | 
| 400       if (arguments.length == 1) |  | 
| 401         websocket = new RealWebSocket(url); |  | 
| 402       else |  | 
| 403         websocket = new RealWebSocket(url, arguments[1]); |  | 
| 404 | 395 | 
| 405       checkRequest(websocket.url, blocked => | 396       checkRequest(websocket.url, blocked => | 
| 406       { | 397       { | 
| 407         if (blocked) | 398         if (blocked) | 
| 408           closeWebSocket(websocket); | 399           closeWebSocket(websocket); | 
| 409       }); | 400       }); | 
| 410 | 401 | 
| 411       return websocket; | 402       return websocket; | 
| 412     } | 403     } | 
| 413     WrappedWebSocket.prototype = RealWebSocket.prototype; | 404     WrappedWebSocket.prototype = RealWebSocket.prototype; | 
| 414     WebSocket = WrappedWebSocket.bind(); | 405     window.WebSocket = WrappedWebSocket.bind(); | 
| 415     Object.defineProperties(WebSocket, { | 406     Object.defineProperties(WebSocket, { | 
| 416       CONNECTING: {value: RealWebSocket.CONNECTING, enumerable: true}, | 407       CONNECTING: {value: RealWebSocket.CONNECTING, enumerable: true}, | 
| 417       OPEN: {value: RealWebSocket.OPEN, enumerable: true}, | 408       OPEN: {value: RealWebSocket.OPEN, enumerable: true}, | 
| 418       CLOSING: {value: RealWebSocket.CLOSING, enumerable: true}, | 409       CLOSING: {value: RealWebSocket.CLOSING, enumerable: true}, | 
| 419       CLOSED: {value: RealWebSocket.CLOSED, enumerable: true}, | 410       CLOSED: {value: RealWebSocket.CLOSED, enumerable: true}, | 
| 420       prototype: {value: RealWebSocket.prototype} | 411       prototype: {value: RealWebSocket.prototype} | 
| 421     }); | 412     }); | 
| 422 | 413 | 
| 423     RealWebSocket.prototype.constructor = WebSocket; | 414     RealWebSocket.prototype.constructor = WebSocket; | 
| 424   }, eventName); | 415   }, randomEventName); | 
| 425 } | 416 } | 
| 426 | 417 | 
| 427 function ElemHide() | 418 function ElemHide() | 
| 428 { | 419 { | 
| 429   this.shadow = this.createShadowTree(); | 420   this.shadow = this.createShadowTree(); | 
| 430   this.style = null; | 421   this.style = null; | 
| 431   this.tracer = null; | 422   this.tracer = null; | 
| 432 | 423 | 
| 433   this.elemHideEmulation = new ElemHideEmulation( | 424   this.elemHideEmulation = new ElemHideEmulation( | 
| 434     window, | 425     window, | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 467     shadow.appendChild(document.createElement("shadow")); | 458     shadow.appendChild(document.createElement("shadow")); | 
| 468 | 459 | 
| 469     // Stop the website from messing with our shadow root (#4191, #4298). | 460     // Stop the website from messing with our shadow root (#4191, #4298). | 
| 470     if ("shadowRoot" in Element.prototype) | 461     if ("shadowRoot" in Element.prototype) | 
| 471     { | 462     { | 
| 472       runInPageContext(() => | 463       runInPageContext(() => | 
| 473       { | 464       { | 
| 474         let ourShadowRoot = document.documentElement.shadowRoot; | 465         let ourShadowRoot = document.documentElement.shadowRoot; | 
| 475         if (!ourShadowRoot) | 466         if (!ourShadowRoot) | 
| 476           return; | 467           return; | 
| 477         let desc = Object.getOwnPropertyDescriptor(Element.prototype, "shadowRoo
     t"); | 468         let desc = Object.getOwnPropertyDescriptor(Element.prototype, | 
|  | 469                                                    "shadowRoot"); | 
| 478         let shadowRoot = Function.prototype.call.bind(desc.get); | 470         let shadowRoot = Function.prototype.call.bind(desc.get); | 
| 479 | 471 | 
| 480         Object.defineProperty(Element.prototype, "shadowRoot", { | 472         Object.defineProperty(Element.prototype, "shadowRoot", { | 
| 481           configurable: true, enumerable: true, get() | 473           configurable: true, enumerable: true, get() | 
| 482           { | 474           { | 
| 483             let shadow = shadowRoot(this); | 475             let thisShadow = shadowRoot(this); | 
| 484             return shadow == ourShadowRoot ? null : shadow; | 476             return thisShadow == ourShadowRoot ? null : thisShadow; | 
| 485           } | 477           } | 
| 486         }); | 478         }); | 
| 487       }, null); | 479       }, null); | 
| 488     } | 480     } | 
| 489 | 481 | 
| 490     return shadow; | 482     return shadow; | 
| 491   }, | 483   }, | 
| 492 | 484 | 
| 493   addSelectors(selectors, filters) | 485   addSelectors(selectors, filters) | 
| 494   { | 486   { | 
| 495     if (selectors.length == 0) | 487     if (selectors.length == 0) | 
| 496       return; | 488       return; | 
| 497 | 489 | 
| 498     if (!this.style) | 490     if (!this.style) | 
| 499     { | 491     { | 
| 500       // Create <style> element lazily, only if we add styles. Add it to | 492       // Create <style> element lazily, only if we add styles. Add it to | 
| 501       // the shadow DOM if possible. Otherwise fallback to the <head> or | 493       // the shadow DOM if possible. Otherwise fallback to the <head> or | 
| 502       // <html> element. If we have injected a style element before that | 494       // <html> element. If we have injected a style element before that | 
| 503       // has been removed (the sheet property is null), create a new one. | 495       // has been removed (the sheet property is null), create a new one. | 
| 504       this.style = document.createElement("style"); | 496       this.style = document.createElement("style"); | 
| 505       (this.shadow || document.head | 497       (this.shadow || document.head || | 
| 506                    || document.documentElement).appendChild(this.style); | 498                       document.documentElement).appendChild(this.style); | 
| 507 | 499 | 
| 508       // It can happen that the frame already navigated to a different | 500       // It can happen that the frame already navigated to a different | 
| 509       // document while we were waiting for the background page to respond. | 501       // document while we were waiting for the background page to respond. | 
| 510       // In that case the sheet property will stay null, after addind the | 502       // In that case the sheet property will stay null, after addind the | 
| 511       // <style> element to the shadow DOM. | 503       // <style> element to the shadow DOM. | 
| 512       if (!this.style.sheet) | 504       if (!this.style.sheet) | 
| 513         return; | 505         return; | 
| 514     } | 506     } | 
| 515 | 507 | 
| 516     // If using shadow DOM, we have to add the ::content pseudo-element | 508     // If using shadow DOM, we have to add the ::content pseudo-element | 
| 517     // before each selector, in order to match elements within the | 509     // before each selector, in order to match elements within the | 
| 518     // insertion point. | 510     // insertion point. | 
| 519     let preparedSelectors = []; | 511     let preparedSelectors = []; | 
| 520     if (this.shadow) | 512     if (this.shadow) | 
| 521     { | 513     { | 
| 522       for (let selector of selectors) | 514       for (let selector of selectors) | 
| 523       { | 515       { | 
| 524         let subSelectors = splitSelector(selector); | 516         let subSelectors = splitSelector(selector); | 
| 525         for (let subSelector of subSelectors) | 517         for (let subSelector of subSelectors) | 
| 526           preparedSelectors.push("::content " + subSelector); | 518           preparedSelectors.push("::content " + subSelector); | 
| 527       } | 519       } | 
| 528     } | 520     } | 
| 529     else | 521     else | 
| 530     { |  | 
| 531       preparedSelectors = selectors; | 522       preparedSelectors = selectors; | 
| 532     } |  | 
| 533 | 523 | 
| 534     // Safari only allows 8192 primitive selectors to be injected at once[1], we | 524     // Safari only allows 8192 primitive selectors to be injected at once[1], we | 
| 535     // therefore chunk the inserted selectors into groups of 200 to be safe. | 525     // therefore chunk the inserted selectors into groups of 200 to be safe. | 
| 536     // (Chrome also has a limit, larger... but we're not certain exactly what it | 526     // (Chrome also has a limit, larger... but we're not certain exactly what it | 
| 537     //  is! Edge apparently has no such limit.) | 527     //  is! Edge apparently has no such limit.) | 
| 538     // [1] - https://github.com/WebKit/webkit/blob/1cb2227f6b2a1035f7bdc46e5ab69
     debb75fc1de/Source/WebCore/css/RuleSet.h#L68 | 528     // [1] - https://github.com/WebKit/webkit/blob/1cb2227f6b2a1035f7bdc46e5ab69
     debb75fc1de/Source/WebCore/css/RuleSet.h#L68 | 
| 539     for (let i = 0; i < preparedSelectors.length; i += this.selectorGroupSize) | 529     for (let i = 0; i < preparedSelectors.length; i += this.selectorGroupSize) | 
| 540     { | 530     { | 
| 541       let selector = preparedSelectors.slice(i, i + this.selectorGroupSize).join
     (", "); | 531       let selector = preparedSelectors.slice( | 
|  | 532         i, i + this.selectorGroupSize | 
|  | 533       ).join(", "); | 
| 542       this.style.sheet.insertRule(selector + "{display: none !important;}", | 534       this.style.sheet.insertRule(selector + "{display: none !important;}", | 
| 543                                   this.style.sheet.cssRules.length); | 535                                   this.style.sheet.cssRules.length); | 
| 544     } | 536     } | 
| 545 | 537 | 
| 546     if (this.tracer) | 538     if (this.tracer) | 
| 547       this.tracer.addSelectors(selectors, filters || selectors); | 539       this.tracer.addSelectors(selectors, filters || selectors); | 
| 548   }, | 540   }, | 
| 549 | 541 | 
| 550   apply() | 542   apply() | 
| 551   { | 543   { | 
| (...skipping 14 matching lines...) Expand all  Loading... | 
| 566       this.elemHideEmulation.apply(); | 558       this.elemHideEmulation.apply(); | 
| 567     }); | 559     }); | 
| 568   } | 560   } | 
| 569 }; | 561 }; | 
| 570 | 562 | 
| 571 if (document instanceof HTMLDocument) | 563 if (document instanceof HTMLDocument) | 
| 572 { | 564 { | 
| 573   checkSitekey(); | 565   checkSitekey(); | 
| 574   wrapWebSocket(); | 566   wrapWebSocket(); | 
| 575 | 567 | 
| 576   // This variable is also used by our other content scripts, outside of the | 568   elemhide = new ElemHide(); | 
| 577   // current scope. |  | 
| 578   var elemhide = new ElemHide(); |  | 
| 579   elemhide.apply(); | 569   elemhide.apply(); | 
| 580 | 570 | 
| 581   document.addEventListener("error", event => | 571   document.addEventListener("error", event => | 
| 582   { | 572   { | 
| 583     checkCollapse(event.target); | 573     checkCollapse(event.target); | 
| 584   }, true); | 574   }, true); | 
| 585 | 575 | 
| 586   document.addEventListener("load", event => | 576   document.addEventListener("load", event => | 
| 587   { | 577   { | 
| 588     let element = event.target; | 578     let element = event.target; | 
| 589     if (/^i?frame$/.test(element.localName)) | 579     if (/^i?frame$/.test(element.localName)) | 
| 590       checkCollapse(element); | 580       checkCollapse(element); | 
| 591   }, true); | 581   }, true); | 
| 592 } | 582 } | 
| OLD | NEW | 
|---|