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

Side by Side Diff: include.preload.js

Issue 29338588: Issue 3699 - Patch DOM API in order to prevent disabling the injected stylesheet (Closed)
Patch Set: Created March 17, 2016, 7:47 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | safari/include.youtube.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 }, 324 },
325 325
326 disconnect: function() 326 disconnect: function()
327 { 327 {
328 this.document.removeEventListener("DOMContentLoaded", this.trace); 328 this.document.removeEventListener("DOMContentLoaded", this.trace);
329 this.observer.disconnect(); 329 this.observer.disconnect();
330 clearTimeout(this.timeout); 330 clearTimeout(this.timeout);
331 } 331 }
332 }; 332 };
333 333
334 function reinjectRulesWhenRemoved(document, style) 334 function runInPage(document, arg, fn)
335 { 335 {
336 var MutationObserver = window.MutationObserver || window.WebKitMutationObserve r; 336 var script = document.createElement("script");
337 if (!MutationObserver) 337 script.async = false;
338 return; 338 script.textContent = "(" + fn + ")(" + arg + ");";
339 document.documentElement.appendChild(script);
340 document.documentElement.removeChild(script);
341 }
339 342
340 var observer = new MutationObserver(function(mutations) 343 function protectStylesheet(document, style)
344 {
345 var id = Math.random().toString(36).substr(2);
346 style.id = id;
347
348 runInPage(document, '"' + id + '"', function(id)
341 { 349 {
342 var isStyleRemoved = false; 350 var style = document.getElementById(id) ||
343 for (var i = 0; i < mutations.length; i++) 351 document.documentElement.shadowRoot.getElementById(id);
352 style.removeAttribute("id");
353
354 var removeChild = Node.prototype.removeChild;
355 Node.prototype.removeChild = function(child)
344 { 356 {
345 if ([].indexOf.call(mutations[i].removedNodes, style) != -1) 357 if (child != style)
358 removeChild.call(this, child);
359 };
360
361 var remove = Element.prototype.remove;
362 if (remove)
363 Element.prototype.remove = function()
346 { 364 {
347 isStyleRemoved = true; 365 if (this != style)
348 break; 366 remove.call(this);
367 };
368
369 var deleteRule = CSSStyleSheet.prototype.deleteRule;
370 CSSStyleSheet.prototype.deleteRule = function(index)
371 {
372 if (this != style.sheet)
373 deleteRule.call(this, index);
374 };
375
376 var removeRule = CSSStyleSheet.prototype.removeRule;
377 if (removeRule)
378 CSSStyleSheet.prototype.removeRule = function(index)
379 {
380 if (this != style.sheet)
381 removeRule.call(this, index);
382 };
383
384 Object.defineProperty(
385 style, 'disabled',
386 {
387 value: false,
388 enumerable: true
349 } 389 }
350 } 390 );
351 if (!isStyleRemoved)
352 return;
353 391
354 observer.disconnect(); 392 Object.defineProperty(
355 393 style.sheet, 'disabled',
356 var n = document.styleSheets.length;
357 if (n == 0)
358 return;
359
360 var stylesheet = document.styleSheets[n - 1];
361 ext.backgroundPage.sendMessage(
362 {type: "get-selectors"},
363
364 function(response)
365 { 394 {
366 var selectors = response.selectors; 395 value: false,
367 while (selectors.length > 0) 396 enumerable: true
368 {
369 var selector = selectors.splice(0, SELECTOR_GROUP_SIZE).join(", ");
370
371 // Using non-standard addRule() here. This is the only way
372 // to add rules at the end of a cross-origin stylesheet
373 // because we don't know how many rules are already in there
374 stylesheet.addRule(selector, "display: none !important;");
375 }
376 } 397 }
377 ); 398 );
378 }); 399 });
379
380 observer.observe(style.parentNode, {childList: true});
381 return observer;
382 } 400 }
383 401
384 function init(document) 402 function init(document)
385 { 403 {
386 var shadow = null; 404 var shadow = null;
387 var style = null; 405 var style = null;
388 var observer = null;
389 var tracer = null; 406 var tracer = null;
390 var propertyFilters = new CSSPropertyFilters(window, addElemHideSelectors); 407 var propertyFilters = new CSSPropertyFilters(window, addElemHideSelectors);
391 408
392 // Use Shadow DOM if available to don't mess with web pages that rely on 409 // Use Shadow DOM if available to don't mess with web pages that rely on
393 // the order of their own <style> tags (#309). 410 // the order of their own <style> tags (#309).
394 // 411 //
395 // However, creating a shadow root breaks running CSS transitions. So we 412 // However, creating a shadow root breaks running CSS transitions. So we
396 // have to create the shadow root before transistions might start (#452). 413 // have to create the shadow root before transistions might start (#452).
397 // 414 //
398 // Also, using shadow DOM causes issues on some Google websites, 415 // Also, using shadow DOM causes issues on some Google websites,
(...skipping 18 matching lines...) Expand all
417 style = document.createElement("style"); 434 style = document.createElement("style");
418 (shadow || document.head || document.documentElement).appendChild(style); 435 (shadow || document.head || document.documentElement).appendChild(style);
419 436
420 // It can happen that the frame already navigated to a different 437 // It can happen that the frame already navigated to a different
421 // document while we were waiting for the background page to respond. 438 // document while we were waiting for the background page to respond.
422 // In that case the sheet property will stay null, after addind the 439 // In that case the sheet property will stay null, after addind the
423 // <style> element to the shadow DOM. 440 // <style> element to the shadow DOM.
424 if (!style.sheet) 441 if (!style.sheet)
425 return; 442 return;
426 443
427 observer = reinjectRulesWhenRemoved(document, style); 444 protectStylesheet(document, style);
428 } 445 }
429 446
430 // If using shadow DOM, we have to add the ::content pseudo-element 447 // If using shadow DOM, we have to add the ::content pseudo-element
431 // before each selector, in order to match elements within the 448 // before each selector, in order to match elements within the
432 // insertion point. 449 // insertion point.
433 if (shadow) 450 if (shadow)
434 { 451 {
435 var preparedSelectors = []; 452 var preparedSelectors = [];
436 for (var i = 0; i < selectors.length; i++) 453 for (var i = 0; i < selectors.length; i++)
437 { 454 {
(...skipping 16 matching lines...) Expand all
454 var updateStylesheet = function() 471 var updateStylesheet = function()
455 { 472 {
456 var selectors = null; 473 var selectors = null;
457 var CSSPropertyFiltersLoaded = false; 474 var CSSPropertyFiltersLoaded = false;
458 475
459 var checkLoaded = function() 476 var checkLoaded = function()
460 { 477 {
461 if (!selectors || !CSSPropertyFiltersLoaded) 478 if (!selectors || !CSSPropertyFiltersLoaded)
462 return; 479 return;
463 480
464 if (observer)
465 observer.disconnect();
466 observer = null;
467
468 if (tracer) 481 if (tracer)
469 tracer.disconnect(); 482 tracer.disconnect();
470 tracer = null; 483 tracer = null;
471 484
472 if (style && style.parentElement) 485 if (style && style.parentElement)
473 style.parentElement.removeChild(style); 486 style.parentElement.removeChild(style);
474 style = null; 487 style = null;
475 488
476 addElemHideSelectors(selectors.selectors); 489 addElemHideSelectors(selectors.selectors);
477 propertyFilters.apply(); 490 propertyFilters.apply();
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 }, true); 550 }, true);
538 551
539 return updateStylesheet; 552 return updateStylesheet;
540 } 553 }
541 554
542 if (document instanceof HTMLDocument) 555 if (document instanceof HTMLDocument)
543 { 556 {
544 checkSitekey(); 557 checkSitekey();
545 window.updateStylesheet = init(document); 558 window.updateStylesheet = init(document);
546 } 559 }
OLDNEW
« no previous file with comments | « no previous file | safari/include.youtube.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld