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

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

Issue 29807560: Issue 6745 - Prefer strict equality operator (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Created June 14, 2018, 4:11 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 | « lib/common.js ('k') | lib/downloader.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
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 "use strict"; 18 "use strict";
19 19
20 const {textToRegExp, filterToRegExp, splitSelector} = require("../common"); 20 const {textToRegExp, filterToRegExp, splitSelector} = require("../common");
21 const {indexOf} = require("../coreUtils"); 21 const {indexOf} = require("../coreUtils");
22 22
23 let MIN_INVOCATION_INTERVAL = 3000; 23 let MIN_INVOCATION_INTERVAL = 3000;
24 const MAX_SYNCHRONOUS_PROCESSING_TIME = 50; 24 const MAX_SYNCHRONOUS_PROCESSING_TIME = 50;
25 const abpSelectorRegexp = /:-abp-([\w-]+)\(/i; 25 const abpSelectorRegexp = /:-abp-([\w-]+)\(/i;
26 26
27 function getCachedPropertyValue(object, name, defaultValueFunc = () => {}) 27 function getCachedPropertyValue(object, name, defaultValueFunc = () => {})
28 { 28 {
29 let value = object[name]; 29 let value = object[name];
30 if (typeof value == "undefined") 30 if (typeof value === "undefined")
31 Object.defineProperty(object, name, {value: value = defaultValueFunc()}); 31 Object.defineProperty(object, name, {value: value = defaultValueFunc()});
32 return value; 32 return value;
33 } 33 }
34 34
35 /** Return position of node from parent. 35 /** Return position of node from parent.
36 * @param {Node} node the node to find the position of. 36 * @param {Node} node the node to find the position of.
37 * @return {number} One-based index like for :nth-child(), or 0 on error. 37 * @return {number} One-based index like for :nth-child(), or 0 on error.
38 */ 38 */
39 function positionInParent(node) 39 function positionInParent(node)
40 { 40 {
41 return indexOf(node.parentNode.children, node) + 1; 41 return indexOf(node.parentNode.children, node) + 1;
42 } 42 }
43 43
44 function makeSelector(node, selector = "") 44 function makeSelector(node, selector = "")
45 { 45 {
46 if (node == null) 46 if (!node)
47 return null; 47 return null;
48 if (!node.parentElement) 48 if (!node.parentElement)
49 { 49 {
50 let newSelector = ":root"; 50 let newSelector = ":root";
51 if (selector) 51 if (selector)
52 newSelector += " > " + selector; 52 newSelector += " > " + selector;
53 return newSelector; 53 return newSelector;
54 } 54 }
55 let idx = positionInParent(node); 55 let idx = positionInParent(node);
56 if (idx > 0) 56 if (idx > 0)
57 { 57 {
58 let newSelector = `${node.tagName}:nth-child(${idx})`; 58 let newSelector = `${node.tagName}:nth-child(${idx})`;
59 if (selector) 59 if (selector)
60 newSelector += " > " + selector; 60 newSelector += " > " + selector;
61 return makeSelector(node.parentElement, newSelector); 61 return makeSelector(node.parentElement, newSelector);
62 } 62 }
63 63
64 return selector; 64 return selector;
65 } 65 }
66 66
67 function parseSelectorContent(content, startIndex) 67 function parseSelectorContent(content, startIndex)
68 { 68 {
69 let parens = 1; 69 let parens = 1;
70 let quote = null; 70 let quote = null;
71 let i = startIndex; 71 let i = startIndex;
72 for (; i < content.length; i++) 72 for (; i < content.length; i++)
73 { 73 {
74 let c = content[i]; 74 let c = content[i];
75 if (c == "\\") 75 if (c === "\\")
76 { 76 {
77 // Ignore escaped characters 77 // Ignore escaped characters
78 i++; 78 i++;
79 } 79 }
80 else if (quote) 80 else if (quote)
81 { 81 {
82 if (c == quote) 82 if (c === quote)
83 quote = null; 83 quote = null;
84 } 84 }
85 else if (c == "'" || c == '"') 85 else if (c === "'" || c === '"')
86 quote = c; 86 quote = c;
87 else if (c == "(") 87 else if (c === "(")
88 parens++; 88 parens++;
89 else if (c == ")") 89 else if (c === ")")
90 { 90 {
91 parens--; 91 parens--;
92 if (parens == 0) 92 if (parens === 0)
93 break; 93 break;
94 } 94 }
95 } 95 }
96 96
97 if (parens > 0) 97 if (parens > 0)
98 return null; 98 return null;
99 return {text: content.substring(startIndex, i), end: i}; 99 return {text: content.substring(startIndex, i), end: i};
100 } 100 }
101 101
102 /** Stringified style objects 102 /** Stringified style objects
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 148
149 /** 149 /**
150 * Query selector. If it is relative, will try :scope. 150 * Query selector. If it is relative, will try :scope.
151 * @param {Node} subtree the element to query selector 151 * @param {Node} subtree the element to query selector
152 * @param {string} selector the selector to query 152 * @param {string} selector the selector to query
153 * @param {bool} [all=false] true to perform querySelectorAll() 153 * @param {bool} [all=false] true to perform querySelectorAll()
154 * @returns {?(Node|NodeList)} result of the query. null in case of error. 154 * @returns {?(Node|NodeList)} result of the query. null in case of error.
155 */ 155 */
156 function scopedQuerySelector(subtree, selector, all) 156 function scopedQuerySelector(subtree, selector, all)
157 { 157 {
158 if (selector[0] == ">") 158 if (selector[0] === ">")
159 { 159 {
160 selector = ":scope" + selector; 160 selector = ":scope" + selector;
161 if (scopeSupported) 161 if (scopeSupported)
162 { 162 {
163 return all ? subtree.querySelectorAll(selector) : 163 return all ? subtree.querySelectorAll(selector) :
164 subtree.querySelector(selector); 164 subtree.querySelector(selector);
165 } 165 }
166 if (scopeSupported == null) 166 if (scopeSupported === null)
167 return tryQuerySelector(subtree, selector, all); 167 return tryQuerySelector(subtree, selector, all);
168 return null; 168 return null;
169 } 169 }
170 return all ? subtree.querySelectorAll(selector) : 170 return all ? subtree.querySelectorAll(selector) :
171 subtree.querySelector(selector); 171 subtree.querySelector(selector);
172 } 172 }
173 173
174 function scopedQuerySelectorAll(subtree, selector) 174 function scopedQuerySelectorAll(subtree, selector)
175 { 175 {
176 return scopedQuerySelector(subtree, selector, true); 176 return scopedQuerySelector(subtree, selector, true);
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 else 348 else
349 yield null; 349 yield null;
350 } 350 }
351 } 351 }
352 } 352 }
353 }; 353 };
354 354
355 function PropsSelector(propertyExpression) 355 function PropsSelector(propertyExpression)
356 { 356 {
357 let regexpString; 357 let regexpString;
358 if (propertyExpression.length >= 2 && propertyExpression[0] == "/" && 358 if (propertyExpression.length >= 2 && propertyExpression[0] === "/" &&
359 propertyExpression[propertyExpression.length - 1] == "/") 359 propertyExpression[propertyExpression.length - 1] === "/")
360 { 360 {
361 regexpString = propertyExpression.slice(1, -1) 361 regexpString = propertyExpression.slice(1, -1)
362 .replace("\\7B ", "{").replace("\\7D ", "}"); 362 .replace("\\7B ", "{").replace("\\7D ", "}");
363 } 363 }
364 else 364 else
365 regexpString = filterToRegExp(propertyExpression); 365 regexpString = filterToRegExp(propertyExpression);
366 366
367 this._regexp = new RegExp(regexpString, "i"); 367 this._regexp = new RegExp(regexpString, "i");
368 } 368 }
369 369
370 PropsSelector.prototype = { 370 PropsSelector.prototype = {
371 dependsOnStyles: true, 371 dependsOnStyles: true,
372 372
373 *findPropsSelectors(styles, prefix, regexp) 373 *findPropsSelectors(styles, prefix, regexp)
374 { 374 {
375 for (let style of styles) 375 for (let style of styles)
376 if (regexp.test(style.style)) 376 if (regexp.test(style.style))
377 for (let subSelector of style.subSelectors) 377 for (let subSelector of style.subSelectors)
378 { 378 {
379 if (subSelector.startsWith("*") && 379 if (subSelector.startsWith("*") &&
380 !incompletePrefixRegexp.test(prefix)) 380 !incompletePrefixRegexp.test(prefix))
381 { 381 {
382 subSelector = subSelector.substr(1); 382 subSelector = subSelector.substr(1);
383 } 383 }
384 let idx = subSelector.lastIndexOf("::"); 384 let idx = subSelector.lastIndexOf("::");
385 if (idx != -1) 385 if (idx !== -1)
386 subSelector = subSelector.substr(0, idx); 386 subSelector = subSelector.substr(0, idx);
387 yield prefix + subSelector; 387 yield prefix + subSelector;
388 } 388 }
389 }, 389 },
390 390
391 *getSelectors(prefix, subtree, styles) 391 *getSelectors(prefix, subtree, styles)
392 { 392 {
393 for (let selector of this.findPropsSelectors(styles, prefix, this._regexp)) 393 for (let selector of this.findPropsSelectors(styles, prefix, this._regexp))
394 yield [selector, subtree]; 394 yield [selector, subtree];
395 } 395 }
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
480 function extractMutationTypes(mutations) 480 function extractMutationTypes(mutations)
481 { 481 {
482 let types = new Set(); 482 let types = new Set();
483 483
484 for (let mutation of mutations) 484 for (let mutation of mutations)
485 { 485 {
486 types.add(mutation.type); 486 types.add(mutation.type);
487 487
488 // There are only 3 types of mutations: "attributes", "characterData", and 488 // There are only 3 types of mutations: "attributes", "characterData", and
489 // "childList". 489 // "childList".
490 if (types.size == 3) 490 if (types.size === 3)
491 break; 491 break;
492 } 492 }
493 493
494 return types; 494 return types;
495 } 495 }
496 496
497 function filterPatterns(patterns, {stylesheets, mutations}) 497 function filterPatterns(patterns, {stylesheets, mutations})
498 { 498 {
499 if (!stylesheets && !mutations) 499 if (!stylesheets && !mutations)
500 return patterns.slice(); 500 return patterns.slice();
(...skipping 24 matching lines...) Expand all
525 this.hideElemsFunc = hideElemsFunc; 525 this.hideElemsFunc = hideElemsFunc;
526 this.observer = new MutationObserver(this.observe.bind(this)); 526 this.observer = new MutationObserver(this.observe.bind(this));
527 this.useInlineStyles = true; 527 this.useInlineStyles = true;
528 } 528 }
529 529
530 ElemHideEmulation.prototype = { 530 ElemHideEmulation.prototype = {
531 isSameOrigin(stylesheet) 531 isSameOrigin(stylesheet)
532 { 532 {
533 try 533 try
534 { 534 {
535 return new URL(stylesheet.href).origin == this.document.location.origin; 535 return new URL(stylesheet.href).origin === this.document.location.origin;
536 } 536 }
537 catch (e) 537 catch (e)
538 { 538 {
539 // Invalid URL, assume that it is first-party. 539 // Invalid URL, assume that it is first-party.
540 return true; 540 return true;
541 } 541 }
542 }, 542 },
543 543
544 /** Parse the selector 544 /** Parse the selector
545 * @param {string} selector the selector to parse 545 * @param {string} selector the selector to parse
546 * @return {Array} selectors is an array of objects, 546 * @return {Array} selectors is an array of objects,
547 * or null in case of errors. 547 * or null in case of errors.
548 */ 548 */
549 parseSelector(selector) 549 parseSelector(selector)
550 { 550 {
551 if (selector.length == 0) 551 if (selector.length === 0)
552 return []; 552 return [];
553 553
554 let match = abpSelectorRegexp.exec(selector); 554 let match = abpSelectorRegexp.exec(selector);
555 if (!match) 555 if (!match)
556 return [new PlainSelector(selector)]; 556 return [new PlainSelector(selector)];
557 557
558 let selectors = []; 558 let selectors = [];
559 if (match.index > 0) 559 if (match.index > 0)
560 selectors.push(new PlainSelector(selector.substr(0, match.index))); 560 selectors.push(new PlainSelector(selector.substr(0, match.index)));
561 561
562 let startIndex = match.index + match[0].length; 562 let startIndex = match.index + match[0].length;
563 let content = parseSelectorContent(selector, startIndex); 563 let content = parseSelectorContent(selector, startIndex);
564 if (!content) 564 if (!content)
565 { 565 {
566 console.error(new SyntaxError("Failed to parse Adblock Plus " + 566 console.error(new SyntaxError("Failed to parse Adblock Plus " +
567 `selector ${selector} ` + 567 `selector ${selector} ` +
568 "due to unmatched parentheses.")); 568 "due to unmatched parentheses."));
569 return null; 569 return null;
570 } 570 }
571 if (match[1] == "properties") 571 if (match[1] === "properties")
572 selectors.push(new PropsSelector(content.text)); 572 selectors.push(new PropsSelector(content.text));
573 else if (match[1] == "has") 573 else if (match[1] === "has")
574 { 574 {
575 let hasSelectors = this.parseSelector(content.text); 575 let hasSelectors = this.parseSelector(content.text);
576 if (hasSelectors == null) 576 if (hasSelectors === null)
577 return null; 577 return null;
578 selectors.push(new HasSelector(hasSelectors)); 578 selectors.push(new HasSelector(hasSelectors));
579 } 579 }
580 else if (match[1] == "contains") 580 else if (match[1] === "contains")
581 selectors.push(new ContainsSelector(content.text)); 581 selectors.push(new ContainsSelector(content.text));
582 else 582 else
583 { 583 {
584 // this is an error, can't parse selector. 584 // this is an error, can't parse selector.
585 console.error(new SyntaxError("Failed to parse Adblock Plus " + 585 console.error(new SyntaxError("Failed to parse Adblock Plus " +
586 `selector ${selector}, invalid ` + 586 `selector ${selector}, invalid ` +
587 `pseudo-class :-abp-${match[1]}().`)); 587 `pseudo-class :-abp-${match[1]}().`));
588 return null; 588 return null;
589 } 589 }
590 590
591 let suffix = this.parseSelector(selector.substr(content.end + 1)); 591 let suffix = this.parseSelector(selector.substr(content.end + 1));
592 if (suffix == null) 592 if (suffix === null)
593 return null; 593 return null;
594 594
595 selectors.push(...suffix); 595 selectors.push(...suffix);
596 596
597 if (selectors.length == 1 && selectors[0] instanceof ContainsSelector) 597 if (selectors.length === 1 && selectors[0] instanceof ContainsSelector)
598 { 598 {
599 console.error(new SyntaxError("Failed to parse Adblock Plus " + 599 console.error(new SyntaxError("Failed to parse Adblock Plus " +
600 `selector ${selector}, can't ` + 600 `selector ${selector}, can't ` +
601 "have a lonely :-abp-contains().")); 601 "have a lonely :-abp-contains()."));
602 return null; 602 return null;
603 } 603 }
604 return selectors; 604 return selectors;
605 }, 605 },
606 606
607 /** 607 /**
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
664 // in that case. 664 // in that case.
665 // See https://searchfox.org/mozilla-central/rev/f65d7528e34ef1a7665b4a1 a7b7cdb1388fcd3aa/layout/style/StyleSheet.cpp#699 665 // See https://searchfox.org/mozilla-central/rev/f65d7528e34ef1a7665b4a1 a7b7cdb1388fcd3aa/layout/style/StyleSheet.cpp#699
666 continue; 666 continue;
667 } 667 }
668 668
669 if (!rules) 669 if (!rules)
670 continue; 670 continue;
671 671
672 for (let rule of rules) 672 for (let rule of rules)
673 { 673 {
674 if (rule.type != rule.STYLE_RULE) 674 if (rule.type !== rule.STYLE_RULE)
675 continue; 675 continue;
676 676
677 cssStyles.push(stringifyStyle(rule)); 677 cssStyles.push(stringifyStyle(rule));
678 } 678 }
679 } 679 }
680 680
681 let pattern = null; 681 let pattern = null;
682 let generator = null; 682 let generator = null;
683 683
684 let processPatterns = () => 684 let processPatterns = () =>
685 { 685 {
686 let cycleStart = performance.now(); 686 let cycleStart = performance.now();
687 687
688 if (!pattern) 688 if (!pattern)
689 { 689 {
690 if (!patterns.length) 690 if (!patterns.length)
691 { 691 {
692 if (selectors.length > 0) 692 if (selectors.length > 0)
693 this.addSelectorsFunc(selectors, selectorFilters); 693 this.addSelectorsFunc(selectors, selectorFilters);
694 if (elements.length > 0) 694 if (elements.length > 0)
695 this.hideElemsFunc(elements, elementFilters); 695 this.hideElemsFunc(elements, elementFilters);
696 if (typeof done == "function") 696 if (typeof done === "function")
697 done(); 697 done();
698 return; 698 return;
699 } 699 }
700 700
701 pattern = patterns.shift(); 701 pattern = patterns.shift();
702 702
703 generator = evaluate(pattern.selectors, 0, "", 703 generator = evaluate(pattern.selectors, 0, "",
704 this.document, cssStyles); 704 this.document, cssStyles);
705 } 705 }
706 for (let selector of generator) 706 for (let selector of generator)
707 { 707 {
708 if (selector != null) 708 if (selector !== null)
709 { 709 {
710 if (!this.useInlineStyles) 710 if (!this.useInlineStyles)
711 { 711 {
712 selectors.push(selector); 712 selectors.push(selector);
713 selectorFilters.push(pattern.text); 713 selectorFilters.push(pattern.text);
714 } 714 }
715 else 715 else
716 { 716 {
717 for (let element of this.document.querySelectorAll(selector)) 717 for (let element of this.document.querySelectorAll(selector))
718 { 718 {
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
805 this._scheduledProcessing = {stylesheets, mutations}; 805 this._scheduledProcessing = {stylesheets, mutations};
806 setTimeout(() => 806 setTimeout(() =>
807 { 807 {
808 let params = Object.assign({}, this._scheduledProcessing); 808 let params = Object.assign({}, this._scheduledProcessing);
809 this._filteringInProgress = true; 809 this._filteringInProgress = true;
810 this._scheduledProcessing = null; 810 this._scheduledProcessing = null;
811 this._addSelectors(params.stylesheets, params.mutations, completion); 811 this._addSelectors(params.stylesheets, params.mutations, completion);
812 }, 812 },
813 MIN_INVOCATION_INTERVAL - (performance.now() - this._lastInvocation)); 813 MIN_INVOCATION_INTERVAL - (performance.now() - this._lastInvocation));
814 } 814 }
815 else if (this.document.readyState == "loading") 815 else if (this.document.readyState === "loading")
816 { 816 {
817 this._scheduledProcessing = {stylesheets, mutations}; 817 this._scheduledProcessing = {stylesheets, mutations};
818 let handler = () => 818 let handler = () =>
819 { 819 {
820 this.document.removeEventListener("DOMContentLoaded", handler); 820 this.document.removeEventListener("DOMContentLoaded", handler);
821 let params = Object.assign({}, this._scheduledProcessing); 821 let params = Object.assign({}, this._scheduledProcessing);
822 this._filteringInProgress = true; 822 this._filteringInProgress = true;
823 this._scheduledProcessing = null; 823 this._scheduledProcessing = null;
824 this._addSelectors(params.stylesheets, params.mutations, completion); 824 this._addSelectors(params.stylesheets, params.mutations, completion);
825 }; 825 };
(...skipping 17 matching lines...) Expand all
843 { 843 {
844 this.queueFiltering(null, mutations); 844 this.queueFiltering(null, mutations);
845 }, 845 },
846 846
847 apply(patterns) 847 apply(patterns)
848 { 848 {
849 this.patterns = []; 849 this.patterns = [];
850 for (let pattern of patterns) 850 for (let pattern of patterns)
851 { 851 {
852 let selectors = this.parseSelector(pattern.selector); 852 let selectors = this.parseSelector(pattern.selector);
853 if (selectors != null && selectors.length > 0) 853 if (selectors !== null && selectors.length > 0)
854 this.patterns.push(new Pattern(selectors, pattern.text)); 854 this.patterns.push(new Pattern(selectors, pattern.text));
855 } 855 }
856 856
857 if (this.patterns.length > 0) 857 if (this.patterns.length > 0)
858 { 858 {
859 this.queueFiltering(); 859 this.queueFiltering();
860 this.observer.observe( 860 this.observer.observe(
861 this.document, 861 this.document,
862 { 862 {
863 childList: true, 863 childList: true,
864 attributes: shouldObserveAttributes(this.patterns), 864 attributes: shouldObserveAttributes(this.patterns),
865 characterData: shouldObserveCharacterData(this.patterns), 865 characterData: shouldObserveCharacterData(this.patterns),
866 subtree: true 866 subtree: true
867 } 867 }
868 ); 868 );
869 this.document.addEventListener("load", this.onLoad.bind(this), true); 869 this.document.addEventListener("load", this.onLoad.bind(this), true);
870 } 870 }
871 } 871 }
872 }; 872 };
873 873
874 exports.ElemHideEmulation = ElemHideEmulation; 874 exports.ElemHideEmulation = ElemHideEmulation;
OLDNEW
« no previous file with comments | « lib/common.js ('k') | lib/downloader.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld