| Index: lib/content/elemHideEmulation.js |
| =================================================================== |
| --- a/lib/content/elemHideEmulation.js |
| +++ b/lib/content/elemHideEmulation.js |
| @@ -141,16 +141,17 @@ |
| // document.querySelectorAll() call which didn't produce any results, make |
| // sure there is at least one point where execution can pause. |
| yield null; |
| } |
| function PlainSelector(selector) |
| { |
| this._selector = selector; |
| + this.maybeDependsOnAttributes = /\[.+\]/.test(selector); |
|
hub
2017/10/23 13:18:55
What about the changes of `class` and `id` ?
Manish Jethani
2017/10/23 22:52:07
Done.
|
| } |
| PlainSelector.prototype = { |
| /** |
| * Generator function returning a pair of selector |
| * string and subtree. |
| * @param {string} prefix the prefix for the selector. |
| * @param {Node} subtree the subtree we work on. |
| @@ -173,16 +174,30 @@ |
| HasSelector.prototype = { |
| requiresHiding: true, |
| get dependsOnStyles() |
| { |
| return this._innerSelectors.some(selector => selector.dependsOnStyles); |
| }, |
| + get dependsOnCharacterData() |
| + { |
| + return this._innerSelectors.some( |
| + selector => selector.dependsOnCharacterData |
| + ); |
| + }, |
| + |
| + get maybeDependsOnAttributes() |
| + { |
| + return this._innerSelectors.some( |
| + selector => selector.maybeDependsOnAttributes |
| + ); |
| + }, |
| + |
| *getSelectors(prefix, subtree, styles) |
| { |
| for (let element of this.getElements(prefix, subtree, styles)) |
| yield [makeSelector(element, ""), element]; |
| }, |
| /** |
| * Generator function returning selected elements. |
| @@ -224,16 +239,17 @@ |
| function ContainsSelector(textContent) |
| { |
| this._text = textContent; |
| } |
| ContainsSelector.prototype = { |
| requiresHiding: true, |
| + dependsOnCharacterData: true, |
| *getSelectors(prefix, subtree, stylesheet) |
| { |
| for (let element of this.getElements(prefix, subtree, stylesheet)) |
| yield [makeSelector(element, ""), subtree]; |
| }, |
| *getElements(prefix, subtree, stylesheet) |
| @@ -297,16 +313,43 @@ |
| }; |
| function isSelectorHidingOnlyPattern(pattern) |
| { |
| return pattern.selectors.some(s => s.preferHideWithSelector) && |
| !pattern.selectors.some(s => s.requiresHiding); |
| } |
| +function shouldObserveAttributes(patterns) |
| +{ |
| + // Observe changes to attributes if either there's a plain selector that |
| + // looks like an attribute selector in one of the patterns |
| + // (e.g. "a[href='https://example.com/']") |
| + // or there's a properties selector nested inside a has selector |
| + // (e.g. "div:-abp-has(:-abp-properties(color: blue))") |
| + return patterns.some( |
| + pattern => pattern.selectors.some( |
| + selector => selector.maybeDependsOnAttributes || |
| + selector instanceof HasSelector && |
| + selector.dependsOnStyles |
| + ) |
| + ); |
| +} |
| + |
| +function shouldObserveCharacterData(patterns) |
| +{ |
| + // Observe changes to character data only if there's a contains selector in |
| + // one of the patterns. |
| + return patterns.some( |
| + pattern => pattern.selectors.some( |
| + selector => selector.dependsOnCharacterData |
| + ) |
| + ); |
| +} |
| + |
| function ElemHideEmulation(addSelectorsFunc, hideElemsFunc) |
| { |
| this.document = document; |
| this.addSelectorsFunc = addSelectorsFunc; |
| this.hideElemsFunc = hideElemsFunc; |
| this.observer = new MutationObserver(this.observe.bind(this)); |
| } |
| @@ -582,18 +625,18 @@ |
| if (this.patterns.length > 0) |
| { |
| this.queueFiltering(); |
| this.observer.observe( |
| this.document, |
| { |
| childList: true, |
| - attributes: true, |
| - characterData: true, |
| + attributes: shouldObserveAttributes(this.patterns), |
| + characterData: shouldObserveCharacterData(this.patterns), |
| subtree: true |
| } |
| ); |
| this.document.addEventListener("load", this.onLoad.bind(this), true); |
| } |
| } |
| }; |