Left: | ||
Right: |
LEFT | RIGHT |
---|---|
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-2017 eyeo GmbH | 3 * Copyright (C) 2006-2017 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 |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
251 | 251 |
252 if (parsed.canSafelyMatchAsLowercase || filter.matchCase) | 252 if (parsed.canSafelyMatchAsLowercase || filter.matchCase) |
253 trigger["url-filter-is-case-sensitive"] = true; | 253 trigger["url-filter-is-case-sensitive"] = true; |
254 | 254 |
255 let included = []; | 255 let included = []; |
256 let excluded = []; | 256 let excluded = []; |
257 | 257 |
258 parseDomains(filter.domains, included, excluded); | 258 parseDomains(filter.domains, included, excluded); |
259 | 259 |
260 if (exceptionDomains) | 260 if (exceptionDomains) |
261 excluded = excluded.concat(exceptionDomains); | 261 excluded = excluded.concat(exceptionDomains); |
Sebastian Noack
2017/05/21 20:44:35
I wonder whether it would be better to avoid conca
Manish Jethani
2017/05/21 21:03:57
JSHydra does not support the spread operator. It's
| |
262 | 262 |
263 if (withResourceTypes) | 263 if (withResourceTypes) |
264 { | 264 { |
265 trigger["resource-type"] = getResourceTypes(filter); | 265 trigger["resource-type"] = getResourceTypes(filter); |
266 | 266 |
267 if (trigger["resource-type"].length == 0) | 267 if (trigger["resource-type"].length == 0) |
268 return; | 268 return; |
269 } | 269 } |
270 | 270 |
271 if (filter.thirdParty != null) | 271 if (filter.thirdParty != null) |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
347 { | 347 { |
348 newSelector.push(selector.substring(i, pos.start)); | 348 newSelector.push(selector.substring(i, pos.start)); |
349 newSelector.push('[id=', selector.substring(pos.start + 1, pos.end), ']'); | 349 newSelector.push('[id=', selector.substring(pos.start + 1, pos.end), ']'); |
350 i = pos.end; | 350 i = pos.end; |
351 } | 351 } |
352 newSelector.push(selector.substring(i)); | 352 newSelector.push(selector.substring(i)); |
353 | 353 |
354 return newSelector.join(""); | 354 return newSelector.join(""); |
355 } | 355 } |
356 | 356 |
357 function addCSSRules(rules, selectors, matchDomain) | |
358 { | |
359 while (selectors.length) | |
360 { | |
361 let selector = selectors.splice(0, selectorLimit).join(", "); | |
362 | |
363 // As of Safari 9.0 element IDs are matched as lowercase. We work around | |
364 // this by converting to the attribute format [id="elementID"] | |
365 selector = convertIDSelectorsToAttributeSelectors(selector); | |
366 | |
367 rules.push({ | |
368 trigger: {"url-filter": matchDomain, | |
369 "url-filter-is-case-sensitive": true}, | |
370 action: {type: "css-display-none", | |
371 selector: selector} | |
372 }); | |
373 } | |
374 } | |
375 | |
357 let ContentBlockerList = | 376 let ContentBlockerList = |
358 /** | 377 /** |
359 * Create a new Adblock Plus filter to content blocker list converter | 378 * Create a new Adblock Plus filter to content blocker list converter |
360 * | 379 * |
361 * @constructor | 380 * @constructor |
362 */ | 381 */ |
363 exports.ContentBlockerList = function () | 382 exports.ContentBlockerList = function () |
364 { | 383 { |
365 this.requestFilters = []; | 384 this.requestFilters = []; |
366 this.requestExceptions = []; | 385 this.requestExceptions = []; |
367 this.elemhideFilters = []; | 386 this.elemhideFilters = []; |
368 this.elemhideExceptions = []; | 387 this.elemhideExceptions = []; |
369 this.genericblockExceptions = []; | 388 this.genericblockExceptions = []; |
389 this.generichideExceptions = []; | |
370 this.elemhideSelectorExceptions = new Map(); | 390 this.elemhideSelectorExceptions = new Map(); |
371 }; | 391 }; |
372 | 392 |
373 /** | 393 /** |
374 * Add Adblock Plus filter to be converted | 394 * Add Adblock Plus filter to be converted |
375 * | 395 * |
376 * @param {Filter} filter Filter to convert | 396 * @param {Filter} filter Filter to convert |
377 */ | 397 */ |
378 ContentBlockerList.prototype.addFilter = function(filter) | 398 ContentBlockerList.prototype.addFilter = function(filter) |
379 { | 399 { |
380 if (filter.sitekeys) | 400 if (filter.sitekeys) |
381 return; | 401 return; |
382 if (filter instanceof filterClasses.RegExpFilter && | 402 if (filter instanceof filterClasses.RegExpFilter && |
383 filter.regexpSource == null) | 403 filter.regexpSource == null) |
384 return; | 404 return; |
385 | 405 |
386 if (filter instanceof filterClasses.BlockingFilter) | 406 if (filter instanceof filterClasses.BlockingFilter) |
387 this.requestFilters.push(filter); | 407 this.requestFilters.push(filter); |
388 | 408 |
389 if (filter instanceof filterClasses.WhitelistFilter) | 409 if (filter instanceof filterClasses.WhitelistFilter) |
390 { | 410 { |
391 if (filter.contentType & (typeMap.DOCUMENT | whitelistableRequestTypes)) | 411 if (filter.contentType & (typeMap.DOCUMENT | whitelistableRequestTypes)) |
392 this.requestExceptions.push(filter); | 412 this.requestExceptions.push(filter); |
393 | 413 |
394 if (filter.contentType & typeMap.ELEMHIDE) | |
395 this.elemhideExceptions.push(filter); | |
396 | |
397 if (filter.contentType & typeMap.GENERICBLOCK) | 414 if (filter.contentType & typeMap.GENERICBLOCK) |
398 this.genericblockExceptions.push(filter); | 415 this.genericblockExceptions.push(filter); |
416 | |
417 if (filter.contentType & typeMap.ELEMHIDE) | |
418 this.elemhideExceptions.push(filter); | |
419 else if (filter.contentType & typeMap.GENERICHIDE) | |
420 this.generichideExceptions.push(filter); | |
399 } | 421 } |
400 | 422 |
401 if (filter instanceof filterClasses.ElemHideFilter) | 423 if (filter instanceof filterClasses.ElemHideFilter) |
402 this.elemhideFilters.push(filter); | 424 this.elemhideFilters.push(filter); |
403 | 425 |
404 if (filter instanceof filterClasses.ElemHideException) | 426 if (filter instanceof filterClasses.ElemHideException) |
405 { | 427 { |
406 let domains = this.elemhideSelectorExceptions[filter.selector]; | 428 let domains = this.elemhideSelectorExceptions[filter.selector]; |
407 if (!domains) | 429 if (!domains) |
408 domains = this.elemhideSelectorExceptions[filter.selector] = []; | 430 domains = this.elemhideSelectorExceptions[filter.selector] = []; |
409 | 431 |
410 parseDomains(filter.domains, domains, []); | 432 parseDomains(filter.domains, domains, []); |
411 } | 433 } |
412 }; | 434 }; |
413 | 435 |
414 /** | 436 /** |
415 * Generate content blocker list for all filters that were added | 437 * Generate content blocker list for all filters that were added |
416 * | 438 * |
417 * @returns {Filter} filter Filter to convert | 439 * @returns {Filter} filter Filter to convert |
418 */ | 440 */ |
419 ContentBlockerList.prototype.generateRules = function(filter) | 441 ContentBlockerList.prototype.generateRules = function(filter) |
420 { | 442 { |
421 let rules = []; | 443 let rules = []; |
422 | 444 |
445 let genericSelectors = []; | |
423 let groupedElemhideFilters = new Map(); | 446 let groupedElemhideFilters = new Map(); |
447 | |
424 for (let filter of this.elemhideFilters) | 448 for (let filter of this.elemhideFilters) |
425 { | 449 { |
426 let result = convertElemHideFilter(filter, this.elemhideSelectorExceptions); | 450 let result = convertElemHideFilter(filter, this.elemhideSelectorExceptions); |
427 if (!result) | 451 if (!result) |
428 continue; | 452 continue; |
429 | 453 |
430 if (result.matchDomains.length == 0) | 454 if (result.matchDomains.length == 0) |
431 result.matchDomains = ["^https?://"]; | |
432 | |
433 for (let matchDomain of result.matchDomains) | |
434 { | 455 { |
435 let group = groupedElemhideFilters.get(matchDomain) || []; | 456 genericSelectors.push(result.selector); |
436 group.push(result.selector); | |
437 groupedElemhideFilters.set(matchDomain, group); | |
438 } | 457 } |
439 } | 458 else |
459 { | |
460 for (let matchDomain of result.matchDomains) | |
461 { | |
462 let group = groupedElemhideFilters.get(matchDomain) || []; | |
463 group.push(result.selector); | |
464 groupedElemhideFilters.set(matchDomain, group); | |
465 } | |
466 } | |
467 } | |
468 | |
469 addCSSRules(rules, genericSelectors, "^https?://"); | |
470 | |
471 // Right after the generic element hiding filters, add the exceptions that | |
472 // should apply only to those filters. | |
473 for (let filter of this.generichideExceptions) | |
474 convertFilterAddRules(rules, filter, "ignore-previous-rules", false); | |
440 | 475 |
441 groupedElemhideFilters.forEach((selectors, matchDomain) => | 476 groupedElemhideFilters.forEach((selectors, matchDomain) => |
442 { | 477 { |
443 while (selectors.length) | 478 addCSSRules(rules, selectors, matchDomain); |
444 { | |
445 let selector = selectors.splice(0, selectorLimit).join(", "); | |
446 | |
447 // As of Safari 9.0 element IDs are matched as lowercase. We work around | |
448 // this by converting to the attribute format [id="elementID"] | |
449 selector = convertIDSelectorsToAttributeSelectors(selector); | |
450 | |
451 rules.push({ | |
452 trigger: {"url-filter": matchDomain, | |
453 "url-filter-is-case-sensitive": true}, | |
454 action: {type: "css-display-none", | |
455 selector: selector} | |
456 }); | |
457 } | |
458 }); | 479 }); |
459 | 480 |
460 for (let filter of this.elemhideExceptions) | 481 for (let filter of this.elemhideExceptions) |
461 convertFilterAddRules(rules, filter, "ignore-previous-rules", false); | 482 convertFilterAddRules(rules, filter, "ignore-previous-rules", false); |
462 | 483 |
463 let requestFilterExceptionDomains = []; | 484 let requestFilterExceptionDomains = []; |
464 for (let filter of this.genericblockExceptions) | 485 for (let filter of this.genericblockExceptions) |
465 { | 486 { |
466 let parsed = parseFilterRegexpSource(filter.regexpSource); | 487 let parsed = parseFilterRegexpSource(filter.regexpSource); |
467 if (parsed.hostname) | 488 if (parsed.hostname) |
468 requestFilterExceptionDomains.push(parsed.hostname); | 489 requestFilterExceptionDomains.push(parsed.hostname); |
469 } | 490 } |
470 | 491 |
471 for (let filter of this.requestFilters) | 492 for (let filter of this.requestFilters) |
472 { | 493 { |
473 convertFilterAddRules(rules, filter, "block", true, | 494 convertFilterAddRules(rules, filter, "block", true, |
474 requestFilterExceptionDomains); | 495 requestFilterExceptionDomains); |
475 } | 496 } |
476 | 497 |
477 for (let filter of this.requestExceptions) | 498 for (let filter of this.requestExceptions) |
478 convertFilterAddRules(rules, filter, "ignore-previous-rules", true); | 499 convertFilterAddRules(rules, filter, "ignore-previous-rules", true); |
479 | 500 |
480 return rules.filter(rule => !hasNonASCI(rule)); | 501 return rules.filter(rule => !hasNonASCI(rule)); |
481 }; | 502 }; |
LEFT | RIGHT |