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

Side by Side Diff: lib/content/elemHideEmulation.js

Issue 30024560: Issue 7450 - Implement hide-if-contains-visible-text snippet (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Created March 6, 2019, 3:21 p.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 | test/browser/elemHideEmulation.js » ('j') | 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
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 } 335 }
336 yield null; 336 yield null;
337 337
338 if (testInfo) 338 if (testInfo)
339 testInfo.lastProcessedElements.add(element); 339 testInfo.lastProcessedElements.add(element);
340 } 340 }
341 } 341 }
342 } 342 }
343 } 343 }
344 344
345 /**
346 * Determine if the text inside the element is visible.
347 * @param {Element} element the leaf element we are checking.
348 * @returns {bool} whether the text is visible.
349 */
350 function isTextVisible(element)
351 {
352 let style = window.getComputedStyle(element);
hub 2019/03/06 16:34:11 I wonder if it is worth complexifying the code to
Manish Jethani 2019/03/12 12:24:09 If you have `<div style="display: none"><div>Spons
hub 2019/03/14 10:12:40 I think we can constrain to "visible within the sp
Manish Jethani 2019/03/14 11:36:33 OK, perhaps I can change my example to this: `<art
hub 2019/03/20 14:19:55 Actually I believe it should not hide it. But it d
hub 2019/03/20 16:31:11 This is handled properly now.
353
354 if (style.getPropertyValue("opacity") == "0")
355 return false;
356 if (style.getPropertyValue("font-size") == "0px")
357 return false;
358 let visibility = style.getPropertyValue("visibility");
359 if (visibility == "hidden" || visibility == "collapse")
360 return false;
361 if (style.getPropertyValue("display") == "none")
362 return false;
363 if (style.getPropertyValue("color") ==
364 style.getPropertyValue("background-color"))
365 return false;
366
367 return true;
368 }
369
370 /**
371 * Returns the visible text content from an element and its children.
372 * @param {Element} element the element whose visible text we want.
373 * @returns {String} the text that is visible.
374 */
375 function getVisibleContent(element)
Manish Jethani 2019/03/12 08:44:01 Instead of doing all this, why not just use the `i
hub 2019/03/12 09:29:29 innerText doesn't know about opacity, 0 sized font
Manish Jethani 2019/03/12 12:24:09 Acknowledged.
376 {
377 let text = "";
378 for (let node of element.childNodes)
379 {
380 switch (node.nodeType)
381 {
382 case Node.ELEMENT_NODE:
383 text += getVisibleContent(node);
384 break;
385 case Node.TEXT_NODE:
386 if (isTextVisible(element))
387 text += node.nodeValue;
388 break;
389 }
390 }
391 return text;
392 }
393
345 class ContainsSelector 394 class ContainsSelector
346 { 395 {
347 constructor(textContent) 396 constructor(textContent, onlyVisible = false)
348 { 397 {
349 this.dependsOnDOM = true; 398 this.dependsOnDOM = true;
350 this.dependsOnCharacterData = true; 399 this.dependsOnCharacterData = true;
351 400
401 this._onlyVisible = onlyVisible;
352 this._regexp = makeRegExpParameter(textContent); 402 this._regexp = makeRegExpParameter(textContent);
353 } 403 }
354 404
355 *getSelectors(prefix, subtree, styles, targets) 405 *getSelectors(prefix, subtree, styles, targets)
356 { 406 {
357 for (let element of this.getElements(prefix, subtree, styles, targets)) 407 for (let element of this.getElements(prefix, subtree, styles, targets))
358 yield [makeSelector(element), subtree]; 408 yield [makeSelector(element), subtree];
359 } 409 }
360 410
361 *getElements(prefix, subtree, styles, targets) 411 *getElements(prefix, subtree, styles, targets)
362 { 412 {
363 let actualPrefix = (!prefix || incompletePrefixRegexp.test(prefix)) ? 413 let actualPrefix = (!prefix || incompletePrefixRegexp.test(prefix)) ?
364 prefix + "*" : prefix; 414 prefix + "*" : prefix;
365 415
366 let elements = scopedQuerySelectorAll(subtree, actualPrefix); 416 let elements = scopedQuerySelectorAll(subtree, actualPrefix);
367 417
368 if (elements) 418 if (!elements)
419 return;
420
421 if (this._onlyVisible)
422 {
423 for (let element of elements)
424 {
425 let visibleContent = getVisibleContent(element);
426 if (this._regexp && this._regexp.test(visibleContent))
427 yield element;
428 else
429 yield null;
430 }
431 }
432 else
369 { 433 {
370 let lastRoot = null; 434 let lastRoot = null;
371 for (let element of elements) 435 for (let element of elements)
372 { 436 {
373 // For a filter like div:-abp-contains(Hello) and a subtree like 437 // For a filter like div:-abp-contains(Hello) and a subtree like
374 // <div id="a"><div id="b"><div id="c">Hello</div></div></div> 438 // <div id="a"><div id="b"><div id="c">Hello</div></div></div>
375 // we're only interested in div#a 439 // we're only interested in div#a
376 if (lastRoot && lastRoot.contains(element)) 440 if (lastRoot && lastRoot.contains(element))
377 { 441 {
378 yield null; 442 yield null;
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after
659 selectors.push(new PropsSelector(content.text)); 723 selectors.push(new PropsSelector(content.text));
660 else if (match[1] == "has") 724 else if (match[1] == "has")
661 { 725 {
662 let hasSelectors = this.parseSelector(content.text); 726 let hasSelectors = this.parseSelector(content.text);
663 if (hasSelectors == null) 727 if (hasSelectors == null)
664 return null; 728 return null;
665 selectors.push(new HasSelector(hasSelectors)); 729 selectors.push(new HasSelector(hasSelectors));
666 } 730 }
667 else if (match[1] == "contains") 731 else if (match[1] == "contains")
668 selectors.push(new ContainsSelector(content.text)); 732 selectors.push(new ContainsSelector(content.text));
733 else if (match[1] == "contains-visible")
734 selectors.push(new ContainsSelector(content.text, true));
669 else 735 else
670 { 736 {
671 // this is an error, can't parse selector. 737 // this is an error, can't parse selector.
672 console.error(new SyntaxError("Failed to parse Adblock Plus " + 738 console.error(new SyntaxError("Failed to parse Adblock Plus " +
673 `selector ${selector}, invalid ` + 739 `selector ${selector}, invalid ` +
674 `pseudo-class :-abp-${match[1]}().`)); 740 `pseudo-class :-abp-${match[1]}().`));
675 return null; 741 return null;
676 } 742 }
677 743
678 let suffix = this.parseSelector(selector.substring(content.end + 1)); 744 let suffix = this.parseSelector(selector.substring(content.end + 1));
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
964 characterData: shouldObserveCharacterData(this.patterns), 1030 characterData: shouldObserveCharacterData(this.patterns),
965 subtree: true 1031 subtree: true
966 } 1032 }
967 ); 1033 );
968 this.document.addEventListener("load", this.onLoad.bind(this), true); 1034 this.document.addEventListener("load", this.onLoad.bind(this), true);
969 } 1035 }
970 } 1036 }
971 } 1037 }
972 1038
973 exports.ElemHideEmulation = ElemHideEmulation; 1039 exports.ElemHideEmulation = ElemHideEmulation;
OLDNEW
« no previous file with comments | « no previous file | test/browser/elemHideEmulation.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld