| 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 const {indexOf} = require("../coreUtils"); |   21 const {indexOf} = require("../coreUtils"); | 
|   22  |   22  | 
|   23 let MIN_INVOCATION_INTERVAL = 3000; |   23 let MIN_INVOCATION_INTERVAL = 3000; | 
|   24 const MAX_SYNCHRONOUS_PROCESSING_TIME = 50; |   24 const MAX_SYNCHRONOUS_PROCESSING_TIME = 50; | 
|   25 const abpSelectorRegexp = /:-abp-([\w-]+)\(/i; |   25 const abpSelectorRegexp = /:-abp-([\w-]+)\(/i; | 
|   26  |   26  | 
 |   27 let debugInfo = null; | 
 |   28  | 
 |   29 function setDebugMode() | 
 |   30 { | 
 |   31   debugInfo = { | 
 |   32     lastProcessedElements: new Set() | 
 |   33   }; | 
 |   34 } | 
 |   35  | 
 |   36 exports.setDebugMode = setDebugMode; | 
 |   37  | 
 |   38 function getDebugInfo() | 
 |   39 { | 
 |   40   return debugInfo; | 
 |   41 } | 
 |   42  | 
 |   43 exports.getDebugInfo = getDebugInfo; | 
 |   44  | 
|   27 function getCachedPropertyValue(object, name, defaultValueFunc = () => {}) |   45 function getCachedPropertyValue(object, name, defaultValueFunc = () => {}) | 
|   28 { |   46 { | 
|   29   let value = object[name]; |   47   let value = object[name]; | 
|   30   if (typeof value == "undefined") |   48   if (typeof value == "undefined") | 
|   31     Object.defineProperty(object, name, {value: value = defaultValueFunc()}); |   49     Object.defineProperty(object, name, {value: value = defaultValueFunc()}); | 
|   32   return value; |   50   return value; | 
|   33 } |   51 } | 
|   34  |   52  | 
|   35 /** Return position of node from parent. |   53 /** Return position of node from parent. | 
|   36  * @param {Node} node the node to find the position of. |   54  * @param {Node} node the node to find the position of. | 
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  192   try |  210   try | 
|  193   { |  211   { | 
|  194     return new RegExp(pattern, flags); |  212     return new RegExp(pattern, flags); | 
|  195   } |  213   } | 
|  196   catch (e) |  214   catch (e) | 
|  197   { |  215   { | 
|  198   } |  216   } | 
|  199   return null; |  217   return null; | 
|  200 } |  218 } | 
|  201  |  219  | 
|  202 function* evaluate(chain, index, prefix, subtree, styles) |  220 function* evaluate(chain, index, prefix, subtree, styles, targets) | 
|  203 { |  221 { | 
|  204   if (index >= chain.length) |  222   if (index >= chain.length) | 
|  205   { |  223   { | 
|  206     yield prefix; |  224     yield prefix; | 
|  207     return; |  225     return; | 
|  208   } |  226   } | 
|  209   for (let [selector, element] of |  227   for (let [selector, element] of | 
|  210        chain[index].getSelectors(prefix, subtree, styles)) |  228        chain[index].getSelectors(prefix, subtree, styles, targets)) | 
|  211   { |  229   { | 
|  212     if (selector == null) |  230     if (selector == null) | 
|  213       yield null; |  231       yield null; | 
|  214     else |  232     else | 
|  215       yield* evaluate(chain, index + 1, selector, element, styles); |  233       yield* evaluate(chain, index + 1, selector, element, styles, targets); | 
|  216   } |  234   } | 
|  217   // Just in case the getSelectors() generator above had to run some heavy |  235   // Just in case the getSelectors() generator above had to run some heavy | 
|  218   // document.querySelectorAll() call which didn't produce any results, make |  236   // document.querySelectorAll() call which didn't produce any results, make | 
|  219   // sure there is at least one point where execution can pause. |  237   // sure there is at least one point where execution can pause. | 
|  220   yield null; |  238   yield null; | 
|  221 } |  239 } | 
|  222  |  240  | 
|  223 function PlainSelector(selector) |  241 function PlainSelector(selector) | 
|  224 { |  242 { | 
|  225   this._selector = selector; |  243   this._selector = selector; | 
|  226   this.maybeDependsOnAttributes = /[#.]|\[.+\]/.test(selector); |  244   this.maybeDependsOnAttributes = /[#.]|\[.+\]/.test(selector); | 
|  227   this.dependsOnDOM = this.maybeDependsOnAttributes; |  245   this.dependsOnDOM = this.maybeDependsOnAttributes; | 
 |  246   this.maybeContainsSiblingCombinators = /[~+]/.test(selector); | 
|  228 } |  247 } | 
|  229  |  248  | 
|  230 PlainSelector.prototype = { |  249 PlainSelector.prototype = { | 
|  231   /** |  250   /** | 
|  232    * Generator function returning a pair of selector |  251    * Generator function returning a pair of selector | 
|  233    * string and subtree. |  252    * string and subtree. | 
|  234    * @param {string} prefix the prefix for the selector. |  253    * @param {string} prefix the prefix for the selector. | 
|  235    * @param {Node} subtree the subtree we work on. |  254    * @param {Node} subtree the subtree we work on. | 
|  236    * @param {StringifiedStyle[]} styles the stringified style objects. |  255    * @param {StringifiedStyle[]} styles the stringified style objects. | 
 |  256    * @param {Node[]} [targets] the nodes we are interested in. | 
|  237    */ |  257    */ | 
|  238   *getSelectors(prefix, subtree, styles) |  258   *getSelectors(prefix, subtree, styles, targets) | 
|  239   { |  259   { | 
|  240     yield [prefix + this._selector, subtree]; |  260     yield [prefix + this._selector, subtree]; | 
|  241   } |  261   } | 
|  242 }; |  262 }; | 
|  243  |  263  | 
|  244 const incompletePrefixRegexp = /[\s>+~]$/; |  264 const incompletePrefixRegexp = /[\s>+~]$/; | 
|  245  |  265  | 
|  246 function HasSelector(selectors) |  266 function HasSelector(selectors) | 
|  247 { |  267 { | 
|  248   this._innerSelectors = selectors; |  268   this._innerSelectors = selectors; | 
| (...skipping 14 matching lines...) Expand all  Loading... | 
|  263     ); |  283     ); | 
|  264   }, |  284   }, | 
|  265  |  285  | 
|  266   get maybeDependsOnAttributes() |  286   get maybeDependsOnAttributes() | 
|  267   { |  287   { | 
|  268     return this._innerSelectors.some( |  288     return this._innerSelectors.some( | 
|  269       selector => selector.maybeDependsOnAttributes |  289       selector => selector.maybeDependsOnAttributes | 
|  270     ); |  290     ); | 
|  271   }, |  291   }, | 
|  272  |  292  | 
|  273   *getSelectors(prefix, subtree, styles) |  293   *getSelectors(prefix, subtree, styles, targets) | 
|  274   { |  294   { | 
|  275     for (let element of this.getElements(prefix, subtree, styles)) |  295     for (let element of this.getElements(prefix, subtree, styles, targets)) | 
|  276       yield [makeSelector(element), element]; |  296       yield [makeSelector(element), element]; | 
|  277   }, |  297   }, | 
|  278  |  298  | 
|  279   /** |  299   /** | 
|  280    * Generator function returning selected elements. |  300    * Generator function returning selected elements. | 
|  281    * @param {string} prefix the prefix for the selector. |  301    * @param {string} prefix the prefix for the selector. | 
|  282    * @param {Node} subtree the subtree we work on. |  302    * @param {Node} subtree the subtree we work on. | 
|  283    * @param {StringifiedStyle[]} styles the stringified style objects. |  303    * @param {StringifiedStyle[]} styles the stringified style objects. | 
 |  304    * @param {Node[]} [targets] the nodes we are interested in. | 
|  284    */ |  305    */ | 
|  285   *getElements(prefix, subtree, styles) |  306   *getElements(prefix, subtree, styles, targets) | 
|  286   { |  307   { | 
|  287     let actualPrefix = (!prefix || incompletePrefixRegexp.test(prefix)) ? |  308     let actualPrefix = (!prefix || incompletePrefixRegexp.test(prefix)) ? | 
|  288         prefix + "*" : prefix; |  309         prefix + "*" : prefix; | 
|  289     let elements = scopedQuerySelectorAll(subtree, actualPrefix); |  310     let elements = scopedQuerySelectorAll(subtree, actualPrefix); | 
|  290     if (elements) |  311     if (elements) | 
|  291     { |  312     { | 
|  292       for (let element of elements) |  313       for (let element of elements) | 
|  293       { |  314       { | 
|  294         let iter = evaluate(this._innerSelectors, 0, "", element, styles); |  315         // If the element is neither an ancestor nor a descendant of one of the | 
 |  316         // targets, we can skip it. | 
 |  317         if (targets && !targets.some(target => element.contains(target) || | 
 |  318                                                target.contains(element))) | 
 |  319         { | 
 |  320           yield null; | 
 |  321           continue; | 
 |  322         } | 
 |  323  | 
 |  324         let iter = evaluate(this._innerSelectors, 0, "", element, styles, | 
 |  325                             targets); | 
|  295         for (let selector of iter) |  326         for (let selector of iter) | 
|  296         { |  327         { | 
|  297           if (selector == null) |  328           if (selector == null) | 
|  298             yield null; |  329             yield null; | 
|  299           else if (scopedQuerySelector(element, selector)) |  330           else if (scopedQuerySelector(element, selector)) | 
|  300             yield element; |  331             yield element; | 
|  301         } |  332         } | 
|  302         yield null; |  333         yield null; | 
 |  334  | 
 |  335         if (debugInfo) | 
 |  336           debugInfo.lastProcessedElements.add(element); | 
|  303       } |  337       } | 
|  304     } |  338     } | 
|  305   } |  339   } | 
|  306 }; |  340 }; | 
|  307  |  341  | 
|  308 function ContainsSelector(textContent) |  342 function ContainsSelector(textContent) | 
|  309 { |  343 { | 
|  310   this._regexp = makeRegExpParameter(textContent); |  344   this._regexp = makeRegExpParameter(textContent); | 
|  311 } |  345 } | 
|  312  |  346  | 
|  313 ContainsSelector.prototype = { |  347 ContainsSelector.prototype = { | 
|  314   dependsOnDOM: true, |  348   dependsOnDOM: true, | 
|  315   dependsOnCharacterData: true, |  349   dependsOnCharacterData: true, | 
|  316  |  350  | 
|  317   *getSelectors(prefix, subtree, styles) |  351   *getSelectors(prefix, subtree, styles, targets) | 
|  318   { |  352   { | 
|  319     for (let element of this.getElements(prefix, subtree, styles)) |  353     for (let element of this.getElements(prefix, subtree, styles, targets)) | 
|  320       yield [makeSelector(element), subtree]; |  354       yield [makeSelector(element), subtree]; | 
|  321   }, |  355   }, | 
|  322  |  356  | 
|  323   *getElements(prefix, subtree, styles) |  357   *getElements(prefix, subtree, styles, targets) | 
|  324   { |  358   { | 
|  325     let actualPrefix = (!prefix || incompletePrefixRegexp.test(prefix)) ? |  359     let actualPrefix = (!prefix || incompletePrefixRegexp.test(prefix)) ? | 
|  326         prefix + "*" : prefix; |  360         prefix + "*" : prefix; | 
|  327  |  361  | 
|  328     let elements = scopedQuerySelectorAll(subtree, actualPrefix); |  362     let elements = scopedQuerySelectorAll(subtree, actualPrefix); | 
|  329  |  363  | 
|  330     if (elements) |  364     if (elements) | 
|  331     { |  365     { | 
|  332       let lastRoot = null; |  366       let lastRoot = null; | 
|  333       for (let element of elements) |  367       for (let element of elements) | 
|  334       { |  368       { | 
|  335         // For a filter like div:-abp-contains(Hello) and a subtree like |  369         // For a filter like div:-abp-contains(Hello) and a subtree like | 
|  336         // <div id="a"><div id="b"><div id="c">Hello</div></div></div> |  370         // <div id="a"><div id="b"><div id="c">Hello</div></div></div> | 
|  337         // we're only interested in div#a |  371         // we're only interested in div#a | 
|  338         if (lastRoot && lastRoot.contains(element)) |  372         if (lastRoot && lastRoot.contains(element)) | 
|  339         { |  373         { | 
|  340           yield null; |  374           yield null; | 
|  341           continue; |  375           continue; | 
|  342         } |  376         } | 
|  343  |  377  | 
|  344         lastRoot = element; |  378         lastRoot = element; | 
|  345  |  379  | 
 |  380         if (targets && !targets.some(target => element.contains(target) || | 
 |  381                                                target.contains(element))) | 
 |  382         { | 
 |  383           yield null; | 
 |  384           continue; | 
 |  385         } | 
 |  386  | 
|  346         if (this._regexp && this._regexp.test(element.textContent)) |  387         if (this._regexp && this._regexp.test(element.textContent)) | 
|  347           yield element; |  388           yield element; | 
|  348         else |  389         else | 
|  349           yield null; |  390           yield null; | 
 |  391  | 
 |  392         if (debugInfo) | 
 |  393           debugInfo.lastProcessedElements.add(element); | 
|  350       } |  394       } | 
|  351     } |  395     } | 
|  352   } |  396   } | 
|  353 }; |  397 }; | 
|  354  |  398  | 
|  355 function PropsSelector(propertyExpression) |  399 function PropsSelector(propertyExpression) | 
|  356 { |  400 { | 
|  357   let regexpString; |  401   let regexpString; | 
|  358   if (propertyExpression.length >= 2 && propertyExpression[0] == "/" && |  402   if (propertyExpression.length >= 2 && propertyExpression[0] == "/" && | 
|  359       propertyExpression[propertyExpression.length - 1] == "/") |  403       propertyExpression[propertyExpression.length - 1] == "/") | 
| (...skipping 21 matching lines...) Expand all  Loading... | 
|  381           { |  425           { | 
|  382             subSelector = subSelector.substr(1); |  426             subSelector = subSelector.substr(1); | 
|  383           } |  427           } | 
|  384           let idx = subSelector.lastIndexOf("::"); |  428           let idx = subSelector.lastIndexOf("::"); | 
|  385           if (idx != -1) |  429           if (idx != -1) | 
|  386             subSelector = subSelector.substr(0, idx); |  430             subSelector = subSelector.substr(0, idx); | 
|  387           yield prefix + subSelector; |  431           yield prefix + subSelector; | 
|  388         } |  432         } | 
|  389   }, |  433   }, | 
|  390  |  434  | 
|  391   *getSelectors(prefix, subtree, styles) |  435   *getSelectors(prefix, subtree, styles, targets) | 
|  392   { |  436   { | 
|  393     for (let selector of this.findPropsSelectors(styles, prefix, this._regexp)) |  437     for (let selector of this.findPropsSelectors(styles, prefix, this._regexp)) | 
|  394       yield [selector, subtree]; |  438       yield [selector, subtree]; | 
|  395   } |  439   } | 
|  396 }; |  440 }; | 
|  397  |  441  | 
|  398 function Pattern(selectors, text) |  442 function Pattern(selectors, text) | 
|  399 { |  443 { | 
|  400   this.selectors = selectors; |  444   this.selectors = selectors; | 
|  401   this.text = text; |  445   this.text = text; | 
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  447   get dependsOnCharacterData() |  491   get dependsOnCharacterData() | 
|  448   { |  492   { | 
|  449     // Observe changes to character data only if there's a contains selector in |  493     // Observe changes to character data only if there's a contains selector in | 
|  450     // one of the patterns. |  494     // one of the patterns. | 
|  451     return getCachedPropertyValue( |  495     return getCachedPropertyValue( | 
|  452       this, "_dependsOnCharacterData", |  496       this, "_dependsOnCharacterData", | 
|  453       () => this.selectors.some(selector => selector.dependsOnCharacterData) |  497       () => this.selectors.some(selector => selector.dependsOnCharacterData) | 
|  454     ); |  498     ); | 
|  455   }, |  499   }, | 
|  456  |  500  | 
 |  501   get maybeContainsSiblingCombinators() | 
 |  502   { | 
 |  503     return getCachedPropertyValue( | 
 |  504       this, "_maybeContainsSiblingCombinators", | 
 |  505       () => this.selectors.some(selector => | 
 |  506                                 selector.maybeContainsSiblingCombinators) | 
 |  507     ); | 
 |  508   }, | 
 |  509  | 
|  457   matchesMutationTypes(mutationTypes) |  510   matchesMutationTypes(mutationTypes) | 
|  458   { |  511   { | 
|  459     let mutationTypeMatchMap = getCachedPropertyValue( |  512     let mutationTypeMatchMap = getCachedPropertyValue( | 
|  460       this, "_mutationTypeMatchMap", |  513       this, "_mutationTypeMatchMap", | 
|  461       () => new Map([ |  514       () => new Map([ | 
|  462         // All types of DOM-dependent patterns are affected by mutations of |  515         // All types of DOM-dependent patterns are affected by mutations of | 
|  463         // type "childList". |  516         // type "childList". | 
|  464         ["childList", true], |  517         ["childList", true], | 
|  465         ["attributes", this.maybeDependsOnAttributes], |  518         ["attributes", this.maybeDependsOnAttributes], | 
|  466         ["characterData", this.dependsOnCharacterData] |  519         ["characterData", this.dependsOnCharacterData] | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
|  487  |  540  | 
|  488     // There are only 3 types of mutations: "attributes", "characterData", and |  541     // There are only 3 types of mutations: "attributes", "characterData", and | 
|  489     // "childList". |  542     // "childList". | 
|  490     if (types.size == 3) |  543     if (types.size == 3) | 
|  491       break; |  544       break; | 
|  492   } |  545   } | 
|  493  |  546  | 
|  494   return types; |  547   return types; | 
|  495 } |  548 } | 
|  496  |  549  | 
 |  550 function extractMutationTargets(mutations) | 
 |  551 { | 
 |  552   if (!mutations) | 
 |  553     return null; | 
 |  554  | 
 |  555   let targets = new Set(); | 
 |  556  | 
 |  557   for (let mutation of mutations) | 
 |  558   { | 
 |  559     if (mutation.type == "childList") | 
 |  560     { | 
 |  561       // When new nodes are added, we're interested in the added nodes rather | 
 |  562       // than the parent. | 
 |  563       for (let node of mutation.addedNodes) | 
 |  564         targets.add(node); | 
 |  565     } | 
 |  566     else | 
 |  567     { | 
 |  568       targets.add(mutation.target); | 
 |  569     } | 
 |  570   } | 
 |  571  | 
 |  572   return [...targets]; | 
 |  573 } | 
 |  574  | 
|  497 function filterPatterns(patterns, {stylesheets, mutations}) |  575 function filterPatterns(patterns, {stylesheets, mutations}) | 
|  498 { |  576 { | 
|  499   if (!stylesheets && !mutations) |  577   if (!stylesheets && !mutations) | 
|  500     return patterns.slice(); |  578     return patterns.slice(); | 
|  501  |  579  | 
|  502   let mutationTypes = mutations ? extractMutationTypes(mutations) : null; |  580   let mutationTypes = mutations ? extractMutationTypes(mutations) : null; | 
|  503  |  581  | 
|  504   return patterns.filter( |  582   return patterns.filter( | 
|  505     pattern => (stylesheets && pattern.dependsOnStyles) || |  583     pattern => (stylesheets && pattern.dependsOnStyles) || | 
|  506                (mutations && pattern.dependsOnDOM && |  584                (mutations && pattern.dependsOnDOM && | 
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  614    * @param {MutationRecord[]} [mutations] |  692    * @param {MutationRecord[]} [mutations] | 
|  615    *    The list of DOM mutations that have been applied to the document and |  693    *    The list of DOM mutations that have been applied to the document and | 
|  616    *    made reprocessing necessary. This parameter shouldn't be passed in for |  694    *    made reprocessing necessary. This parameter shouldn't be passed in for | 
|  617    *    the initial processing, the entire document will be considered |  695    *    the initial processing, the entire document will be considered | 
|  618    *    then and all rules, including the ones not dependent on the DOM. |  696    *    then and all rules, including the ones not dependent on the DOM. | 
|  619    * @param {function} [done] |  697    * @param {function} [done] | 
|  620    *    Callback to call when done. |  698    *    Callback to call when done. | 
|  621    */ |  699    */ | 
|  622   _addSelectors(stylesheets, mutations, done) |  700   _addSelectors(stylesheets, mutations, done) | 
|  623   { |  701   { | 
 |  702     if (debugInfo) | 
 |  703       debugInfo.lastProcessedElements.clear(); | 
 |  704  | 
|  624     let patterns = filterPatterns(this.patterns, {stylesheets, mutations}); |  705     let patterns = filterPatterns(this.patterns, {stylesheets, mutations}); | 
|  625  |  706  | 
|  626     let selectors = []; |  707     let selectors = []; | 
|  627     let selectorFilters = []; |  708     let selectorFilters = []; | 
|  628  |  709  | 
|  629     let elements = []; |  710     let elements = []; | 
|  630     let elementFilters = []; |  711     let elementFilters = []; | 
|  631  |  712  | 
|  632     let cssStyles = []; |  713     let cssStyles = []; | 
|  633  |  714  | 
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  671  |  752  | 
|  672       for (let rule of rules) |  753       for (let rule of rules) | 
|  673       { |  754       { | 
|  674         if (rule.type != rule.STYLE_RULE) |  755         if (rule.type != rule.STYLE_RULE) | 
|  675           continue; |  756           continue; | 
|  676  |  757  | 
|  677         cssStyles.push(stringifyStyle(rule)); |  758         cssStyles.push(stringifyStyle(rule)); | 
|  678       } |  759       } | 
|  679     } |  760     } | 
|  680  |  761  | 
 |  762     let targets = extractMutationTargets(mutations); | 
 |  763  | 
|  681     let pattern = null; |  764     let pattern = null; | 
|  682     let generator = null; |  765     let generator = null; | 
|  683  |  766  | 
|  684     let processPatterns = () => |  767     let processPatterns = () => | 
|  685     { |  768     { | 
|  686       let cycleStart = performance.now(); |  769       let cycleStart = performance.now(); | 
|  687  |  770  | 
|  688       if (!pattern) |  771       if (!pattern) | 
|  689       { |  772       { | 
|  690         if (!patterns.length) |  773         if (!patterns.length) | 
|  691         { |  774         { | 
|  692           if (selectors.length > 0) |  775           if (selectors.length > 0) | 
|  693             this.addSelectorsFunc(selectors, selectorFilters); |  776             this.addSelectorsFunc(selectors, selectorFilters); | 
|  694           if (elements.length > 0) |  777           if (elements.length > 0) | 
|  695             this.hideElemsFunc(elements, elementFilters); |  778             this.hideElemsFunc(elements, elementFilters); | 
|  696           if (typeof done == "function") |  779           if (typeof done == "function") | 
|  697             done(); |  780             done(); | 
|  698           return; |  781           return; | 
|  699         } |  782         } | 
|  700  |  783  | 
|  701         pattern = patterns.shift(); |  784         pattern = patterns.shift(); | 
|  702  |  785  | 
 |  786         let evaluationTargets = targets; | 
 |  787  | 
 |  788         // If the pattern appears to contain any sibling combinators, we can't | 
 |  789         // easily optimize based on the mutation targets. Since this is a | 
 |  790         // special case, skip the optimization. By setting it to null here we | 
 |  791         // make sure we process the entire DOM. | 
 |  792         if (pattern.maybeContainsSiblingCombinators) | 
 |  793           evaluationTargets = null; | 
 |  794  | 
 |  795         // Ignore mutation targets when using style sheets, because we may have | 
 |  796         // to update all the CSS selectors. | 
 |  797         if (!this.useInlineStyles) | 
 |  798           evaluationTargets = null; | 
 |  799  | 
|  703         generator = evaluate(pattern.selectors, 0, "", |  800         generator = evaluate(pattern.selectors, 0, "", | 
|  704                              this.document, cssStyles); |  801                              this.document, cssStyles, evaluationTargets); | 
|  705       } |  802       } | 
|  706       for (let selector of generator) |  803       for (let selector of generator) | 
|  707       { |  804       { | 
|  708         if (selector != null) |  805         if (selector != null) | 
|  709         { |  806         { | 
|  710           if (!this.useInlineStyles) |  807           if (!this.useInlineStyles) | 
|  711           { |  808           { | 
|  712             selectors.push(selector); |  809             selectors.push(selector); | 
|  713             selectorFilters.push(pattern.text); |  810             selectorFilters.push(pattern.text); | 
|  714           } |  811           } | 
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  834  |  931  | 
|  835   onLoad(event) |  932   onLoad(event) | 
|  836   { |  933   { | 
|  837     let stylesheet = event.target.sheet; |  934     let stylesheet = event.target.sheet; | 
|  838     if (stylesheet) |  935     if (stylesheet) | 
|  839       this.queueFiltering([stylesheet]); |  936       this.queueFiltering([stylesheet]); | 
|  840   }, |  937   }, | 
|  841  |  938  | 
|  842   observe(mutations) |  939   observe(mutations) | 
|  843   { |  940   { | 
 |  941     if (debugInfo) | 
 |  942     { | 
 |  943       // In debug mode, filter out any mutations likely done by us | 
 |  944       // (i.e. style="display: none !important"). This makes it easier to | 
 |  945       // observe how the code responds to DOM mutations. | 
 |  946       // | 
 |  947       // Note: This also creates the potential for "heisenbugs", but as long as | 
 |  948       // this is the only instance it should be manageable. | 
 |  949       mutations = mutations.filter( | 
 |  950         ({type, attributeName, target: {style: newValue}, oldValue}) => | 
 |  951         !(type == "attributes" && attributeName == "style" && | 
 |  952           newValue.display == "none" && oldValue.display != "none") | 
 |  953       ); | 
 |  954  | 
 |  955       if (mutations.length == 0) | 
 |  956         return; | 
 |  957     } | 
 |  958  | 
|  844     this.queueFiltering(null, mutations); |  959     this.queueFiltering(null, mutations); | 
|  845   }, |  960   }, | 
|  846  |  961  | 
|  847   apply(patterns) |  962   apply(patterns) | 
|  848   { |  963   { | 
|  849     this.patterns = []; |  964     this.patterns = []; | 
|  850     for (let pattern of patterns) |  965     for (let pattern of patterns) | 
|  851     { |  966     { | 
|  852       let selectors = this.parseSelector(pattern.selector); |  967       let selectors = this.parseSelector(pattern.selector); | 
|  853       if (selectors != null && selectors.length > 0) |  968       if (selectors != null && selectors.length > 0) | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
|  865           characterData: shouldObserveCharacterData(this.patterns), |  980           characterData: shouldObserveCharacterData(this.patterns), | 
|  866           subtree: true |  981           subtree: true | 
|  867         } |  982         } | 
|  868       ); |  983       ); | 
|  869       this.document.addEventListener("load", this.onLoad.bind(this), true); |  984       this.document.addEventListener("load", this.onLoad.bind(this), true); | 
|  870     } |  985     } | 
|  871   } |  986   } | 
|  872 }; |  987 }; | 
|  873  |  988  | 
|  874 exports.ElemHideEmulation = ElemHideEmulation; |  989 exports.ElemHideEmulation = ElemHideEmulation; | 
| OLD | NEW |