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

Side by Side 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.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 /* eslint-env webextensions */ 18 /* eslint-env webextensions */
19 /* eslint no-console: "off" */ 19 /* eslint no-console: "off" */
20 20
21 "use strict"; 21 "use strict";
22 22
23 /** 23 /**
24 * Escapes regular expression special characters in a string. The returned
25 * string may be passed to the <code>RegExp</code> constructor to match the
26 * original string.
27 *
28 * @param {string} string The string in which to escape special characters.
29 *
30 * @returns {string} A new string with the special characters escaped.
31 */
32 function regexEscape(string)
33 {
34 return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
35 }
36
37 /**
38 * Converts a given pattern to a regular expression.
39 *
40 * @param {string} pattern The pattern to convert. If the pattern begins and
41 * ends with a slash (<code>/</code>), the text in between is treated as a
42 * regular expression; otherwise the pattern is treated as raw text.
43 *
44 * @returns {RegExp} A <code>RegExp</code> object based on the given pattern.
45 */
46 function toRegExp(pattern)
47 {
48 if (pattern.length >= 2 && pattern[0] == "/" &&
49 pattern[pattern.length - 1] == "/")
50 {
51 return new RegExp(pattern.substring(1, pattern.length - 1));
52 }
53
54 return new RegExp(regexEscape(pattern));
55 }
56
57 /**
24 * Injects JavaScript code into the document using a temporary 58 * Injects JavaScript code into the document using a temporary
25 * <code>script</code> element. 59 * <code>script</code> element.
26 * 60 *
27 * @param {string} code The code to inject. 61 * @param {string} code The code to inject.
28 * @param {Array.<function|string>} [dependencies] A list of dependencies 62 * @param {Array.<function|string>} [dependencies] A list of dependencies
29 * to inject along with the code. A dependency may be either a function or a 63 * to inject along with the code. A dependency may be either a function or a
30 * string containing some executable code. 64 * string containing some executable code.
31 */ 65 */
32 function injectCode(code, dependencies = []) 66 function injectCode(code, dependencies = [])
33 { 67 {
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 window.uabDetect = true; 213 window.uabDetect = true;
180 } 214 }
181 215
182 exports["uabinject-defuser"] = makeInjector(uabinjectDefuser); 216 exports["uabinject-defuser"] = makeInjector(uabinjectDefuser);
183 217
184 /** 218 /**
185 * Hides any HTML element or one of its ancestors matching a CSS selector if 219 * Hides any HTML element or one of its ancestors matching a CSS selector if
186 * the text content of the element's shadow contains a given string. 220 * the text content of the element's shadow contains a given string.
187 * 221 *
188 * @param {string} search The string to look for in every HTML element's 222 * @param {string} search The string to look for in every HTML element's
189 * shadow. 223 * shadow. If the string begins and ends with a slash (<code>/</code>), the
224 * text in between is treated as a regular expression.
190 * @param {string} selector The CSS selector that an HTML element must match 225 * @param {string} selector The CSS selector that an HTML element must match
191 * for it to be hidden. 226 * for it to be hidden.
192 */ 227 */
193 function hideIfShadowContains(search, selector = "*") 228 function hideIfShadowContains(search, selector = "*")
194 { 229 {
195 let originalAttachShadow = Element.prototype.attachShadow; 230 let originalAttachShadow = Element.prototype.attachShadow;
196 231
197 // If there's no Element.attachShadow API present then we don't care, it must 232 // If there's no Element.attachShadow API present then we don't care, it must
198 // be Firefox or an older version of Chrome. 233 // be Firefox or an older version of Chrome.
199 if (!originalAttachShadow) 234 if (!originalAttachShadow)
200 return; 235 return;
201 236
237 let re = toRegExp(search);
238
202 // Mutation observers mapped to their corresponding shadow roots and their 239 // Mutation observers mapped to their corresponding shadow roots and their
203 // hosts. 240 // hosts.
204 let shadows = new WeakMap(); 241 let shadows = new WeakMap();
205 242
206 function observeShadow(mutations, observer) 243 function observeShadow(mutations, observer)
207 { 244 {
208 let {host, root} = shadows.get(observer) || {}; 245 let {host, root} = shadows.get(observer) || {};
209 246
210 // Since it's a weak map, it's possible that either the element or its 247 // Since it's a weak map, it's possible that either the element or its
211 // shadow has been removed. 248 // shadow has been removed.
212 if (!host || !root) 249 if (!host || !root)
213 return; 250 return;
214 251
215 // If the shadow contains the given text, check if the host or one of its 252 // If the shadow contains the given text, check if the host or one of its
216 // ancestors matches the selector; if a matching element is found, hide 253 // ancestors matches the selector; if a matching element is found, hide
217 // it. 254 // it.
218 if (root.textContent.includes(search)) 255 if (re.test(root.textContent))
219 { 256 {
220 let closest = host.closest(selector); 257 let closest = host.closest(selector);
221 if (closest) 258 if (closest)
222 hideElement(closest); 259 hideElement(closest);
223 } 260 }
224 } 261 }
225 262
226 Object.defineProperty(Element.prototype, "attachShadow", { 263 Object.defineProperty(Element.prototype, "attachShadow", {
227 value(...args) 264 value(...args)
228 { 265 {
(...skipping 14 matching lines...) Expand all
243 // DOM, the mutation observer too will be freed eventually and the entry 280 // DOM, the mutation observer too will be freed eventually and the entry
244 // will be removed. 281 // will be removed.
245 shadows.set(observer, {host: this, root}); 282 shadows.set(observer, {host: this, root});
246 283
247 return root; 284 return root;
248 } 285 }
249 }); 286 });
250 } 287 }
251 288
252 exports["hide-if-shadow-contains"] = makeInjector(hideIfShadowContains, 289 exports["hide-if-shadow-contains"] = makeInjector(hideIfShadowContains,
290 toRegExp, regexEscape,
253 hideElement); 291 hideElement);
254 292
255 /** 293 /**
256 * Hides any HTML element or one of its ancestors matching a CSS selector if 294 * Hides any HTML element or one of its ancestors matching a CSS selector if
257 * the text content of the element contains a given string. 295 * the text content of the element contains a given string.
258 * 296 *
259 * @param {string} search The string to look for in HTML elements. 297 * @param {string} search The string to look for in HTML elements. If the
298 * string begins and ends with a slash (<code>/</code>), the text in between
299 * is treated as a regular expression.
260 * @param {string} selector The CSS selector that an HTML element must match 300 * @param {string} selector The CSS selector that an HTML element must match
261 * for it to be hidden. 301 * for it to be hidden.
262 * @param {string?} [searchSelector] The CSS selector that an HTML element 302 * @param {string?} [searchSelector] The CSS selector that an HTML element
263 * containing the given string must match. Defaults to the value of the 303 * containing the given string must match. Defaults to the value of the
264 * <code>selector</code> argument. 304 * <code>selector</code> argument.
265 */ 305 */
266 function hideIfContains(search, selector = "*", searchSelector = null) 306 function hideIfContains(search, selector = "*", searchSelector = null)
267 { 307 {
268 if (searchSelector == null) 308 if (searchSelector == null)
269 searchSelector = selector; 309 searchSelector = selector;
270 310
311 let re = toRegExp(search);
312
271 new MutationObserver(() => 313 new MutationObserver(() =>
272 { 314 {
273 for (let element of document.querySelectorAll(searchSelector)) 315 for (let element of document.querySelectorAll(searchSelector))
274 { 316 {
275 if (element.textContent.includes(search)) 317 if (re.test(element.textContent))
276 { 318 {
277 let closest = element.closest(selector); 319 let closest = element.closest(selector);
278 if (closest) 320 if (closest)
279 hideElement(closest); 321 hideElement(closest);
280 } 322 }
281 } 323 }
282 }) 324 })
283 .observe(document, {childList: true, characterData: true, subtree: true}); 325 .observe(document, {childList: true, characterData: true, subtree: true});
284 } 326 }
285 327
(...skipping 22 matching lines...) Expand all
308 // We don't have the location of the element in its former parent, 350 // We don't have the location of the element in its former parent,
309 // but it's usually OK to just add it at the end. 351 // but it's usually OK to just add it at the end.
310 mutation.target.appendChild(node); 352 mutation.target.appendChild(node);
311 } 353 }
312 } 354 }
313 } 355 }
314 }); 356 });
315 } 357 }
316 358
317 exports.readd = readd; 359 exports.readd = readd;
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld