 Issue 29712655:
  Issue 6437 - Skip styles-only patterns on DOM mutations  (Closed) 
  Base URL: https://hg.adblockplus.org/adblockpluscore/
    
  
    Issue 29712655:
  Issue 6437 - Skip styles-only patterns on DOM mutations  (Closed) 
  Base URL: https://hg.adblockplus.org/adblockpluscore/| Left: | ||
| Right: | 
| 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-present eyeo GmbH | 3 * Copyright (C) 2006-present 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 "use strict"; | 18 "use strict"; | 
| 19 | 19 | 
| 20 const {textToRegExp, filterToRegExp, splitSelector} = require("../common"); | 20 const {textToRegExp, filterToRegExp, splitSelector} = require("../common"); | 
| 21 | 21 | 
| 22 let MIN_INVOCATION_INTERVAL = 3000; | 22 let MIN_INVOCATION_INTERVAL = 3000; | 
| 23 const MAX_SYNCHRONOUS_PROCESSING_TIME = 50; | 23 const MAX_SYNCHRONOUS_PROCESSING_TIME = 50; | 
| 24 const abpSelectorRegexp = /:-abp-([\w-]+)\(/i; | 24 const abpSelectorRegexp = /:-abp-([\w-]+)\(/i; | 
| 25 | 25 | 
| 26 function getCachedPropertyValue(object, name, defaultValueFunc = () => {}) | |
| 27 { | |
| 28 let value = object[name]; | |
| 29 if (value === undefined) | |
| 
hub
2018/03/14 13:04:03
there is the argument of value === undefined vs ty
 
Manish Jethani
2018/03/14 14:54:53
Oh yeah, for the sake of consistency though I've m
 | |
| 30 Object.defineProperty(object, name, {value: value = defaultValueFunc()}); | |
| 31 return value; | |
| 32 } | |
| 33 | |
| 26 /** Return position of node from parent. | 34 /** Return position of node from parent. | 
| 27 * @param {Node} node the node to find the position of. | 35 * @param {Node} node the node to find the position of. | 
| 28 * @return {number} One-based index like for :nth-child(), or 0 on error. | 36 * @return {number} One-based index like for :nth-child(), or 0 on error. | 
| 29 */ | 37 */ | 
| 30 function positionInParent(node) | 38 function positionInParent(node) | 
| 31 { | 39 { | 
| 32 let {children} = node.parentNode; | 40 let {children} = node.parentNode; | 
| 33 for (let i = 0; i < children.length; i++) | 41 for (let i = 0; i < children.length; i++) | 
| 34 if (children[i] == node) | 42 if (children[i] == node) | 
| 35 return i + 1; | 43 return i + 1; | 
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 237 | 245 | 
| 238 const incompletePrefixRegexp = /[\s>+~]$/; | 246 const incompletePrefixRegexp = /[\s>+~]$/; | 
| 239 | 247 | 
| 240 function HasSelector(selectors) | 248 function HasSelector(selectors) | 
| 241 { | 249 { | 
| 242 this._innerSelectors = selectors; | 250 this._innerSelectors = selectors; | 
| 243 } | 251 } | 
| 244 | 252 | 
| 245 HasSelector.prototype = { | 253 HasSelector.prototype = { | 
| 246 requiresHiding: true, | 254 requiresHiding: true, | 
| 255 dependsOnDOM: true, | |
| 247 | 256 | 
| 248 get dependsOnStyles() | 257 get dependsOnStyles() | 
| 249 { | 258 { | 
| 250 return this._innerSelectors.some(selector => selector.dependsOnStyles); | 259 return this._innerSelectors.some(selector => selector.dependsOnStyles); | 
| 251 }, | 260 }, | 
| 252 | 261 | 
| 253 get dependsOnCharacterData() | 262 get dependsOnCharacterData() | 
| 254 { | 263 { | 
| 255 return this._innerSelectors.some( | 264 return this._innerSelectors.some( | 
| 256 selector => selector.dependsOnCharacterData | 265 selector => selector.dependsOnCharacterData | 
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 299 } | 308 } | 
| 300 }; | 309 }; | 
| 301 | 310 | 
| 302 function ContainsSelector(textContent) | 311 function ContainsSelector(textContent) | 
| 303 { | 312 { | 
| 304 this._regexp = makeRegExpParameter(textContent); | 313 this._regexp = makeRegExpParameter(textContent); | 
| 305 } | 314 } | 
| 306 | 315 | 
| 307 ContainsSelector.prototype = { | 316 ContainsSelector.prototype = { | 
| 308 requiresHiding: true, | 317 requiresHiding: true, | 
| 318 dependsOnDOM: true, | |
| 309 dependsOnCharacterData: true, | 319 dependsOnCharacterData: true, | 
| 310 | 320 | 
| 311 *getSelectors(prefix, subtree, styles) | 321 *getSelectors(prefix, subtree, styles) | 
| 312 { | 322 { | 
| 313 for (let element of this.getElements(prefix, subtree, styles)) | 323 for (let element of this.getElements(prefix, subtree, styles)) | 
| 314 yield [makeSelector(element, ""), subtree]; | 324 yield [makeSelector(element, ""), subtree]; | 
| 315 }, | 325 }, | 
| 316 | 326 | 
| 317 *getElements(prefix, subtree, styles) | 327 *getElements(prefix, subtree, styles) | 
| 318 { | 328 { | 
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 370 } | 380 } | 
| 371 }, | 381 }, | 
| 372 | 382 | 
| 373 *getSelectors(prefix, subtree, styles) | 383 *getSelectors(prefix, subtree, styles) | 
| 374 { | 384 { | 
| 375 for (let selector of this.findPropsSelectors(styles, prefix, this._regexp)) | 385 for (let selector of this.findPropsSelectors(styles, prefix, this._regexp)) | 
| 376 yield [selector, subtree]; | 386 yield [selector, subtree]; | 
| 377 } | 387 } | 
| 378 }; | 388 }; | 
| 379 | 389 | 
| 380 function isSelectorHidingOnlyPattern(pattern) | 390 function Pattern(selectors, text) | 
| 381 { | 391 { | 
| 382 return pattern.selectors.some(s => s.preferHideWithSelector) && | 392 this.selectors = selectors; | 
| 383 !pattern.selectors.some(s => s.requiresHiding); | 393 this.text = text; | 
| 394 } | |
| 395 | |
| 396 Pattern.prototype = { | |
| 397 isSelectorHidingOnlyPattern() | |
| 398 { | |
| 399 return getCachedPropertyValue( | |
| 400 this, "_selectorHidingOnlyPattern", | |
| 401 () => this.selectors.some(selector => selector.preferHideWithSelector) && | |
| 402 !this.selectors.some(selector => selector.requiresHiding) | |
| 403 ); | |
| 404 }, | |
| 405 | |
| 406 get dependsOnStyles() | |
| 407 { | |
| 408 return getCachedPropertyValue( | |
| 409 this, "_dependsOnStyles", | |
| 410 () => this.selectors.some(selector => selector.dependsOnStyles) | |
| 411 ); | |
| 412 }, | |
| 413 | |
| 414 get dependsOnDOM() | |
| 415 { | |
| 416 return getCachedPropertyValue( | |
| 417 this, "_dependsOnDOM", | |
| 418 () => this.selectors.some(selector => selector.dependsOnDOM) | |
| 419 ); | |
| 420 }, | |
| 421 | |
| 422 get dependsOnStylesAndDOM() | |
| 423 { | |
| 424 return getCachedPropertyValue( | |
| 425 this, "_dependsOnStylesAndDOM", | |
| 426 () => this.selectors.some(selector => selector.dependsOnStyles && | |
| 427 selector.dependsOnDOM) | |
| 428 ); | |
| 429 }, | |
| 430 | |
| 431 get maybeDependsOnAttributes() | |
| 432 { | |
| 433 // Observe changes to attributes if either there's a plain selector that | |
| 434 // looks like an ID selector, class selector, or attribute selector in one | |
| 435 // of the patterns (e.g. "a[href='https://example.com/']") | |
| 436 // or there's a properties selector nested inside a has selector | |
| 437 // (e.g. "div:-abp-has(:-abp-properties(color: blue))") | |
| 438 return getCachedPropertyValue( | |
| 439 this, "_maybeDependsOnAttributes", | |
| 440 () => this.selectors.some( | |
| 441 selector => selector.maybeDependsOnAttributes || | |
| 442 (selector instanceof HasSelector && | |
| 443 selector.dependsOnStyles) | |
| 444 ) | |
| 445 ); | |
| 446 }, | |
| 447 | |
| 448 get dependsOnCharacterData() | |
| 449 { | |
| 450 // Observe changes to character data only if there's a contains selector in | |
| 451 // one of the patterns. | |
| 452 return getCachedPropertyValue( | |
| 453 this, "_dependsOnCharacterData", | |
| 454 () => this.selectors.some(selector => selector.dependsOnCharacterData) | |
| 455 ); | |
| 456 } | |
| 457 }; | |
| 458 | |
| 459 function filterPatterns(patterns, {stylesheets, mutations}) | |
| 460 { | |
| 461 if (!stylesheets && !mutations) | |
| 462 return patterns.slice(); | |
| 463 | |
| 464 return patterns.filter( | |
| 465 pattern => (stylesheets && pattern.dependsOnStyles) || | |
| 466 (mutations && pattern.dependsOnDOM) | |
| 467 ); | |
| 384 } | 468 } | 
| 385 | 469 | 
| 386 function shouldObserveAttributes(patterns) | 470 function shouldObserveAttributes(patterns) | 
| 387 { | 471 { | 
| 388 // Observe changes to attributes if either there's a plain selector that | 472 return patterns.some(pattern => pattern.maybeDependsOnAttributes); | 
| 389 // looks like an ID selector, class selector, or attribute selector in one of | |
| 390 // the patterns (e.g. "a[href='https://example.com/']") | |
| 391 // or there's a properties selector nested inside a has selector | |
| 392 // (e.g. "div:-abp-has(:-abp-properties(color: blue))") | |
| 393 return patterns.some( | |
| 394 pattern => pattern.selectors.some( | |
| 395 selector => selector.maybeDependsOnAttributes || | |
| 396 (selector instanceof HasSelector && | |
| 397 selector.dependsOnStyles) | |
| 398 ) | |
| 399 ); | |
| 400 } | 473 } | 
| 401 | 474 | 
| 402 function shouldObserveCharacterData(patterns) | 475 function shouldObserveCharacterData(patterns) | 
| 403 { | 476 { | 
| 404 // Observe changes to character data only if there's a contains selector in | 477 return patterns.some(pattern => pattern.dependsOnCharacterData); | 
| 405 // one of the patterns. | |
| 406 return patterns.some( | |
| 407 pattern => pattern.selectors.some( | |
| 408 selector => selector.dependsOnCharacterData | |
| 409 ) | |
| 410 ); | |
| 411 } | 478 } | 
| 412 | 479 | 
| 413 function ElemHideEmulation(addSelectorsFunc, hideElemsFunc) | 480 function ElemHideEmulation(addSelectorsFunc, hideElemsFunc) | 
| 414 { | 481 { | 
| 415 this.document = document; | 482 this.document = document; | 
| 416 this.addSelectorsFunc = addSelectorsFunc; | 483 this.addSelectorsFunc = addSelectorsFunc; | 
| 417 this.hideElemsFunc = hideElemsFunc; | 484 this.hideElemsFunc = hideElemsFunc; | 
| 418 this.observer = new MutationObserver(this.observe.bind(this)); | 485 this.observer = new MutationObserver(this.observe.bind(this)); | 
| 419 } | 486 } | 
| 420 | 487 | 
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 495 return selectors; | 562 return selectors; | 
| 496 }, | 563 }, | 
| 497 | 564 | 
| 498 /** | 565 /** | 
| 499 * Processes the current document and applies all rules to it. | 566 * Processes the current document and applies all rules to it. | 
| 500 * @param {CSSStyleSheet[]} [stylesheets] | 567 * @param {CSSStyleSheet[]} [stylesheets] | 
| 501 * The list of new stylesheets that have been added to the document and | 568 * The list of new stylesheets that have been added to the document and | 
| 502 * made reprocessing necessary. This parameter shouldn't be passed in for | 569 * made reprocessing necessary. This parameter shouldn't be passed in for | 
| 503 * the initial processing, all of document's stylesheets will be considered | 570 * the initial processing, all of document's stylesheets will be considered | 
| 504 * then and all rules, including the ones not dependent on styles. | 571 * then and all rules, including the ones not dependent on styles. | 
| 572 * @param {MutationRecord[]} [mutations] | |
| 573 * The list of DOM mutations that have been applied to the document and | |
| 574 * made reprocessing necessary. This parameter shouldn't be passed in for | |
| 575 * the initial processing, the entire document will be considered | |
| 576 * then and all rules, including the ones not dependent on the DOM. | |
| 505 * @param {function} [done] | 577 * @param {function} [done] | 
| 506 * Callback to call when done. | 578 * Callback to call when done. | 
| 507 */ | 579 */ | 
| 508 _addSelectors(stylesheets, done) | 580 _addSelectors(stylesheets, mutations, done) | 
| 509 { | 581 { | 
| 582 let patterns = filterPatterns(this.patterns, {stylesheets, mutations}); | |
| 583 | |
| 510 let selectors = []; | 584 let selectors = []; | 
| 511 let selectorFilters = []; | 585 let selectorFilters = []; | 
| 512 | 586 | 
| 513 let elements = []; | 587 let elements = []; | 
| 514 let elementFilters = []; | 588 let elementFilters = []; | 
| 515 | 589 | 
| 516 let cssStyles = []; | 590 let cssStyles = []; | 
| 517 | 591 | 
| 518 let stylesheetOnlyChange = !!stylesheets; | 592 // If neither any style sheets nor any DOM mutations have been specified, | 
| 519 if (!stylesheets) | 593 // do full processing. | 
| 594 if (!stylesheets && !mutations) | |
| 520 stylesheets = this.document.styleSheets; | 595 stylesheets = this.document.styleSheets; | 
| 521 | 596 | 
| 522 for (let stylesheet of stylesheets) | 597 // If there are any DOM mutations and any of the patterns depends on both | 
| 598 // style sheets and the DOM (e.g. -abp-has(-abp-properties)), find all the | |
| 599 // rules in every style sheet in the document, because we need to run | |
| 600 // querySelectorAll afterwards. On the other hand, if we only have patterns | |
| 601 // that depend on either styles or DOM both not both | |
| 602 // (e.g. -abp-properties or -abp-contains), we can skip this part. | |
| 603 if (mutations && patterns.some(pattern => pattern.dependsOnStylesAndDOM)) | |
| 604 stylesheets = this.document.styleSheets; | |
| 605 | |
| 606 for (let stylesheet of stylesheets || []) | |
| 523 { | 607 { | 
| 524 // Explicitly ignore third-party stylesheets to ensure consistent behavior | 608 // Explicitly ignore third-party stylesheets to ensure consistent behavior | 
| 525 // between Firefox and Chrome. | 609 // between Firefox and Chrome. | 
| 526 if (!this.isSameOrigin(stylesheet)) | 610 if (!this.isSameOrigin(stylesheet)) | 
| 527 continue; | 611 continue; | 
| 528 | 612 | 
| 529 let rules = stylesheet.cssRules; | 613 let rules = stylesheet.cssRules; | 
| 530 if (!rules) | 614 if (!rules) | 
| 531 continue; | 615 continue; | 
| 532 | 616 | 
| 533 for (let rule of rules) | 617 for (let rule of rules) | 
| 534 { | 618 { | 
| 535 if (rule.type != rule.STYLE_RULE) | 619 if (rule.type != rule.STYLE_RULE) | 
| 536 continue; | 620 continue; | 
| 537 | 621 | 
| 538 cssStyles.push(stringifyStyle(rule)); | 622 cssStyles.push(stringifyStyle(rule)); | 
| 539 } | 623 } | 
| 540 } | 624 } | 
| 541 | 625 | 
| 542 let patterns = this.patterns.slice(); | |
| 543 let pattern = null; | 626 let pattern = null; | 
| 544 let generator = null; | 627 let generator = null; | 
| 545 | 628 | 
| 546 let processPatterns = () => | 629 let processPatterns = () => | 
| 547 { | 630 { | 
| 548 let cycleStart = performance.now(); | 631 let cycleStart = performance.now(); | 
| 549 | 632 | 
| 550 if (!pattern) | 633 if (!pattern) | 
| 551 { | 634 { | 
| 552 if (!patterns.length) | 635 if (!patterns.length) | 
| 553 { | 636 { | 
| 554 this.addSelectorsFunc(selectors, selectorFilters); | 637 if (selectors.length > 0) | 
| 
Manish Jethani
2018/03/08 21:08:15
We need to do this because of an existing bug, whi
 
Manish Jethani
2018/03/08 21:28:34
Sorry, I just checked, there is no bug. In any cas
 | |
| 555 this.hideElemsFunc(elements, elementFilters); | 638 this.addSelectorsFunc(selectors, selectorFilters); | 
| 639 if (elements.length > 0) | |
| 640 this.hideElemsFunc(elements, elementFilters); | |
| 556 if (typeof done == "function") | 641 if (typeof done == "function") | 
| 557 done(); | 642 done(); | 
| 558 return; | 643 return; | 
| 559 } | 644 } | 
| 560 | 645 | 
| 561 pattern = patterns.shift(); | 646 pattern = patterns.shift(); | 
| 562 | 647 | 
| 563 if (stylesheetOnlyChange && | |
| 564 !pattern.selectors.some(selector => selector.dependsOnStyles)) | |
| 565 { | |
| 566 pattern = null; | |
| 567 return processPatterns(); | |
| 568 } | |
| 569 generator = evaluate(pattern.selectors, 0, "", | 648 generator = evaluate(pattern.selectors, 0, "", | 
| 570 this.document, cssStyles); | 649 this.document, cssStyles); | 
| 571 } | 650 } | 
| 572 for (let selector of generator) | 651 for (let selector of generator) | 
| 573 { | 652 { | 
| 574 if (selector != null) | 653 if (selector != null) | 
| 575 { | 654 { | 
| 576 if (isSelectorHidingOnlyPattern(pattern)) | 655 if (pattern.isSelectorHidingOnlyPattern()) | 
| 577 { | 656 { | 
| 578 selectors.push(selector); | 657 selectors.push(selector); | 
| 579 selectorFilters.push(pattern.text); | 658 selectorFilters.push(pattern.text); | 
| 580 } | 659 } | 
| 581 else | 660 else | 
| 582 { | 661 { | 
| 583 for (let element of this.document.querySelectorAll(selector)) | 662 for (let element of this.document.querySelectorAll(selector)) | 
| 584 { | 663 { | 
| 585 elements.push(element); | 664 elements.push(element); | 
| 586 elementFilters.push(pattern.text); | 665 elementFilters.push(pattern.text); | 
| (...skipping 26 matching lines...) Expand all Loading... | |
| 613 }, | 692 }, | 
| 614 | 693 | 
| 615 _filteringInProgress: false, | 694 _filteringInProgress: false, | 
| 616 _lastInvocation: -MIN_INVOCATION_INTERVAL, | 695 _lastInvocation: -MIN_INVOCATION_INTERVAL, | 
| 617 _scheduledProcessing: null, | 696 _scheduledProcessing: null, | 
| 618 | 697 | 
| 619 /** | 698 /** | 
| 620 * Re-run filtering either immediately or queued. | 699 * Re-run filtering either immediately or queued. | 
| 621 * @param {CSSStyleSheet[]} [stylesheets] | 700 * @param {CSSStyleSheet[]} [stylesheets] | 
| 622 * new stylesheets to be processed. This parameter should be omitted | 701 * new stylesheets to be processed. This parameter should be omitted | 
| 623 * for DOM modification (full reprocessing required). | 702 * for full reprocessing. | 
| 703 * @param {MutationRecord[]} [mutations] | |
| 704 * new DOM mutations to be processed. This parameter should be omitted | |
| 705 * for full reprocessing. | |
| 624 */ | 706 */ | 
| 625 queueFiltering(stylesheets) | 707 queueFiltering(stylesheets, mutations) | 
| 626 { | 708 { | 
| 627 let completion = () => | 709 let completion = () => | 
| 628 { | 710 { | 
| 629 this._lastInvocation = performance.now(); | 711 this._lastInvocation = performance.now(); | 
| 630 this._filteringInProgress = false; | 712 this._filteringInProgress = false; | 
| 631 if (this._scheduledProcessing) | 713 if (this._scheduledProcessing) | 
| 632 { | 714 { | 
| 633 let newStylesheets = this._scheduledProcessing.stylesheets; | 715 let params = Object.assign({}, this._scheduledProcessing); | 
| 634 this._scheduledProcessing = null; | 716 this._scheduledProcessing = null; | 
| 635 this.queueFiltering(newStylesheets); | 717 this.queueFiltering(params.stylesheets, params.mutations); | 
| 636 } | 718 } | 
| 637 }; | 719 }; | 
| 638 | 720 | 
| 639 if (this._scheduledProcessing) | 721 if (this._scheduledProcessing) | 
| 640 { | 722 { | 
| 641 if (!stylesheets) | 723 if (!stylesheets && !mutations) | 
| 642 this._scheduledProcessing.stylesheets = null; | 724 { | 
| 643 else if (this._scheduledProcessing.stylesheets) | 725 this._scheduledProcessing = {}; | 
| 644 this._scheduledProcessing.stylesheets.push(...stylesheets); | 726 } | 
| 727 else | |
| 728 { | |
| 729 if (stylesheets) | |
| 730 { | |
| 731 if (!this._scheduledProcessing.stylesheets) | |
| 732 this._scheduledProcessing.stylesheets = []; | |
| 733 this._scheduledProcessing.stylesheets.push(...stylesheets); | |
| 734 } | |
| 735 if (mutations) | |
| 736 { | |
| 737 if (!this._scheduledProcessing.mutations) | |
| 738 this._scheduledProcessing.mutations = []; | |
| 739 this._scheduledProcessing.mutations.push(...mutations); | |
| 740 } | |
| 741 } | |
| 645 } | 742 } | 
| 646 else if (this._filteringInProgress) | 743 else if (this._filteringInProgress) | 
| 647 { | 744 { | 
| 648 this._scheduledProcessing = {stylesheets}; | 745 this._scheduledProcessing = {stylesheets, mutations}; | 
| 649 } | 746 } | 
| 650 else if (performance.now() - this._lastInvocation < MIN_INVOCATION_INTERVAL) | 747 else if (performance.now() - this._lastInvocation < MIN_INVOCATION_INTERVAL) | 
| 651 { | 748 { | 
| 652 this._scheduledProcessing = {stylesheets}; | 749 this._scheduledProcessing = {stylesheets, mutations}; | 
| 653 setTimeout(() => | 750 setTimeout(() => | 
| 654 { | 751 { | 
| 655 let newStylesheets = this._scheduledProcessing.stylesheets; | 752 let params = Object.assign({}, this._scheduledProcessing); | 
| 656 this._filteringInProgress = true; | 753 this._filteringInProgress = true; | 
| 657 this._scheduledProcessing = null; | 754 this._scheduledProcessing = null; | 
| 658 this._addSelectors(newStylesheets, completion); | 755 this._addSelectors(params.stylesheets, params.mutations, completion); | 
| 659 }, | 756 }, | 
| 660 MIN_INVOCATION_INTERVAL - (performance.now() - this._lastInvocation)); | 757 MIN_INVOCATION_INTERVAL - (performance.now() - this._lastInvocation)); | 
| 661 } | 758 } | 
| 662 else if (this.document.readyState == "loading") | 759 else if (this.document.readyState == "loading") | 
| 663 { | 760 { | 
| 664 this._scheduledProcessing = {stylesheets}; | 761 this._scheduledProcessing = {stylesheets, mutations}; | 
| 665 let handler = () => | 762 let handler = () => | 
| 666 { | 763 { | 
| 667 document.removeEventListener("DOMContentLoaded", handler); | 764 document.removeEventListener("DOMContentLoaded", handler); | 
| 668 let newStylesheets = this._scheduledProcessing.stylesheets; | 765 let params = Object.assign({}, this._scheduledProcessing); | 
| 669 this._filteringInProgress = true; | 766 this._filteringInProgress = true; | 
| 670 this._scheduledProcessing = null; | 767 this._scheduledProcessing = null; | 
| 671 this._addSelectors(newStylesheets, completion); | 768 this._addSelectors(params.stylesheets, params.mutations, completion); | 
| 672 }; | 769 }; | 
| 673 document.addEventListener("DOMContentLoaded", handler); | 770 document.addEventListener("DOMContentLoaded", handler); | 
| 674 } | 771 } | 
| 675 else | 772 else | 
| 676 { | 773 { | 
| 677 this._filteringInProgress = true; | 774 this._filteringInProgress = true; | 
| 678 this._addSelectors(stylesheets, completion); | 775 this._addSelectors(stylesheets, mutations, completion); | 
| 679 } | 776 } | 
| 680 }, | 777 }, | 
| 681 | 778 | 
| 682 onLoad(event) | 779 onLoad(event) | 
| 683 { | 780 { | 
| 684 let stylesheet = event.target.sheet; | 781 let stylesheet = event.target.sheet; | 
| 685 if (stylesheet) | 782 if (stylesheet) | 
| 686 this.queueFiltering([stylesheet]); | 783 this.queueFiltering([stylesheet]); | 
| 687 }, | 784 }, | 
| 688 | 785 | 
| 689 observe(mutations) | 786 observe(mutations) | 
| 690 { | 787 { | 
| 691 this.queueFiltering(); | 788 this.queueFiltering(null, mutations); | 
| 692 }, | 789 }, | 
| 693 | 790 | 
| 694 apply(patterns) | 791 apply(patterns) | 
| 695 { | 792 { | 
| 696 this.patterns = []; | 793 this.patterns = []; | 
| 697 for (let pattern of patterns) | 794 for (let pattern of patterns) | 
| 698 { | 795 { | 
| 699 let selectors = this.parseSelector(pattern.selector); | 796 let selectors = this.parseSelector(pattern.selector); | 
| 700 if (selectors != null && selectors.length > 0) | 797 if (selectors != null && selectors.length > 0) | 
| 701 this.patterns.push({selectors, text: pattern.text}); | 798 this.patterns.push(new Pattern(selectors, pattern.text)); | 
| 702 } | 799 } | 
| 703 | 800 | 
| 704 if (this.patterns.length > 0) | 801 if (this.patterns.length > 0) | 
| 705 { | 802 { | 
| 706 this.queueFiltering(); | 803 this.queueFiltering(); | 
| 707 this.observer.observe( | 804 this.observer.observe( | 
| 708 this.document, | 805 this.document, | 
| 709 { | 806 { | 
| 710 childList: true, | 807 childList: true, | 
| 711 attributes: shouldObserveAttributes(this.patterns), | 808 attributes: shouldObserveAttributes(this.patterns), | 
| 712 characterData: shouldObserveCharacterData(this.patterns), | 809 characterData: shouldObserveCharacterData(this.patterns), | 
| 713 subtree: true | 810 subtree: true | 
| 714 } | 811 } | 
| 715 ); | 812 ); | 
| 716 this.document.addEventListener("load", this.onLoad.bind(this), true); | 813 this.document.addEventListener("load", this.onLoad.bind(this), true); | 
| 717 } | 814 } | 
| 718 } | 815 } | 
| 719 }; | 816 }; | 
| 720 | 817 | 
| 721 exports.ElemHideEmulation = ElemHideEmulation; | 818 exports.ElemHideEmulation = ElemHideEmulation; | 
| OLD | NEW |