Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: lib/content/elemHideEmulation.js

Issue 29556808: Issue 5797 - Removed obsolete arguments from ElemHideEmulation constructor (Closed)
Patch Set: Created Sept. 27, 2017, 12:18 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-present eyeo GmbH 3 * Copyright (C) 2006-present 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 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 yield [selector, subtree]; 295 yield [selector, subtree];
296 } 296 }
297 }; 297 };
298 298
299 function isSelectorHidingOnlyPattern(pattern) 299 function isSelectorHidingOnlyPattern(pattern)
300 { 300 {
301 return pattern.selectors.some(s => s.preferHideWithSelector) && 301 return pattern.selectors.some(s => s.preferHideWithSelector) &&
302 !pattern.selectors.some(s => s.requiresHiding); 302 !pattern.selectors.some(s => s.requiresHiding);
303 } 303 }
304 304
305 function ElemHideEmulation(window, getFiltersFunc, addSelectorsFunc, 305 function ElemHideEmulation(addSelectorsFunc, hideElemsFunc)
306 hideElemsFunc)
307 { 306 {
308 this.window = window; 307 this.document = document;
Sebastian Noack 2017/09/27 00:20:45 We still need a way to mock the document the eleme
309 this.getFiltersFunc = getFiltersFunc;
310 this.addSelectorsFunc = addSelectorsFunc; 308 this.addSelectorsFunc = addSelectorsFunc;
311 this.hideElemsFunc = hideElemsFunc; 309 this.hideElemsFunc = hideElemsFunc;
312 this.observer = new window.MutationObserver(this.observe.bind(this)); 310 this.observer = new MutationObserver(this.observe.bind(this));
313 } 311 }
314 312
315 ElemHideEmulation.prototype = { 313 ElemHideEmulation.prototype = {
316 isSameOrigin(stylesheet) 314 isSameOrigin(stylesheet)
317 { 315 {
318 try 316 try
319 { 317 {
320 return new URL(stylesheet.href).origin == this.window.location.origin; 318 return new URL(stylesheet.href).origin == this.document.location.origin;
321 } 319 }
322 catch (e) 320 catch (e)
323 { 321 {
324 // Invalid URL, assume that it is first-party. 322 // Invalid URL, assume that it is first-party.
325 return true; 323 return true;
326 } 324 }
327 }, 325 },
328 326
329 /** Parse the selector 327 /** Parse the selector
330 * @param {string} selector the selector to parse 328 * @param {string} selector the selector to parse
(...skipping 10 matching lines...) Expand all
341 return [new PlainSelector(selector)]; 339 return [new PlainSelector(selector)];
342 340
343 let selectors = []; 341 let selectors = [];
344 if (match.index > 0) 342 if (match.index > 0)
345 selectors.push(new PlainSelector(selector.substr(0, match.index))); 343 selectors.push(new PlainSelector(selector.substr(0, match.index)));
346 344
347 let startIndex = match.index + match[0].length; 345 let startIndex = match.index + match[0].length;
348 let content = parseSelectorContent(selector, startIndex); 346 let content = parseSelectorContent(selector, startIndex);
349 if (!content) 347 if (!content)
350 { 348 {
351 this.window.console.error( 349 console.error(new SyntaxError("Failed to parse Adblock Plus " +
352 new SyntaxError("Failed to parse Adblock Plus " + 350 `selector ${selector} ` +
353 `selector ${selector} ` + 351 "due to unmatched parentheses."));
354 "due to unmatched parentheses."));
355 return null; 352 return null;
356 } 353 }
357 if (match[1] == "properties") 354 if (match[1] == "properties")
358 selectors.push(new PropsSelector(content.text)); 355 selectors.push(new PropsSelector(content.text));
359 else if (match[1] == "has") 356 else if (match[1] == "has")
360 { 357 {
361 let hasSelectors = this.parseSelector(content.text); 358 let hasSelectors = this.parseSelector(content.text);
362 if (hasSelectors == null) 359 if (hasSelectors == null)
363 return null; 360 return null;
364 selectors.push(new HasSelector(hasSelectors)); 361 selectors.push(new HasSelector(hasSelectors));
365 } 362 }
366 else if (match[1] == "contains") 363 else if (match[1] == "contains")
367 selectors.push(new ContainsSelector(content.text)); 364 selectors.push(new ContainsSelector(content.text));
368 else 365 else
369 { 366 {
370 // this is an error, can't parse selector. 367 // this is an error, can't parse selector.
371 this.window.console.error( 368 console.error(new SyntaxError("Failed to parse Adblock Plus " +
372 new SyntaxError("Failed to parse Adblock Plus " + 369 `selector ${selector}, invalid ` +
373 `selector ${selector}, invalid ` + 370 `pseudo-class :-abp-${match[1]}().`));
374 `pseudo-class :-abp-${match[1]}().`));
375 return null; 371 return null;
376 } 372 }
377 373
378 let suffix = this.parseSelector(selector.substr(content.end + 1)); 374 let suffix = this.parseSelector(selector.substr(content.end + 1));
379 if (suffix == null) 375 if (suffix == null)
380 return null; 376 return null;
381 377
382 selectors.push(...suffix); 378 selectors.push(...suffix);
383 379
384 if (selectors.length == 1 && selectors[0] instanceof ContainsSelector) 380 if (selectors.length == 1 && selectors[0] instanceof ContainsSelector)
385 { 381 {
386 this.window.console.error( 382 console.error(new SyntaxError("Failed to parse Adblock Plus " +
387 new SyntaxError("Failed to parse Adblock Plus " + 383 `selector ${selector}, can't ` +
388 `selector ${selector}, can't ` + 384 "have a lonely :-abp-contains()."));
389 "have a lonely :-abp-contains()."));
390 return null; 385 return null;
391 } 386 }
392 return selectors; 387 return selectors;
393 }, 388 },
394 389
395 /** 390 /**
396 * Processes the current document and applies all rules to it. 391 * Processes the current document and applies all rules to it.
397 * @param {CSSStyleSheet[]} [stylesheets] 392 * @param {CSSStyleSheet[]} [stylesheets]
398 * The list of new stylesheets that have been added to the document and 393 * The list of new stylesheets that have been added to the document and
399 * made reprocessing necessary. This parameter shouldn't be passed in for 394 * made reprocessing necessary. This parameter shouldn't be passed in for
400 * the initial processing, all of document's stylesheets will be considered 395 * the initial processing, all of document's stylesheets will be considered
401 * then and all rules, including the ones not dependent on styles. 396 * then and all rules, including the ones not dependent on styles.
402 * @param {function} [done] 397 * @param {function} [done]
403 * Callback to call when done. 398 * Callback to call when done.
404 */ 399 */
405 _addSelectors(stylesheets, done) 400 _addSelectors(stylesheets, done)
406 { 401 {
407 let selectors = []; 402 let selectors = [];
408 let selectorFilters = []; 403 let selectorFilters = [];
409 404
410 let elements = []; 405 let elements = [];
411 let elementFilters = []; 406 let elementFilters = [];
412 407
413 let cssStyles = []; 408 let cssStyles = [];
414 409
415 let stylesheetOnlyChange = !!stylesheets; 410 let stylesheetOnlyChange = !!stylesheets;
416 if (!stylesheets) 411 if (!stylesheets)
417 stylesheets = this.window.document.styleSheets; 412 stylesheets = this.document.styleSheets;
418 413
419 // Chrome < 51 doesn't have an iterable StyleSheetList 414 // Chrome < 51 doesn't have an iterable StyleSheetList
420 // https://issues.adblockplus.org/ticket/5381 415 // https://issues.adblockplus.org/ticket/5381
421 for (let i = 0; i < stylesheets.length; i++) 416 for (let i = 0; i < stylesheets.length; i++)
422 { 417 {
423 let stylesheet = stylesheets[i]; 418 let stylesheet = stylesheets[i];
424 // Explicitly ignore third-party stylesheets to ensure consistent behavior 419 // Explicitly ignore third-party stylesheets to ensure consistent behavior
425 // between Firefox and Chrome. 420 // between Firefox and Chrome.
426 if (!this.isSameOrigin(stylesheet)) 421 if (!this.isSameOrigin(stylesheet))
427 continue; 422 continue;
428 423
429 let rules = stylesheet.cssRules; 424 let rules = stylesheet.cssRules;
430 if (!rules) 425 if (!rules)
431 continue; 426 continue;
432 427
433 // Chrome < 51 doesn't have an iterable CSSRuleList 428 // Chrome < 51 doesn't have an iterable CSSRuleList
434 // https://issues.adblockplus.org/ticket/5773 429 // https://issues.adblockplus.org/ticket/5773
435 for (let j = 0; j < rules.length; j++) 430 for (let j = 0; j < rules.length; j++)
436 { 431 {
437 let rule = rules[j]; 432 let rule = rules[j];
438 if (rule.type != rule.STYLE_RULE) 433 if (rule.type != rule.STYLE_RULE)
439 continue; 434 continue;
440 435
441 cssStyles.push(stringifyStyle(rule)); 436 cssStyles.push(stringifyStyle(rule));
442 } 437 }
443 } 438 }
444 439
445 let {document} = this.window;
446
447 let patterns = this.patterns.slice(); 440 let patterns = this.patterns.slice();
448 let pattern = null; 441 let pattern = null;
449 let generator = null; 442 let generator = null;
450 443
451 let processPatterns = () => 444 let processPatterns = () =>
452 { 445 {
453 let cycleStart = this.window.performance.now(); 446 let cycleStart = performance.now();
454 447
455 if (!pattern) 448 if (!pattern)
456 { 449 {
457 if (!patterns.length) 450 if (!patterns.length)
458 { 451 {
459 this.addSelectorsFunc(selectors, selectorFilters); 452 this.addSelectorsFunc(selectors, selectorFilters);
460 this.hideElemsFunc(elements, elementFilters); 453 this.hideElemsFunc(elements, elementFilters);
461 if (typeof done == "function") 454 if (typeof done == "function")
462 done(); 455 done();
463 return; 456 return;
464 } 457 }
465 458
466 pattern = patterns.shift(); 459 pattern = patterns.shift();
467 460
468 if (stylesheetOnlyChange && 461 if (stylesheetOnlyChange &&
469 !pattern.selectors.some(selector => selector.dependsOnStyles)) 462 !pattern.selectors.some(selector => selector.dependsOnStyles))
470 { 463 {
471 pattern = null; 464 pattern = null;
472 return processPatterns(); 465 return processPatterns();
473 } 466 }
474 generator = evaluate(pattern.selectors, 0, "", document, cssStyles); 467 generator = evaluate(pattern.selectors, 0, "",
468 this.document, cssStyles);
475 } 469 }
476 for (let selector of generator) 470 for (let selector of generator)
477 { 471 {
478 if (selector != null) 472 if (selector != null)
479 { 473 {
480 if (isSelectorHidingOnlyPattern(pattern)) 474 if (isSelectorHidingOnlyPattern(pattern))
481 { 475 {
482 selectors.push(selector); 476 selectors.push(selector);
483 selectorFilters.push(pattern.text); 477 selectorFilters.push(pattern.text);
484 } 478 }
485 else 479 else
486 { 480 {
487 for (let element of document.querySelectorAll(selector)) 481 for (let element of this.document.querySelectorAll(selector))
488 { 482 {
489 elements.push(element); 483 elements.push(element);
490 elementFilters.push(pattern.text); 484 elementFilters.push(pattern.text);
491 } 485 }
492 } 486 }
493 } 487 }
494 if (this.window.performance.now() - 488 if (performance.now() - cycleStart > MAX_SYNCHRONOUS_PROCESSING_TIME)
495 cycleStart > MAX_SYNCHRONOUS_PROCESSING_TIME)
496 { 489 {
497 this.window.setTimeout(processPatterns, 0); 490 setTimeout(processPatterns, 0);
498 return; 491 return;
499 } 492 }
500 } 493 }
501 pattern = null; 494 pattern = null;
502 return processPatterns(); 495 return processPatterns();
503 }; 496 };
504 497
505 processPatterns(); 498 processPatterns();
506 }, 499 },
507 500
(...skipping 16 matching lines...) Expand all
524 /** 517 /**
525 * Re-run filtering either immediately or queued. 518 * Re-run filtering either immediately or queued.
526 * @param {CSSStyleSheet[]} [stylesheets] 519 * @param {CSSStyleSheet[]} [stylesheets]
527 * new stylesheets to be processed. This parameter should be omitted 520 * new stylesheets to be processed. This parameter should be omitted
528 * for DOM modification (full reprocessing required). 521 * for DOM modification (full reprocessing required).
529 */ 522 */
530 queueFiltering(stylesheets) 523 queueFiltering(stylesheets)
531 { 524 {
532 let completion = () => 525 let completion = () =>
533 { 526 {
534 this._lastInvocation = this.window.performance.now(); 527 this._lastInvocation = performance.now();
535 this._filteringInProgress = false; 528 this._filteringInProgress = false;
536 if (this._scheduledProcessing) 529 if (this._scheduledProcessing)
537 { 530 {
538 let newStylesheets = this._scheduledProcessing.stylesheets; 531 let newStylesheets = this._scheduledProcessing.stylesheets;
539 this._scheduledProcessing = null; 532 this._scheduledProcessing = null;
540 this.queueFiltering(newStylesheets); 533 this.queueFiltering(newStylesheets);
541 } 534 }
542 }; 535 };
543 536
544 if (this._scheduledProcessing) 537 if (this._scheduledProcessing)
545 { 538 {
546 if (!stylesheets) 539 if (!stylesheets)
547 this._scheduledProcessing.stylesheets = null; 540 this._scheduledProcessing.stylesheets = null;
548 else if (this._scheduledProcessing.stylesheets) 541 else if (this._scheduledProcessing.stylesheets)
549 this._scheduledProcessing.stylesheets.push(...stylesheets); 542 this._scheduledProcessing.stylesheets.push(...stylesheets);
550 } 543 }
551 else if (this._filteringInProgress) 544 else if (this._filteringInProgress)
552 { 545 {
553 this._scheduledProcessing = {stylesheets}; 546 this._scheduledProcessing = {stylesheets};
554 } 547 }
555 else if (this.window.performance.now() - 548 else if (performance.now() - this._lastInvocation < MIN_INVOCATION_INTERVAL)
556 this._lastInvocation < MIN_INVOCATION_INTERVAL)
557 { 549 {
558 this._scheduledProcessing = {stylesheets}; 550 this._scheduledProcessing = {stylesheets};
559 this.window.setTimeout(() => 551 setTimeout(() =>
560 { 552 {
561 let newStylesheets = this._scheduledProcessing.stylesheets; 553 let newStylesheets = this._scheduledProcessing.stylesheets;
562 this._filteringInProgress = true; 554 this._filteringInProgress = true;
563 this._scheduledProcessing = null; 555 this._scheduledProcessing = null;
564 this._addSelectors(newStylesheets, completion); 556 this._addSelectors(newStylesheets, completion);
565 }, 557 },
566 MIN_INVOCATION_INTERVAL - 558 MIN_INVOCATION_INTERVAL - (performance.now() - this._lastInvocation));
567 (this.window.performance.now() - this._lastInvocation));
568 } 559 }
569 else 560 else
570 { 561 {
571 this._filteringInProgress = true; 562 this._filteringInProgress = true;
572 this._addSelectors(stylesheets, completion); 563 this._addSelectors(stylesheets, completion);
573 } 564 }
574 }, 565 },
575 566
576 onLoad(event) 567 onLoad(event)
577 { 568 {
578 let stylesheet = event.target.sheet; 569 let stylesheet = event.target.sheet;
579 if (stylesheet) 570 if (stylesheet)
580 this.queueFiltering([stylesheet]); 571 this.queueFiltering([stylesheet]);
581 }, 572 },
582 573
583 observe(mutations) 574 observe(mutations)
584 { 575 {
585 this.queueFiltering(); 576 this.queueFiltering();
586 }, 577 },
587 578
588 apply() 579 apply(patterns)
589 { 580 {
590 this.getFiltersFunc(patterns => 581 this.patterns = [];
582 for (let pattern of patterns)
591 { 583 {
592 this.patterns = []; 584 let selectors = this.parseSelector(pattern.selector);
593 for (let pattern of patterns) 585 if (selectors != null && selectors.length > 0)
594 { 586 this.patterns.push({selectors, text: pattern.text});
595 let selectors = this.parseSelector(pattern.selector); 587 }
596 if (selectors != null && selectors.length > 0)
597 this.patterns.push({selectors, text: pattern.text});
598 }
599 588
600 if (this.patterns.length > 0) 589 if (this.patterns.length > 0)
601 { 590 {
602 let {document} = this.window; 591 this.queueFiltering();
603 this.queueFiltering(); 592 this.observer.observe(
604 this.observer.observe( 593 this.document,
605 document, 594 {
606 { 595 childList: true,
607 childList: true, 596 attributes: true,
608 attributes: true, 597 characterData: true,
609 characterData: true, 598 subtree: true
610 subtree: true 599 }
611 } 600 );
612 ); 601 this.document.addEventListener("load", this.onLoad.bind(this), true);
613 document.addEventListener("load", this.onLoad.bind(this), true); 602 }
614 }
615 });
616 } 603 }
617 }; 604 };
618 605
619 exports.ElemHideEmulation = ElemHideEmulation; 606 exports.ElemHideEmulation = ElemHideEmulation;
OLDNEW

Powered by Google App Engine
This is Rietveld