| 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 |