| 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-2017 eyeo GmbH | 3  * Copyright (C) 2006-2017 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 filterToRegExp */ | 18 /* globals filterToRegExp */ | 
| 19 | 19 | 
| 20 "use strict"; | 20 "use strict"; | 
| 21 | 21 | 
|  | 22 const MIN_INVOCATION_INTERVAL = 3000; | 
| 22 const abpSelectorRegexp = /:-abp-([\w-]+)\(/i; | 23 const abpSelectorRegexp = /:-abp-([\w-]+)\(/i; | 
| 23 | 24 | 
| 24 let reportError = () => {}; | 25 let reportError = () => {}; | 
| 25 | 26 | 
| 26 function splitSelector(selector) | 27 function splitSelector(selector) | 
| 27 { | 28 { | 
| 28   if (selector.indexOf(",") == -1) | 29   if (selector.indexOf(",") == -1) | 
| 29     return [selector]; | 30     return [selector]; | 
| 30 | 31 | 
| 31   let selectors = []; | 32   let selectors = []; | 
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 192 const incompletePrefixRegexp = /[\s>+~]$/; | 193 const incompletePrefixRegexp = /[\s>+~]$/; | 
| 193 | 194 | 
| 194 function HasSelector(selectors) | 195 function HasSelector(selectors) | 
| 195 { | 196 { | 
| 196   this._innerSelectors = selectors; | 197   this._innerSelectors = selectors; | 
| 197 } | 198 } | 
| 198 | 199 | 
| 199 HasSelector.prototype = { | 200 HasSelector.prototype = { | 
| 200   requiresHiding: true, | 201   requiresHiding: true, | 
| 201 | 202 | 
|  | 203   get dependsOnStyles() | 
|  | 204   { | 
|  | 205     return this._innerSelectors.some(selector => selector.dependsOnStyles); | 
|  | 206   }, | 
|  | 207 | 
| 202   *getSelectors(prefix, subtree, styles) | 208   *getSelectors(prefix, subtree, styles) | 
| 203   { | 209   { | 
| 204     for (let element of this.getElements(prefix, subtree, styles)) | 210     for (let element of this.getElements(prefix, subtree, styles)) | 
| 205       yield [makeSelector(element, ""), element]; | 211       yield [makeSelector(element, ""), element]; | 
| 206   }, | 212   }, | 
| 207 | 213 | 
| 208   /** | 214   /** | 
| 209    * Generator function returning selected elements. | 215    * Generator function returning selected elements. | 
| 210    * @param {string} prefix the prefix for the selector. | 216    * @param {string} prefix the prefix for the selector. | 
| 211    * @param {Node} subtree the subtree we work on. | 217    * @param {Node} subtree the subtree we work on. | 
| (...skipping 28 matching lines...) Expand all  Loading... | 
| 240       .replace("\\x7B ", "{").replace("\\x7D ", "}"); | 246       .replace("\\x7B ", "{").replace("\\x7D ", "}"); | 
| 241   } | 247   } | 
| 242   else | 248   else | 
| 243     regexpString = filterToRegExp(propertyExpression); | 249     regexpString = filterToRegExp(propertyExpression); | 
| 244 | 250 | 
| 245   this._regexp = new RegExp(regexpString, "i"); | 251   this._regexp = new RegExp(regexpString, "i"); | 
| 246 } | 252 } | 
| 247 | 253 | 
| 248 PropsSelector.prototype = { | 254 PropsSelector.prototype = { | 
| 249   preferHideWithSelector: true, | 255   preferHideWithSelector: true, | 
|  | 256   dependsOnStyles: true, | 
| 250 | 257 | 
| 251   *findPropsSelectors(styles, prefix, regexp) | 258   *findPropsSelectors(styles, prefix, regexp) | 
| 252   { | 259   { | 
| 253     for (let style of styles) | 260     for (let style of styles) | 
| 254       if (regexp.test(style.style)) | 261       if (regexp.test(style.style)) | 
| 255         for (let subSelector of style.subSelectors) | 262         for (let subSelector of style.subSelectors) | 
| 256           yield prefix + subSelector; | 263           yield prefix + subSelector; | 
| 257   }, | 264   }, | 
| 258 | 265 | 
| 259   *getSelectors(prefix, subtree, styles) | 266   *getSelectors(prefix, subtree, styles) | 
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 335 | 342 | 
| 336     let suffix = this.parseSelector(selector.substr(content.end + 1)); | 343     let suffix = this.parseSelector(selector.substr(content.end + 1)); | 
| 337     if (suffix == null) | 344     if (suffix == null) | 
| 338       return null; | 345       return null; | 
| 339 | 346 | 
| 340     selectors.push(...suffix); | 347     selectors.push(...suffix); | 
| 341 | 348 | 
| 342     return selectors; | 349     return selectors; | 
| 343   }, | 350   }, | 
| 344 | 351 | 
|  | 352   _lastInvocation: 0, | 
|  | 353 | 
|  | 354   /** | 
|  | 355    * Processes the current document and applies all rules to it. | 
|  | 356    * @param {CSSStyleSheet[]} [stylesheets] | 
|  | 357    *    The list of new stylesheets that have been added to the document and | 
|  | 358    *    made reprocessing necessary. This parameter shouldn't be passed in for | 
|  | 359    *    the initial processing, all of document's stylesheets will be considered | 
|  | 360    *    then and all rules, including the ones not dependent on styles. | 
|  | 361    */ | 
| 345   addSelectors(stylesheets) | 362   addSelectors(stylesheets) | 
| 346   { | 363   { | 
|  | 364     this._lastInvocation = Date.now(); | 
|  | 365 | 
| 347     let selectors = []; | 366     let selectors = []; | 
| 348     let selectorFilters = []; | 367     let selectorFilters = []; | 
| 349 | 368 | 
| 350     let elements = []; | 369     let elements = []; | 
| 351     let elementFilters = []; | 370     let elementFilters = []; | 
| 352 | 371 | 
| 353     let cssStyles = []; | 372     let cssStyles = []; | 
| 354 | 373 | 
|  | 374     let stylesheetOnlyChange = !!stylesheets; | 
|  | 375     if (!stylesheets) | 
|  | 376       stylesheets = this.window.document.styleSheets; | 
|  | 377 | 
| 355     for (let stylesheet of stylesheets) | 378     for (let stylesheet of stylesheets) | 
| 356     { | 379     { | 
| 357       // Explicitly ignore third-party stylesheets to ensure consistent behavior | 380       // Explicitly ignore third-party stylesheets to ensure consistent behavior | 
| 358       // between Firefox and Chrome. | 381       // between Firefox and Chrome. | 
| 359       if (!this.isSameOrigin(stylesheet)) | 382       if (!this.isSameOrigin(stylesheet)) | 
| 360         continue; | 383         continue; | 
| 361 | 384 | 
| 362       let rules = stylesheet.cssRules; | 385       let rules = stylesheet.cssRules; | 
| 363       if (!rules) | 386       if (!rules) | 
| 364         continue; | 387         continue; | 
| 365 | 388 | 
| 366       for (let rule of rules) | 389       for (let rule of rules) | 
| 367       { | 390       { | 
| 368         if (rule.type != rule.STYLE_RULE) | 391         if (rule.type != rule.STYLE_RULE) | 
| 369           continue; | 392           continue; | 
| 370 | 393 | 
| 371         cssStyles.push(stringifyStyle(rule)); | 394         cssStyles.push(stringifyStyle(rule)); | 
| 372       } | 395       } | 
| 373     } | 396     } | 
| 374 | 397 | 
| 375     let {document} = this.window; | 398     let {document} = this.window; | 
| 376     for (let pattern of this.patterns) | 399     for (let pattern of this.patterns) | 
| 377     { | 400     { | 
|  | 401       if (stylesheetOnlyChange && | 
|  | 402           !pattern.selectors.some(selector => selector.dependsOnStyles)) | 
|  | 403       { | 
|  | 404         continue; | 
|  | 405       } | 
|  | 406 | 
| 378       for (let selector of evaluate(pattern.selectors, | 407       for (let selector of evaluate(pattern.selectors, | 
| 379                                     0, "", document, cssStyles)) | 408                                     0, "", document, cssStyles)) | 
| 380       { | 409       { | 
| 381         if (pattern.selectors.some(s => s.preferHideWithSelector) && | 410         if (pattern.selectors.some(s => s.preferHideWithSelector) && | 
| 382             !pattern.selectors.some(s => s.requiresHiding)) | 411             !pattern.selectors.some(s => s.requiresHiding)) | 
| 383         { | 412         { | 
| 384           selectors.push(selector); | 413           selectors.push(selector); | 
| 385           selectorFilters.push(pattern.text); | 414           selectorFilters.push(pattern.text); | 
| 386         } | 415         } | 
| 387         else | 416         else | 
| 388         { | 417         { | 
| 389           for (let element of document.querySelectorAll(selector)) | 418           for (let element of document.querySelectorAll(selector)) | 
| 390           { | 419           { | 
| 391             elements.push(element); | 420             elements.push(element); | 
| 392             elementFilters.push(pattern.text); | 421             elementFilters.push(pattern.text); | 
| 393           } | 422           } | 
| 394         } | 423         } | 
| 395       } | 424       } | 
| 396     } | 425     } | 
| 397 | 426 | 
| 398     this.addSelectorsFunc(selectors, selectorFilters); | 427     this.addSelectorsFunc(selectors, selectorFilters); | 
| 399     this.hideElemsFunc(elements, elementFilters); | 428     this.hideElemsFunc(elements, elementFilters); | 
| 400   }, | 429   }, | 
| 401 | 430 | 
|  | 431   _stylesheetQueue: null, | 
|  | 432 | 
| 402   onLoad(event) | 433   onLoad(event) | 
| 403   { | 434   { | 
| 404     let stylesheet = event.target.sheet; | 435     let stylesheet = event.target.sheet; | 
| 405     if (stylesheet) | 436     if (stylesheet) | 
| 406       this.addSelectors([stylesheet]); | 437     { | 
|  | 438       if (!this._stylesheetQueue && | 
|  | 439           Date.now() - this._lastInvocation < MIN_INVOCATION_INTERVAL) | 
|  | 440       { | 
|  | 441         this._stylesheetQueue = []; | 
|  | 442         this.window.setTimeout(() => | 
|  | 443         { | 
|  | 444           let stylesheets = this._stylesheetQueue; | 
|  | 445           this._stylesheetQueue = null; | 
|  | 446           this.addSelectors(stylesheets); | 
|  | 447         }, MIN_INVOCATION_INTERVAL - (Date.now() - this._lastInvocation)); | 
|  | 448       } | 
|  | 449 | 
|  | 450       if (this._stylesheetQueue) | 
|  | 451         this._stylesheetQueue.push(stylesheet); | 
|  | 452       else | 
|  | 453         this.addSelectors([stylesheet]); | 
|  | 454     } | 
| 407   }, | 455   }, | 
| 408 | 456 | 
| 409   apply() | 457   apply() | 
| 410   { | 458   { | 
| 411     this.getFiltersFunc(patterns => | 459     this.getFiltersFunc(patterns => | 
| 412     { | 460     { | 
| 413       this.patterns = []; | 461       this.patterns = []; | 
| 414       for (let pattern of patterns) | 462       for (let pattern of patterns) | 
| 415       { | 463       { | 
| 416         let selectors = this.parseSelector(pattern.selector); | 464         let selectors = this.parseSelector(pattern.selector); | 
| 417         if (selectors != null && selectors.length > 0) | 465         if (selectors != null && selectors.length > 0) | 
| 418           this.patterns.push({selectors, text: pattern.text}); | 466           this.patterns.push({selectors, text: pattern.text}); | 
| 419       } | 467       } | 
| 420 | 468 | 
| 421       if (this.patterns.length > 0) | 469       if (this.patterns.length > 0) | 
| 422       { | 470       { | 
| 423         let {document} = this.window; | 471         let {document} = this.window; | 
| 424         this.addSelectors(document.styleSheets); | 472         this.addSelectors(); | 
| 425         document.addEventListener("load", this.onLoad.bind(this), true); | 473         document.addEventListener("load", this.onLoad.bind(this), true); | 
| 426       } | 474       } | 
| 427     }); | 475     }); | 
| 428   } | 476   } | 
| 429 }; | 477 }; | 
| OLD | NEW | 
|---|