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

Side by Side Diff: lib/filterClasses.js

Issue 29375915: Issue 4878 - Start using ESLint for adblockpluscore (Closed)
Patch Set: Addressed Sebastian's initial feedback Created Feb. 21, 2017, 6:12 a.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 "use strict";
19
18 /** 20 /**
19 * @fileOverview Definition of Filter class and its subclasses. 21 * @fileOverview Definition of Filter class and its subclasses.
20 */ 22 */
21 23
22 let {FilterNotifier} = require("filterNotifier"); 24 let {FilterNotifier} = require("filterNotifier");
23 let {extend} = require("coreUtils"); 25 let {extend} = require("coreUtils");
24 let {filterToRegExp} = require("common"); 26 let {filterToRegExp} = require("common");
25 27
26 /** 28 /**
27 * Abstract base class for filters 29 * Abstract base class for filters
28 * 30 *
29 * @param {String} text string representation of the filter 31 * @param {string} text string representation of the filter
30 * @constructor 32 * @constructor
31 */ 33 */
32 function Filter(text) 34 function Filter(text)
33 { 35 {
34 this.text = text; 36 this.text = text;
35 this.subscriptions = []; 37 this.subscriptions = [];
36 } 38 }
37 exports.Filter = Filter; 39 exports.Filter = Filter;
38 40
39 Filter.prototype = 41 Filter.prototype =
40 { 42 {
41 /** 43 /**
42 * String representation of the filter 44 * String representation of the filter
43 * @type String 45 * @type {string}
44 */ 46 */
45 text: null, 47 text: null,
46 48
47 /** 49 /**
48 * Filter subscriptions the filter belongs to 50 * Filter subscriptions the filter belongs to
49 * @type Subscription[] 51 * @type {Subscription[]}
50 */ 52 */
51 subscriptions: null, 53 subscriptions: null,
52 54
53 /** 55 /**
54 * Filter type as a string, e.g. "blocking". 56 * Filter type as a string, e.g. "blocking".
55 * @type String 57 * @type {string}
56 */ 58 */
57 get type() 59 get type()
58 { 60 {
59 throw new Error("Please define filter type in the subclass"); 61 throw new Error("Please define filter type in the subclass");
60 }, 62 },
61 63
62 /** 64 /**
63 * Serializes the filter to an array of strings for writing out on the disk. 65 * Serializes the filter to an array of strings for writing out on the disk.
64 * @param {string[]} buffer buffer to push the serialization results into 66 * @param {string[]} buffer buffer to push the serialization results into
65 */ 67 */
66 serialize: function(buffer) 68 serialize(buffer)
67 { 69 {
68 buffer.push("[Filter]"); 70 buffer.push("[Filter]");
69 buffer.push("text=" + this.text); 71 buffer.push("text=" + this.text);
70 }, 72 },
71 73
72 toString: function() 74 toString()
73 { 75 {
74 return this.text; 76 return this.text;
75 } 77 }
76 }; 78 };
77 79
78 /** 80 /**
79 * Cache for known filters, maps string representation to filter objects. 81 * Cache for known filters, maps string representation to filter objects.
80 * @type Object 82 * @type {Object}
81 */ 83 */
82 Filter.knownFilters = Object.create(null); 84 Filter.knownFilters = Object.create(null);
83 85
84 /** 86 /**
85 * Regular expression that element hiding filters should match 87 * Regular expression that element hiding filters should match
86 * @type RegExp 88 * @type {RegExp}
87 */ 89 */
88 Filter.elemhideRegExp = /^([^\/\*\|\@"!]*?)#(\@)?(?:([\w\-]+|\*)((?:\([\w\-]+(?: [$^*]?=[^\(\)"]*)?\))*)|#(.+))$/; 90 Filter.elemhideRegExp = /^([^/*|@"!]*?)#(@)?(?:([\w-]+|\*)((?:\([\w-]+(?:[$^*]?= [^()"]*)?\))*)|#(.+))$/;
89 /** 91 /**
90 * Regular expression that RegExp filters specified as RegExps should match 92 * Regular expression that RegExp filters specified as RegExps should match
91 * @type RegExp 93 * @type {RegExp}
92 */ 94 */
93 Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[ ^,\s]+)?)*)?$/; 95 Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w-]+(?:=[^,\s]+)?(?:,~?[\w-]+(?:=[^, \s]+)?)*)?$/;
94 /** 96 /**
95 * Regular expression that options on a RegExp filter should match 97 * Regular expression that options on a RegExp filter should match
96 * @type RegExp 98 * @type {RegExp}
97 */ 99 */
98 Filter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)$/ ; 100 Filter.optionsRegExp = /\$(~?[\w-]+(?:=[^,\s]+)?(?:,~?[\w-]+(?:=[^,\s]+)?)*)$/;
99 101
100 /** 102 /**
101 * Creates a filter of correct type from its text representation - does the basi c parsing and 103 * Creates a filter of correct type from its text representation -
102 * calls the right constructor then. 104 * does the basic parsing and calls the right constructor then.
103 * 105 *
104 * @param {String} text as in Filter() 106 * @param {string} text as in Filter()
105 * @return {Filter} 107 * @return {Filter}
106 */ 108 */
107 Filter.fromText = function(text) 109 Filter.fromText = function(text)
108 { 110 {
109 if (text in Filter.knownFilters) 111 if (text in Filter.knownFilters)
110 return Filter.knownFilters[text]; 112 return Filter.knownFilters[text];
111 113
112 let ret; 114 let ret;
113 let match = (text.indexOf("#") >= 0 ? Filter.elemhideRegExp.exec(text) : null) ; 115 let match = (text.includes("#") ? Filter.elemhideRegExp.exec(text) : null);
114 if (match) 116 if (match)
115 ret = ElemHideBase.fromText(text, match[1], !!match[2], match[3], match[4], match[5]); 117 {
118 ret = ElemHideBase.fromText(
119 text, match[1], !!match[2], match[3], match[4], match[5]
120 );
121 }
116 else if (text[0] == "!") 122 else if (text[0] == "!")
117 ret = new CommentFilter(text); 123 ret = new CommentFilter(text);
118 else 124 else
119 ret = RegExpFilter.fromText(text); 125 ret = RegExpFilter.fromText(text);
120 126
121 Filter.knownFilters[ret.text] = ret; 127 Filter.knownFilters[ret.text] = ret;
122 return ret; 128 return ret;
123 }; 129 };
124 130
125 /** 131 /**
126 * Deserializes a filter 132 * Deserializes a filter
127 * 133 *
128 * @param {Object} obj map of serialized properties and their values 134 * @param {Object} obj map of serialized properties and their values
129 * @return {Filter} filter or null if the filter couldn't be created 135 * @return {Filter} filter or null if the filter couldn't be created
130 */ 136 */
131 Filter.fromObject = function(obj) 137 Filter.fromObject = function(obj)
132 { 138 {
133 let ret = Filter.fromText(obj.text); 139 let ret = Filter.fromText(obj.text);
134 if (ret instanceof ActiveFilter) 140 if (ret instanceof ActiveFilter)
135 { 141 {
136 if ("disabled" in obj) 142 if ("disabled" in obj)
137 ret._disabled = (obj.disabled == "true"); 143 ret._disabled = (obj.disabled == "true");
138 if ("hitCount" in obj) 144 if ("hitCount" in obj)
139 ret._hitCount = parseInt(obj.hitCount) || 0; 145 ret._hitCount = parseInt(obj.hitCount, 10) || 0;
140 if ("lastHit" in obj) 146 if ("lastHit" in obj)
141 ret._lastHit = parseInt(obj.lastHit) || 0; 147 ret._lastHit = parseInt(obj.lastHit, 10) || 0;
142 } 148 }
143 return ret; 149 return ret;
144 }; 150 };
145 151
146 /** 152 /**
147 * Removes unnecessary whitespaces from filter text, will only return null if 153 * Removes unnecessary whitespaces from filter text, will only return null if
148 * the input parameter is null. 154 * the input parameter is null.
155 * @param {string} text
156 * @return {string}
149 */ 157 */
150 Filter.normalize = function(/**String*/ text) /**String*/ 158 Filter.normalize = function(text)
151 { 159 {
152 if (!text) 160 if (!text)
153 return text; 161 return text;
154 162
155 // Remove line breaks and such 163 // Remove line breaks and such
156 text = text.replace(/[^\S ]/g, ""); 164 text = text.replace(/[^\S ]/g, "");
157 165
158 if (/^\s*!/.test(text)) 166 if (/^\s*!/.test(text))
159 { 167 {
160 // Don't remove spaces inside comments 168 // Don't remove spaces inside comments
161 return text.trim(); 169 return text.trim();
162 } 170 }
163 else if (Filter.elemhideRegExp.test(text)) 171 else if (Filter.elemhideRegExp.test(text))
164 { 172 {
165 // Special treatment for element hiding filters, right side is allowed to co ntain spaces 173 // Special treatment for element hiding filters, right side is
166 let [, domain, separator, selector] = /^(.*?)(#\@?#?)(.*)$/.exec(text); 174 // allowed to contain spaces
175 let [, domain, separator, selector] = /^(.*?)(#@?#?)(.*)$/.exec(text);
167 return domain.replace(/\s/g, "") + separator + selector.trim(); 176 return domain.replace(/\s/g, "") + separator + selector.trim();
168 } 177 }
169 else 178 return text.replace(/\s/g, "");
170 return text.replace(/\s/g, "");
171 }; 179 };
172 180
173 /** 181 /**
174 * @see filterToRegExp 182 * @see filterToRegExp
175 */ 183 */
176 Filter.toRegExp = filterToRegExp; 184 Filter.toRegExp = filterToRegExp;
177 185
178 /** 186 /**
179 * Class for invalid filters 187 * Class for invalid filters
180 * @param {String} text see Filter() 188 * @param {string} text see Filter()
181 * @param {String} reason Reason why this filter is invalid 189 * @param {string} reason Reason why this filter is invalid
182 * @constructor 190 * @constructor
183 * @augments Filter 191 * @augments Filter
184 */ 192 */
185 function InvalidFilter(text, reason) 193 function InvalidFilter(text, reason)
186 { 194 {
187 Filter.call(this, text); 195 Filter.call(this, text);
188 196
189 this.reason = reason; 197 this.reason = reason;
190 } 198 }
191 exports.InvalidFilter = InvalidFilter; 199 exports.InvalidFilter = InvalidFilter;
192 200
193 InvalidFilter.prototype = extend(Filter, { 201 InvalidFilter.prototype = extend(Filter, {
194 type: "invalid", 202 type: "invalid",
195 203
196 /** 204 /**
197 * Reason why this filter is invalid 205 * Reason why this filter is invalid
198 * @type String 206 * @type {string}
199 */ 207 */
200 reason: null, 208 reason: null,
201 209
202 /** 210 /**
203 * See Filter.serialize() 211 * See Filter.serialize()
212 * @param {string[]} buffer buffer to push the serialization results into
204 */ 213 */
205 serialize: function(buffer) {} 214 serialize(buffer) {}
206 }); 215 });
207 216
208 /** 217 /**
209 * Class for comments 218 * Class for comments
210 * @param {String} text see Filter() 219 * @param {string} text see Filter()
211 * @constructor 220 * @constructor
212 * @augments Filter 221 * @augments Filter
213 */ 222 */
214 function CommentFilter(text) 223 function CommentFilter(text)
215 { 224 {
216 Filter.call(this, text); 225 Filter.call(this, text);
217 } 226 }
218 exports.CommentFilter = CommentFilter; 227 exports.CommentFilter = CommentFilter;
219 228
220 CommentFilter.prototype = extend(Filter, { 229 CommentFilter.prototype = extend(Filter, {
221 type: "comment", 230 type: "comment",
222 231
223 /** 232 /**
224 * See Filter.serialize() 233 * See Filter.serialize()
234 * @param {string[]} buffer buffer to push the serialization results into
225 */ 235 */
226 serialize: function(buffer) {} 236 serialize(buffer) {}
227 }); 237 });
228 238
229 /** 239 /**
230 * Abstract base class for filters that can get hits 240 * Abstract base class for filters that can get hits
231 * @param {String} text see Filter() 241 * @param {string} text see Filter()
232 * @param {String} [domains] Domains that the filter is restricted to separated by domainSeparator e.g. "foo.com|bar.com|~baz.com" 242 * @param {string} [domains] Domains that the filter is restricted to
243 * separated by domainSeparator e.g. "foo.com|bar.com|~baz.com"
233 * @constructor 244 * @constructor
234 * @augments Filter 245 * @augments Filter
235 */ 246 */
236 function ActiveFilter(text, domains) 247 function ActiveFilter(text, domains)
237 { 248 {
238 Filter.call(this, text); 249 Filter.call(this, text);
239 250
240 this.domainSource = domains; 251 this.domainSource = domains;
241 } 252 }
242 exports.ActiveFilter = ActiveFilter; 253 exports.ActiveFilter = ActiveFilter;
243 254
244 ActiveFilter.prototype = extend(Filter, { 255 ActiveFilter.prototype = extend(Filter, {
245 _disabled: false, 256 _disabled: false,
246 _hitCount: 0, 257 _hitCount: 0,
247 _lastHit: 0, 258 _lastHit: 0,
248 259
249 /** 260 /**
250 * Defines whether the filter is disabled 261 * Defines whether the filter is disabled
251 * @type Boolean 262 * @type {boolean}
252 */ 263 */
253 get disabled() 264 get disabled()
254 { 265 {
255 return this._disabled; 266 return this._disabled;
256 }, 267 },
257 set disabled(value) 268 set disabled(value)
258 { 269 {
259 if (value != this._disabled) 270 if (value != this._disabled)
260 { 271 {
261 let oldValue = this._disabled; 272 let oldValue = this._disabled;
262 this._disabled = value; 273 this._disabled = value;
263 FilterNotifier.triggerListeners("filter.disabled", this, value, oldValue); 274 FilterNotifier.triggerListeners("filter.disabled", this, value, oldValue);
264 } 275 }
265 return this._disabled; 276 return this._disabled;
266 }, 277 },
267 278
268 /** 279 /**
269 * Number of hits on the filter since the last reset 280 * Number of hits on the filter since the last reset
270 * @type Number 281 * @type {Number}
271 */ 282 */
272 get hitCount() 283 get hitCount()
273 { 284 {
274 return this._hitCount; 285 return this._hitCount;
275 }, 286 },
276 set hitCount(value) 287 set hitCount(value)
277 { 288 {
278 if (value != this._hitCount) 289 if (value != this._hitCount)
279 { 290 {
280 let oldValue = this._hitCount; 291 let oldValue = this._hitCount;
281 this._hitCount = value; 292 this._hitCount = value;
282 FilterNotifier.triggerListeners("filter.hitCount", this, value, oldValue); 293 FilterNotifier.triggerListeners("filter.hitCount", this, value, oldValue);
283 } 294 }
284 return this._hitCount; 295 return this._hitCount;
285 }, 296 },
286 297
287 /** 298 /**
288 * Last time the filter had a hit (in milliseconds since the beginning of the epoch) 299 * Last time the filter had a hit (in milliseconds since the
289 * @type Number 300 * beginning of the epoch)
301 * @type {Number}
290 */ 302 */
291 get lastHit() 303 get lastHit()
292 { 304 {
293 return this._lastHit; 305 return this._lastHit;
294 }, 306 },
295 set lastHit(value) 307 set lastHit(value)
296 { 308 {
297 if (value != this._lastHit) 309 if (value != this._lastHit)
298 { 310 {
299 let oldValue = this._lastHit; 311 let oldValue = this._lastHit;
300 this._lastHit = value; 312 this._lastHit = value;
301 FilterNotifier.triggerListeners("filter.lastHit", this, value, oldValue); 313 FilterNotifier.triggerListeners("filter.lastHit", this, value, oldValue);
302 } 314 }
303 return this._lastHit; 315 return this._lastHit;
304 }, 316 },
305 317
306 /** 318 /**
307 * String that the domains property should be generated from 319 * String that the domains property should be generated from
308 * @type String 320 * @type {string}
309 */ 321 */
310 domainSource: null, 322 domainSource: null,
311 323
312 /** 324 /**
313 * Separator character used in domainSource property, must be overridden by su bclasses 325 * Separator character used in domainSource property, must be
314 * @type String 326 * overridden by subclasses
327 * @type {string}
315 */ 328 */
316 domainSeparator: null, 329 domainSeparator: null,
317 330
318 /** 331 /**
319 * Determines whether the trailing dot in domain names isn't important and 332 * Determines whether the trailing dot in domain names isn't important and
320 * should be ignored, must be overridden by subclasses. 333 * should be ignored, must be overridden by subclasses.
321 * @type Boolean 334 * @type {boolean}
322 */ 335 */
323 ignoreTrailingDot: true, 336 ignoreTrailingDot: true,
324 337
325 /** 338 /**
326 * Determines whether domainSource is already upper-case, 339 * Determines whether domainSource is already upper-case,
327 * can be overridden by subclasses. 340 * can be overridden by subclasses.
328 * @type Boolean 341 * @type {boolean}
329 */ 342 */
330 domainSourceIsUpperCase: false, 343 domainSourceIsUpperCase: false,
331 344
332 /** 345 /**
333 * Map containing domains that this filter should match on/not match on or nul l if the filter should match on all domains 346 * Map containing domains that this filter should match on/not match
334 * @type Object 347 * on or null if the filter should match on all domains
348 * @type {Object}
335 */ 349 */
336 get domains() 350 get domains()
337 { 351 {
338 // Despite this property being cached, the getter is called 352 // Despite this property being cached, the getter is called
339 // several times on Safari, due to WebKit bug 132872 353 // several times on Safari, due to WebKit bug 132872
340 let prop = Object.getOwnPropertyDescriptor(this, "domains"); 354 let prop = Object.getOwnPropertyDescriptor(this, "domains");
341 if (prop) 355 if (prop)
342 return prop.value; 356 return prop.value;
343 357
344 let domains = null; 358 let domains = null;
345 359
346 if (this.domainSource) 360 if (this.domainSource)
347 { 361 {
348 let source = this.domainSource; 362 let source = this.domainSource;
349 if (!this.domainSourceIsUpperCase) { 363 if (!this.domainSourceIsUpperCase)
364 {
350 // RegExpFilter already have uppercase domains 365 // RegExpFilter already have uppercase domains
351 source = source.toUpperCase(); 366 source = source.toUpperCase();
352 } 367 }
353 let list = source.split(this.domainSeparator); 368 let list = source.split(this.domainSeparator);
354 if (list.length == 1 && list[0][0] != "~") 369 if (list.length == 1 && list[0][0] != "~")
355 { 370 {
356 // Fast track for the common one-domain scenario 371 // Fast track for the common one-domain scenario
357 domains = Object.create(null); 372 domains = Object.create(null);
358 domains[""] = false; 373 domains[""] = false;
359 if (this.ignoreTrailingDot) 374 if (this.ignoreTrailingDot)
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 409
395 this.domainSource = null; 410 this.domainSource = null;
396 } 411 }
397 412
398 Object.defineProperty(this, "domains", {value: domains, enumerable: true}); 413 Object.defineProperty(this, "domains", {value: domains, enumerable: true});
399 return this.domains; 414 return this.domains;
400 }, 415 },
401 416
402 /** 417 /**
403 * Array containing public keys of websites that this filter should apply to 418 * Array containing public keys of websites that this filter should apply to
404 * @type string[] 419 * @type {string[]}
405 */ 420 */
406 sitekeys: null, 421 sitekeys: null,
407 422
408 /** 423 /**
409 * Checks whether this filter is active on a domain. 424 * Checks whether this filter is active on a domain.
410 * @param {String} docDomain domain name of the document that loads the URL 425 * @param {string} docDomain domain name of the document that loads the URL
411 * @param {String} [sitekey] public key provided by the document 426 * @param {string} [sitekey] public key provided by the document
412 * @return {Boolean} true in case of the filter being active 427 * @return {boolean} true in case of the filter being active
413 */ 428 */
414 isActiveOnDomain: function(docDomain, sitekey) 429 isActiveOnDomain(docDomain, sitekey)
415 { 430 {
416 // Sitekeys are case-sensitive so we shouldn't convert them to upper-case to avoid false 431 // Sitekeys are case-sensitive so we shouldn't convert them to
417 // positives here. Instead we need to change the way filter options are pars ed. 432 // upper-case to avoid false positives here. Instead we need to
418 if (this.sitekeys && (!sitekey || this.sitekeys.indexOf(sitekey.toUpperCase( )) < 0)) 433 // change the way filter options are parsed.
434 if (this.sitekeys &&
435 (!sitekey || this.sitekeys.indexOf(sitekey.toUpperCase()) < 0))
419 return false; 436 return false;
420 437
421 // If no domains are set the rule matches everywhere 438 // If no domains are set the rule matches everywhere
422 if (!this.domains) 439 if (!this.domains)
423 return true; 440 return true;
424 441
425 // If the document has no host name, match only if the filter isn't restrict ed to specific domains 442 // If the document has no host name, match only if the filter
443 // isn't restricted to specific domains
426 if (!docDomain) 444 if (!docDomain)
427 return this.domains[""]; 445 return this.domains[""];
428 446
429 if (this.ignoreTrailingDot) 447 if (this.ignoreTrailingDot)
430 docDomain = docDomain.replace(/\.+$/, ""); 448 docDomain = docDomain.replace(/\.+$/, "");
431 docDomain = docDomain.toUpperCase(); 449 docDomain = docDomain.toUpperCase();
432 450
433 while (true) 451 while (true)
434 { 452 {
435 if (docDomain in this.domains) 453 if (docDomain in this.domains)
436 return this.domains[docDomain]; 454 return this.domains[docDomain];
437 455
438 let nextDot = docDomain.indexOf("."); 456 let nextDot = docDomain.indexOf(".");
439 if (nextDot < 0) 457 if (nextDot < 0)
440 break; 458 break;
441 docDomain = docDomain.substr(nextDot + 1); 459 docDomain = docDomain.substr(nextDot + 1);
442 } 460 }
443 return this.domains[""]; 461 return this.domains[""];
444 }, 462 },
445 463
446 /** 464 /**
447 * Checks whether this filter is active only on a domain and its subdomains. 465 * Checks whether this filter is active only on a domain and its subdomains.
466 * @param {string} docDomain
467 * @return {boolean}
448 */ 468 */
449 isActiveOnlyOnDomain: function(/**String*/ docDomain) /**Boolean*/ 469 isActiveOnlyOnDomain(docDomain)
450 { 470 {
451 if (!docDomain || !this.domains || this.domains[""]) 471 if (!docDomain || !this.domains || this.domains[""])
452 return false; 472 return false;
453 473
454 if (this.ignoreTrailingDot) 474 if (this.ignoreTrailingDot)
455 docDomain = docDomain.replace(/\.+$/, ""); 475 docDomain = docDomain.replace(/\.+$/, "");
456 docDomain = docDomain.toUpperCase(); 476 docDomain = docDomain.toUpperCase();
457 477
458 for (let domain in this.domains) 478 for (let domain in this.domains)
459 if (this.domains[domain] && domain != docDomain && (domain.length <= docDo main.length || domain.indexOf("." + docDomain) != domain.length - docDomain.leng th - 1)) 479 {
480 if (this.domains[domain] && domain != docDomain &&
481 (domain.length <= docDomain.length ||
482 domain.indexOf("." + docDomain) !=
483 domain.length - docDomain.length - 1))
Sebastian Noack 2017/02/21 09:19:31 Perhaps this rather complex condition is either to
kzar 2017/02/21 10:37:01 Looks much clearer to me, Done.
460 return false; 484 return false;
485 }
461 486
462 return true; 487 return true;
463 }, 488 },
464 489
465 /** 490 /**
466 * Checks whether this filter is generic or specific 491 * Checks whether this filter is generic or specific
492 * @return {boolean}
467 */ 493 */
468 isGeneric: function() /**Boolean*/ 494 isGeneric()
469 { 495 {
470 return !(this.sitekeys && this.sitekeys.length) && 496 return !(this.sitekeys && this.sitekeys.length) &&
471 (!this.domains || this.domains[""]); 497 (!this.domains || this.domains[""]);
472 }, 498 },
473 499
474 /** 500 /**
475 * See Filter.serialize() 501 * See Filter.serialize()
502 * @param {string[]} buffer buffer to push the serialization results into
476 */ 503 */
477 serialize: function(buffer) 504 serialize(buffer)
478 { 505 {
479 if (this._disabled || this._hitCount || this._lastHit) 506 if (this._disabled || this._hitCount || this._lastHit)
480 { 507 {
481 Filter.prototype.serialize.call(this, buffer); 508 Filter.prototype.serialize.call(this, buffer);
482 if (this._disabled) 509 if (this._disabled)
483 buffer.push("disabled=true"); 510 buffer.push("disabled=true");
484 if (this._hitCount) 511 if (this._hitCount)
485 buffer.push("hitCount=" + this._hitCount); 512 buffer.push("hitCount=" + this._hitCount);
486 if (this._lastHit) 513 if (this._lastHit)
487 buffer.push("lastHit=" + this._lastHit); 514 buffer.push("lastHit=" + this._lastHit);
488 } 515 }
489 } 516 }
490 }); 517 });
491 518
492 /** 519 /**
493 * Abstract base class for RegExp-based filters 520 * Abstract base class for RegExp-based filters
494 * @param {String} text see Filter() 521 * @param {string} text see Filter()
495 * @param {String} regexpSource filter part that the regular expression should b e build from 522 * @param {string} regexpSource filter part that the regular expression should
496 * @param {Number} [contentType] Content types the filter applies to, combinatio n of values from RegExpFilter.typeMap 523 * be build from
497 * @param {Boolean} [matchCase] Defines whether the filter should distinguish be tween lower and upper case letters 524 * @param {Number} [contentType] Content types the filter applies to,
498 * @param {String} [domains] Domains that the filter is restricted to, e.g. "foo .com|bar.com|~baz.com" 525 * combination of values from RegExpFilter.typeMap
499 * @param {Boolean} [thirdParty] Defines whether the filter should apply to thir d-party or first-party content only 526 * @param {boolean} [matchCase] Defines whether the filter should distinguish
500 * @param {String} [sitekeys] Public keys of websites that this filter should ap ply to 527 * between lower and upper case letters
528 * @param {string} [domains] Domains that the filter is restricted to,
529 * e.g. "foo.com|bar.com|~baz.com"
530 * @param {boolean} [thirdParty] Defines whether the filter should apply to
531 * third-party or first-party content only
532 * @param {string} [sitekeys] Public keys of websites that this filter should
533 * apply to
501 * @constructor 534 * @constructor
502 * @augments ActiveFilter 535 * @augments ActiveFilter
503 */ 536 */
504 function RegExpFilter(text, regexpSource, contentType, matchCase, domains, third Party, sitekeys) 537 function RegExpFilter(text, regexpSource, contentType, matchCase, domains,
538 thirdParty, sitekeys)
505 { 539 {
506 ActiveFilter.call(this, text, domains, sitekeys); 540 ActiveFilter.call(this, text, domains, sitekeys);
507 541
508 if (contentType != null) 542 if (contentType != null)
509 this.contentType = contentType; 543 this.contentType = contentType;
510 if (matchCase) 544 if (matchCase)
511 this.matchCase = matchCase; 545 this.matchCase = matchCase;
512 if (thirdParty != null) 546 if (thirdParty != null)
513 this.thirdParty = thirdParty; 547 this.thirdParty = thirdParty;
514 if (sitekeys != null) 548 if (sitekeys != null)
515 this.sitekeySource = sitekeys; 549 this.sitekeySource = sitekeys;
516 550
517 if (regexpSource.length >= 2 && regexpSource[0] == "/" && regexpSource[regexpS ource.length - 1] == "/") 551 if (regexpSource.length >= 2 &&
552 regexpSource[0] == "/" &&
553 regexpSource[regexpSource.length - 1] == "/")
518 { 554 {
519 // The filter is a regular expression - convert it immediately to catch synt ax errors 555 // The filter is a regular expression - convert it immediately to
520 let regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2), thi s.matchCase ? "" : "i"); 556 // catch syntax errors
557 let regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2),
558 this.matchCase ? "" : "i");
521 Object.defineProperty(this, "regexp", {value: regexp}); 559 Object.defineProperty(this, "regexp", {value: regexp});
522 } 560 }
523 else 561 else
524 { 562 {
525 // No need to convert this filter to regular expression yet, do it on demand 563 // No need to convert this filter to regular expression yet, do it on demand
526 this.regexpSource = regexpSource; 564 this.regexpSource = regexpSource;
527 } 565 }
528 } 566 }
529 exports.RegExpFilter = RegExpFilter; 567 exports.RegExpFilter = RegExpFilter;
530 568
531 RegExpFilter.prototype = extend(ActiveFilter, { 569 RegExpFilter.prototype = extend(ActiveFilter, {
532 /** 570 /**
533 * @see ActiveFilter.domainSourceIsUpperCase 571 * @see ActiveFilter.domainSourceIsUpperCase
534 */ 572 */
535 domainSourceIsUpperCase: true, 573 domainSourceIsUpperCase: true,
536 574
537 /** 575 /**
538 * Number of filters contained, will always be 1 (required to optimize Matcher ). 576 * Number of filters contained, will always be 1 (required to
539 * @type Integer 577 * optimize Matcher).
578 * @type {number}
540 */ 579 */
541 length: 1, 580 length: 1,
542 581
543 /** 582 /**
544 * @see ActiveFilter.domainSeparator 583 * @see ActiveFilter.domainSeparator
545 */ 584 */
546 domainSeparator: "|", 585 domainSeparator: "|",
547 586
548 /** 587 /**
549 * Expression from which a regular expression should be generated - for delaye d creation of the regexp property 588 * Expression from which a regular expression should be generated -
550 * @type String 589 * for delayed creation of the regexp property
590 * @type {string}
551 */ 591 */
552 regexpSource: null, 592 regexpSource: null,
553 /** 593 /**
554 * Regular expression to be used when testing against this filter 594 * Regular expression to be used when testing against this filter
555 * @type RegExp 595 * @type {RegExp}
556 */ 596 */
557 get regexp() 597 get regexp()
558 { 598 {
559 // Despite this property being cached, the getter is called 599 // Despite this property being cached, the getter is called
560 // several times on Safari, due to WebKit bug 132872 600 // several times on Safari, due to WebKit bug 132872
561 let prop = Object.getOwnPropertyDescriptor(this, "regexp"); 601 let prop = Object.getOwnPropertyDescriptor(this, "regexp");
562 if (prop) 602 if (prop)
563 return prop.value; 603 return prop.value;
564 604
565 let source = Filter.toRegExp(this.regexpSource); 605 let source = Filter.toRegExp(this.regexpSource);
566 let regexp = new RegExp(source, this.matchCase ? "" : "i"); 606 let regexp = new RegExp(source, this.matchCase ? "" : "i");
567 Object.defineProperty(this, "regexp", {value: regexp}); 607 Object.defineProperty(this, "regexp", {value: regexp});
568 return regexp; 608 return regexp;
569 }, 609 },
570 /** 610 /**
571 * Content types the filter applies to, combination of values from RegExpFilte r.typeMap 611 * Content types the filter applies to, combination of values from
572 * @type Number 612 * RegExpFilter.typeMap
613 * @type {Number}
573 */ 614 */
574 contentType: 0x7FFFFFFF, 615 contentType: 0x7FFFFFFF,
575 /** 616 /**
576 * Defines whether the filter should distinguish between lower and upper case letters 617 * Defines whether the filter should distinguish between lower and
577 * @type Boolean 618 * upper case letters
619 * @type {boolean}
578 */ 620 */
579 matchCase: false, 621 matchCase: false,
580 /** 622 /**
581 * Defines whether the filter should apply to third-party or first-party conte nt only. Can be null (apply to all content). 623 * Defines whether the filter should apply to third-party or
582 * @type Boolean 624 * first-party content only. Can be null (apply to all content).
625 * @type {boolean}
583 */ 626 */
584 thirdParty: null, 627 thirdParty: null,
585 628
586 /** 629 /**
587 * String that the sitekey property should be generated from 630 * String that the sitekey property should be generated from
588 * @type String 631 * @type {string}
589 */ 632 */
590 sitekeySource: null, 633 sitekeySource: null,
591 634
592 /** 635 /**
593 * Array containing public keys of websites that this filter should apply to 636 * Array containing public keys of websites that this filter should apply to
594 * @type string[] 637 * @type {string[]}
595 */ 638 */
596 get sitekeys() 639 get sitekeys()
597 { 640 {
598 // Despite this property being cached, the getter is called 641 // Despite this property being cached, the getter is called
599 // several times on Safari, due to WebKit bug 132872 642 // several times on Safari, due to WebKit bug 132872
600 let prop = Object.getOwnPropertyDescriptor(this, "sitekeys"); 643 let prop = Object.getOwnPropertyDescriptor(this, "sitekeys");
601 if (prop) 644 if (prop)
602 return prop.value; 645 return prop.value;
603 646
604 let sitekeys = null; 647 let sitekeys = null;
605 648
606 if (this.sitekeySource) 649 if (this.sitekeySource)
607 { 650 {
608 sitekeys = this.sitekeySource.split("|"); 651 sitekeys = this.sitekeySource.split("|");
609 this.sitekeySource = null; 652 this.sitekeySource = null;
610 } 653 }
611 654
612 Object.defineProperty(this, "sitekeys", {value: sitekeys, enumerable: true}) ; 655 Object.defineProperty(
656 this, "sitekeys", {value: sitekeys, enumerable: true}
657 );
613 return this.sitekeys; 658 return this.sitekeys;
614 }, 659 },
615 660
616 /** 661 /**
617 * Tests whether the URL matches this filter 662 * Tests whether the URL matches this filter
618 * @param {String} location URL to be tested 663 * @param {string} location URL to be tested
619 * @param {number} typeMask bitmask of content / request types to match 664 * @param {number} typeMask bitmask of content / request types to match
620 * @param {String} docDomain domain name of the document that loads the URL 665 * @param {string} docDomain domain name of the document that loads the URL
621 * @param {Boolean} thirdParty should be true if the URL is a third-party requ est 666 * @param {boolean} thirdParty should be true if the URL is a third-party
622 * @param {String} sitekey public key provided by the document 667 * request
623 * @return {Boolean} true in case of a match 668 * @param {string} sitekey public key provided by the document
669 * @return {boolean} true in case of a match
624 */ 670 */
625 matches: function(location, typeMask, docDomain, thirdParty, sitekey) 671 matches(location, typeMask, docDomain, thirdParty, sitekey)
626 { 672 {
627 if (this.contentType & typeMask && 673 if (this.contentType & typeMask &&
628 (this.thirdParty == null || this.thirdParty == thirdParty) && 674 (this.thirdParty == null || this.thirdParty == thirdParty) &&
629 this.isActiveOnDomain(docDomain, sitekey) && this.regexp.test(location)) 675 this.isActiveOnDomain(docDomain, sitekey) && this.regexp.test(location))
630 {
631 return true; 676 return true;
632 }
633
634 return false; 677 return false;
635 } 678 }
636 }); 679 });
637 680
638 // Required to optimize Matcher, see also RegExpFilter.prototype.length 681 // Required to optimize Matcher, see also RegExpFilter.prototype.length
639 Object.defineProperty(RegExpFilter.prototype, "0", 682 Object.defineProperty(RegExpFilter.prototype, "0", {
640 { 683 get() { return this; }
641 get: function() { return this; }
642 }); 684 });
643 685
644 /** 686 /**
645 * Creates a RegExp filter from its text representation 687 * Creates a RegExp filter from its text representation
646 * @param {String} text same as in Filter() 688 * @param {string} text same as in Filter()
689 * @return {RegExpFilter}
647 */ 690 */
648 RegExpFilter.fromText = function(text) 691 RegExpFilter.fromText = function(text)
649 { 692 {
650 let blocking = true; 693 let blocking = true;
651 let origText = text; 694 let origText = text;
652 if (text.indexOf("@@") == 0) 695 if (text.indexOf("@@") == 0)
653 { 696 {
654 blocking = false; 697 blocking = false;
655 text = text.substr(2); 698 text = text.substr(2);
656 } 699 }
(...skipping 22 matching lines...) Expand all
679 option = option.replace(/-/, "_"); 722 option = option.replace(/-/, "_");
680 if (option in RegExpFilter.typeMap) 723 if (option in RegExpFilter.typeMap)
681 { 724 {
682 if (contentType == null) 725 if (contentType == null)
683 contentType = 0; 726 contentType = 0;
684 contentType |= RegExpFilter.typeMap[option]; 727 contentType |= RegExpFilter.typeMap[option];
685 } 728 }
686 else if (option[0] == "~" && option.substr(1) in RegExpFilter.typeMap) 729 else if (option[0] == "~" && option.substr(1) in RegExpFilter.typeMap)
687 { 730 {
688 if (contentType == null) 731 if (contentType == null)
689 contentType = RegExpFilter.prototype.contentType; 732 ({contentType} = RegExpFilter.prototype);
690 contentType &= ~RegExpFilter.typeMap[option.substr(1)]; 733 contentType &= ~RegExpFilter.typeMap[option.substr(1)];
691 } 734 }
692 else if (option == "MATCH_CASE") 735 else if (option == "MATCH_CASE")
693 matchCase = true; 736 matchCase = true;
694 else if (option == "~MATCH_CASE") 737 else if (option == "~MATCH_CASE")
695 matchCase = false; 738 matchCase = false;
696 else if (option == "DOMAIN" && typeof value != "undefined") 739 else if (option == "DOMAIN" && typeof value != "undefined")
697 domains = value; 740 domains = value;
698 else if (option == "THIRD_PARTY") 741 else if (option == "THIRD_PARTY")
699 thirdParty = true; 742 thirdParty = true;
700 else if (option == "~THIRD_PARTY") 743 else if (option == "~THIRD_PARTY")
701 thirdParty = false; 744 thirdParty = false;
702 else if (option == "COLLAPSE") 745 else if (option == "COLLAPSE")
703 collapse = true; 746 collapse = true;
704 else if (option == "~COLLAPSE") 747 else if (option == "~COLLAPSE")
705 collapse = false; 748 collapse = false;
706 else if (option == "SITEKEY" && typeof value != "undefined") 749 else if (option == "SITEKEY" && typeof value != "undefined")
707 sitekeys = value; 750 sitekeys = value;
708 else 751 else
709 return new InvalidFilter(origText, "filter_unknown_option"); 752 return new InvalidFilter(origText, "filter_unknown_option");
710 } 753 }
711 } 754 }
712 755
713 try 756 try
714 { 757 {
715 if (blocking) 758 if (blocking)
716 return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys, collapse); 759 {
717 else 760 return new BlockingFilter(origText, text, contentType, matchCase, domains,
718 return new WhitelistFilter(origText, text, contentType, matchCase, domains , thirdParty, sitekeys); 761 thirdParty, sitekeys, collapse);
762 }
763 return new WhitelistFilter(origText, text, contentType, matchCase, domains,
764 thirdParty, sitekeys);
719 } 765 }
720 catch (e) 766 catch (e)
721 { 767 {
722 return new InvalidFilter(origText, "filter_invalid_regexp"); 768 return new InvalidFilter(origText, "filter_invalid_regexp");
723 } 769 }
724 }; 770 };
725 771
726 /** 772 /**
727 * Maps type strings like "SCRIPT" or "OBJECT" to bit masks 773 * Maps type strings like "SCRIPT" or "OBJECT" to bit masks
728 */ 774 */
(...skipping 25 matching lines...) Expand all
754 // DOCUMENT, ELEMHIDE, POPUP, GENERICHIDE and GENERICBLOCK options shouldn't 800 // DOCUMENT, ELEMHIDE, POPUP, GENERICHIDE and GENERICBLOCK options shouldn't
755 // be there by default 801 // be there by default
756 RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.DOCUMENT | 802 RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.DOCUMENT |
757 RegExpFilter.typeMap.ELEMHIDE | 803 RegExpFilter.typeMap.ELEMHIDE |
758 RegExpFilter.typeMap.POPUP | 804 RegExpFilter.typeMap.POPUP |
759 RegExpFilter.typeMap.GENERICHIDE | 805 RegExpFilter.typeMap.GENERICHIDE |
760 RegExpFilter.typeMap.GENERICBLOCK); 806 RegExpFilter.typeMap.GENERICBLOCK);
761 807
762 /** 808 /**
763 * Class for blocking filters 809 * Class for blocking filters
764 * @param {String} text see Filter() 810 * @param {string} text see Filter()
765 * @param {String} regexpSource see RegExpFilter() 811 * @param {string} regexpSource see RegExpFilter()
766 * @param {Number} contentType see RegExpFilter() 812 * @param {Number} contentType see RegExpFilter()
767 * @param {Boolean} matchCase see RegExpFilter() 813 * @param {boolean} matchCase see RegExpFilter()
768 * @param {String} domains see RegExpFilter() 814 * @param {string} domains see RegExpFilter()
769 * @param {Boolean} thirdParty see RegExpFilter() 815 * @param {boolean} thirdParty see RegExpFilter()
770 * @param {String} sitekeys see RegExpFilter() 816 * @param {string} sitekeys see RegExpFilter()
771 * @param {Boolean} collapse defines whether the filter should collapse blocked content, can be null 817 * @param {boolean} collapse defines whether the filter should collapse blocked
818 * content, can be null
772 * @constructor 819 * @constructor
773 * @augments RegExpFilter 820 * @augments RegExpFilter
774 */ 821 */
775 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, thi rdParty, sitekeys, collapse) 822 function BlockingFilter(text, regexpSource, contentType, matchCase, domains,
823 thirdParty, sitekeys, collapse)
776 { 824 {
777 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, t hirdParty, sitekeys); 825 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains,
826 thirdParty, sitekeys);
778 827
779 this.collapse = collapse; 828 this.collapse = collapse;
780 } 829 }
781 exports.BlockingFilter = BlockingFilter; 830 exports.BlockingFilter = BlockingFilter;
782 831
783 BlockingFilter.prototype = extend(RegExpFilter, { 832 BlockingFilter.prototype = extend(RegExpFilter, {
784 type: "blocking", 833 type: "blocking",
785 834
786 /** 835 /**
787 * Defines whether the filter should collapse blocked content. Can be null (us e the global preference). 836 * Defines whether the filter should collapse blocked content.
788 * @type Boolean 837 * Can be null (use the global preference).
838 * @type {boolean}
789 */ 839 */
790 collapse: null 840 collapse: null
791 }); 841 });
792 842
793 /** 843 /**
794 * Class for whitelist filters 844 * Class for whitelist filters
795 * @param {String} text see Filter() 845 * @param {string} text see Filter()
796 * @param {String} regexpSource see RegExpFilter() 846 * @param {string} regexpSource see RegExpFilter()
797 * @param {Number} contentType see RegExpFilter() 847 * @param {Number} contentType see RegExpFilter()
798 * @param {Boolean} matchCase see RegExpFilter() 848 * @param {boolean} matchCase see RegExpFilter()
799 * @param {String} domains see RegExpFilter() 849 * @param {string} domains see RegExpFilter()
800 * @param {Boolean} thirdParty see RegExpFilter() 850 * @param {boolean} thirdParty see RegExpFilter()
801 * @param {String} sitekeys see RegExpFilter() 851 * @param {string} sitekeys see RegExpFilter()
802 * @constructor 852 * @constructor
803 * @augments RegExpFilter 853 * @augments RegExpFilter
804 */ 854 */
805 function WhitelistFilter(text, regexpSource, contentType, matchCase, domains, th irdParty, sitekeys) 855 function WhitelistFilter(text, regexpSource, contentType, matchCase, domains,
856 thirdParty, sitekeys)
806 { 857 {
807 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, t hirdParty, sitekeys); 858 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains,
859 thirdParty, sitekeys);
808 } 860 }
809 exports.WhitelistFilter = WhitelistFilter; 861 exports.WhitelistFilter = WhitelistFilter;
810 862
811 WhitelistFilter.prototype = extend(RegExpFilter, { 863 WhitelistFilter.prototype = extend(RegExpFilter, {
812 type: "whitelist" 864 type: "whitelist"
813 }); 865 });
814 866
815 /** 867 /**
816 * Base class for element hiding filters 868 * Base class for element hiding filters
817 * @param {String} text see Filter() 869 * @param {string} text see Filter()
818 * @param {String} [domains] Host names or domains the filter should be restrict ed to 870 * @param {string} [domains] Host names or domains the filter should be
819 * @param {String} selector CSS selector for the HTML elements that should be hidden 871 * restricted to
872 * @param {string} selector CSS selector for the HTML elements that should be
873 * hidden
820 * @constructor 874 * @constructor
821 * @augments ActiveFilter 875 * @augments ActiveFilter
822 */ 876 */
823 function ElemHideBase(text, domains, selector) 877 function ElemHideBase(text, domains, selector)
824 { 878 {
825 ActiveFilter.call(this, text, domains || null); 879 ActiveFilter.call(this, text, domains || null);
826 880
827 if (domains) 881 if (domains)
828 this.selectorDomain = domains.replace(/,~[^,]+/g, "").replace(/^~[^,]+,?/, " ").toLowerCase(); 882 {
883 this.selectorDomain = domains.replace(/,~[^,]+/g, "").
884 replace(/^~[^,]+,?/, "").toLowerCase();
Sebastian Noack 2017/02/21 09:19:30 I think it's more readable when indented like this
kzar 2017/02/21 10:37:01 Done.
885 }
829 886
830 // Braces are being escaped to prevent CSS rule injection. 887 // Braces are being escaped to prevent CSS rule injection.
831 this.selector = selector.replace("{", "\\x7B ").replace("}", "\\x7D "); 888 this.selector = selector.replace("{", "\\x7B ").replace("}", "\\x7D ");
832 } 889 }
833 exports.ElemHideBase = ElemHideBase; 890 exports.ElemHideBase = ElemHideBase;
834 891
835 ElemHideBase.prototype = extend(ActiveFilter, { 892 ElemHideBase.prototype = extend(ActiveFilter, {
836 /** 893 /**
837 * @see ActiveFilter.domainSeparator 894 * @see ActiveFilter.domainSeparator
838 */ 895 */
839 domainSeparator: ",", 896 domainSeparator: ",",
840 897
841 /** 898 /**
842 * @see ActiveFilter.ignoreTrailingDot 899 * @see ActiveFilter.ignoreTrailingDot
843 */ 900 */
844 ignoreTrailingDot: false, 901 ignoreTrailingDot: false,
845 902
846 /** 903 /**
847 * Host name or domain the filter should be restricted to (can be null for no restriction) 904 * Host name or domain the filter should be restricted to (can be null for
848 * @type String 905 * no restriction)
906 * @type {string}
849 */ 907 */
850 selectorDomain: null, 908 selectorDomain: null,
851 /** 909 /**
852 * CSS selector for the HTML elements that should be hidden 910 * CSS selector for the HTML elements that should be hidden
853 * @type String 911 * @type {string}
854 */ 912 */
855 selector: null 913 selector: null
856 }); 914 });
857 915
858 /** 916 /**
859 * Creates an element hiding filter from a pre-parsed text representation 917 * Creates an element hiding filter from a pre-parsed text representation
860 * 918 *
861 * @param {String} text same as in Filter() 919 * @param {string} text same as in Filter()
862 * @param {String} domain domain part of the text representation (can be e mpty) 920 * @param {string} domain domain part of the text representation
863 * @param {Boolean} isException exception rule indicator 921 * (can be empty)
864 * @param {String} tagName tag name part (can be empty) 922 * @param {boolean} isException exception rule indicator
865 * @param {String} attrRules attribute matching rules (can be empty) 923 * @param {string} tagName tag name part (can be empty)
866 * @param {String} selector raw CSS selector (can be empty) 924 * @param {string} attrRules attribute matching rules (can be empty)
867 * @return {ElemHideFilter|ElemHideException|ElemHideEmulationFilter|InvalidFilt er} 925 * @param {string} selector raw CSS selector (can be empty)
926 * @return {ElemHideFilter|ElemHideException|
927 * ElemHideEmulationFilter|InvalidFilter}
868 */ 928 */
869 ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules, selector) 929 ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules,
930 selector)
870 { 931 {
871 if (!selector) 932 if (!selector)
872 { 933 {
873 if (tagName == "*") 934 if (tagName == "*")
874 tagName = ""; 935 tagName = "";
875 936
876 let id = null; 937 let id = null;
877 let additional = ""; 938 let additional = "";
878 if (attrRules) 939 if (attrRules)
879 { 940 {
880 attrRules = attrRules.match(/\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\)/g); 941 attrRules = attrRules.match(/\([\w-]+(?:[$^*]?=[^()"]*)?\)/g);
881 for (let rule of attrRules) 942 for (let rule of attrRules)
882 { 943 {
883 rule = rule.substr(1, rule.length - 2); 944 rule = rule.substr(1, rule.length - 2);
884 let separatorPos = rule.indexOf("="); 945 let separatorPos = rule.indexOf("=");
885 if (separatorPos > 0) 946 if (separatorPos > 0)
886 { 947 {
887 rule = rule.replace(/=/, '="') + '"'; 948 rule = rule.replace(/=/, '="') + '"';
888 additional += "[" + rule + "]"; 949 additional += "[" + rule + "]";
889 } 950 }
890 else 951 else
891 { 952 {
892 if (id) 953 if (id)
893 return new InvalidFilter(text, "filter_elemhide_duplicate_id"); 954 return new InvalidFilter(text, "filter_elemhide_duplicate_id");
894 955
895 id = rule; 956 id = rule;
896 } 957 }
897 } 958 }
898 } 959 }
899 960
900 if (id) 961 if (id)
901 selector = tagName + "." + id + additional + "," + tagName + "#" + id + ad ditional; 962 selector = `${tagName}.${id}${additional},${tagName}#${id}${additional}`;
902 else if (tagName || additional) 963 else if (tagName || additional)
903 selector = tagName + additional; 964 selector = tagName + additional;
904 else 965 else
905 return new InvalidFilter(text, "filter_elemhide_nocriteria"); 966 return new InvalidFilter(text, "filter_elemhide_nocriteria");
906 } 967 }
907 968
908 // We don't allow ElemHide filters which have any empty domains. 969 // We don't allow ElemHide filters which have any empty domains.
909 // Note: The ElemHide.prototype.domainSeparator is duplicated here, if that 970 // Note: The ElemHide.prototype.domainSeparator is duplicated here, if that
910 // changes this must be changed too. 971 // changes this must be changed too.
911 if (domain && /(^|,)~?(,|$)/.test(domain)) 972 if (domain && /(^|,)~?(,|$)/.test(domain))
(...skipping 10 matching lines...) Expand all
922 return new InvalidFilter(text, "filter_elemhideemulation_nodomain"); 983 return new InvalidFilter(text, "filter_elemhideemulation_nodomain");
923 984
924 return new ElemHideEmulationFilter(text, domain, selector); 985 return new ElemHideEmulationFilter(text, domain, selector);
925 } 986 }
926 987
927 return new ElemHideFilter(text, domain, selector); 988 return new ElemHideFilter(text, domain, selector);
928 }; 989 };
929 990
930 /** 991 /**
931 * Class for element hiding filters 992 * Class for element hiding filters
932 * @param {String} text see Filter() 993 * @param {string} text see Filter()
933 * @param {String} domains see ElemHideBase() 994 * @param {string} domains see ElemHideBase()
934 * @param {String} selector see ElemHideBase() 995 * @param {string} selector see ElemHideBase()
935 * @constructor 996 * @constructor
936 * @augments ElemHideBase 997 * @augments ElemHideBase
937 */ 998 */
938 function ElemHideFilter(text, domains, selector) 999 function ElemHideFilter(text, domains, selector)
939 { 1000 {
940 ElemHideBase.call(this, text, domains, selector); 1001 ElemHideBase.call(this, text, domains, selector);
941 } 1002 }
942 exports.ElemHideFilter = ElemHideFilter; 1003 exports.ElemHideFilter = ElemHideFilter;
943 1004
944 ElemHideFilter.prototype = extend(ElemHideBase, { 1005 ElemHideFilter.prototype = extend(ElemHideBase, {
945 type: "elemhide" 1006 type: "elemhide"
946 }); 1007 });
947 1008
948 /** 1009 /**
949 * Class for element hiding exceptions 1010 * Class for element hiding exceptions
950 * @param {String} text see Filter() 1011 * @param {string} text see Filter()
951 * @param {String} domains see ElemHideBase() 1012 * @param {string} domains see ElemHideBase()
952 * @param {String} selector see ElemHideBase() 1013 * @param {string} selector see ElemHideBase()
953 * @constructor 1014 * @constructor
954 * @augments ElemHideBase 1015 * @augments ElemHideBase
955 */ 1016 */
956 function ElemHideException(text, domains, selector) 1017 function ElemHideException(text, domains, selector)
957 { 1018 {
958 ElemHideBase.call(this, text, domains, selector); 1019 ElemHideBase.call(this, text, domains, selector);
959 } 1020 }
960 exports.ElemHideException = ElemHideException; 1021 exports.ElemHideException = ElemHideException;
961 1022
962 ElemHideException.prototype = extend(ElemHideBase, { 1023 ElemHideException.prototype = extend(ElemHideBase, {
963 type: "elemhideexception" 1024 type: "elemhideexception"
964 }); 1025 });
965 1026
966 /** 1027 /**
967 * Class for element hiding emulation filters 1028 * Class for element hiding emulation filters
968 * @param {String} text see Filter() 1029 * @param {string} text see Filter()
969 * @param {String} domains see ElemHideBase() 1030 * @param {string} domains see ElemHideBase()
970 * @param {String} selector see ElemHideBase() 1031 * @param {string} selector see ElemHideBase()
971 * @constructor 1032 * @constructor
972 * @augments ElemHideBase 1033 * @augments ElemHideBase
973 */ 1034 */
974 function ElemHideEmulationFilter(text, domains, selector) 1035 function ElemHideEmulationFilter(text, domains, selector)
975 { 1036 {
976 ElemHideBase.call(this, text, domains, selector); 1037 ElemHideBase.call(this, text, domains, selector);
977 } 1038 }
978 exports.ElemHideEmulationFilter = ElemHideEmulationFilter; 1039 exports.ElemHideEmulationFilter = ElemHideEmulationFilter;
979 1040
980 ElemHideEmulationFilter.prototype = extend(ElemHideBase, { 1041 ElemHideEmulationFilter.prototype = extend(ElemHideBase, {
981 type: "elemhideemulation" 1042 type: "elemhideemulation"
982 }); 1043 });
OLDNEW

Powered by Google App Engine
This is Rietveld