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

Side by Side Diff: lib/filterClasses.js

Issue 5730585574113280: Issue 2390 - Created filter class for CSS property filters (Closed)
Patch Set: Rebased changes Created June 8, 2015, 1:32 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
« no previous file with comments | « chrome/locale/en-US/global.properties ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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-2015 Eyeo GmbH 3 * Copyright (C) 2006-2015 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 {Utils} = require("utils");
23 24
24 /** 25 /**
25 * Abstract base class for filters 26 * Abstract base class for filters
26 * 27 *
27 * @param {String} text string representation of the filter 28 * @param {String} text string representation of the filter
28 * @constructor 29 * @constructor
29 */ 30 */
30 function Filter(text) 31 function Filter(text)
31 { 32 {
32 this.text = text; 33 this.text = text;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
78 /** 79 /**
79 * Regular expression that RegExp filters specified as RegExps should match 80 * Regular expression that RegExp filters specified as RegExps should match
80 * @type RegExp 81 * @type RegExp
81 */ 82 */
82 Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[ ^,\s]+)?)*)?$/; 83 Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[ ^,\s]+)?)*)?$/;
83 /** 84 /**
84 * Regular expression that options on a RegExp filter should match 85 * Regular expression that options on a RegExp filter should match
85 * @type RegExp 86 * @type RegExp
86 */ 87 */
87 Filter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)$/ ; 88 Filter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)$/ ;
89 /**
90 * Regular expression that CSS property filters should match
91 * Properties must not contain " or '
92 * @type RegExp
93 */
94 Filter.csspropertyRegExp = /\[\-abp\-properties=(["'])([^"']+)\1\]/;
88 95
89 /** 96 /**
90 * Creates a filter of correct type from its text representation - does the basi c parsing and 97 * Creates a filter of correct type from its text representation - does the basi c parsing and
91 * calls the right constructor then. 98 * calls the right constructor then.
92 * 99 *
93 * @param {String} text as in Filter() 100 * @param {String} text as in Filter()
94 * @return {Filter} 101 * @return {Filter}
95 */ 102 */
96 Filter.fromText = function(text) 103 Filter.fromText = function(text)
97 { 104 {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 { 160 {
154 // Special treatment for element hiding filters, right side is allowed to co ntain spaces 161 // Special treatment for element hiding filters, right side is allowed to co ntain spaces
155 let [, domain, separator, selector] = /^(.*?)(#\@?#?)(.*)$/.exec(text); 162 let [, domain, separator, selector] = /^(.*?)(#\@?#?)(.*)$/.exec(text);
156 return domain.replace(/\s/g, "") + separator + selector.trim(); 163 return domain.replace(/\s/g, "") + separator + selector.trim();
157 } 164 }
158 else 165 else
159 return text.replace(/\s/g, ""); 166 return text.replace(/\s/g, "");
160 }; 167 };
161 168
162 /** 169 /**
170 * Converts filter text into regular expression string
171 * @param {String} text as in Filter()
172 * @return {String} regular expression representation of filter text
173 */
174 Filter.toRegExp = function(text)
175 {
176 return text
177 .replace(/\*+/g, "*") // remove multiple wildcards
178 .replace(/\^\|$/, "^") // remove anchors following separator placehold er
179 .replace(/\W/g, "\\$&") // escape special symbols
180 .replace(/\\\*/g, ".*") // replace wildcards by .*
181 // process separator placeholders (all ANSI characters but alphanumeric char acters and _%.-)
182 .replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5E\\x6 0\\x7B-\\x7F]|$)")
183 .replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?") // process ex tended anchor at expression start
184 .replace(/^\\\|/, "^") // process anchor at expression start
185 .replace(/\\\|$/, "$") // process anchor at expression end
186 .replace(/^(\.\*)/, "") // remove leading wildcards
187 .replace(/(\.\*)$/, ""); // remove trailing wildcards
188 }
189
190 /**
163 * Class for invalid filters 191 * Class for invalid filters
164 * @param {String} text see Filter() 192 * @param {String} text see Filter()
165 * @param {String} reason Reason why this filter is invalid 193 * @param {String} reason Reason why this filter is invalid
166 * @constructor 194 * @constructor
167 * @augments Filter 195 * @augments Filter
168 */ 196 */
169 function InvalidFilter(text, reason) 197 function InvalidFilter(text, reason)
170 { 198 {
171 Filter.call(this, text); 199 Filter.call(this, text);
172 200
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 * @type RegExp 564 * @type RegExp
537 */ 565 */
538 get regexp() 566 get regexp()
539 { 567 {
540 // Despite this property being cached, the getter is called 568 // Despite this property being cached, the getter is called
541 // several times on Safari, due to WebKit bug 132872 569 // several times on Safari, due to WebKit bug 132872
542 let prop = Object.getOwnPropertyDescriptor(this, "regexp"); 570 let prop = Object.getOwnPropertyDescriptor(this, "regexp");
543 if (prop) 571 if (prop)
544 return prop.value; 572 return prop.value;
545 573
546 // Remove multiple wildcards 574 let source = Filter.toRegExp(this.regexpSource);
547 let source = this.regexpSource
548 .replace(/\*+/g, "*") // remove multiple wildcards
549 .replace(/\^\|$/, "^") // remove anchors following separator placeho lder
550 .replace(/\W/g, "\\$&") // escape special symbols
551 .replace(/\\\*/g, ".*") // replace wildcards by .*
552 // process separator placeholders (all ANSI characters but alphanumeric ch aracters and _%.-)
553 .replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5E\\ x60\\x7B-\\x7F]|$)")
554 .replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?") // process extended anchor at expression start
555 .replace(/^\\\|/, "^") // process anchor at expression start
556 .replace(/\\\|$/, "$") // process anchor at expression end
557 .replace(/^(\.\*)/, "") // remove leading wildcards
558 .replace(/(\.\*)$/, ""); // remove trailing wildcards
559
560 let regexp = new RegExp(source, this.matchCase ? "" : "i"); 575 let regexp = new RegExp(source, this.matchCase ? "" : "i");
561 Object.defineProperty(this, "regexp", {value: regexp}); 576 Object.defineProperty(this, "regexp", {value: regexp});
562 return regexp; 577 return regexp;
563 }, 578 },
564 /** 579 /**
565 * Content types the filter applies to, combination of values from RegExpFilte r.typeMap 580 * Content types the filter applies to, combination of values from RegExpFilte r.typeMap
566 * @type Number 581 * @type Number
567 */ 582 */
568 contentType: 0x7FFFFFFF, 583 contentType: 0x7FFFFFFF,
569 /** 584 /**
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after
845 }; 860 };
846 861
847 /** 862 /**
848 * Creates an element hiding filter from a pre-parsed text representation 863 * Creates an element hiding filter from a pre-parsed text representation
849 * 864 *
850 * @param {String} text same as in Filter() 865 * @param {String} text same as in Filter()
851 * @param {String} domain domain part of the text representation (can be emp ty) 866 * @param {String} domain domain part of the text representation (can be emp ty)
852 * @param {String} tagName tag name part (can be empty) 867 * @param {String} tagName tag name part (can be empty)
853 * @param {String} attrRules attribute matching rules (can be empty) 868 * @param {String} attrRules attribute matching rules (can be empty)
854 * @param {String} selector raw CSS selector (can be empty) 869 * @param {String} selector raw CSS selector (can be empty)
855 * @return {ElemHideFilter|ElemHideException|InvalidFilter} 870 * @return {ElemHideFilter|ElemHideException|CSSPropertyFilter|InvalidFilter}
856 */ 871 */
857 ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules, selector) 872 ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules, selector)
858 { 873 {
859 if (!selector) 874 if (!selector)
860 { 875 {
861 if (tagName == "*") 876 if (tagName == "*")
862 tagName = ""; 877 tagName = "";
863 878
864 let id = null; 879 let id = null;
865 let additional = ""; 880 let additional = "";
866 if (attrRules) { 881 if (attrRules)
882 {
867 attrRules = attrRules.match(/\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\)/g); 883 attrRules = attrRules.match(/\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\)/g);
868 for (let rule of attrRules) { 884 for (let rule of attrRules)
885 {
869 rule = rule.substr(1, rule.length - 2); 886 rule = rule.substr(1, rule.length - 2);
870 let separatorPos = rule.indexOf("="); 887 let separatorPos = rule.indexOf("=");
871 if (separatorPos > 0) { 888 if (separatorPos > 0)
889 {
872 rule = rule.replace(/=/, '="') + '"'; 890 rule = rule.replace(/=/, '="') + '"';
873 additional += "[" + rule + "]"; 891 additional += "[" + rule + "]";
874 } 892 }
875 else { 893 else
894 {
876 if (id) 895 if (id)
877 {
878 let {Utils} = require("utils");
879 return new InvalidFilter(text, Utils.getString("filter_elemhide_dupl icate_id")); 896 return new InvalidFilter(text, Utils.getString("filter_elemhide_dupl icate_id"));
880 } 897
881 else 898 id = rule;
882 id = rule;
883 } 899 }
884 } 900 }
885 } 901 }
886 902
887 if (id) 903 if (id)
888 selector = tagName + "." + id + additional + "," + tagName + "#" + id + ad ditional; 904 selector = tagName + "." + id + additional + "," + tagName + "#" + id + ad ditional;
889 else if (tagName || additional) 905 else if (tagName || additional)
890 selector = tagName + additional; 906 selector = tagName + additional;
891 else 907 else
892 {
893 let {Utils} = require("utils");
894 return new InvalidFilter(text, Utils.getString("filter_elemhide_nocriteria ")); 908 return new InvalidFilter(text, Utils.getString("filter_elemhide_nocriteria "));
895 }
896 } 909 }
910
897 if (isException) 911 if (isException)
898 return new ElemHideException(text, domain, selector); 912 return new ElemHideException(text, domain, selector);
899 else 913
900 return new ElemHideFilter(text, domain, selector); 914 if (Filter.csspropertyRegExp.test(selector))
915 {
916 // CSS property filters are inefficient so we need to make sure that
917 // they're only applied if they specify active domains
918 if (!/,[^~][^,.]*\.[^,]/.test("," + domain))
919 return new InvalidFilter(text, Utils.getString("filter_cssproperty_nodomai n"));
920
921 return new CSSPropertyFilter(text, domain, selector);
922 }
923
924 return new ElemHideFilter(text, domain, selector);
901 }; 925 };
902 926
903 /** 927 /**
904 * Class for element hiding filters 928 * Class for element hiding filters
905 * @param {String} text see Filter() 929 * @param {String} text see Filter()
906 * @param {String} domains see ElemHideBase() 930 * @param {String} domains see ElemHideBase()
907 * @param {String} selector see ElemHideBase() 931 * @param {String} selector see ElemHideBase()
908 * @constructor 932 * @constructor
909 * @augments ElemHideBase 933 * @augments ElemHideBase
910 */ 934 */
(...skipping 19 matching lines...) Expand all
930 function ElemHideException(text, domains, selector) 954 function ElemHideException(text, domains, selector)
931 { 955 {
932 ElemHideBase.call(this, text, domains, selector); 956 ElemHideBase.call(this, text, domains, selector);
933 } 957 }
934 exports.ElemHideException = ElemHideException; 958 exports.ElemHideException = ElemHideException;
935 959
936 ElemHideException.prototype = 960 ElemHideException.prototype =
937 { 961 {
938 __proto__: ElemHideBase.prototype 962 __proto__: ElemHideBase.prototype
939 }; 963 };
964
965 /**
966 * Class for CSS property filters
967 * @param {String} text see Filter()
968 * @param {String} domains see ElemHideBase()
969 * @param {String} selector see ElemHideBase()
970 * @constructor
971 * @augments ElemHideBase
972 */
973 function CSSPropertyFilter(text, domains, selector)
974 {
975 ElemHideBase.call(this, text, domains, selector);
976
977 let properties;
978 [properties, , this.regexpSource] = selector.match(Filter.csspropertyRegExp);
979 [this.selectorPrefix, this.selectorSuffix] = selector.split(properties);
980 }
981 exports.CSSPropertyFilter = CSSPropertyFilter;
982
983 CSSPropertyFilter.prototype =
984 {
985 __proto__: ElemHideBase.prototype,
986
987 /**
988 * Expression from which a regular expression should be generated for matching
989 * CSS properties - for delayed creation of the regexpString property
990 * @type String
991 */
992 regexpSource: null,
993 /**
994 * Substring of CSS selector before properties for the HTML elements that
995 * should be hidden
996 * @type String
997 */
998 selectorPrefix: null,
999 /**
1000 * Substring of CSS selector after properties for the HTML elements that
1001 * should be hidden
1002 * @type String
1003 */
1004 selectorSuffix: null,
1005
1006 /**
1007 * Raw regular expression string to be used when testing CSS properties
1008 * against this filter
1009 * @type String
1010 */
1011 get regexpString()
1012 {
1013 // Despite this property being cached, the getter is called
1014 // several times on Safari, due to WebKit bug 132872
1015 let prop = Object.getOwnPropertyDescriptor(this, "regexpString");
1016 if (prop)
1017 return prop.value;
1018
1019 let regexp = Filter.toRegExp(this.regexpSource);
1020 Object.defineProperty(this, "regexpString", {value: regexp});
1021 return regexp;
1022 }
1023 };
OLDNEW
« no previous file with comments | « chrome/locale/en-US/global.properties ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld