OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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; |
OLD | NEW |