| 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 (typeof value == "undefined") | 
 |   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) | 
|  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 |