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