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: Fix Cu.imports in synchronizer.js that I missed previously Created March 14, 2017, 9:03 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()
212 * @inheritdoc
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 * @inheritdoc
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
232 * @param {String} [domains] Domains that the filter is restricted to separated by domainSeparator e.g. "foo.com|bar.com|~baz.com" 242 * see Filter()
243 * @param {string} [domains]
244 * Domains that the filter is restricted to separated by domainSeparator
245 * e.g. "foo.com|bar.com|~baz.com"
233 * @constructor 246 * @constructor
234 * @augments Filter 247 * @augments Filter
235 */ 248 */
236 function ActiveFilter(text, domains) 249 function ActiveFilter(text, domains)
237 { 250 {
238 Filter.call(this, text); 251 Filter.call(this, text);
239 252
240 this.domainSource = domains; 253 this.domainSource = domains;
241 } 254 }
242 exports.ActiveFilter = ActiveFilter; 255 exports.ActiveFilter = ActiveFilter;
243 256
244 ActiveFilter.prototype = extend(Filter, { 257 ActiveFilter.prototype = extend(Filter, {
245 _disabled: false, 258 _disabled: false,
246 _hitCount: 0, 259 _hitCount: 0,
247 _lastHit: 0, 260 _lastHit: 0,
248 261
249 /** 262 /**
250 * Defines whether the filter is disabled 263 * Defines whether the filter is disabled
251 * @type Boolean 264 * @type {boolean}
252 */ 265 */
253 get disabled() 266 get disabled()
254 { 267 {
255 return this._disabled; 268 return this._disabled;
256 }, 269 },
257 set disabled(value) 270 set disabled(value)
258 { 271 {
259 if (value != this._disabled) 272 if (value != this._disabled)
260 { 273 {
261 let oldValue = this._disabled; 274 let oldValue = this._disabled;
262 this._disabled = value; 275 this._disabled = value;
263 FilterNotifier.triggerListeners("filter.disabled", this, value, oldValue); 276 FilterNotifier.triggerListeners("filter.disabled", this, value, oldValue);
264 } 277 }
265 return this._disabled; 278 return this._disabled;
266 }, 279 },
267 280
268 /** 281 /**
269 * Number of hits on the filter since the last reset 282 * Number of hits on the filter since the last reset
270 * @type Number 283 * @type {number}
271 */ 284 */
272 get hitCount() 285 get hitCount()
273 { 286 {
274 return this._hitCount; 287 return this._hitCount;
275 }, 288 },
276 set hitCount(value) 289 set hitCount(value)
277 { 290 {
278 if (value != this._hitCount) 291 if (value != this._hitCount)
279 { 292 {
280 let oldValue = this._hitCount; 293 let oldValue = this._hitCount;
281 this._hitCount = value; 294 this._hitCount = value;
282 FilterNotifier.triggerListeners("filter.hitCount", this, value, oldValue); 295 FilterNotifier.triggerListeners("filter.hitCount", this, value, oldValue);
283 } 296 }
284 return this._hitCount; 297 return this._hitCount;
285 }, 298 },
286 299
287 /** 300 /**
288 * Last time the filter had a hit (in milliseconds since the beginning of the epoch) 301 * Last time the filter had a hit (in milliseconds since the beginning of the
289 * @type Number 302 * epoch)
303 * @type {number}
290 */ 304 */
291 get lastHit() 305 get lastHit()
292 { 306 {
293 return this._lastHit; 307 return this._lastHit;
294 }, 308 },
295 set lastHit(value) 309 set lastHit(value)
296 { 310 {
297 if (value != this._lastHit) 311 if (value != this._lastHit)
298 { 312 {
299 let oldValue = this._lastHit; 313 let oldValue = this._lastHit;
300 this._lastHit = value; 314 this._lastHit = value;
301 FilterNotifier.triggerListeners("filter.lastHit", this, value, oldValue); 315 FilterNotifier.triggerListeners("filter.lastHit", this, value, oldValue);
302 } 316 }
303 return this._lastHit; 317 return this._lastHit;
304 }, 318 },
305 319
306 /** 320 /**
307 * String that the domains property should be generated from 321 * String that the domains property should be generated from
308 * @type String 322 * @type {string}
309 */ 323 */
310 domainSource: null, 324 domainSource: null,
311 325
312 /** 326 /**
313 * Separator character used in domainSource property, must be overridden by su bclasses 327 * Separator character used in domainSource property, must be
314 * @type String 328 * overridden by subclasses
329 * @type {string}
315 */ 330 */
316 domainSeparator: null, 331 domainSeparator: null,
317 332
318 /** 333 /**
319 * Determines whether the trailing dot in domain names isn't important and 334 * Determines whether the trailing dot in domain names isn't important and
320 * should be ignored, must be overridden by subclasses. 335 * should be ignored, must be overridden by subclasses.
321 * @type Boolean 336 * @type {boolean}
322 */ 337 */
323 ignoreTrailingDot: true, 338 ignoreTrailingDot: true,
324 339
325 /** 340 /**
326 * Determines whether domainSource is already upper-case, 341 * Determines whether domainSource is already upper-case,
327 * can be overridden by subclasses. 342 * can be overridden by subclasses.
328 * @type Boolean 343 * @type {boolean}
329 */ 344 */
330 domainSourceIsUpperCase: false, 345 domainSourceIsUpperCase: false,
331 346
332 /** 347 /**
333 * Map containing domains that this filter should match on/not match on or nul l if the filter should match on all domains 348 * Map containing domains that this filter should match on/not match
334 * @type Object 349 * on or null if the filter should match on all domains
350 * @type {Object}
335 */ 351 */
336 get domains() 352 get domains()
337 { 353 {
338 // Despite this property being cached, the getter is called 354 // Despite this property being cached, the getter is called
339 // several times on Safari, due to WebKit bug 132872 355 // several times on Safari, due to WebKit bug 132872
340 let prop = Object.getOwnPropertyDescriptor(this, "domains"); 356 let prop = Object.getOwnPropertyDescriptor(this, "domains");
341 if (prop) 357 if (prop)
342 return prop.value; 358 return prop.value;
343 359
344 let domains = null; 360 let domains = null;
345 361
346 if (this.domainSource) 362 if (this.domainSource)
347 { 363 {
348 let source = this.domainSource; 364 let source = this.domainSource;
349 if (!this.domainSourceIsUpperCase) { 365 if (!this.domainSourceIsUpperCase)
366 {
350 // RegExpFilter already have uppercase domains 367 // RegExpFilter already have uppercase domains
351 source = source.toUpperCase(); 368 source = source.toUpperCase();
352 } 369 }
353 let list = source.split(this.domainSeparator); 370 let list = source.split(this.domainSeparator);
354 if (list.length == 1 && list[0][0] != "~") 371 if (list.length == 1 && list[0][0] != "~")
355 { 372 {
356 // Fast track for the common one-domain scenario 373 // Fast track for the common one-domain scenario
357 domains = Object.create(null); 374 domains = Object.create(null);
358 domains[""] = false; 375 domains[""] = false;
359 if (this.ignoreTrailingDot) 376 if (this.ignoreTrailingDot)
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 411
395 this.domainSource = null; 412 this.domainSource = null;
396 } 413 }
397 414
398 Object.defineProperty(this, "domains", {value: domains, enumerable: true}); 415 Object.defineProperty(this, "domains", {value: domains, enumerable: true});
399 return this.domains; 416 return this.domains;
400 }, 417 },
401 418
402 /** 419 /**
403 * Array containing public keys of websites that this filter should apply to 420 * Array containing public keys of websites that this filter should apply to
404 * @type string[] 421 * @type {string[]}
405 */ 422 */
406 sitekeys: null, 423 sitekeys: null,
407 424
408 /** 425 /**
409 * Checks whether this filter is active on a domain. 426 * Checks whether this filter is active on a domain.
410 * @param {String} docDomain domain name of the document that loads the URL 427 * @param {string} docDomain domain name of the document that loads the URL
411 * @param {String} [sitekey] public key provided by the document 428 * @param {string} [sitekey] public key provided by the document
412 * @return {Boolean} true in case of the filter being active 429 * @return {boolean} true in case of the filter being active
413 */ 430 */
414 isActiveOnDomain: function(docDomain, sitekey) 431 isActiveOnDomain(docDomain, sitekey)
415 { 432 {
416 // Sitekeys are case-sensitive so we shouldn't convert them to upper-case to avoid false 433 // 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. 434 // upper-case to avoid false positives here. Instead we need to
418 if (this.sitekeys && (!sitekey || this.sitekeys.indexOf(sitekey.toUpperCase( )) < 0)) 435 // change the way filter options are parsed.
436 if (this.sitekeys &&
437 (!sitekey || this.sitekeys.indexOf(sitekey.toUpperCase()) < 0))
438 {
419 return false; 439 return false;
440 }
420 441
421 // If no domains are set the rule matches everywhere 442 // If no domains are set the rule matches everywhere
422 if (!this.domains) 443 if (!this.domains)
423 return true; 444 return true;
424 445
425 // If the document has no host name, match only if the filter isn't restrict ed to specific domains 446 // If the document has no host name, match only if the filter
447 // isn't restricted to specific domains
426 if (!docDomain) 448 if (!docDomain)
427 return this.domains[""]; 449 return this.domains[""];
428 450
429 if (this.ignoreTrailingDot) 451 if (this.ignoreTrailingDot)
430 docDomain = docDomain.replace(/\.+$/, ""); 452 docDomain = docDomain.replace(/\.+$/, "");
431 docDomain = docDomain.toUpperCase(); 453 docDomain = docDomain.toUpperCase();
432 454
433 while (true) 455 while (true)
434 { 456 {
435 if (docDomain in this.domains) 457 if (docDomain in this.domains)
436 return this.domains[docDomain]; 458 return this.domains[docDomain];
437 459
438 let nextDot = docDomain.indexOf("."); 460 let nextDot = docDomain.indexOf(".");
439 if (nextDot < 0) 461 if (nextDot < 0)
440 break; 462 break;
441 docDomain = docDomain.substr(nextDot + 1); 463 docDomain = docDomain.substr(nextDot + 1);
442 } 464 }
443 return this.domains[""]; 465 return this.domains[""];
444 }, 466 },
445 467
446 /** 468 /**
447 * Checks whether this filter is active only on a domain and its subdomains. 469 * Checks whether this filter is active only on a domain and its subdomains.
470 * @param {string} docDomain
471 * @return {boolean}
448 */ 472 */
449 isActiveOnlyOnDomain: function(/**String*/ docDomain) /**Boolean*/ 473 isActiveOnlyOnDomain(docDomain)
450 { 474 {
451 if (!docDomain || !this.domains || this.domains[""]) 475 if (!docDomain || !this.domains || this.domains[""])
452 return false; 476 return false;
453 477
454 if (this.ignoreTrailingDot) 478 if (this.ignoreTrailingDot)
455 docDomain = docDomain.replace(/\.+$/, ""); 479 docDomain = docDomain.replace(/\.+$/, "");
456 docDomain = docDomain.toUpperCase(); 480 docDomain = docDomain.toUpperCase();
457 481
458 for (let domain in this.domains) 482 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)) 483 {
460 return false; 484 if (this.domains[domain] && domain != docDomain)
485 {
486 if (domain.length <= docDomain.length)
487 return false;
488
489 if (!domain.endsWith("." + docDomain))
490 return false;
491 }
492 }
461 493
462 return true; 494 return true;
463 }, 495 },
464 496
465 /** 497 /**
466 * Checks whether this filter is generic or specific 498 * Checks whether this filter is generic or specific
499 * @return {boolean}
467 */ 500 */
468 isGeneric: function() /**Boolean*/ 501 isGeneric()
469 { 502 {
470 return !(this.sitekeys && this.sitekeys.length) && 503 return !(this.sitekeys && this.sitekeys.length) &&
471 (!this.domains || this.domains[""]); 504 (!this.domains || this.domains[""]);
472 }, 505 },
473 506
474 /** 507 /**
475 * See Filter.serialize() 508 * See Filter.serialize()
509 * @inheritdoc
476 */ 510 */
477 serialize: function(buffer) 511 serialize(buffer)
478 { 512 {
479 if (this._disabled || this._hitCount || this._lastHit) 513 if (this._disabled || this._hitCount || this._lastHit)
480 { 514 {
481 Filter.prototype.serialize.call(this, buffer); 515 Filter.prototype.serialize.call(this, buffer);
482 if (this._disabled) 516 if (this._disabled)
483 buffer.push("disabled=true"); 517 buffer.push("disabled=true");
484 if (this._hitCount) 518 if (this._hitCount)
485 buffer.push("hitCount=" + this._hitCount); 519 buffer.push("hitCount=" + this._hitCount);
486 if (this._lastHit) 520 if (this._lastHit)
487 buffer.push("lastHit=" + this._lastHit); 521 buffer.push("lastHit=" + this._lastHit);
488 } 522 }
489 } 523 }
490 }); 524 });
491 525
492 /** 526 /**
493 * Abstract base class for RegExp-based filters 527 * Abstract base class for RegExp-based filters
494 * @param {String} text see Filter() 528 * @param {string} text see Filter()
495 * @param {String} regexpSource filter part that the regular expression should b e build from 529 * @param {string} regexpSource
496 * @param {Number} [contentType] Content types the filter applies to, combinatio n of values from RegExpFilter.typeMap 530 * 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 531 * @param {number} [contentType]
498 * @param {String} [domains] Domains that the filter is restricted to, e.g. "foo .com|bar.com|~baz.com" 532 * 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 533 * RegExpFilter.typeMap
500 * @param {String} [sitekeys] Public keys of websites that this filter should ap ply to 534 * @param {boolean} [matchCase]
535 * Defines whether the filter should distinguish between lower and upper case
536 * letters
537 * @param {string} [domains]
538 * Domains that the filter is restricted to, e.g. "foo.com|bar.com|~baz.com"
539 * @param {boolean} [thirdParty]
540 * Defines whether the filter should apply to third-party or first-party
541 * content only
542 * @param {string} [sitekeys]
543 * Public keys of websites that this filter should apply to
501 * @constructor 544 * @constructor
502 * @augments ActiveFilter 545 * @augments ActiveFilter
503 */ 546 */
504 function RegExpFilter(text, regexpSource, contentType, matchCase, domains, third Party, sitekeys) 547 function RegExpFilter(text, regexpSource, contentType, matchCase, domains,
548 thirdParty, sitekeys)
505 { 549 {
506 ActiveFilter.call(this, text, domains, sitekeys); 550 ActiveFilter.call(this, text, domains, sitekeys);
507 551
508 if (contentType != null) 552 if (contentType != null)
509 this.contentType = contentType; 553 this.contentType = contentType;
510 if (matchCase) 554 if (matchCase)
511 this.matchCase = matchCase; 555 this.matchCase = matchCase;
512 if (thirdParty != null) 556 if (thirdParty != null)
513 this.thirdParty = thirdParty; 557 this.thirdParty = thirdParty;
514 if (sitekeys != null) 558 if (sitekeys != null)
515 this.sitekeySource = sitekeys; 559 this.sitekeySource = sitekeys;
516 560
517 if (regexpSource.length >= 2 && regexpSource[0] == "/" && regexpSource[regexpS ource.length - 1] == "/") 561 if (regexpSource.length >= 2 &&
562 regexpSource[0] == "/" &&
563 regexpSource[regexpSource.length - 1] == "/")
518 { 564 {
519 // The filter is a regular expression - convert it immediately to catch synt ax errors 565 // 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"); 566 // catch syntax errors
567 let regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2),
568 this.matchCase ? "" : "i");
521 Object.defineProperty(this, "regexp", {value: regexp}); 569 Object.defineProperty(this, "regexp", {value: regexp});
522 } 570 }
523 else 571 else
524 { 572 {
525 // No need to convert this filter to regular expression yet, do it on demand 573 // No need to convert this filter to regular expression yet, do it on demand
526 this.regexpSource = regexpSource; 574 this.regexpSource = regexpSource;
527 } 575 }
528 } 576 }
529 exports.RegExpFilter = RegExpFilter; 577 exports.RegExpFilter = RegExpFilter;
530 578
531 RegExpFilter.prototype = extend(ActiveFilter, { 579 RegExpFilter.prototype = extend(ActiveFilter, {
532 /** 580 /**
533 * @see ActiveFilter.domainSourceIsUpperCase 581 * @see ActiveFilter.domainSourceIsUpperCase
534 */ 582 */
535 domainSourceIsUpperCase: true, 583 domainSourceIsUpperCase: true,
536 584
537 /** 585 /**
538 * Number of filters contained, will always be 1 (required to optimize Matcher ). 586 * Number of filters contained, will always be 1 (required to
539 * @type Integer 587 * optimize Matcher).
588 * @type {number}
540 */ 589 */
541 length: 1, 590 length: 1,
542 591
543 /** 592 /**
544 * @see ActiveFilter.domainSeparator 593 * @see ActiveFilter.domainSeparator
545 */ 594 */
546 domainSeparator: "|", 595 domainSeparator: "|",
547 596
548 /** 597 /**
549 * Expression from which a regular expression should be generated - for delaye d creation of the regexp property 598 * Expression from which a regular expression should be generated -
550 * @type String 599 * for delayed creation of the regexp property
600 * @type {string}
551 */ 601 */
552 regexpSource: null, 602 regexpSource: null,
553 /** 603 /**
554 * Regular expression to be used when testing against this filter 604 * Regular expression to be used when testing against this filter
555 * @type RegExp 605 * @type {RegExp}
556 */ 606 */
557 get regexp() 607 get regexp()
558 { 608 {
559 // Despite this property being cached, the getter is called 609 // Despite this property being cached, the getter is called
560 // several times on Safari, due to WebKit bug 132872 610 // several times on Safari, due to WebKit bug 132872
561 let prop = Object.getOwnPropertyDescriptor(this, "regexp"); 611 let prop = Object.getOwnPropertyDescriptor(this, "regexp");
562 if (prop) 612 if (prop)
563 return prop.value; 613 return prop.value;
564 614
565 let source = Filter.toRegExp(this.regexpSource); 615 let source = Filter.toRegExp(this.regexpSource);
566 let regexp = new RegExp(source, this.matchCase ? "" : "i"); 616 let regexp = new RegExp(source, this.matchCase ? "" : "i");
567 Object.defineProperty(this, "regexp", {value: regexp}); 617 Object.defineProperty(this, "regexp", {value: regexp});
568 return regexp; 618 return regexp;
569 }, 619 },
570 /** 620 /**
571 * Content types the filter applies to, combination of values from RegExpFilte r.typeMap 621 * Content types the filter applies to, combination of values from
572 * @type Number 622 * RegExpFilter.typeMap
623 * @type {number}
573 */ 624 */
574 contentType: 0x7FFFFFFF, 625 contentType: 0x7FFFFFFF,
575 /** 626 /**
576 * Defines whether the filter should distinguish between lower and upper case letters 627 * Defines whether the filter should distinguish between lower and
577 * @type Boolean 628 * upper case letters
629 * @type {boolean}
578 */ 630 */
579 matchCase: false, 631 matchCase: false,
580 /** 632 /**
581 * Defines whether the filter should apply to third-party or first-party conte nt only. Can be null (apply to all content). 633 * Defines whether the filter should apply to third-party or
582 * @type Boolean 634 * first-party content only. Can be null (apply to all content).
635 * @type {boolean}
583 */ 636 */
584 thirdParty: null, 637 thirdParty: null,
585 638
586 /** 639 /**
587 * String that the sitekey property should be generated from 640 * String that the sitekey property should be generated from
588 * @type String 641 * @type {string}
589 */ 642 */
590 sitekeySource: null, 643 sitekeySource: null,
591 644
592 /** 645 /**
593 * Array containing public keys of websites that this filter should apply to 646 * Array containing public keys of websites that this filter should apply to
594 * @type string[] 647 * @type {string[]}
595 */ 648 */
596 get sitekeys() 649 get sitekeys()
597 { 650 {
598 // Despite this property being cached, the getter is called 651 // Despite this property being cached, the getter is called
599 // several times on Safari, due to WebKit bug 132872 652 // several times on Safari, due to WebKit bug 132872
600 let prop = Object.getOwnPropertyDescriptor(this, "sitekeys"); 653 let prop = Object.getOwnPropertyDescriptor(this, "sitekeys");
601 if (prop) 654 if (prop)
602 return prop.value; 655 return prop.value;
603 656
604 let sitekeys = null; 657 let sitekeys = null;
605 658
606 if (this.sitekeySource) 659 if (this.sitekeySource)
607 { 660 {
608 sitekeys = this.sitekeySource.split("|"); 661 sitekeys = this.sitekeySource.split("|");
609 this.sitekeySource = null; 662 this.sitekeySource = null;
610 } 663 }
611 664
612 Object.defineProperty(this, "sitekeys", {value: sitekeys, enumerable: true}) ; 665 Object.defineProperty(
666 this, "sitekeys", {value: sitekeys, enumerable: true}
667 );
613 return this.sitekeys; 668 return this.sitekeys;
614 }, 669 },
615 670
616 /** 671 /**
617 * Tests whether the URL matches this filter 672 * Tests whether the URL matches this filter
618 * @param {String} location URL to be tested 673 * @param {string} location URL to be tested
619 * @param {number} typeMask bitmask of content / request types to match 674 * @param {number} typeMask bitmask of content / request types to match
620 * @param {String} docDomain domain name of the document that loads the URL 675 * @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 676 * @param {boolean} thirdParty should be true if the URL is a third-party
622 * @param {String} sitekey public key provided by the document 677 * request
623 * @return {Boolean} true in case of a match 678 * @param {string} sitekey public key provided by the document
679 * @return {boolean} true in case of a match
624 */ 680 */
625 matches: function(location, typeMask, docDomain, thirdParty, sitekey) 681 matches(location, typeMask, docDomain, thirdParty, sitekey)
626 { 682 {
627 if (this.contentType & typeMask && 683 if (this.contentType & typeMask &&
628 (this.thirdParty == null || this.thirdParty == thirdParty) && 684 (this.thirdParty == null || this.thirdParty == thirdParty) &&
629 this.isActiveOnDomain(docDomain, sitekey) && this.regexp.test(location)) 685 this.isActiveOnDomain(docDomain, sitekey) && this.regexp.test(location))
630 { 686 {
631 return true; 687 return true;
632 } 688 }
633
634 return false; 689 return false;
635 } 690 }
636 }); 691 });
637 692
638 // Required to optimize Matcher, see also RegExpFilter.prototype.length 693 // Required to optimize Matcher, see also RegExpFilter.prototype.length
639 Object.defineProperty(RegExpFilter.prototype, "0", 694 Object.defineProperty(RegExpFilter.prototype, "0", {
640 { 695 get() { return this; }
641 get: function() { return this; }
642 }); 696 });
643 697
644 /** 698 /**
645 * Creates a RegExp filter from its text representation 699 * Creates a RegExp filter from its text representation
646 * @param {String} text same as in Filter() 700 * @param {string} text same as in Filter()
701 * @return {Filter}
647 */ 702 */
648 RegExpFilter.fromText = function(text) 703 RegExpFilter.fromText = function(text)
649 { 704 {
650 let blocking = true; 705 let blocking = true;
651 let origText = text; 706 let origText = text;
652 if (text.indexOf("@@") == 0) 707 if (text.indexOf("@@") == 0)
653 { 708 {
654 blocking = false; 709 blocking = false;
655 text = text.substr(2); 710 text = text.substr(2);
656 } 711 }
(...skipping 22 matching lines...) Expand all
679 option = option.replace(/-/, "_"); 734 option = option.replace(/-/, "_");
680 if (option in RegExpFilter.typeMap) 735 if (option in RegExpFilter.typeMap)
681 { 736 {
682 if (contentType == null) 737 if (contentType == null)
683 contentType = 0; 738 contentType = 0;
684 contentType |= RegExpFilter.typeMap[option]; 739 contentType |= RegExpFilter.typeMap[option];
685 } 740 }
686 else if (option[0] == "~" && option.substr(1) in RegExpFilter.typeMap) 741 else if (option[0] == "~" && option.substr(1) in RegExpFilter.typeMap)
687 { 742 {
688 if (contentType == null) 743 if (contentType == null)
689 contentType = RegExpFilter.prototype.contentType; 744 ({contentType} = RegExpFilter.prototype);
690 contentType &= ~RegExpFilter.typeMap[option.substr(1)]; 745 contentType &= ~RegExpFilter.typeMap[option.substr(1)];
691 } 746 }
692 else if (option == "MATCH_CASE") 747 else if (option == "MATCH_CASE")
693 matchCase = true; 748 matchCase = true;
694 else if (option == "~MATCH_CASE") 749 else if (option == "~MATCH_CASE")
695 matchCase = false; 750 matchCase = false;
696 else if (option == "DOMAIN" && typeof value != "undefined") 751 else if (option == "DOMAIN" && typeof value != "undefined")
697 domains = value; 752 domains = value;
698 else if (option == "THIRD_PARTY") 753 else if (option == "THIRD_PARTY")
699 thirdParty = true; 754 thirdParty = true;
700 else if (option == "~THIRD_PARTY") 755 else if (option == "~THIRD_PARTY")
701 thirdParty = false; 756 thirdParty = false;
702 else if (option == "COLLAPSE") 757 else if (option == "COLLAPSE")
703 collapse = true; 758 collapse = true;
704 else if (option == "~COLLAPSE") 759 else if (option == "~COLLAPSE")
705 collapse = false; 760 collapse = false;
706 else if (option == "SITEKEY" && typeof value != "undefined") 761 else if (option == "SITEKEY" && typeof value != "undefined")
707 sitekeys = value; 762 sitekeys = value;
708 else 763 else
709 return new InvalidFilter(origText, "filter_unknown_option"); 764 return new InvalidFilter(origText, "filter_unknown_option");
710 } 765 }
711 } 766 }
712 767
713 try 768 try
714 { 769 {
715 if (blocking) 770 if (blocking)
716 return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys, collapse); 771 {
717 else 772 return new BlockingFilter(origText, text, contentType, matchCase, domains,
718 return new WhitelistFilter(origText, text, contentType, matchCase, domains , thirdParty, sitekeys); 773 thirdParty, sitekeys, collapse);
774 }
775 return new WhitelistFilter(origText, text, contentType, matchCase, domains,
776 thirdParty, sitekeys);
719 } 777 }
720 catch (e) 778 catch (e)
721 { 779 {
722 return new InvalidFilter(origText, "filter_invalid_regexp"); 780 return new InvalidFilter(origText, "filter_invalid_regexp");
723 } 781 }
724 }; 782 };
725 783
726 /** 784 /**
727 * Maps type strings like "SCRIPT" or "OBJECT" to bit masks 785 * Maps type strings like "SCRIPT" or "OBJECT" to bit masks
728 */ 786 */
(...skipping 25 matching lines...) Expand all
754 // DOCUMENT, ELEMHIDE, POPUP, GENERICHIDE and GENERICBLOCK options shouldn't 812 // DOCUMENT, ELEMHIDE, POPUP, GENERICHIDE and GENERICBLOCK options shouldn't
755 // be there by default 813 // be there by default
756 RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.DOCUMENT | 814 RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.DOCUMENT |
757 RegExpFilter.typeMap.ELEMHIDE | 815 RegExpFilter.typeMap.ELEMHIDE |
758 RegExpFilter.typeMap.POPUP | 816 RegExpFilter.typeMap.POPUP |
759 RegExpFilter.typeMap.GENERICHIDE | 817 RegExpFilter.typeMap.GENERICHIDE |
760 RegExpFilter.typeMap.GENERICBLOCK); 818 RegExpFilter.typeMap.GENERICBLOCK);
761 819
762 /** 820 /**
763 * Class for blocking filters 821 * Class for blocking filters
764 * @param {String} text see Filter() 822 * @param {string} text see Filter()
765 * @param {String} regexpSource see RegExpFilter() 823 * @param {string} regexpSource see RegExpFilter()
766 * @param {Number} contentType see RegExpFilter() 824 * @param {number} contentType see RegExpFilter()
767 * @param {Boolean} matchCase see RegExpFilter() 825 * @param {boolean} matchCase see RegExpFilter()
768 * @param {String} domains see RegExpFilter() 826 * @param {string} domains see RegExpFilter()
769 * @param {Boolean} thirdParty see RegExpFilter() 827 * @param {boolean} thirdParty see RegExpFilter()
770 * @param {String} sitekeys see RegExpFilter() 828 * @param {string} sitekeys see RegExpFilter()
771 * @param {Boolean} collapse defines whether the filter should collapse blocked content, can be null 829 * @param {boolean} collapse
830 * defines whether the filter should collapse blocked content, can be null
772 * @constructor 831 * @constructor
773 * @augments RegExpFilter 832 * @augments RegExpFilter
774 */ 833 */
775 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, thi rdParty, sitekeys, collapse) 834 function BlockingFilter(text, regexpSource, contentType, matchCase, domains,
835 thirdParty, sitekeys, collapse)
776 { 836 {
777 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, t hirdParty, sitekeys); 837 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains,
838 thirdParty, sitekeys);
778 839
779 this.collapse = collapse; 840 this.collapse = collapse;
780 } 841 }
781 exports.BlockingFilter = BlockingFilter; 842 exports.BlockingFilter = BlockingFilter;
782 843
783 BlockingFilter.prototype = extend(RegExpFilter, { 844 BlockingFilter.prototype = extend(RegExpFilter, {
784 type: "blocking", 845 type: "blocking",
785 846
786 /** 847 /**
787 * Defines whether the filter should collapse blocked content. Can be null (us e the global preference). 848 * Defines whether the filter should collapse blocked content.
788 * @type Boolean 849 * Can be null (use the global preference).
850 * @type {boolean}
789 */ 851 */
790 collapse: null 852 collapse: null
791 }); 853 });
792 854
793 /** 855 /**
794 * Class for whitelist filters 856 * Class for whitelist filters
795 * @param {String} text see Filter() 857 * @param {string} text see Filter()
796 * @param {String} regexpSource see RegExpFilter() 858 * @param {string} regexpSource see RegExpFilter()
797 * @param {Number} contentType see RegExpFilter() 859 * @param {number} contentType see RegExpFilter()
798 * @param {Boolean} matchCase see RegExpFilter() 860 * @param {boolean} matchCase see RegExpFilter()
799 * @param {String} domains see RegExpFilter() 861 * @param {string} domains see RegExpFilter()
800 * @param {Boolean} thirdParty see RegExpFilter() 862 * @param {boolean} thirdParty see RegExpFilter()
801 * @param {String} sitekeys see RegExpFilter() 863 * @param {string} sitekeys see RegExpFilter()
802 * @constructor 864 * @constructor
803 * @augments RegExpFilter 865 * @augments RegExpFilter
804 */ 866 */
805 function WhitelistFilter(text, regexpSource, contentType, matchCase, domains, th irdParty, sitekeys) 867 function WhitelistFilter(text, regexpSource, contentType, matchCase, domains,
868 thirdParty, sitekeys)
806 { 869 {
807 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, t hirdParty, sitekeys); 870 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains,
871 thirdParty, sitekeys);
808 } 872 }
809 exports.WhitelistFilter = WhitelistFilter; 873 exports.WhitelistFilter = WhitelistFilter;
810 874
811 WhitelistFilter.prototype = extend(RegExpFilter, { 875 WhitelistFilter.prototype = extend(RegExpFilter, {
812 type: "whitelist" 876 type: "whitelist"
813 }); 877 });
814 878
815 /** 879 /**
816 * Base class for element hiding filters 880 * Base class for element hiding filters
817 * @param {String} text see Filter() 881 * @param {string} text see Filter()
818 * @param {String} [domains] Host names or domains the filter should be restrict ed to 882 * @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 883 * restricted to
884 * @param {string} selector CSS selector for the HTML elements that should be
885 * hidden
820 * @constructor 886 * @constructor
821 * @augments ActiveFilter 887 * @augments ActiveFilter
822 */ 888 */
823 function ElemHideBase(text, domains, selector) 889 function ElemHideBase(text, domains, selector)
824 { 890 {
825 ActiveFilter.call(this, text, domains || null); 891 ActiveFilter.call(this, text, domains || null);
826 892
827 if (domains) 893 if (domains)
828 this.selectorDomain = domains.replace(/,~[^,]+/g, "").replace(/^~[^,]+,?/, " ").toLowerCase(); 894 {
895 this.selectorDomain = domains.replace(/,~[^,]+/g, "")
896 .replace(/^~[^,]+,?/, "").toLowerCase();
897 }
829 898
830 // Braces are being escaped to prevent CSS rule injection. 899 // Braces are being escaped to prevent CSS rule injection.
831 this.selector = selector.replace("{", "\\x7B ").replace("}", "\\x7D "); 900 this.selector = selector.replace("{", "\\x7B ").replace("}", "\\x7D ");
832 } 901 }
833 exports.ElemHideBase = ElemHideBase; 902 exports.ElemHideBase = ElemHideBase;
834 903
835 ElemHideBase.prototype = extend(ActiveFilter, { 904 ElemHideBase.prototype = extend(ActiveFilter, {
836 /** 905 /**
837 * @see ActiveFilter.domainSeparator 906 * @see ActiveFilter.domainSeparator
838 */ 907 */
839 domainSeparator: ",", 908 domainSeparator: ",",
840 909
841 /** 910 /**
842 * @see ActiveFilter.ignoreTrailingDot 911 * @see ActiveFilter.ignoreTrailingDot
843 */ 912 */
844 ignoreTrailingDot: false, 913 ignoreTrailingDot: false,
845 914
846 /** 915 /**
847 * Host name or domain the filter should be restricted to (can be null for no restriction) 916 * Host name or domain the filter should be restricted to (can be null for
848 * @type String 917 * no restriction)
918 * @type {string}
849 */ 919 */
850 selectorDomain: null, 920 selectorDomain: null,
851 /** 921 /**
852 * CSS selector for the HTML elements that should be hidden 922 * CSS selector for the HTML elements that should be hidden
853 * @type String 923 * @type {string}
854 */ 924 */
855 selector: null 925 selector: null
856 }); 926 });
857 927
858 /** 928 /**
859 * Creates an element hiding filter from a pre-parsed text representation 929 * Creates an element hiding filter from a pre-parsed text representation
860 * 930 *
861 * @param {String} text same as in Filter() 931 * @param {string} text same as in Filter()
862 * @param {String} domain domain part of the text representation (can be e mpty) 932 * @param {string} domain
863 * @param {Boolean} isException exception rule indicator 933 * domain part of the text representation (can be empty)
864 * @param {String} tagName tag name part (can be empty) 934 * @param {boolean} isException exception rule indicator
865 * @param {String} attrRules attribute matching rules (can be empty) 935 * @param {string} tagName tag name part (can be empty)
866 * @param {String} selector raw CSS selector (can be empty) 936 * @param {string} attrRules attribute matching rules (can be empty)
867 * @return {ElemHideFilter|ElemHideException|ElemHideEmulationFilter|InvalidFilt er} 937 * @param {string} selector raw CSS selector (can be empty)
938 * @return {ElemHideFilter|ElemHideException|
939 * ElemHideEmulationFilter|InvalidFilter}
868 */ 940 */
869 ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules, selector) 941 ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules,
942 selector)
870 { 943 {
871 if (!selector) 944 if (!selector)
872 { 945 {
873 if (tagName == "*") 946 if (tagName == "*")
874 tagName = ""; 947 tagName = "";
875 948
876 let id = null; 949 let id = null;
877 let additional = ""; 950 let additional = "";
878 if (attrRules) 951 if (attrRules)
879 { 952 {
880 attrRules = attrRules.match(/\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\)/g); 953 attrRules = attrRules.match(/\([\w-]+(?:[$^*]?=[^()"]*)?\)/g);
881 for (let rule of attrRules) 954 for (let rule of attrRules)
882 { 955 {
883 rule = rule.substr(1, rule.length - 2); 956 rule = rule.substr(1, rule.length - 2);
884 let separatorPos = rule.indexOf("="); 957 let separatorPos = rule.indexOf("=");
885 if (separatorPos > 0) 958 if (separatorPos > 0)
886 { 959 {
887 rule = rule.replace(/=/, '="') + '"'; 960 rule = rule.replace(/=/, '="') + '"';
888 additional += "[" + rule + "]"; 961 additional += "[" + rule + "]";
889 } 962 }
890 else 963 else
891 { 964 {
892 if (id) 965 if (id)
893 return new InvalidFilter(text, "filter_elemhide_duplicate_id"); 966 return new InvalidFilter(text, "filter_elemhide_duplicate_id");
894 967
895 id = rule; 968 id = rule;
896 } 969 }
897 } 970 }
898 } 971 }
899 972
900 if (id) 973 if (id)
901 selector = tagName + "." + id + additional + "," + tagName + "#" + id + ad ditional; 974 selector = `${tagName}.${id}${additional},${tagName}#${id}${additional}`;
902 else if (tagName || additional) 975 else if (tagName || additional)
903 selector = tagName + additional; 976 selector = tagName + additional;
904 else 977 else
905 return new InvalidFilter(text, "filter_elemhide_nocriteria"); 978 return new InvalidFilter(text, "filter_elemhide_nocriteria");
906 } 979 }
907 980
908 // We don't allow ElemHide filters which have any empty domains. 981 // We don't allow ElemHide filters which have any empty domains.
909 // Note: The ElemHide.prototype.domainSeparator is duplicated here, if that 982 // Note: The ElemHide.prototype.domainSeparator is duplicated here, if that
910 // changes this must be changed too. 983 // changes this must be changed too.
911 if (domain && /(^|,)~?(,|$)/.test(domain)) 984 if (domain && /(^|,)~?(,|$)/.test(domain))
(...skipping 10 matching lines...) Expand all
922 return new InvalidFilter(text, "filter_elemhideemulation_nodomain"); 995 return new InvalidFilter(text, "filter_elemhideemulation_nodomain");
923 996
924 return new ElemHideEmulationFilter(text, domain, selector); 997 return new ElemHideEmulationFilter(text, domain, selector);
925 } 998 }
926 999
927 return new ElemHideFilter(text, domain, selector); 1000 return new ElemHideFilter(text, domain, selector);
928 }; 1001 };
929 1002
930 /** 1003 /**
931 * Class for element hiding filters 1004 * Class for element hiding filters
932 * @param {String} text see Filter() 1005 * @param {string} text see Filter()
933 * @param {String} domains see ElemHideBase() 1006 * @param {string} domains see ElemHideBase()
934 * @param {String} selector see ElemHideBase() 1007 * @param {string} selector see ElemHideBase()
935 * @constructor 1008 * @constructor
936 * @augments ElemHideBase 1009 * @augments ElemHideBase
937 */ 1010 */
938 function ElemHideFilter(text, domains, selector) 1011 function ElemHideFilter(text, domains, selector)
939 { 1012 {
940 ElemHideBase.call(this, text, domains, selector); 1013 ElemHideBase.call(this, text, domains, selector);
941 } 1014 }
942 exports.ElemHideFilter = ElemHideFilter; 1015 exports.ElemHideFilter = ElemHideFilter;
943 1016
944 ElemHideFilter.prototype = extend(ElemHideBase, { 1017 ElemHideFilter.prototype = extend(ElemHideBase, {
945 type: "elemhide" 1018 type: "elemhide"
946 }); 1019 });
947 1020
948 /** 1021 /**
949 * Class for element hiding exceptions 1022 * Class for element hiding exceptions
950 * @param {String} text see Filter() 1023 * @param {string} text see Filter()
951 * @param {String} domains see ElemHideBase() 1024 * @param {string} domains see ElemHideBase()
952 * @param {String} selector see ElemHideBase() 1025 * @param {string} selector see ElemHideBase()
953 * @constructor 1026 * @constructor
954 * @augments ElemHideBase 1027 * @augments ElemHideBase
955 */ 1028 */
956 function ElemHideException(text, domains, selector) 1029 function ElemHideException(text, domains, selector)
957 { 1030 {
958 ElemHideBase.call(this, text, domains, selector); 1031 ElemHideBase.call(this, text, domains, selector);
959 } 1032 }
960 exports.ElemHideException = ElemHideException; 1033 exports.ElemHideException = ElemHideException;
961 1034
962 ElemHideException.prototype = extend(ElemHideBase, { 1035 ElemHideException.prototype = extend(ElemHideBase, {
963 type: "elemhideexception" 1036 type: "elemhideexception"
964 }); 1037 });
965 1038
966 /** 1039 /**
967 * Class for element hiding emulation filters 1040 * Class for element hiding emulation filters
968 * @param {String} text see Filter() 1041 * @param {string} text see Filter()
969 * @param {String} domains see ElemHideBase() 1042 * @param {string} domains see ElemHideBase()
970 * @param {String} selector see ElemHideBase() 1043 * @param {string} selector see ElemHideBase()
971 * @constructor 1044 * @constructor
972 * @augments ElemHideBase 1045 * @augments ElemHideBase
973 */ 1046 */
974 function ElemHideEmulationFilter(text, domains, selector) 1047 function ElemHideEmulationFilter(text, domains, selector)
975 { 1048 {
976 ElemHideBase.call(this, text, domains, selector); 1049 ElemHideBase.call(this, text, domains, selector);
977 } 1050 }
978 exports.ElemHideEmulationFilter = ElemHideEmulationFilter; 1051 exports.ElemHideEmulationFilter = ElemHideEmulationFilter;
979 1052
980 ElemHideEmulationFilter.prototype = extend(ElemHideBase, { 1053 ElemHideEmulationFilter.prototype = extend(ElemHideBase, {
981 type: "elemhideemulation" 1054 type: "elemhideemulation"
982 }); 1055 });
OLDNEW
« no previous file with comments | « lib/events.js ('k') | lib/filterListener.js » ('j') | lib/synchronizer.js » ('J')

Powered by Google App Engine
This is Rietveld