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: Use MutationObserver again Created March 18, 2016, 5:30 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 | no next file » | 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 reinjectStyleSheetWhenRemoved(document, style)
335 { 335 {
336 var MutationObserver = window.MutationObserver || window.WebKitMutationObserve r; 336 var MutationObserver = window.MutationObserver ||
337 window.WebKitMutationObserver;
337 if (!MutationObserver) 338 if (!MutationObserver)
338 return; 339 return null;
339 340
340 var observer = new MutationObserver(function(mutations) 341 var parentNode = style.parentNode;
342 var observer = new MutationObserver(function()
341 { 343 {
342 var isStyleRemoved = false; 344 if (style.parentNode != parentNode)
343 for (var i = 0; i < mutations.length; i++) 345 parentNode.appendChild(style);
344 {
345 if ([].indexOf.call(mutations[i].removedNodes, style) != -1)
346 {
347 isStyleRemoved = true;
348 break;
349 }
350 }
351 if (!isStyleRemoved)
352 return;
353
354 observer.disconnect();
355
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 {
366 var selectors = response.selectors;
367 while (selectors.length > 0)
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 }
377 );
378 }); 346 });
379 347
380 observer.observe(style.parentNode, {childList: true}); 348 observer.observe(parentNode, {childList: true});
381 return observer; 349 return observer;
382 } 350 }
383 351
352 function protectStyleSheet(document, style)
353 {
354 var id = Math.random().toString(36).substr(2)
355 style.id = id;
356
357 var code = [
358 "(function()",
359 "{",
360 ' var style = document.getElementById("' + id + '") ||',
361 ' document.documentElement.shadowRoot.getElementById("' + id + '");',
Sebastian Noack 2016/03/18 17:58:54 (Yes, I know that this line is 6 characters too lo
kzar 2016/03/18 19:18:32 Acknowledged.
362 ' style.removeAttribute("id");'
363 ];
364
365 var disableables = ["style", "style.sheet"];
366 for (var i = 0; i < disableables.length; i++)
367 {
368 code.push(" Object.defineProperty(" + disableables[i] + ', "disabled", '
369 + "{value: false, enumerable: true});") ;
370 }
371
372 var methods = ["deleteRule", "removeRule"];
373 for (var j = 0; j < methods.length; j++)
kzar 2016/03/18 19:18:32 Nit: Just re-use the existing `i` variable instead
Sebastian Noack 2016/03/18 19:23:55 I'm not sure whether it's a good idea to make the
374 {
375 var method = methods[j];
376 if (method in CSSStyleSheet.prototype)
377 {
378 var origin = "CSSStyleSheet.prototype." + method;
379 code.push(" var " + method + " = " + origin + ";",
380 " " + origin + " = function(index)",
381 " {",
382 " if (this != style.sheet)",
383 " " + method + ".apply(this, index);",
384 " }");
385 }
386 }
387
388 code.push("})();");
389
390 var script = document.createElement("script");
391 script.async = false;
392 script.textContent = code.join("\n");
393 document.documentElement.appendChild(script);
394 document.documentElement.removeChild(script);
395 }
396
384 function init(document) 397 function init(document)
385 { 398 {
386 var shadow = null; 399 var shadow = null;
387 var style = null; 400 var style = null;
388 var observer = null; 401 var observer = null;
389 var tracer = null; 402 var tracer = null;
390 var propertyFilters = new CSSPropertyFilters(window, addElemHideSelectors); 403 var propertyFilters = new CSSPropertyFilters(window, addElemHideSelectors);
391 404
392 // Use Shadow DOM if available to don't mess with web pages that rely on 405 // Use Shadow DOM if available to don't mess with web pages that rely on
393 // the order of their own <style> tags (#309). 406 // the order of their own <style> tags (#309).
(...skipping 23 matching lines...) Expand all
417 style = document.createElement("style"); 430 style = document.createElement("style");
418 (shadow || document.head || document.documentElement).appendChild(style); 431 (shadow || document.head || document.documentElement).appendChild(style);
419 432
420 // It can happen that the frame already navigated to a different 433 // It can happen that the frame already navigated to a different
421 // document while we were waiting for the background page to respond. 434 // document while we were waiting for the background page to respond.
422 // In that case the sheet property will stay null, after addind the 435 // In that case the sheet property will stay null, after addind the
423 // <style> element to the shadow DOM. 436 // <style> element to the shadow DOM.
424 if (!style.sheet) 437 if (!style.sheet)
425 return; 438 return;
426 439
427 observer = reinjectRulesWhenRemoved(document, style); 440 observer = reinjectStyleSheetWhenRemoved(document, style);
441 protectStyleSheet(document, style);
428 } 442 }
429 443
430 // If using shadow DOM, we have to add the ::content pseudo-element 444 // If using shadow DOM, we have to add the ::content pseudo-element
431 // before each selector, in order to match elements within the 445 // before each selector, in order to match elements within the
432 // insertion point. 446 // insertion point.
433 if (shadow) 447 if (shadow)
434 { 448 {
435 var preparedSelectors = []; 449 var preparedSelectors = [];
436 for (var i = 0; i < selectors.length; i++) 450 for (var i = 0; i < selectors.length; i++)
437 { 451 {
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 }, true); 551 }, true);
538 552
539 return updateStylesheet; 553 return updateStylesheet;
540 } 554 }
541 555
542 if (document instanceof HTMLDocument) 556 if (document instanceof HTMLDocument)
543 { 557 {
544 checkSitekey(); 558 checkSitekey();
545 window.updateStylesheet = init(document); 559 window.updateStylesheet = init(document);
546 } 560 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld