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

Side by Side Diff: lib/filterClasses.js

Issue 29361668: Issue 4394 - Create a filter class for element hiding emulation filters (Closed) Base URL: https://bitbucket.org/fhd/adblockpluscore
Patch Set: Address Wladimir's comments Created Nov. 21, 2016, 2:34 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
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-2016 Eyeo GmbH 3 * Copyright (C) 2006-2016 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 /** 18 /**
19 * @fileOverview Definition of Filter class and its subclasses. 19 * @fileOverview Definition of Filter class and its subclasses.
20 */ 20 */
21 21
22 let {FilterNotifier} = require("filterNotifier"); 22 let {FilterNotifier} = require("filterNotifier");
23 let {extend} = require("coreUtils"); 23 let {extend} = require("coreUtils");
24 let {filterToRegExp} = require("common");
24 25
25 /** 26 /**
26 * Abstract base class for filters 27 * Abstract base class for filters
27 * 28 *
28 * @param {String} text string representation of the filter 29 * @param {String} text string representation of the filter
29 * @constructor 30 * @constructor
30 */ 31 */
31 function Filter(text) 32 function Filter(text)
32 { 33 {
33 this.text = text; 34 this.text = text;
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 /** 89 /**
89 * Regular expression that RegExp filters specified as RegExps should match 90 * Regular expression that RegExp filters specified as RegExps should match
90 * @type RegExp 91 * @type RegExp
91 */ 92 */
92 Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[ ^,\s]+)?)*)?$/; 93 Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[ ^,\s]+)?)*)?$/;
93 /** 94 /**
94 * Regular expression that options on a RegExp filter should match 95 * Regular expression that options on a RegExp filter should match
95 * @type RegExp 96 * @type RegExp
96 */ 97 */
97 Filter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)$/ ; 98 Filter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)$/ ;
98 /**
99 * Regular expression that CSS property filters should match
100 * Properties must not contain " or '
101 * @type RegExp
102 */
103 Filter.csspropertyRegExp = /\[\-abp\-properties=(["'])([^"']+)\1\]/;
104 99
105 /** 100 /**
106 * Creates a filter of correct type from its text representation - does the basi c parsing and 101 * Creates a filter of correct type from its text representation - does the basi c parsing and
107 * calls the right constructor then. 102 * calls the right constructor then.
108 * 103 *
109 * @param {String} text as in Filter() 104 * @param {String} text as in Filter()
110 * @return {Filter} 105 * @return {Filter}
111 */ 106 */
112 Filter.fromText = function(text) 107 Filter.fromText = function(text)
113 { 108 {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 { 164 {
170 // Special treatment for element hiding filters, right side is allowed to co ntain spaces 165 // Special treatment for element hiding filters, right side is allowed to co ntain spaces
171 let [, domain, separator, selector] = /^(.*?)(#\@?#?)(.*)$/.exec(text); 166 let [, domain, separator, selector] = /^(.*?)(#\@?#?)(.*)$/.exec(text);
172 return domain.replace(/\s/g, "") + separator + selector.trim(); 167 return domain.replace(/\s/g, "") + separator + selector.trim();
173 } 168 }
174 else 169 else
175 return text.replace(/\s/g, ""); 170 return text.replace(/\s/g, "");
176 }; 171 };
177 172
178 /** 173 /**
179 * Converts filter text into regular expression string 174 * @see filterToRegExp
180 * @param {String} text as in Filter()
181 * @return {String} regular expression representation of filter text
182 */ 175 */
183 Filter.toRegExp = function(text) 176 Filter.toRegExp = filterToRegExp;
184 {
185 return text
186 .replace(/\*+/g, "*") // remove multiple wildcards
187 .replace(/\^\|$/, "^") // remove anchors following separator placehold er
188 .replace(/\W/g, "\\$&") // escape special symbols
189 .replace(/\\\*/g, ".*") // replace wildcards by .*
190 // process separator placeholders (all ANSI characters but alphanumeric char acters and _%.-)
191 .replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5E\\x6 0\\x7B-\\x7F]|$)")
192 .replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?") // process ex tended anchor at expression start
193 .replace(/^\\\|/, "^") // process anchor at expression start
194 .replace(/\\\|$/, "$") // process anchor at expression end
195 .replace(/^(\.\*)/, "") // remove leading wildcards
196 .replace(/(\.\*)$/, ""); // remove trailing wildcards
197 }
198 177
199 /** 178 /**
200 * Class for invalid filters 179 * Class for invalid filters
201 * @param {String} text see Filter() 180 * @param {String} text see Filter()
202 * @param {String} reason Reason why this filter is invalid 181 * @param {String} reason Reason why this filter is invalid
203 * @constructor 182 * @constructor
204 * @augments Filter 183 * @augments Filter
205 */ 184 */
206 function InvalidFilter(text, reason) 185 function InvalidFilter(text, reason)
207 { 186 {
(...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after
876 855
877 /** 856 /**
878 * Creates an element hiding filter from a pre-parsed text representation 857 * Creates an element hiding filter from a pre-parsed text representation
879 * 858 *
880 * @param {String} text same as in Filter() 859 * @param {String} text same as in Filter()
881 * @param {String} domain domain part of the text representation (can be e mpty) 860 * @param {String} domain domain part of the text representation (can be e mpty)
882 * @param {Boolean} isException exception rule indicator 861 * @param {Boolean} isException exception rule indicator
883 * @param {String} tagName tag name part (can be empty) 862 * @param {String} tagName tag name part (can be empty)
884 * @param {String} attrRules attribute matching rules (can be empty) 863 * @param {String} attrRules attribute matching rules (can be empty)
885 * @param {String} selector raw CSS selector (can be empty) 864 * @param {String} selector raw CSS selector (can be empty)
886 * @return {ElemHideFilter|ElemHideException|CSSPropertyFilter|InvalidFilter} 865 * @return {ElemHideFilter|ElemHideException|ElemHideEmulationFilter|InvalidFilt er}
887 */ 866 */
888 ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules, selector) 867 ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules, selector)
889 { 868 {
890 if (!selector) 869 if (!selector)
891 { 870 {
892 if (tagName == "*") 871 if (tagName == "*")
893 tagName = ""; 872 tagName = "";
894 873
895 let id = null; 874 let id = null;
896 let additional = ""; 875 let additional = "";
(...skipping 29 matching lines...) Expand all
926 905
927 // We don't allow ElemHide filters which have any empty domains. 906 // We don't allow ElemHide filters which have any empty domains.
928 // Note: The ElemHide.prototype.domainSeparator is duplicated here, if that 907 // Note: The ElemHide.prototype.domainSeparator is duplicated here, if that
929 // changes this must be changed too. 908 // changes this must be changed too.
930 if (domain && /(^|,)~?(,|$)/.test(domain)) 909 if (domain && /(^|,)~?(,|$)/.test(domain))
931 return new InvalidFilter(text, "filter_invalid_domain"); 910 return new InvalidFilter(text, "filter_invalid_domain");
932 911
933 if (isException) 912 if (isException)
934 return new ElemHideException(text, domain, selector); 913 return new ElemHideException(text, domain, selector);
935 914
936 let match = Filter.csspropertyRegExp.exec(selector); 915 if (selector.indexOf("[-abp-properties") != -1 ||
937 if (match) 916 selector.indexOf(":has(") != -1)
kzar 2016/11/21 16:24:55 You're still checking for ":has".
Felix Dahlke 2016/11/21 17:26:12 Done.
938 { 917 {
939 // CSS property filters are inefficient so we need to make sure that 918 // Element hiding emulation filters are inefficient so we need to make sure
940 // they're only applied if they specify active domains 919 // that they're only applied if they specify active domains
941 if (!/,[^~][^,.]*\.[^,]/.test("," + domain)) 920 if (!/,[^~][^,.]*\.[^,]/.test("," + domain))
942 return new InvalidFilter(text, "filter_cssproperty_nodomain"); 921 return new InvalidFilter(text, "filter_elemhideemulation_nodomain");
943 922
944 return new CSSPropertyFilter(text, domain, selector, match[2], 923 return new ElemHideEmulationFilter(text, domain, selector);
945 selector.substr(0, match.index),
946 selector.substr(match.index + match[0].length));
947 } 924 }
948 925
949 return new ElemHideFilter(text, domain, selector); 926 return new ElemHideFilter(text, domain, selector);
950 }; 927 };
951 928
952 /** 929 /**
953 * Class for element hiding filters 930 * Class for element hiding filters
954 * @param {String} text see Filter() 931 * @param {String} text see Filter()
955 * @param {String} domains see ElemHideBase() 932 * @param {String} domains see ElemHideBase()
956 * @param {String} selector see ElemHideBase() 933 * @param {String} selector see ElemHideBase()
(...skipping 22 matching lines...) Expand all
979 { 956 {
980 ElemHideBase.call(this, text, domains, selector); 957 ElemHideBase.call(this, text, domains, selector);
981 } 958 }
982 exports.ElemHideException = ElemHideException; 959 exports.ElemHideException = ElemHideException;
983 960
984 ElemHideException.prototype = extend(ElemHideBase, { 961 ElemHideException.prototype = extend(ElemHideBase, {
985 type: "elemhideexception" 962 type: "elemhideexception"
986 }); 963 });
987 964
988 /** 965 /**
989 * Class for CSS property filters 966 * Class for element hiding emulation filters
990 * @param {String} text see Filter() 967 * @param {String} text see Filter()
991 * @param {String} domains see ElemHideBase() 968 * @param {String} domains see ElemHideBase()
992 * @param {String} selector see ElemHideBase() 969 * @param {String} selector see ElemHideBase()
993 * @param {String} regexpSource see CSSPropertyFilter.regexpSource
994 * @param {String} selectorPrefix see CSSPropertyFilter.selectorPrefix
995 * @param {String} selectorSuffix see CSSPropertyFilter.selectorSuffix
996 * @constructor 970 * @constructor
997 * @augments ElemHideBase 971 * @augments ElemHideBase
998 */ 972 */
999 function CSSPropertyFilter(text, domains, selector, regexpSource, 973 function ElemHideEmulationFilter(text, domains, selector)
1000 selectorPrefix, selectorSuffix)
1001 { 974 {
1002 ElemHideBase.call(this, text, domains, selector); 975 ElemHideBase.call(this, text, domains, selector);
976 }
977 exports.ElemHideEmulationFilter = ElemHideEmulationFilter;
1003 978
1004 this.regexpSource = regexpSource; 979 ElemHideEmulationFilter.prototype = extend(ElemHideBase, {
1005 this.selectorPrefix = selectorPrefix; 980 type: "elemhideemulation"
1006 this.selectorSuffix = selectorSuffix;
1007 }
1008 exports.CSSPropertyFilter = CSSPropertyFilter;
1009
1010 CSSPropertyFilter.prototype = extend(ElemHideBase, {
1011 type: "cssproperty",
1012
1013 /**
1014 * Expression from which a regular expression should be generated for matching
1015 * CSS properties - for delayed creation of the regexpString property
1016 * @type String
1017 */
1018 regexpSource: null,
1019 /**
1020 * Substring of CSS selector before properties for the HTML elements that
1021 * should be hidden
1022 * @type String
1023 */
1024 selectorPrefix: null,
1025 /**
1026 * Substring of CSS selector after properties for the HTML elements that
1027 * should be hidden
1028 * @type String
1029 */
1030 selectorSuffix: null,
1031
1032 /**
1033 * Raw regular expression string to be used when testing CSS properties
1034 * against this filter
1035 * @type String
1036 */
1037 get regexpString()
1038 {
1039 // Despite this property being cached, the getter is called
1040 // several times on Safari, due to WebKit bug 132872
1041 let prop = Object.getOwnPropertyDescriptor(this, "regexpString");
1042 if (prop)
1043 return prop.value;
1044
1045 let regexp;
1046 if (this.regexpSource.length >= 2 && this.regexpSource[0] == "/" &&
1047 this.regexpSource[this.regexpSource.length - 1] == "/")
1048 regexp = this.regexpSource.slice(1, -1);
1049 else
1050 regexp = Filter.toRegExp(this.regexpSource);
1051 Object.defineProperty(this, "regexpString", {value: regexp});
1052 return regexp;
1053 }
1054 }); 981 });
OLDNEW

Powered by Google App Engine
This is Rietveld