Index: lib/content/snippets.js |
=================================================================== |
--- a/lib/content/snippets.js |
+++ b/lib/content/snippets.js |
@@ -16,16 +16,50 @@ |
*/ |
/* eslint-env webextensions */ |
/* eslint no-console: "off" */ |
"use strict"; |
/** |
+ * Escapes regular expression special characters in a string. The returned |
+ * string may be passed to the <code>RegExp</code> constructor to match the |
+ * original string. |
+ * |
+ * @param {string} string The string in which to escape special characters. |
+ * |
+ * @returns {string} A new string with the special characters escaped. |
+ */ |
+function regexEscape(string) |
+{ |
+ return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); |
+} |
+ |
+/** |
+ * Converts a given pattern to a regular expression. |
+ * |
+ * @param {string} pattern The pattern to convert. If the pattern begins and |
+ * ends with a slash (<code>/</code>), the text in between is treated as a |
+ * regular expression; otherwise the pattern is treated as raw text. |
+ * |
+ * @returns {RegExp} A <code>RegExp</code> object based on the given pattern. |
+ */ |
+function toRegExp(pattern) |
+{ |
+ if (pattern.length >= 2 && pattern[0] == "/" && |
+ pattern[pattern.length - 1] == "/") |
+ { |
+ return new RegExp(pattern.substring(1, pattern.length - 1)); |
+ } |
+ |
+ return new RegExp(regexEscape(pattern)); |
+} |
+ |
+/** |
* Injects JavaScript code into the document using a temporary |
* <code>script</code> element. |
* |
* @param {string} code The code to inject. |
* @param {Array.<function|string>} [dependencies] A list of dependencies |
* to inject along with the code. A dependency may be either a function or a |
* string containing some executable code. |
*/ |
@@ -181,46 +215,49 @@ |
exports["uabinject-defuser"] = makeInjector(uabinjectDefuser); |
/** |
* Hides any HTML element or one of its ancestors matching a CSS selector if |
* the text content of the element's shadow contains a given string. |
* |
* @param {string} search The string to look for in every HTML element's |
- * shadow. |
+ * shadow. 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. |
*/ |
function hideIfShadowContains(search, selector = "*") |
{ |
let originalAttachShadow = Element.prototype.attachShadow; |
// If there's no Element.attachShadow API present then we don't care, it must |
// be Firefox or an older version of Chrome. |
if (!originalAttachShadow) |
return; |
+ let re = toRegExp(search); |
+ |
// Mutation observers mapped to their corresponding shadow roots and their |
// hosts. |
let shadows = new WeakMap(); |
function observeShadow(mutations, observer) |
{ |
let {host, root} = shadows.get(observer) || {}; |
// Since it's a weak map, it's possible that either the element or its |
// shadow has been removed. |
if (!host || !root) |
return; |
// If the shadow contains the given text, check if the host or one of its |
// ancestors matches the selector; if a matching element is found, hide |
// it. |
- if (root.textContent.includes(search)) |
+ if (re.test(root.textContent)) |
{ |
let closest = host.closest(selector); |
if (closest) |
hideElement(closest); |
} |
} |
Object.defineProperty(Element.prototype, "attachShadow", { |
@@ -245,39 +282,44 @@ |
shadows.set(observer, {host: this, root}); |
return root; |
} |
}); |
} |
exports["hide-if-shadow-contains"] = makeInjector(hideIfShadowContains, |
+ toRegExp, regexEscape, |
hideElement); |
/** |
* 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. |
+ * @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 |
* 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); |
+ |
new MutationObserver(() => |
{ |
for (let element of document.querySelectorAll(searchSelector)) |
{ |
- if (element.textContent.includes(search)) |
+ if (re.test(element.textContent)) |
{ |
let closest = element.closest(selector); |
if (closest) |
hideElement(closest); |
} |
} |
}) |
.observe(document, {childList: true, characterData: true, subtree: true}); |