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

Delta Between Two Patch Sets: include.preload.js

Issue 29338491: Issue 3823 - Split up message responder code (Closed)
Left Patch Set: Created March 17, 2016, 2:04 p.m.
Right Patch Set: Moved get-domain-enabled-state to whitelisting module Created March 22, 2016, 8:22 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « chrome/devtools.js ('k') | lib/devtools.js » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
18 var SELECTOR_GROUP_SIZE = 20; 19 var SELECTOR_GROUP_SIZE = 20;
19 20
20 var typeMap = { 21 var typeMap = {
21 "img": "IMAGE", 22 "img": "IMAGE",
22 "input": "IMAGE", 23 "input": "IMAGE",
23 "picture": "IMAGE", 24 "picture": "IMAGE",
24 "audio": "MEDIA", 25 "audio": "MEDIA",
25 "video": "MEDIA", 26 "video": "MEDIA",
26 "frame": "SUBDOCUMENT", 27 "frame": "SUBDOCUMENT",
27 "iframe": "SUBDOCUMENT", 28 "iframe": "SUBDOCUMENT",
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 { 121 {
121 if (/^(?!https?:)[\w-]+:/i.test(urls[i])) 122 if (/^(?!https?:)[\w-]+:/i.test(urls[i]))
122 urls.splice(i--, 1); 123 urls.splice(i--, 1);
123 } 124 }
124 125
125 return urls; 126 return urls;
126 } 127 }
127 128
128 function checkCollapse(element) 129 function checkCollapse(element)
129 { 130 {
130 var tag = element.localName;
131 if (tag in typeMap)
132 {
133 // This element failed loading, did we block it?
134 var urls = getURLsFromElement(element);
135 if (urls.length == 0)
136 return;
137
138 ext.backgroundPage.sendMessage(
139 {
140 type: "should-collapse",
141 urls: urls,
142 mediatype: typeMap[tag],
143 baseURL: document.location.href
144 },
145
146 function(response)
147 {
148 if (response && element.parentNode)
149 {
150 var property = "display";
151 var value = "none";
152
153 // <frame> cannot be removed, doing that will mess up the frameset
154 if (tag == "frame")
155 {
156 property = "visibility";
157 value = "hidden";
158 }
159
160 // <input type="image"> elements try to load their image again
161 // when the "display" CSS property is set. So we have to check
162 // that it isn't already collapsed to avoid an infinite recursion.
163 if (element.style.getPropertyValue(property) != value ||
164 element.style.getPropertyPriority(property) != "important")
165 element.style.setProperty(property, value, "important");
166 }
167 }
168 );
169 }
170
171 window.collapsing = true; 131 window.collapsing = true;
132
133 var mediatype = typeMap[element.localName];
134 if (!mediatype)
135 return;
136
137 var urls = getURLsFromElement(element);
138 if (urls.length == 0)
139 return;
140
141 ext.backgroundPage.sendMessage(
142 {
143 type: "should-collapse",
144 urls: urls,
145 mediatype: mediatype,
146 baseURL: document.location.href
147 },
148
149 function(collapse)
150 {
151 function collapseElement()
152 {
153 if (element.localName == "frame")
154 element.style.setProperty("visibility", "hidden", "important");
155 else
156 element.style.setProperty("display", "none", "important");
157 }
158
159 if (collapse && !element._collapsed)
160 {
161 collapseElement();
162 element._collapsed = true;
163
164 if (MutationObserver)
165 new MutationObserver(collapseElement).observe(
166 element, {
167 attributes: true,
168 attributeFilter: ["style"]
169 }
170 );
171 }
172 }
173 );
172 } 174 }
173 175
174 function checkSitekey() 176 function checkSitekey()
175 { 177 {
176 var attr = document.documentElement.getAttribute("data-adblockkey"); 178 var attr = document.documentElement.getAttribute("data-adblockkey");
177 if (attr) 179 if (attr)
178 ext.backgroundPage.sendMessage({type: "filter.addKey", token: attr}); 180 ext.backgroundPage.sendMessage({type: "filter.addKey", token: attr});
179 } 181 }
180 182
181 function getContentDocument(element) 183 function getContentDocument(element)
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 }, 326 },
325 327
326 disconnect: function() 328 disconnect: function()
327 { 329 {
328 this.document.removeEventListener("DOMContentLoaded", this.trace); 330 this.document.removeEventListener("DOMContentLoaded", this.trace);
329 this.observer.disconnect(); 331 this.observer.disconnect();
330 clearTimeout(this.timeout); 332 clearTimeout(this.timeout);
331 } 333 }
332 }; 334 };
333 335
334 function reinjectRulesWhenRemoved(document, style) 336 function reinjectStyleSheetWhenRemoved(document, style)
335 { 337 {
336 var MutationObserver = window.MutationObserver || window.WebKitMutationObserve r;
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;
341 { 342 var observer = new MutationObserver(function()
342 var isStyleRemoved = false; 343 {
343 for (var i = 0; i < mutations.length; i++) 344 if (style.parentNode != parentNode)
344 { 345 parentNode.appendChild(style);
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;
350 }
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 + '");',
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++)
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 + ".call(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);
382 } 395 }
383 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).
394 // 407 //
395 // However, creating a shadow root breaks running CSS transitions. So we 408 // However, creating a shadow root breaks running CSS transitions. So we
396 // have to create the shadow root before transistions might start (#452). 409 // have to create the shadow root before transistions might start (#452).
397 // 410 //
398 // Also, using shadow DOM causes issues on some Google websites, 411 // Also, using shadow DOM causes issues on some Google websites,
399 // including Google Docs and Gmail (#1770, #2602). 412 // including Google Docs, Gmail and Blogger (#1770, #2602, #2687).
400 if ("createShadowRoot" in document.documentElement && !/\.google\.com$/.test(d ocument.domain)) 413 if ("createShadowRoot" in document.documentElement &&
414 !/\.(?:google|blogger)\.com$/.test(document.domain))
401 { 415 {
402 shadow = document.documentElement.createShadowRoot(); 416 shadow = document.documentElement.createShadowRoot();
403 shadow.appendChild(document.createElement("shadow")); 417 shadow.appendChild(document.createElement("shadow"));
404 } 418 }
405 419
406 function addElemHideSelectors(selectors) 420 function addElemHideSelectors(selectors)
407 { 421 {
408 if (selectors.length == 0) 422 if (selectors.length == 0)
409 return; 423 return;
410 424
411 if (!style) 425 if (!style)
412 { 426 {
413 // Create <style> element lazily, only if we add styles. Add it to 427 // Create <style> element lazily, only if we add styles. Add it to
414 // the shadow DOM if possible. Otherwise fallback to the <head> or 428 // the shadow DOM if possible. Otherwise fallback to the <head> or
415 // <html> element. If we have injected a style element before that 429 // <html> element. If we have injected a style element before that
416 // has been removed (the sheet property is null), create a new one. 430 // has been removed (the sheet property is null), create a new one.
417 style = document.createElement("style"); 431 style = document.createElement("style");
418 (shadow || document.head || document.documentElement).appendChild(style); 432 (shadow || document.head || document.documentElement).appendChild(style);
419 433
420 // It can happen that the frame already navigated to a different 434 // It can happen that the frame already navigated to a different
421 // document while we were waiting for the background page to respond. 435 // document while we were waiting for the background page to respond.
422 // In that case the sheet property will stay null, after addind the 436 // In that case the sheet property will stay null, after addind the
423 // <style> element to the shadow DOM. 437 // <style> element to the shadow DOM.
424 if (!style.sheet) 438 if (!style.sheet)
425 return; 439 return;
426 440
427 observer = reinjectRulesWhenRemoved(document, style); 441 observer = reinjectStyleSheetWhenRemoved(document, style);
442 protectStyleSheet(document, style);
428 } 443 }
429 444
430 // If using shadow DOM, we have to add the ::content pseudo-element 445 // If using shadow DOM, we have to add the ::content pseudo-element
431 // before each selector, in order to match elements within the 446 // before each selector, in order to match elements within the
432 // insertion point. 447 // insertion point.
433 if (shadow) 448 if (shadow)
434 { 449 {
435 var preparedSelectors = []; 450 var preparedSelectors = [];
436 for (var i = 0; i < selectors.length; i++) 451 for (var i = 0; i < selectors.length; i++)
437 { 452 {
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 }, true); 552 }, true);
538 553
539 return updateStylesheet; 554 return updateStylesheet;
540 } 555 }
541 556
542 if (document instanceof HTMLDocument) 557 if (document instanceof HTMLDocument)
543 { 558 {
544 checkSitekey(); 559 checkSitekey();
545 window.updateStylesheet = init(document); 560 window.updateStylesheet = init(document);
546 } 561 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld