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-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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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) | |
938 { | 916 { |
939 // CSS property filters are inefficient so we need to make sure that | 917 // Element hiding emulation filters are inefficient so we need to make sure |
940 // they're only applied if they specify active domains | 918 // that they're only applied if they specify active domains |
941 if (!/,[^~][^,.]*\.[^,]/.test("," + domain)) | 919 if (!/,[^~][^,.]*\.[^,]/.test("," + domain)) |
942 return new InvalidFilter(text, "filter_cssproperty_nodomain"); | 920 return new InvalidFilter(text, "filter_elemhideemulation_nodomain"); |
943 | 921 |
944 return new CSSPropertyFilter(text, domain, selector, match[2], | 922 return new ElemHideEmulationFilter(text, domain, selector); |
945 selector.substr(0, match.index), | |
946 selector.substr(match.index + match[0].length)); | |
947 } | 923 } |
948 | 924 |
949 return new ElemHideFilter(text, domain, selector); | 925 return new ElemHideFilter(text, domain, selector); |
950 }; | 926 }; |
951 | 927 |
952 /** | 928 /** |
953 * Class for element hiding filters | 929 * Class for element hiding filters |
954 * @param {String} text see Filter() | 930 * @param {String} text see Filter() |
955 * @param {String} domains see ElemHideBase() | 931 * @param {String} domains see ElemHideBase() |
956 * @param {String} selector see ElemHideBase() | 932 * @param {String} selector see ElemHideBase() |
(...skipping 22 matching lines...) Expand all Loading... |
979 { | 955 { |
980 ElemHideBase.call(this, text, domains, selector); | 956 ElemHideBase.call(this, text, domains, selector); |
981 } | 957 } |
982 exports.ElemHideException = ElemHideException; | 958 exports.ElemHideException = ElemHideException; |
983 | 959 |
984 ElemHideException.prototype = extend(ElemHideBase, { | 960 ElemHideException.prototype = extend(ElemHideBase, { |
985 type: "elemhideexception" | 961 type: "elemhideexception" |
986 }); | 962 }); |
987 | 963 |
988 /** | 964 /** |
989 * Class for CSS property filters | 965 * Class for element hiding emulation filters |
990 * @param {String} text see Filter() | 966 * @param {String} text see Filter() |
991 * @param {String} domains see ElemHideBase() | 967 * @param {String} domains see ElemHideBase() |
992 * @param {String} selector see ElemHideBase() | 968 * @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 | 969 * @constructor |
997 * @augments ElemHideBase | 970 * @augments ElemHideBase |
998 */ | 971 */ |
999 function CSSPropertyFilter(text, domains, selector, regexpSource, | 972 function ElemHideEmulationFilter(text, domains, selector) |
1000 selectorPrefix, selectorSuffix) | |
1001 { | 973 { |
1002 ElemHideBase.call(this, text, domains, selector); | 974 ElemHideBase.call(this, text, domains, selector); |
| 975 } |
| 976 exports.ElemHideEmulationFilter = ElemHideEmulationFilter; |
1003 | 977 |
1004 this.regexpSource = regexpSource; | 978 ElemHideEmulationFilter.prototype = extend(ElemHideBase, { |
1005 this.selectorPrefix = selectorPrefix; | 979 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 }); | 980 }); |
OLD | NEW |