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: Remove the arrow-parens rule Created March 9, 2017, 10:23 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 const {FilterNotifier} = require("filterNotifier");
23 let {extend} = require("coreUtils"); 25 const {extend} = require("coreUtils");
24 let {filterToRegExp} = require("common"); 26 const {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 - does the
102 * calls the right constructor then. 104 * 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 allowed to
166 let [, domain, separator, selector] = /^(.*?)(#\@?#?)(.*)$/.exec(text); 174 // 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()
204 */ 212 */
205 serialize: function(buffer) {} 213 serialize(buffer) {}
206 }); 214 });
207 215
208 /** 216 /**
209 * Class for comments 217 * Class for comments
210 * @param {String} text see Filter() 218 * @param {string} text see Filter()
211 * @constructor 219 * @constructor
212 * @augments Filter 220 * @augments Filter
213 */ 221 */
214 function CommentFilter(text) 222 function CommentFilter(text)
215 { 223 {
216 Filter.call(this, text); 224 Filter.call(this, text);
217 } 225 }
218 exports.CommentFilter = CommentFilter; 226 exports.CommentFilter = CommentFilter;
219 227
220 CommentFilter.prototype = extend(Filter, { 228 CommentFilter.prototype = extend(Filter, {
221 type: "comment", 229 type: "comment",
222 230
223 /** 231 /**
224 * See Filter.serialize() 232 * See Filter.serialize()
225 */ 233 */
226 serialize: function(buffer) {} 234 serialize(buffer) {}
227 }); 235 });
228 236
229 /** 237 /**
230 * Abstract base class for filters that can get hits 238 * Abstract base class for filters that can get hits
231 * @param {String} text see Filter() 239 * @param {string} text
232 * @param {String} [domains] Domains that the filter is restricted to separated by domainSeparator e.g. "foo.com|bar.com|~baz.com" 240 * see Filter()
241 * @param {string} [domains]
242 * Domains that the filter is restricted to separated by domainSeparator
243 * 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 beginning of the
289 * @type Number 300 * 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))
436 {
419 return false; 437 return false;
438 }
420 439
421 // If no domains are set the rule matches everywhere 440 // If no domains are set the rule matches everywhere
422 if (!this.domains) 441 if (!this.domains)
423 return true; 442 return true;
424 443
425 // If the document has no host name, match only if the filter isn't restrict ed to specific domains 444 // If the document has no host name, match only if the filter
445 // isn't restricted to specific domains
426 if (!docDomain) 446 if (!docDomain)
427 return this.domains[""]; 447 return this.domains[""];
428 448
429 if (this.ignoreTrailingDot) 449 if (this.ignoreTrailingDot)
430 docDomain = docDomain.replace(/\.+$/, ""); 450 docDomain = docDomain.replace(/\.+$/, "");
431 docDomain = docDomain.toUpperCase(); 451 docDomain = docDomain.toUpperCase();
432 452
433 while (true) 453 while (true)
434 { 454 {
435 if (docDomain in this.domains) 455 if (docDomain in this.domains)
436 return this.domains[docDomain]; 456 return this.domains[docDomain];
437 457
438 let nextDot = docDomain.indexOf("."); 458 let nextDot = docDomain.indexOf(".");
439 if (nextDot < 0) 459 if (nextDot < 0)
440 break; 460 break;
441 docDomain = docDomain.substr(nextDot + 1); 461 docDomain = docDomain.substr(nextDot + 1);
442 } 462 }
443 return this.domains[""]; 463 return this.domains[""];
444 }, 464 },
445 465
446 /** 466 /**
447 * Checks whether this filter is active only on a domain and its subdomains. 467 * Checks whether this filter is active only on a domain and its subdomains.
468 * @param {string} docDomain
469 * @return {boolean}
448 */ 470 */
449 isActiveOnlyOnDomain: function(/**String*/ docDomain) /**Boolean*/ 471 isActiveOnlyOnDomain(docDomain)
450 { 472 {
451 if (!docDomain || !this.domains || this.domains[""]) 473 if (!docDomain || !this.domains || this.domains[""])
452 return false; 474 return false;
453 475
454 if (this.ignoreTrailingDot) 476 if (this.ignoreTrailingDot)
455 docDomain = docDomain.replace(/\.+$/, ""); 477 docDomain = docDomain.replace(/\.+$/, "");
456 docDomain = docDomain.toUpperCase(); 478 docDomain = docDomain.toUpperCase();
457 479
458 for (let domain in this.domains) 480 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)) 481 {
460 return false; 482 if (this.domains[domain] && domain != docDomain)
483 {
484 if (domain.length <= docDomain.length)
485 return false;
486
487 if (!domain.endsWith("." + docDomain))
488 return false;
489 }
490 }
461 491
462 return true; 492 return true;
463 }, 493 },
464 494
465 /** 495 /**
466 * Checks whether this filter is generic or specific 496 * Checks whether this filter is generic or specific
497 * @return {boolean}
467 */ 498 */
468 isGeneric: function() /**Boolean*/ 499 isGeneric()
469 { 500 {
470 return !(this.sitekeys && this.sitekeys.length) && 501 return !(this.sitekeys && this.sitekeys.length) &&
471 (!this.domains || this.domains[""]); 502 (!this.domains || this.domains[""]);
472 }, 503 },
473 504
474 /** 505 /**
475 * See Filter.serialize() 506 * See Filter.serialize()
476 */ 507 */
477 serialize: function(buffer) 508 serialize(buffer)
478 { 509 {
479 if (this._disabled || this._hitCount || this._lastHit) 510 if (this._disabled || this._hitCount || this._lastHit)
480 { 511 {
481 Filter.prototype.serialize.call(this, buffer); 512 Filter.prototype.serialize.call(this, buffer);
482 if (this._disabled) 513 if (this._disabled)
483 buffer.push("disabled=true"); 514 buffer.push("disabled=true");
484 if (this._hitCount) 515 if (this._hitCount)
485 buffer.push("hitCount=" + this._hitCount); 516 buffer.push("hitCount=" + this._hitCount);
486 if (this._lastHit) 517 if (this._lastHit)
487 buffer.push("lastHit=" + this._lastHit); 518 buffer.push("lastHit=" + this._lastHit);
488 } 519 }
489 } 520 }
490 }); 521 });
491 522
492 /** 523 /**
493 * Abstract base class for RegExp-based filters 524 * Abstract base class for RegExp-based filters
494 * @param {String} text see Filter() 525 * @param {string} text see Filter()
495 * @param {String} regexpSource filter part that the regular expression should b e build from 526 * @param {string} regexpSource
496 * @param {Number} [contentType] Content types the filter applies to, combinatio n of values from RegExpFilter.typeMap 527 * filter part that the regular expression should be build from
497 * @param {Boolean} [matchCase] Defines whether the filter should distinguish be tween lower and upper case letters 528 * @param {number} [contentType]
498 * @param {String} [domains] Domains that the filter is restricted to, e.g. "foo .com|bar.com|~baz.com" 529 * Content types the filter applies to, combination of values from
499 * @param {Boolean} [thirdParty] Defines whether the filter should apply to thir d-party or first-party content only 530 * RegExpFilter.typeMap
500 * @param {String} [sitekeys] Public keys of websites that this filter should ap ply to 531 * @param {boolean} [matchCase]
532 * Defines whether the filter should distinguish between lower and upper case
533 * letters
534 * @param {string} [domains]
535 * Domains that the filter is restricted to, e.g. "foo.com|bar.com|~baz.com"
536 * @param {boolean} [thirdParty]
537 * Defines whether the filter should apply to third-party or first-party
538 * content only
539 * @param {string} [sitekeys]
540 * Public keys of websites that this filter should apply to
501 * @constructor 541 * @constructor
502 * @augments ActiveFilter 542 * @augments ActiveFilter
503 */ 543 */
504 function RegExpFilter(text, regexpSource, contentType, matchCase, domains, third Party, sitekeys) 544 function RegExpFilter(text, regexpSource, contentType, matchCase, domains,
545 thirdParty, sitekeys)
505 { 546 {
506 ActiveFilter.call(this, text, domains, sitekeys); 547 ActiveFilter.call(this, text, domains, sitekeys);
507 548
508 if (contentType != null) 549 if (contentType != null)
509 this.contentType = contentType; 550 this.contentType = contentType;
510 if (matchCase) 551 if (matchCase)
511 this.matchCase = matchCase; 552 this.matchCase = matchCase;
512 if (thirdParty != null) 553 if (thirdParty != null)
513 this.thirdParty = thirdParty; 554 this.thirdParty = thirdParty;
514 if (sitekeys != null) 555 if (sitekeys != null)
515 this.sitekeySource = sitekeys; 556 this.sitekeySource = sitekeys;
516 557
517 if (regexpSource.length >= 2 && regexpSource[0] == "/" && regexpSource[regexpS ource.length - 1] == "/") 558 if (regexpSource.length >= 2 &&
559 regexpSource[0] == "/" &&
560 regexpSource[regexpSource.length - 1] == "/")
518 { 561 {
519 // The filter is a regular expression - convert it immediately to catch synt ax errors 562 // 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"); 563 // catch syntax errors
564 let regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2),
565 this.matchCase ? "" : "i");
521 Object.defineProperty(this, "regexp", {value: regexp}); 566 Object.defineProperty(this, "regexp", {value: regexp});
522 } 567 }
523 else 568 else
524 { 569 {
525 // No need to convert this filter to regular expression yet, do it on demand 570 // No need to convert this filter to regular expression yet, do it on demand
526 this.regexpSource = regexpSource; 571 this.regexpSource = regexpSource;
527 } 572 }
528 } 573 }
529 exports.RegExpFilter = RegExpFilter; 574 exports.RegExpFilter = RegExpFilter;
530 575
531 RegExpFilter.prototype = extend(ActiveFilter, { 576 RegExpFilter.prototype = extend(ActiveFilter, {
532 /** 577 /**
533 * @see ActiveFilter.domainSourceIsUpperCase 578 * @see ActiveFilter.domainSourceIsUpperCase
534 */ 579 */
535 domainSourceIsUpperCase: true, 580 domainSourceIsUpperCase: true,
536 581
537 /** 582 /**
538 * Number of filters contained, will always be 1 (required to optimize Matcher ). 583 * Number of filters contained, will always be 1 (required to
539 * @type Integer 584 * optimize Matcher).
585 * @type {number}
540 */ 586 */
541 length: 1, 587 length: 1,
542 588
543 /** 589 /**
544 * @see ActiveFilter.domainSeparator 590 * @see ActiveFilter.domainSeparator
545 */ 591 */
546 domainSeparator: "|", 592 domainSeparator: "|",
547 593
548 /** 594 /**
549 * Expression from which a regular expression should be generated - for delaye d creation of the regexp property 595 * Expression from which a regular expression should be generated -
550 * @type String 596 * for delayed creation of the regexp property
597 * @type {string}
551 */ 598 */
552 regexpSource: null, 599 regexpSource: null,
553 /** 600 /**
554 * Regular expression to be used when testing against this filter 601 * Regular expression to be used when testing against this filter
555 * @type RegExp 602 * @type {RegExp}
556 */ 603 */
557 get regexp() 604 get regexp()
558 { 605 {
559 // Despite this property being cached, the getter is called 606 // Despite this property being cached, the getter is called
560 // several times on Safari, due to WebKit bug 132872 607 // several times on Safari, due to WebKit bug 132872
561 let prop = Object.getOwnPropertyDescriptor(this, "regexp"); 608 let prop = Object.getOwnPropertyDescriptor(this, "regexp");
562 if (prop) 609 if (prop)
563 return prop.value; 610 return prop.value;
564 611
565 let source = Filter.toRegExp(this.regexpSource); 612 let source = Filter.toRegExp(this.regexpSource);
566 let regexp = new RegExp(source, this.matchCase ? "" : "i"); 613 let regexp = new RegExp(source, this.matchCase ? "" : "i");
567 Object.defineProperty(this, "regexp", {value: regexp}); 614 Object.defineProperty(this, "regexp", {value: regexp});
568 return regexp; 615 return regexp;
569 }, 616 },
570 /** 617 /**
571 * Content types the filter applies to, combination of values from RegExpFilte r.typeMap 618 * Content types the filter applies to, combination of values from
572 * @type Number 619 * RegExpFilter.typeMap
620 * @type {number}
573 */ 621 */
574 contentType: 0x7FFFFFFF, 622 contentType: 0x7FFFFFFF,
575 /** 623 /**
576 * Defines whether the filter should distinguish between lower and upper case letters 624 * Defines whether the filter should distinguish between lower and
577 * @type Boolean 625 * upper case letters
626 * @type {boolean}
578 */ 627 */
579 matchCase: false, 628 matchCase: false,
580 /** 629 /**
581 * Defines whether the filter should apply to third-party or first-party conte nt only. Can be null (apply to all content). 630 * Defines whether the filter should apply to third-party or
582 * @type Boolean 631 * first-party content only. Can be null (apply to all content).
632 * @type {boolean}
583 */ 633 */
584 thirdParty: null, 634 thirdParty: null,
585 635
586 /** 636 /**
587 * String that the sitekey property should be generated from 637 * String that the sitekey property should be generated from
588 * @type String 638 * @type {string}
589 */ 639 */
590 sitekeySource: null, 640 sitekeySource: null,
591 641
592 /** 642 /**
593 * Array containing public keys of websites that this filter should apply to 643 * Array containing public keys of websites that this filter should apply to
594 * @type string[] 644 * @type {string[]}
595 */ 645 */
596 get sitekeys() 646 get sitekeys()
597 { 647 {
598 // Despite this property being cached, the getter is called 648 // Despite this property being cached, the getter is called
599 // several times on Safari, due to WebKit bug 132872 649 // several times on Safari, due to WebKit bug 132872
600 let prop = Object.getOwnPropertyDescriptor(this, "sitekeys"); 650 let prop = Object.getOwnPropertyDescriptor(this, "sitekeys");
601 if (prop) 651 if (prop)
602 return prop.value; 652 return prop.value;
603 653
604 let sitekeys = null; 654 let sitekeys = null;
605 655
606 if (this.sitekeySource) 656 if (this.sitekeySource)
607 { 657 {
608 sitekeys = this.sitekeySource.split("|"); 658 sitekeys = this.sitekeySource.split("|");
609 this.sitekeySource = null; 659 this.sitekeySource = null;
610 } 660 }
611 661
612 Object.defineProperty(this, "sitekeys", {value: sitekeys, enumerable: true}) ; 662 Object.defineProperty(
663 this, "sitekeys", {value: sitekeys, enumerable: true}
664 );
613 return this.sitekeys; 665 return this.sitekeys;
614 }, 666 },
615 667
616 /** 668 /**
617 * Tests whether the URL matches this filter 669 * Tests whether the URL matches this filter
618 * @param {String} location URL to be tested 670 * @param {string} location URL to be tested
619 * @param {number} typeMask bitmask of content / request types to match 671 * @param {number} typeMask bitmask of content / request types to match
620 * @param {String} docDomain domain name of the document that loads the URL 672 * @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 673 * @param {boolean} thirdParty should be true if the URL is a third-party
622 * @param {String} sitekey public key provided by the document 674 * request
623 * @return {Boolean} true in case of a match 675 * @param {string} sitekey public key provided by the document
676 * @return {boolean} true in case of a match
624 */ 677 */
625 matches: function(location, typeMask, docDomain, thirdParty, sitekey) 678 matches(location, typeMask, docDomain, thirdParty, sitekey)
626 { 679 {
627 if (this.contentType & typeMask && 680 if (this.contentType & typeMask &&
628 (this.thirdParty == null || this.thirdParty == thirdParty) && 681 (this.thirdParty == null || this.thirdParty == thirdParty) &&
629 this.isActiveOnDomain(docDomain, sitekey) && this.regexp.test(location)) 682 this.isActiveOnDomain(docDomain, sitekey) && this.regexp.test(location))
630 { 683 {
631 return true; 684 return true;
632 } 685 }
633
634 return false; 686 return false;
635 } 687 }
636 }); 688 });
637 689
638 // Required to optimize Matcher, see also RegExpFilter.prototype.length 690 // Required to optimize Matcher, see also RegExpFilter.prototype.length
639 Object.defineProperty(RegExpFilter.prototype, "0", 691 Object.defineProperty(RegExpFilter.prototype, "0", {
640 { 692 get() { return this; }
641 get: function() { return this; }
642 }); 693 });
643 694
644 /** 695 /**
645 * Creates a RegExp filter from its text representation 696 * Creates a RegExp filter from its text representation
646 * @param {String} text same as in Filter() 697 * @param {string} text same as in Filter()
698 * @return {Filter}
647 */ 699 */
648 RegExpFilter.fromText = function(text) 700 RegExpFilter.fromText = function(text)
649 { 701 {
650 let blocking = true; 702 let blocking = true;
651 let origText = text; 703 let origText = text;
652 if (text.indexOf("@@") == 0) 704 if (text.indexOf("@@") == 0)
653 { 705 {
654 blocking = false; 706 blocking = false;
655 text = text.substr(2); 707 text = text.substr(2);
656 } 708 }
(...skipping 22 matching lines...) Expand all
679 option = option.replace(/-/, "_"); 731 option = option.replace(/-/, "_");
680 if (option in RegExpFilter.typeMap) 732 if (option in RegExpFilter.typeMap)
681 { 733 {
682 if (contentType == null) 734 if (contentType == null)
683 contentType = 0; 735 contentType = 0;
684 contentType |= RegExpFilter.typeMap[option]; 736 contentType |= RegExpFilter.typeMap[option];
685 } 737 }
686 else if (option[0] == "~" && option.substr(1) in RegExpFilter.typeMap) 738 else if (option[0] == "~" && option.substr(1) in RegExpFilter.typeMap)
687 { 739 {
688 if (contentType == null) 740 if (contentType == null)
689 contentType = RegExpFilter.prototype.contentType; 741 ({contentType} = RegExpFilter.prototype);
690 contentType &= ~RegExpFilter.typeMap[option.substr(1)]; 742 contentType &= ~RegExpFilter.typeMap[option.substr(1)];
691 } 743 }
692 else if (option == "MATCH_CASE") 744 else if (option == "MATCH_CASE")
693 matchCase = true; 745 matchCase = true;
694 else if (option == "~MATCH_CASE") 746 else if (option == "~MATCH_CASE")
695 matchCase = false; 747 matchCase = false;
696 else if (option == "DOMAIN" && typeof value != "undefined") 748 else if (option == "DOMAIN" && typeof value != "undefined")
697 domains = value; 749 domains = value;
698 else if (option == "THIRD_PARTY") 750 else if (option == "THIRD_PARTY")
699 thirdParty = true; 751 thirdParty = true;
700 else if (option == "~THIRD_PARTY") 752 else if (option == "~THIRD_PARTY")
701 thirdParty = false; 753 thirdParty = false;
702 else if (option == "COLLAPSE") 754 else if (option == "COLLAPSE")
703 collapse = true; 755 collapse = true;
704 else if (option == "~COLLAPSE") 756 else if (option == "~COLLAPSE")
705 collapse = false; 757 collapse = false;
706 else if (option == "SITEKEY" && typeof value != "undefined") 758 else if (option == "SITEKEY" && typeof value != "undefined")
707 sitekeys = value; 759 sitekeys = value;
708 else 760 else
709 return new InvalidFilter(origText, "filter_unknown_option"); 761 return new InvalidFilter(origText, "filter_unknown_option");
710 } 762 }
711 } 763 }
712 764
713 try 765 try
714 { 766 {
715 if (blocking) 767 if (blocking)
716 return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys, collapse); 768 {
717 else 769 return new BlockingFilter(origText, text, contentType, matchCase, domains,
718 return new WhitelistFilter(origText, text, contentType, matchCase, domains , thirdParty, sitekeys); 770 thirdParty, sitekeys, collapse);
771 }
772 return new WhitelistFilter(origText, text, contentType, matchCase, domains,
773 thirdParty, sitekeys);
719 } 774 }
720 catch (e) 775 catch (e)
721 { 776 {
722 return new InvalidFilter(origText, "filter_invalid_regexp"); 777 return new InvalidFilter(origText, "filter_invalid_regexp");
723 } 778 }
724 }; 779 };
725 780
726 /** 781 /**
727 * Maps type strings like "SCRIPT" or "OBJECT" to bit masks 782 * Maps type strings like "SCRIPT" or "OBJECT" to bit masks
728 */ 783 */
(...skipping 25 matching lines...) Expand all
754 // DOCUMENT, ELEMHIDE, POPUP, GENERICHIDE and GENERICBLOCK options shouldn't 809 // DOCUMENT, ELEMHIDE, POPUP, GENERICHIDE and GENERICBLOCK options shouldn't
755 // be there by default 810 // be there by default
756 RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.DOCUMENT | 811 RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.DOCUMENT |
757 RegExpFilter.typeMap.ELEMHIDE | 812 RegExpFilter.typeMap.ELEMHIDE |
758 RegExpFilter.typeMap.POPUP | 813 RegExpFilter.typeMap.POPUP |
759 RegExpFilter.typeMap.GENERICHIDE | 814 RegExpFilter.typeMap.GENERICHIDE |
760 RegExpFilter.typeMap.GENERICBLOCK); 815 RegExpFilter.typeMap.GENERICBLOCK);
761 816
762 /** 817 /**
763 * Class for blocking filters 818 * Class for blocking filters
764 * @param {String} text see Filter() 819 * @param {string} text see Filter()
765 * @param {String} regexpSource see RegExpFilter() 820 * @param {string} regexpSource see RegExpFilter()
766 * @param {Number} contentType see RegExpFilter() 821 * @param {number} contentType see RegExpFilter()
767 * @param {Boolean} matchCase see RegExpFilter() 822 * @param {boolean} matchCase see RegExpFilter()
768 * @param {String} domains see RegExpFilter() 823 * @param {string} domains see RegExpFilter()
769 * @param {Boolean} thirdParty see RegExpFilter() 824 * @param {boolean} thirdParty see RegExpFilter()
770 * @param {String} sitekeys see RegExpFilter() 825 * @param {string} sitekeys see RegExpFilter()
771 * @param {Boolean} collapse defines whether the filter should collapse blocked content, can be null 826 * @param {boolean} collapse
827 * defines whether the filter should collapse blocked content, can be null
772 * @constructor 828 * @constructor
773 * @augments RegExpFilter 829 * @augments RegExpFilter
774 */ 830 */
775 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, thi rdParty, sitekeys, collapse) 831 function BlockingFilter(text, regexpSource, contentType, matchCase, domains,
832 thirdParty, sitekeys, collapse)
776 { 833 {
777 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, t hirdParty, sitekeys); 834 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains,
835 thirdParty, sitekeys);
778 836
779 this.collapse = collapse; 837 this.collapse = collapse;
780 } 838 }
781 exports.BlockingFilter = BlockingFilter; 839 exports.BlockingFilter = BlockingFilter;
782 840
783 BlockingFilter.prototype = extend(RegExpFilter, { 841 BlockingFilter.prototype = extend(RegExpFilter, {
784 type: "blocking", 842 type: "blocking",
785 843
786 /** 844 /**
787 * Defines whether the filter should collapse blocked content. Can be null (us e the global preference). 845 * Defines whether the filter should collapse blocked content.
788 * @type Boolean 846 * Can be null (use the global preference).
847 * @type {boolean}
789 */ 848 */
790 collapse: null 849 collapse: null
791 }); 850 });
792 851
793 /** 852 /**
794 * Class for whitelist filters 853 * Class for whitelist filters
795 * @param {String} text see Filter() 854 * @param {string} text see Filter()
796 * @param {String} regexpSource see RegExpFilter() 855 * @param {string} regexpSource see RegExpFilter()
797 * @param {Number} contentType see RegExpFilter() 856 * @param {number} contentType see RegExpFilter()
798 * @param {Boolean} matchCase see RegExpFilter() 857 * @param {boolean} matchCase see RegExpFilter()
799 * @param {String} domains see RegExpFilter() 858 * @param {string} domains see RegExpFilter()
800 * @param {Boolean} thirdParty see RegExpFilter() 859 * @param {boolean} thirdParty see RegExpFilter()
801 * @param {String} sitekeys see RegExpFilter() 860 * @param {string} sitekeys see RegExpFilter()
802 * @constructor 861 * @constructor
803 * @augments RegExpFilter 862 * @augments RegExpFilter
804 */ 863 */
805 function WhitelistFilter(text, regexpSource, contentType, matchCase, domains, th irdParty, sitekeys) 864 function WhitelistFilter(text, regexpSource, contentType, matchCase, domains,
865 thirdParty, sitekeys)
806 { 866 {
807 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, t hirdParty, sitekeys); 867 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains,
868 thirdParty, sitekeys);
808 } 869 }
809 exports.WhitelistFilter = WhitelistFilter; 870 exports.WhitelistFilter = WhitelistFilter;
810 871
811 WhitelistFilter.prototype = extend(RegExpFilter, { 872 WhitelistFilter.prototype = extend(RegExpFilter, {
812 type: "whitelist" 873 type: "whitelist"
813 }); 874 });
814 875
815 /** 876 /**
816 * Base class for element hiding filters 877 * Base class for element hiding filters
817 * @param {String} text see Filter() 878 * @param {string} text see Filter()
818 * @param {String} [domains] Host names or domains the filter should be restrict ed to 879 * @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 880 * restricted to
881 * @param {string} selector CSS selector for the HTML elements that should be
882 * hidden
820 * @constructor 883 * @constructor
821 * @augments ActiveFilter 884 * @augments ActiveFilter
822 */ 885 */
823 function ElemHideBase(text, domains, selector) 886 function ElemHideBase(text, domains, selector)
824 { 887 {
825 ActiveFilter.call(this, text, domains || null); 888 ActiveFilter.call(this, text, domains || null);
826 889
827 if (domains) 890 if (domains)
828 this.selectorDomain = domains.replace(/,~[^,]+/g, "").replace(/^~[^,]+,?/, " ").toLowerCase(); 891 {
892 this.selectorDomain = domains.replace(/,~[^,]+/g, "")
893 .replace(/^~[^,]+,?/, "").toLowerCase();
894 }
829 895
830 // Braces are being escaped to prevent CSS rule injection. 896 // Braces are being escaped to prevent CSS rule injection.
831 this.selector = selector.replace("{", "\\x7B ").replace("}", "\\x7D "); 897 this.selector = selector.replace("{", "\\x7B ").replace("}", "\\x7D ");
832 } 898 }
833 exports.ElemHideBase = ElemHideBase; 899 exports.ElemHideBase = ElemHideBase;
834 900
835 ElemHideBase.prototype = extend(ActiveFilter, { 901 ElemHideBase.prototype = extend(ActiveFilter, {
836 /** 902 /**
837 * @see ActiveFilter.domainSeparator 903 * @see ActiveFilter.domainSeparator
838 */ 904 */
839 domainSeparator: ",", 905 domainSeparator: ",",
840 906
841 /** 907 /**
842 * @see ActiveFilter.ignoreTrailingDot 908 * @see ActiveFilter.ignoreTrailingDot
843 */ 909 */
844 ignoreTrailingDot: false, 910 ignoreTrailingDot: false,
845 911
846 /** 912 /**
847 * Host name or domain the filter should be restricted to (can be null for no restriction) 913 * Host name or domain the filter should be restricted to (can be null for
848 * @type String 914 * no restriction)
915 * @type {string}
849 */ 916 */
850 selectorDomain: null, 917 selectorDomain: null,
851 /** 918 /**
852 * CSS selector for the HTML elements that should be hidden 919 * CSS selector for the HTML elements that should be hidden
853 * @type String 920 * @type {string}
854 */ 921 */
855 selector: null 922 selector: null
856 }); 923 });
857 924
858 /** 925 /**
859 * Creates an element hiding filter from a pre-parsed text representation 926 * Creates an element hiding filter from a pre-parsed text representation
860 * 927 *
861 * @param {String} text same as in Filter() 928 * @param {string} text same as in Filter()
862 * @param {String} domain domain part of the text representation (can be e mpty) 929 * @param {string} domain
863 * @param {Boolean} isException exception rule indicator 930 * domain part of the text representation (can be empty)
864 * @param {String} tagName tag name part (can be empty) 931 * @param {boolean} isException exception rule indicator
865 * @param {String} attrRules attribute matching rules (can be empty) 932 * @param {string} tagName tag name part (can be empty)
866 * @param {String} selector raw CSS selector (can be empty) 933 * @param {string} attrRules attribute matching rules (can be empty)
867 * @return {ElemHideFilter|ElemHideException|ElemHideEmulationFilter|InvalidFilt er} 934 * @param {string} selector raw CSS selector (can be empty)
935 * @return {ElemHideFilter|ElemHideException|
936 * ElemHideEmulationFilter|InvalidFilter}
868 */ 937 */
869 ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules, selector) 938 ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules,
939 selector)
870 { 940 {
871 if (!selector) 941 if (!selector)
872 { 942 {
873 if (tagName == "*") 943 if (tagName == "*")
874 tagName = ""; 944 tagName = "";
875 945
876 let id = null; 946 let id = null;
877 let additional = ""; 947 let additional = "";
878 if (attrRules) 948 if (attrRules)
879 { 949 {
880 attrRules = attrRules.match(/\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\)/g); 950 attrRules = attrRules.match(/\([\w-]+(?:[$^*]?=[^()"]*)?\)/g);
881 for (let rule of attrRules) 951 for (let rule of attrRules)
882 { 952 {
883 rule = rule.substr(1, rule.length - 2); 953 rule = rule.substr(1, rule.length - 2);
884 let separatorPos = rule.indexOf("="); 954 let separatorPos = rule.indexOf("=");
885 if (separatorPos > 0) 955 if (separatorPos > 0)
886 { 956 {
887 rule = rule.replace(/=/, '="') + '"'; 957 rule = rule.replace(/=/, '="') + '"';
888 additional += "[" + rule + "]"; 958 additional += "[" + rule + "]";
889 } 959 }
890 else 960 else
891 { 961 {
892 if (id) 962 if (id)
893 return new InvalidFilter(text, "filter_elemhide_duplicate_id"); 963 return new InvalidFilter(text, "filter_elemhide_duplicate_id");
894 964
895 id = rule; 965 id = rule;
896 } 966 }
897 } 967 }
898 } 968 }
899 969
900 if (id) 970 if (id)
901 selector = tagName + "." + id + additional + "," + tagName + "#" + id + ad ditional; 971 selector = `${tagName}.${id}${additional},${tagName}#${id}${additional}`;
902 else if (tagName || additional) 972 else if (tagName || additional)
903 selector = tagName + additional; 973 selector = tagName + additional;
904 else 974 else
905 return new InvalidFilter(text, "filter_elemhide_nocriteria"); 975 return new InvalidFilter(text, "filter_elemhide_nocriteria");
906 } 976 }
907 977
908 // We don't allow ElemHide filters which have any empty domains. 978 // We don't allow ElemHide filters which have any empty domains.
909 // Note: The ElemHide.prototype.domainSeparator is duplicated here, if that 979 // Note: The ElemHide.prototype.domainSeparator is duplicated here, if that
910 // changes this must be changed too. 980 // changes this must be changed too.
911 if (domain && /(^|,)~?(,|$)/.test(domain)) 981 if (domain && /(^|,)~?(,|$)/.test(domain))
(...skipping 10 matching lines...) Expand all
922 return new InvalidFilter(text, "filter_elemhideemulation_nodomain"); 992 return new InvalidFilter(text, "filter_elemhideemulation_nodomain");
923 993
924 return new ElemHideEmulationFilter(text, domain, selector); 994 return new ElemHideEmulationFilter(text, domain, selector);
925 } 995 }
926 996
927 return new ElemHideFilter(text, domain, selector); 997 return new ElemHideFilter(text, domain, selector);
928 }; 998 };
929 999
930 /** 1000 /**
931 * Class for element hiding filters 1001 * Class for element hiding filters
932 * @param {String} text see Filter() 1002 * @param {string} text see Filter()
933 * @param {String} domains see ElemHideBase() 1003 * @param {string} domains see ElemHideBase()
934 * @param {String} selector see ElemHideBase() 1004 * @param {string} selector see ElemHideBase()
935 * @constructor 1005 * @constructor
936 * @augments ElemHideBase 1006 * @augments ElemHideBase
937 */ 1007 */
938 function ElemHideFilter(text, domains, selector) 1008 function ElemHideFilter(text, domains, selector)
939 { 1009 {
940 ElemHideBase.call(this, text, domains, selector); 1010 ElemHideBase.call(this, text, domains, selector);
941 } 1011 }
942 exports.ElemHideFilter = ElemHideFilter; 1012 exports.ElemHideFilter = ElemHideFilter;
943 1013
944 ElemHideFilter.prototype = extend(ElemHideBase, { 1014 ElemHideFilter.prototype = extend(ElemHideBase, {
945 type: "elemhide" 1015 type: "elemhide"
946 }); 1016 });
947 1017
948 /** 1018 /**
949 * Class for element hiding exceptions 1019 * Class for element hiding exceptions
950 * @param {String} text see Filter() 1020 * @param {string} text see Filter()
951 * @param {String} domains see ElemHideBase() 1021 * @param {string} domains see ElemHideBase()
952 * @param {String} selector see ElemHideBase() 1022 * @param {string} selector see ElemHideBase()
953 * @constructor 1023 * @constructor
954 * @augments ElemHideBase 1024 * @augments ElemHideBase
955 */ 1025 */
956 function ElemHideException(text, domains, selector) 1026 function ElemHideException(text, domains, selector)
957 { 1027 {
958 ElemHideBase.call(this, text, domains, selector); 1028 ElemHideBase.call(this, text, domains, selector);
959 } 1029 }
960 exports.ElemHideException = ElemHideException; 1030 exports.ElemHideException = ElemHideException;
961 1031
962 ElemHideException.prototype = extend(ElemHideBase, { 1032 ElemHideException.prototype = extend(ElemHideBase, {
963 type: "elemhideexception" 1033 type: "elemhideexception"
964 }); 1034 });
965 1035
966 /** 1036 /**
967 * Class for element hiding emulation filters 1037 * Class for element hiding emulation filters
968 * @param {String} text see Filter() 1038 * @param {string} text see Filter()
969 * @param {String} domains see ElemHideBase() 1039 * @param {string} domains see ElemHideBase()
970 * @param {String} selector see ElemHideBase() 1040 * @param {string} selector see ElemHideBase()
971 * @constructor 1041 * @constructor
972 * @augments ElemHideBase 1042 * @augments ElemHideBase
973 */ 1043 */
974 function ElemHideEmulationFilter(text, domains, selector) 1044 function ElemHideEmulationFilter(text, domains, selector)
975 { 1045 {
976 ElemHideBase.call(this, text, domains, selector); 1046 ElemHideBase.call(this, text, domains, selector);
977 } 1047 }
978 exports.ElemHideEmulationFilter = ElemHideEmulationFilter; 1048 exports.ElemHideEmulationFilter = ElemHideEmulationFilter;
979 1049
980 ElemHideEmulationFilter.prototype = extend(ElemHideBase, { 1050 ElemHideEmulationFilter.prototype = extend(ElemHideBase, {
981 type: "elemhideemulation" 1051 type: "elemhideemulation"
982 }); 1052 });
OLDNEW
« no previous file with comments | « lib/events.js ('k') | lib/filterListener.js » ('j') | lib/filterNotifier.js » ('J')

Powered by Google App Engine
This is Rietveld