| Index: lib/content/snippets.js |
| =================================================================== |
| --- a/lib/content/snippets.js |
| +++ b/lib/content/snippets.js |
| @@ -403,50 +403,147 @@ |
| } |
| exports["hide-if-shadow-contains"] = makeInjector(hideIfShadowContains, |
| toRegExp, regexEscape, |
| hideElement); |
| /** |
| * Hides any HTML element or one of its ancestors matching a CSS selector if |
| + * it matches the provided condition. |
| + * |
| + * @param {function} match The function that provides the matching condition. |
| + * @param {string} selector The CSS selector that an HTML element must match |
| + * for it to be hidden. |
| + * @param {?string} [searchSelector] The CSS selector that an HTML element |
| + * containing the given string must match. Defaults to the value of the |
| + * <code>selector</code> argument. |
| + */ |
| +function hideIfMatches(match, selector, searchSelector) |
| +{ |
| + if (searchSelector == null) |
| + searchSelector = selector; |
| + |
| + let callback = () => |
| + { |
| + for (let element of document.querySelectorAll(searchSelector)) |
| + { |
| + if (match(element)) |
| + { |
| + let closest = element.closest(selector); |
| + if (closest) |
| + hideElement(closest); |
| + } |
| + } |
| + }; |
| + new MutationObserver(callback) |
| + .observe(document, {childList: true, characterData: true, subtree: true}); |
|
a.giammarchi
2019/04/26 13:33:58
I might make a similar observation we had before (
hub
2019/04/27 17:32:05
The current code is just refactoring of the other
a.giammarchi
2019/04/29 07:27:25
Acknowledged.
hub
2019/04/29 15:20:55
BTW I filed https://gitlab.com/eyeo/adblockplus/ad
|
| + callback(); |
| +} |
| + |
| +/** |
| + * Hides any HTML element or one of its ancestors matching a CSS selector if |
| * the text content of the element contains a given string. |
| * |
| * @param {string} search The string to look for in HTML elements. If the |
| * string begins and ends with a slash (<code>/</code>), the text in between |
| * is treated as a regular expression. |
| * @param {string} selector The CSS selector that an HTML element must match |
| * for it to be hidden. |
| - * @param {string?} [searchSelector] The CSS selector that an HTML element |
| + * @param {?string} [searchSelector] The CSS selector that an HTML element |
| * containing the given string must match. Defaults to the value of the |
| * <code>selector</code> argument. |
| */ |
| function hideIfContains(search, selector = "*", searchSelector = null) |
| { |
| - if (searchSelector == null) |
| - searchSelector = selector; |
| + let re = toRegExp(search); |
| + |
| + hideIfMatches(element => re.test(element.textContent), |
| + selector, searchSelector); |
| +} |
| + |
| +exports["hide-if-contains"] = hideIfContains; |
| + |
| +/** |
| + * Hides any HTML element matching a CSS selector if the visible text content |
| + * of the element contains a given string. |
| + * |
| + * @param {string} search The string to match to the visible text. Is considered |
| + * visible text that isn't hidden by CSS properties or other means. |
| + * If the string begins and ends with a slash (<code>/</code>), the |
| + * text in between is treated as a regular expression. |
| + * @param {string} selector The CSS selector that an HTML element must match |
| + * for it to be hidden. |
| + * @param {?string} [searchSelector] The CSS selector that an HTML element |
| + * containing the given string must match. Defaults to the value of the |
| + * <code>selector</code> argument. |
| + */ |
| +function hideIfContainsVisibleText(search, selector, searchSelector = null) |
| +{ |
| + /** |
| + * Determines if the text inside the element is visible. |
| + * @param {Element} element The element we are checking. |
| + * @param {?CSSStyleDeclaration} [style] The computed style of element. If |
| + * falsey it will be queried. |
|
a.giammarchi
2019/04/26 13:33:58
typo? did you mean `falsy` ?
hub
2019/04/27 17:32:05
Both are acceptable, and we use `falsey` elsewhere
a.giammarchi
2019/04/29 07:27:25
Acknowledged.
|
| + * @returns {bool} Whether the text is visible. |
| + */ |
| + function isTextVisible(element, style) |
| + { |
| + if (!style) |
| + style = window.getComputedStyle(element); |
| + |
| + if (style.getPropertyValue("opacity") == "0") |
| + return false; |
| + if (style.getPropertyValue("font-size") == "0px") |
| + return false; |
| + if (style.getPropertyValue("color") == |
|
a.giammarchi
2019/04/26 13:33:57
shouldn't `color` be checked against `transparent`
hub
2019/04/27 17:32:05
good point. I knew there were things I'm missing.
|
| + style.getPropertyValue("background-color")) |
| + return false; |
| + |
| + return true; |
| + } |
| + |
| + /** |
| + * Returns the visible text content from an element and its descendants. |
| + * @param {Element} element The element whose visible text we want. |
| + * @returns {string} The text that is visible. |
| + */ |
| + function getVisibleContent(element) |
| + { |
| + let style = window.getComputedStyle(element); |
| + if (style.getPropertyValue("display") == "none") |
| + return ""; |
| + let visibility = style.getPropertyValue("visibility"); |
| + if (visibility == "hidden" || visibility == "collapse") |
| + return ""; |
| + |
|
a.giammarchi
2019/04/26 13:51:06
shouldn't `clientWidth` and `clientHeight` be also
hub
2019/04/27 17:32:05
Good point. I'll look into it.
|
| + let text = ""; |
| + for (let node of element.childNodes) |
| + { |
| + switch (node.nodeType) |
| + { |
| + case Node.ELEMENT_NODE: |
| + text += getVisibleContent(node); |
| + break; |
| + case Node.TEXT_NODE: |
| + if (isTextVisible(element, style)) |
| + text += node.nodeValue; |
| + break; |
| + } |
| + } |
| + return text; |
| + } |
| let re = toRegExp(search); |
|
a.giammarchi
2019/04/26 13:33:58
this feature is overall OK but I have one concern:
hub
2019/04/27 17:32:05
Whichever effect applies to the text with CSS, the
a.giammarchi
2019/04/29 07:27:25
If I understand correctly, we might check for "Ads
hub
2019/04/29 13:03:47
I see where this is going. Good point.
Because th
a.giammarchi
2019/04/29 15:31:10
Acknowledged.
|
| - new MutationObserver(() => |
| - { |
| - for (let element of document.querySelectorAll(searchSelector)) |
| - { |
| - if (re.test(element.textContent)) |
| - { |
| - let closest = element.closest(selector); |
| - if (closest) |
| - hideElement(closest); |
| - } |
| - } |
| - }) |
| - .observe(document, {childList: true, characterData: true, subtree: true}); |
| + hideIfMatches(element => re.test(getVisibleContent(element)), |
| + selector, searchSelector); |
| } |
| -exports["hide-if-contains"] = hideIfContains; |
| +exports["hide-if-contains-visible-text"] = hideIfContainsVisibleText; |
| /** |
| * Hides any HTML element or one of its ancestors matching a CSS selector if |
| * the text content of the element contains a given string and, optionally, if |
| * the element's computed style contains a given string. |
| * |
| * @param {string} search The string to look for in HTML elements. If the |
| * string begins and ends with a slash (<code>/</code>), the text in between |