Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: lib/content/snippets.js

Issue 29852577: Issue 6847 - Add regular expression support to snippets (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Created Aug. 11, 2018, 4:53 a.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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});
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld