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

Delta Between Two Patch Sets: lib/filterClasses.js

Issue 29760704: Issue 6592 - Implement $rewrite filter option (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Left Patch Set: More review changes Created May 3, 2018, 6:39 p.m.
Right Patch Set: Just inject URL into the sandbox globals. Created May 17, 2018, 12:50 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | test/.eslintrc.json » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 text = text.replace(/[^\S ]+/g, ""); 181 text = text.replace(/[^\S ]+/g, "");
182 182
183 // Don't remove spaces inside comments 183 // Don't remove spaces inside comments
184 if (/^ *!/.test(text)) 184 if (/^ *!/.test(text))
185 return text.trim(); 185 return text.trim();
186 186
187 // Special treatment for element hiding filters, right side is allowed to 187 // Special treatment for element hiding filters, right side is allowed to
188 // contain spaces 188 // contain spaces
189 if (Filter.elemhideRegExp.test(text)) 189 if (Filter.elemhideRegExp.test(text))
190 { 190 {
191 let [, domain, separator, selector] = /^(.*?)(#[@?]?#?)(.*)$/.exec(text); 191 let [, domains, separator, selector] = /^(.*?)(#[@?]?#?)(.*)$/.exec(text);
192 return domain.replace(/ +/g, "") + separator + selector.trim(); 192 return domains.replace(/ +/g, "") + separator + selector.trim();
193 } 193 }
194 194
195 // For most regexp filters we strip all spaces, but $csp filter options 195 // For most regexp filters we strip all spaces, but $csp filter options
196 // are allowed to contain single (non trailing) spaces. 196 // are allowed to contain single (non trailing) spaces.
197 let strippedText = text.replace(/ +/g, ""); 197 let strippedText = text.replace(/ +/g, "");
198 if (!strippedText.includes("$") || !/\bcsp=/i.test(strippedText)) 198 if (!strippedText.includes("$") || !/\bcsp=/i.test(strippedText))
199 return strippedText; 199 return strippedText;
200 200
201 let optionsMatch = Filter.optionsRegExp.exec(strippedText); 201 let optionsMatch = Filter.optionsRegExp.exec(strippedText);
202 if (!optionsMatch) 202 if (!optionsMatch)
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
367 { 367 {
368 let oldValue = this._lastHit; 368 let oldValue = this._lastHit;
369 this._lastHit = value; 369 this._lastHit = value;
370 FilterNotifier.triggerListeners("filter.lastHit", this, value, oldValue); 370 FilterNotifier.triggerListeners("filter.lastHit", this, value, oldValue);
371 } 371 }
372 return this._lastHit; 372 return this._lastHit;
373 }, 373 },
374 374
375 /** 375 /**
376 * String that the domains property should be generated from 376 * String that the domains property should be generated from
377 * @type {string} 377 * @type {?string}
378 */ 378 */
379 domainSource: null, 379 domainSource: null,
380 380
381 /** 381 /**
382 * Separator character used in domainSource property, must be 382 * Separator character used in domainSource property, must be
383 * overridden by subclasses 383 * overridden by subclasses
384 * @type {string} 384 * @type {string}
385 */ 385 */
386 domainSeparator: null, 386 domainSeparator: null,
387 387
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 464
465 this.domainSource = null; 465 this.domainSource = null;
466 } 466 }
467 467
468 Object.defineProperty(this, "domains", {value: domains, enumerable: true}); 468 Object.defineProperty(this, "domains", {value: domains, enumerable: true});
469 return this.domains; 469 return this.domains;
470 }, 470 },
471 471
472 /** 472 /**
473 * Array containing public keys of websites that this filter should apply to 473 * Array containing public keys of websites that this filter should apply to
474 * @type {string[]} 474 * @type {?string[]}
475 */ 475 */
476 sitekeys: null, 476 sitekeys: null,
477 477
478 /** 478 /**
479 * Checks whether this filter is active on a domain. 479 * Checks whether this filter is active on a domain.
480 * @param {string} docDomain domain name of the document that loads the URL 480 * @param {string} [docDomain] domain name of the document that loads the URL
481 * @param {string} [sitekey] public key provided by the document 481 * @param {string} [sitekey] public key provided by the document
482 * @return {boolean} true in case of the filter being active 482 * @return {boolean} true in case of the filter being active
483 */ 483 */
484 isActiveOnDomain(docDomain, sitekey) 484 isActiveOnDomain(docDomain, sitekey)
485 { 485 {
486 // Sitekeys are case-sensitive so we shouldn't convert them to 486 // Sitekeys are case-sensitive so we shouldn't convert them to
487 // upper-case to avoid false positives here. Instead we need to 487 // upper-case to avoid false positives here. Instead we need to
488 // change the way filter options are parsed. 488 // change the way filter options are parsed.
489 if (this.sitekeys && 489 if (this.sitekeys &&
490 (!sitekey || this.sitekeys.indexOf(sitekey.toUpperCase()) < 0)) 490 (!sitekey || this.sitekeys.indexOf(sitekey.toUpperCase()) < 0))
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
679 contentType: 0x7FFFFFFF, 679 contentType: 0x7FFFFFFF,
680 /** 680 /**
681 * Defines whether the filter should distinguish between lower and 681 * Defines whether the filter should distinguish between lower and
682 * upper case letters 682 * upper case letters
683 * @type {boolean} 683 * @type {boolean}
684 */ 684 */
685 matchCase: false, 685 matchCase: false,
686 /** 686 /**
687 * Defines whether the filter should apply to third-party or 687 * Defines whether the filter should apply to third-party or
688 * first-party content only. Can be null (apply to all content). 688 * first-party content only. Can be null (apply to all content).
689 * @type {boolean} 689 * @type {?boolean}
690 */ 690 */
691 thirdParty: null, 691 thirdParty: null,
692 692
693 /** 693 /**
694 * String that the sitekey property should be generated from 694 * String that the sitekey property should be generated from
695 * @type {string} 695 * @type {?string}
696 */ 696 */
697 sitekeySource: null, 697 sitekeySource: null,
698 698
699 /** 699 /**
700 * Array containing public keys of websites that this filter should apply to 700 * @see ActiveFilter.sitekeys
701 * @type {string[]}
702 */ 701 */
703 get sitekeys() 702 get sitekeys()
704 { 703 {
705 // Despite this property being cached, the getter is called 704 // Despite this property being cached, the getter is called
706 // several times on Safari, due to WebKit bug 132872 705 // several times on Safari, due to WebKit bug 132872
707 let prop = Object.getOwnPropertyDescriptor(this, "sitekeys"); 706 let prop = Object.getOwnPropertyDescriptor(this, "sitekeys");
708 if (prop) 707 if (prop)
709 return prop.value; 708 return prop.value;
710 709
711 let sitekeys = null; 710 let sitekeys = null;
712 711
713 if (this.sitekeySource) 712 if (this.sitekeySource)
714 { 713 {
715 sitekeys = this.sitekeySource.split("|"); 714 sitekeys = this.sitekeySource.split("|");
716 this.sitekeySource = null; 715 this.sitekeySource = null;
717 } 716 }
718 717
719 Object.defineProperty( 718 Object.defineProperty(
720 this, "sitekeys", {value: sitekeys, enumerable: true} 719 this, "sitekeys", {value: sitekeys, enumerable: true}
721 ); 720 );
722 return this.sitekeys; 721 return this.sitekeys;
723 }, 722 },
724 723
725 /** 724 /**
726 * Tests whether the URL matches this filter 725 * Tests whether the URL matches this filter
727 * @param {string} location URL to be tested 726 * @param {string} location URL to be tested
728 * @param {number} typeMask bitmask of content / request types to match 727 * @param {number} typeMask bitmask of content / request types to match
729 * @param {string} docDomain domain name of the document that loads the URL 728 * @param {string} [docDomain] domain name of the document that loads the URL
730 * @param {boolean} thirdParty should be true if the URL is a third-party 729 * @param {boolean} [thirdParty] should be true if the URL is a third-party
731 * request 730 * request
732 * @param {string} sitekey public key provided by the document 731 * @param {string} [sitekey] public key provided by the document
733 * @return {boolean} true in case of a match 732 * @return {boolean} true in case of a match
734 */ 733 */
735 matches(location, typeMask, docDomain, thirdParty, sitekey) 734 matches(location, typeMask, docDomain, thirdParty, sitekey)
736 { 735 {
737 if (this.contentType & typeMask && 736 if (this.contentType & typeMask &&
738 (this.thirdParty == null || this.thirdParty == thirdParty) && 737 (this.thirdParty == null || this.thirdParty == thirdParty) &&
739 this.isActiveOnDomain(docDomain, sitekey) && this.regexp.test(location)) 738 this.isActiveOnDomain(docDomain, sitekey) && this.regexp.test(location))
740 { 739 {
741 return true; 740 return true;
742 } 741 }
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
881 RegExpFilter.typeMap.DOCUMENT | 880 RegExpFilter.typeMap.DOCUMENT |
882 RegExpFilter.typeMap.ELEMHIDE | 881 RegExpFilter.typeMap.ELEMHIDE |
883 RegExpFilter.typeMap.POPUP | 882 RegExpFilter.typeMap.POPUP |
884 RegExpFilter.typeMap.GENERICHIDE | 883 RegExpFilter.typeMap.GENERICHIDE |
885 RegExpFilter.typeMap.GENERICBLOCK); 884 RegExpFilter.typeMap.GENERICBLOCK);
886 885
887 /** 886 /**
888 * Class for blocking filters 887 * Class for blocking filters
889 * @param {string} text see Filter() 888 * @param {string} text see Filter()
890 * @param {string} regexpSource see RegExpFilter() 889 * @param {string} regexpSource see RegExpFilter()
891 * @param {number} contentType see RegExpFilter() 890 * @param {number} [contentType] see RegExpFilter()
892 * @param {boolean} matchCase see RegExpFilter() 891 * @param {boolean} [matchCase] see RegExpFilter()
893 * @param {string} domains see RegExpFilter() 892 * @param {string} [domains] see RegExpFilter()
894 * @param {boolean} thirdParty see RegExpFilter() 893 * @param {boolean} [thirdParty] see RegExpFilter()
895 * @param {string} sitekeys see RegExpFilter() 894 * @param {string} [sitekeys] see RegExpFilter()
896 * @param {boolean} collapse 895 * @param {boolean} [collapse]
897 * defines whether the filter should collapse blocked content, can be null 896 * defines whether the filter should collapse blocked content, can be null
898 * @param {string} [csp] 897 * @param {string} [csp]
899 * Content Security Policy to inject when the filter matches 898 * Content Security Policy to inject when the filter matches
900 * @param {string} [rewrite] 899 * @param {?string} [rewrite]
901 * The rewrite expression 900 * The (optional) rule specifying how to rewrite the URL. See
901 * BlockingFilter.prototype.rewrite.
902 * @constructor 902 * @constructor
903 * @augments RegExpFilter 903 * @augments RegExpFilter
904 */ 904 */
905 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, 905 function BlockingFilter(text, regexpSource, contentType, matchCase, domains,
906 thirdParty, sitekeys, collapse, csp, rewrite) 906 thirdParty, sitekeys, collapse, csp, rewrite)
907 { 907 {
908 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, 908 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains,
909 thirdParty, sitekeys); 909 thirdParty, sitekeys);
910 910
911 this.collapse = collapse; 911 this.collapse = collapse;
912 this.csp = csp; 912 this.csp = csp;
913 this.rewrite = rewrite; 913 this.rewrite = rewrite;
914 } 914 }
915 exports.BlockingFilter = BlockingFilter; 915 exports.BlockingFilter = BlockingFilter;
916 916
917 BlockingFilter.prototype = extend(RegExpFilter, { 917 BlockingFilter.prototype = extend(RegExpFilter, {
918 type: "blocking", 918 type: "blocking",
919 919
920 /** 920 /**
921 * Defines whether the filter should collapse blocked content. 921 * Defines whether the filter should collapse blocked content.
922 * Can be null (use the global preference). 922 * Can be null (use the global preference).
923 * @type {boolean} 923 * @type {?boolean}
924 */ 924 */
925 collapse: null, 925 collapse: null,
926 926
927 /** 927 /**
928 * Content Security Policy to inject for matching requests. 928 * Content Security Policy to inject for matching requests.
929 * @type {string} 929 * @type {?string}
930 */ 930 */
931 csp: null, 931 csp: null,
932 932
933 /** 933 /**
934 * The rewrite expression 934 * The rule specifying how to rewrite the URL.
935 * @type {string} 935 * The syntax is similar to the one of String.prototype.replace().
936 * @type {?string}
936 */ 937 */
937 rewrite: null, 938 rewrite: null,
938 939
939 /** 940 /**
940 * Perform the URL rewrite and check the origin. 941 * Rewrites an URL.
941 * @param {string} urlString the string URL to rewrite 942 * @param {string} url the URL to rewrite
942 * @returns {string?} the rewritten URL, or null if it doesn't match. 943 * @return {string} the rewritten URL, or the original in case of failure
Manish Jethani 2018/05/04 09:56:40 This is no longer true, it never returns null.
hub 2018/05/04 16:18:47 Done.
943 */ 944 */
944 rewriteUrl(urlString) 945 rewriteUrl(url)
945 { 946 {
946 let rewritten = urlString.replace(this.regexp, this.rewrite);
947 try 947 try
948 { 948 {
949 if (new URL(rewritten).origin == new URL(urlString).origin) 949 let rewrittenUrl = new URL(url.replace(this.regexp, this.rewrite), url);
kzar 2018/05/17 12:56:06 I forgot to mention before, I thought how you did
hub 2018/05/17 12:58:39 thanks!
950 return rewritten; 950 if (rewrittenUrl.origin == new URL(url).origin)
951 return rewrittenUrl.href;
951 } 952 }
952 catch (e) 953 catch (e)
953 { 954 {
954 } 955 }
955 956
956 return urlString; 957 return url;
957 } 958 }
958 }); 959 });
959 960
960 /** 961 /**
961 * Class for whitelist filters 962 * Class for whitelist filters
962 * @param {string} text see Filter() 963 * @param {string} text see Filter()
963 * @param {string} regexpSource see RegExpFilter() 964 * @param {string} regexpSource see RegExpFilter()
964 * @param {number} contentType see RegExpFilter() 965 * @param {number} [contentType] see RegExpFilter()
965 * @param {boolean} matchCase see RegExpFilter() 966 * @param {boolean} [matchCase] see RegExpFilter()
966 * @param {string} domains see RegExpFilter() 967 * @param {string} [domains] see RegExpFilter()
967 * @param {boolean} thirdParty see RegExpFilter() 968 * @param {boolean} [thirdParty] see RegExpFilter()
968 * @param {string} sitekeys see RegExpFilter() 969 * @param {string} [sitekeys] see RegExpFilter()
969 * @constructor 970 * @constructor
970 * @augments RegExpFilter 971 * @augments RegExpFilter
971 */ 972 */
972 function WhitelistFilter(text, regexpSource, contentType, matchCase, domains, 973 function WhitelistFilter(text, regexpSource, contentType, matchCase, domains,
973 thirdParty, sitekeys) 974 thirdParty, sitekeys)
974 { 975 {
975 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, 976 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains,
976 thirdParty, sitekeys); 977 thirdParty, sitekeys);
977 } 978 }
978 exports.WhitelistFilter = WhitelistFilter; 979 exports.WhitelistFilter = WhitelistFilter;
(...skipping 11 matching lines...) Expand all
990 * hidden 991 * hidden
991 * @constructor 992 * @constructor
992 * @augments ActiveFilter 993 * @augments ActiveFilter
993 */ 994 */
994 function ElemHideBase(text, domains, selector) 995 function ElemHideBase(text, domains, selector)
995 { 996 {
996 ActiveFilter.call(this, text, domains || null); 997 ActiveFilter.call(this, text, domains || null);
997 998
998 if (domains) 999 if (domains)
999 { 1000 {
1000 this.selectorDomain = domains.replace(/,~[^,]+/g, "") 1001 this.selectorDomains = domains.replace(/,~[^,]+/g, "")
1001 .replace(/^~[^,]+,?/, "").toLowerCase(); 1002 .replace(/^~[^,]+,?/, "").toLowerCase();
1002 } 1003 }
1003 1004
1004 // Braces are being escaped to prevent CSS rule injection. 1005 // Braces are being escaped to prevent CSS rule injection.
1005 this.selector = selector.replace("{", "\\7B ").replace("}", "\\7D "); 1006 this.selector = selector.replace("{", "\\7B ").replace("}", "\\7D ");
1006 } 1007 }
1007 exports.ElemHideBase = ElemHideBase; 1008 exports.ElemHideBase = ElemHideBase;
1008 1009
1009 ElemHideBase.prototype = extend(ActiveFilter, { 1010 ElemHideBase.prototype = extend(ActiveFilter, {
1010 /** 1011 /**
1011 * @see ActiveFilter.domainSeparator 1012 * @see ActiveFilter.domainSeparator
1012 */ 1013 */
1013 domainSeparator: ",", 1014 domainSeparator: ",",
1014 1015
1015 /** 1016 /**
1016 * @see ActiveFilter.ignoreTrailingDot 1017 * @see ActiveFilter.ignoreTrailingDot
1017 */ 1018 */
1018 ignoreTrailingDot: false, 1019 ignoreTrailingDot: false,
1019 1020
1020 /** 1021 /**
1021 * Host name or domain the filter should be restricted to (can be null for 1022 * Host names or domains the filter should be restricted to (can be null for
1022 * no restriction) 1023 * no restriction)
1023 * @type {string} 1024 * @type {?string}
1024 */ 1025 */
1025 selectorDomain: null, 1026 selectorDomains: null,
1026 /** 1027 /**
1027 * CSS selector for the HTML elements that should be hidden 1028 * CSS selector for the HTML elements that should be hidden
1028 * @type {string} 1029 * @type {string}
1029 */ 1030 */
1030 selector: null 1031 selector: null
1031 }); 1032 });
1032 1033
1033 /** 1034 /**
1034 * Creates an element hiding filter from a pre-parsed text representation 1035 * Creates an element hiding filter from a pre-parsed text representation
1035 * 1036 *
1036 * @param {string} text same as in Filter() 1037 * @param {string} text same as in Filter()
1037 * @param {string?} domain 1038 * @param {string} [domains]
1038 * domain part of the text representation 1039 * domains part of the text representation
1039 * @param {string?} type 1040 * @param {string} [type]
1040 * rule type, either empty or @ (exception) or ? (emulation rule) 1041 * rule type, either empty or @ (exception) or ? (emulation rule)
1041 * @param {string} selector raw CSS selector 1042 * @param {string} selector raw CSS selector
1042 * @return {ElemHideFilter|ElemHideException| 1043 * @return {ElemHideFilter|ElemHideException|
1043 * ElemHideEmulationFilter|InvalidFilter} 1044 * ElemHideEmulationFilter|InvalidFilter}
1044 */ 1045 */
1045 ElemHideBase.fromText = function(text, domain, type, selector) 1046 ElemHideBase.fromText = function(text, domains, type, selector)
1046 { 1047 {
1047 // We don't allow ElemHide filters which have any empty domains. 1048 // We don't allow ElemHide filters which have any empty domains.
1048 // Note: The ElemHide.prototype.domainSeparator is duplicated here, if that 1049 // Note: The ElemHide.prototype.domainSeparator is duplicated here, if that
1049 // changes this must be changed too. 1050 // changes this must be changed too.
1050 if (domain && /(^|,)~?(,|$)/.test(domain)) 1051 if (domains && /(^|,)~?(,|$)/.test(domains))
1051 return new InvalidFilter(text, "filter_invalid_domain"); 1052 return new InvalidFilter(text, "filter_invalid_domain");
1052 1053
1053 if (type == "@") 1054 if (type == "@")
1054 return new ElemHideException(text, domain, selector); 1055 return new ElemHideException(text, domains, selector);
1055 1056
1056 if (type == "?") 1057 if (type == "?")
1057 { 1058 {
1058 // Element hiding emulation filters are inefficient so we need to make sure 1059 // Element hiding emulation filters are inefficient so we need to make sure
1059 // that they're only applied if they specify active domains 1060 // that they're only applied if they specify active domains
1060 if (!/,[^~][^,.]*\.[^,]/.test("," + domain)) 1061 if (!/,[^~][^,.]*\.[^,]/.test("," + domains))
1061 return new InvalidFilter(text, "filter_elemhideemulation_nodomain"); 1062 return new InvalidFilter(text, "filter_elemhideemulation_nodomain");
1062 1063
1063 return new ElemHideEmulationFilter(text, domain, selector); 1064 return new ElemHideEmulationFilter(text, domains, selector);
1064 } 1065 }
1065 1066
1066 return new ElemHideFilter(text, domain, selector); 1067 return new ElemHideFilter(text, domains, selector);
1067 }; 1068 };
1068 1069
1069 /** 1070 /**
1070 * Class for element hiding filters 1071 * Class for element hiding filters
1071 * @param {string} text see Filter() 1072 * @param {string} text see Filter()
1072 * @param {string} domains see ElemHideBase() 1073 * @param {string} [domains] see ElemHideBase()
1073 * @param {string} selector see ElemHideBase() 1074 * @param {string} selector see ElemHideBase()
1074 * @constructor 1075 * @constructor
1075 * @augments ElemHideBase 1076 * @augments ElemHideBase
1076 */ 1077 */
1077 function ElemHideFilter(text, domains, selector) 1078 function ElemHideFilter(text, domains, selector)
1078 { 1079 {
1079 ElemHideBase.call(this, text, domains, selector); 1080 ElemHideBase.call(this, text, domains, selector);
1080 } 1081 }
1081 exports.ElemHideFilter = ElemHideFilter; 1082 exports.ElemHideFilter = ElemHideFilter;
1082 1083
1083 ElemHideFilter.prototype = extend(ElemHideBase, { 1084 ElemHideFilter.prototype = extend(ElemHideBase, {
1084 type: "elemhide" 1085 type: "elemhide"
1085 }); 1086 });
1086 1087
1087 /** 1088 /**
1088 * Class for element hiding exceptions 1089 * Class for element hiding exceptions
1089 * @param {string} text see Filter() 1090 * @param {string} text see Filter()
1090 * @param {string} domains see ElemHideBase() 1091 * @param {string} [domains] see ElemHideBase()
1091 * @param {string} selector see ElemHideBase() 1092 * @param {string} selector see ElemHideBase()
1092 * @constructor 1093 * @constructor
1093 * @augments ElemHideBase 1094 * @augments ElemHideBase
1094 */ 1095 */
1095 function ElemHideException(text, domains, selector) 1096 function ElemHideException(text, domains, selector)
1096 { 1097 {
1097 ElemHideBase.call(this, text, domains, selector); 1098 ElemHideBase.call(this, text, domains, selector);
1098 } 1099 }
1099 exports.ElemHideException = ElemHideException; 1100 exports.ElemHideException = ElemHideException;
1100 1101
(...skipping 11 matching lines...) Expand all
1112 */ 1113 */
1113 function ElemHideEmulationFilter(text, domains, selector) 1114 function ElemHideEmulationFilter(text, domains, selector)
1114 { 1115 {
1115 ElemHideBase.call(this, text, domains, selector); 1116 ElemHideBase.call(this, text, domains, selector);
1116 } 1117 }
1117 exports.ElemHideEmulationFilter = ElemHideEmulationFilter; 1118 exports.ElemHideEmulationFilter = ElemHideEmulationFilter;
1118 1119
1119 ElemHideEmulationFilter.prototype = extend(ElemHideBase, { 1120 ElemHideEmulationFilter.prototype = extend(ElemHideBase, {
1120 type: "elemhideemulation" 1121 type: "elemhideemulation"
1121 }); 1122 });
LEFTRIGHT

Powered by Google App Engine
This is Rietveld