| Left: | ||
| Right: |
| 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 {elemHideEmulationFeatureMap, filterToRegExp} = require("shared"); | |
| 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 let emulatedFeatures = 0; |
| 937 if (match) | 916 if (selector.indexOf("[-abp-properties") != -1) |
| 917 emulatedFeatures |= ElemHideEmulationFilter.featureMap.PROPERTY_SELECTOR; | |
| 918 if (selector.indexOf(":has(") != -1) | |
|
kzar
2016/11/04 15:45:56
The feature flags are a nice idea but I wonder wha
Felix Dahlke
2016/11/04 16:43:35
Well, if we detect NO feature here, this would jus
kzar
2016/11/07 12:36:26
I guess my question is what's the point of having
Felix Dahlke
2016/11/07 14:41:24
Well, we have to check for emulated features befor
kzar
2016/11/07 15:59:44
Well we don't need to set a boolean flag here eith
Felix Dahlke
2016/11/07 16:51:24
Yeah of course, my bad.
kzar
2016/11/07 17:10:22
That's not quite true, since if we're recording us
Felix Dahlke
2016/11/08 17:45:35
Well, sure, we don't have to run all checks if one
kzar
2016/11/15 16:54:13
Well no I think that if the only reason to add all
Felix Dahlke
2016/11/15 21:11:44
I still think it makes sense to start detecting (y
Wladimir Palant
2016/11/21 11:39:14
I actually have to agree with Dave here. You are d
Felix Dahlke
2016/11/21 14:38:58
Fair enough, I guess if we're not worried about ba
| |
| 919 emulatedFeatures |= ElemHideEmulationFilter.featureMap.HAS_PSEUDO_CLASS; | |
| 920 | |
| 921 if (emulatedFeatures != 0) | |
| 938 { | 922 { |
| 939 // CSS property filters are inefficient so we need to make sure that | 923 // Element hiding emulation filters are inefficient so we need to make sure |
| 940 // they're only applied if they specify active domains | 924 // that they're only applied if they specify active domains |
| 941 if (!/,[^~][^,.]*\.[^,]/.test("," + domain)) | 925 if (!/,[^~][^,.]*\.[^,]/.test("," + domain)) |
| 942 return new InvalidFilter(text, "filter_cssproperty_nodomain"); | 926 return new InvalidFilter(text, "filter_elemhideemulation_nodomain"); |
| 943 | 927 |
| 944 return new CSSPropertyFilter(text, domain, selector, match[2], | 928 return new ElemHideEmulationFilter(text, domain, selector, |
|
kzar
2016/11/04 15:45:56
I wonder if it's really a good idea to move the lo
Felix Dahlke
2016/11/04 16:43:35
Well, one part of the truth is that I don't know h
kzar
2016/11/07 17:19:25
That's a pretty good point actually, I didn't thin
| |
| 945 selector.substr(0, match.index), | 929 emulatedFeatures); |
| 946 selector.substr(match.index + match[0].length)); | |
| 947 } | 930 } |
| 948 | 931 |
| 949 return new ElemHideFilter(text, domain, selector); | 932 return new ElemHideFilter(text, domain, selector); |
| 950 }; | 933 }; |
| 951 | 934 |
| 952 /** | 935 /** |
| 953 * Class for element hiding filters | 936 * Class for element hiding filters |
| 954 * @param {String} text see Filter() | 937 * @param {String} text see Filter() |
| 955 * @param {String} domains see ElemHideBase() | 938 * @param {String} domains see ElemHideBase() |
| 956 * @param {String} selector see ElemHideBase() | 939 * @param {String} selector see ElemHideBase() |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 979 { | 962 { |
| 980 ElemHideBase.call(this, text, domains, selector); | 963 ElemHideBase.call(this, text, domains, selector); |
| 981 } | 964 } |
| 982 exports.ElemHideException = ElemHideException; | 965 exports.ElemHideException = ElemHideException; |
| 983 | 966 |
| 984 ElemHideException.prototype = extend(ElemHideBase, { | 967 ElemHideException.prototype = extend(ElemHideBase, { |
| 985 type: "elemhideexception" | 968 type: "elemhideexception" |
| 986 }); | 969 }); |
| 987 | 970 |
| 988 /** | 971 /** |
| 989 * Class for CSS property filters | 972 * Class for element hiding emulation filters |
| 990 * @param {String} text see Filter() | 973 * @param {String} text see Filter() |
| 991 * @param {String} domains see ElemHideBase() | 974 * @param {String} domains see ElemHideBase() |
| 992 * @param {String} selector see ElemHideBase() | 975 * @param {String} selector see ElemHideBase() |
| 993 * @param {String} regexpSource see CSSPropertyFilter.regexpSource | 976 * @param {Integer} features see ElemHideEmulationFilter.features |
| 994 * @param {String} selectorPrefix see CSSPropertyFilter.selectorPrefix | |
| 995 * @param {String} selectorSuffix see CSSPropertyFilter.selectorSuffix | |
| 996 * @constructor | 977 * @constructor |
| 997 * @augments ElemHideBase | 978 * @augments ElemHideBase |
| 998 */ | 979 */ |
| 999 function CSSPropertyFilter(text, domains, selector, regexpSource, | 980 function ElemHideEmulationFilter(text, domains, selector, features) |
| 1000 selectorPrefix, selectorSuffix) | |
| 1001 { | 981 { |
| 1002 ElemHideBase.call(this, text, domains, selector); | 982 ElemHideBase.call(this, text, domains, selector); |
| 1003 | 983 |
| 1004 this.regexpSource = regexpSource; | 984 this.features = features; |
| 1005 this.selectorPrefix = selectorPrefix; | |
| 1006 this.selectorSuffix = selectorSuffix; | |
| 1007 } | 985 } |
| 1008 exports.CSSPropertyFilter = CSSPropertyFilter; | 986 exports.ElemHideEmulationFilter = ElemHideEmulationFilter; |
| 1009 | 987 |
| 1010 CSSPropertyFilter.prototype = extend(ElemHideBase, { | 988 ElemHideEmulationFilter.prototype = extend(ElemHideBase, { |
| 1011 type: "cssproperty", | 989 type: "elemhideemulation", |
| 1012 | 990 |
| 1013 /** | 991 /** |
| 1014 * Expression from which a regular expression should be generated for matching | 992 * Features used in this filter, combination of values from |
|
kzar
2016/11/04 15:45:56
Perhaps describe it as bit flags instead of combin
Felix Dahlke
2016/11/04 16:43:35
I thought I'd keep this in line with the doc comme
kzar
2016/11/07 17:19:25
Well bitmap works too. (I guess if you're worried
| |
| 1015 * CSS properties - for delayed creation of the regexpString property | 993 * ElemHideEmulationFilter.featureMap |
| 1016 * @type String | 994 * @type Integer |
| 1017 */ | 995 */ |
| 1018 regexpSource: null, | 996 features: 0 |
| 1019 /** | 997 }); |
| 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 | 998 |
| 1032 /** | 999 /** |
| 1033 * Raw regular expression string to be used when testing CSS properties | 1000 * @see elemHideEmulationFeatureMap |
| 1034 * against this filter | 1001 */ |
| 1035 * @type String | 1002 ElemHideEmulationFilter.featureMap = elemHideEmulationFeatureMap; |
| 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 = Filter.toRegExp(this.regexpSource); | |
| 1046 Object.defineProperty(this, "regexpString", {value: regexp}); | |
| 1047 return regexp; | |
| 1048 } | |
| 1049 }); | |
| OLD | NEW |