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

Side by Side Diff: include.preload.js

Issue 6393086494113792: Issue 154 - Added devtools panel showing blocked and blockable items (Closed)
Patch Set: Fixed typo in JSDoc syntax Created Feb. 2, 2016, 4:31 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 | « dependencies ('k') | lib/devtools.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 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 try 183 try
184 { 184 {
185 return element.contentDocument; 185 return element.contentDocument;
186 } 186 }
187 catch (e) 187 catch (e)
188 { 188 {
189 return null; 189 return null;
190 } 190 }
191 } 191 }
192 192
193 function ElementHidingTracer(document, selectors)
194 {
195 this.document = document;
196 this.selectors = selectors;
197
198 this.changedNodes = [];
199 this.timeout = null;
200
201 this.observer = new MutationObserver(this.observe.bind(this));
202 this.trace = this.trace.bind(this);
203
204 if (document.readyState == "loading")
205 document.addEventListener("DOMContentLoaded", this.trace);
206 else
207 this.trace();
208 }
209 ElementHidingTracer.prototype = {
210 checkNodes: function(nodes)
211 {
212 var matchedSelectors = [];
213
214 // Find all selectors that match any hidden element inside the given nodes.
215 for (var i = 0; i < this.selectors.length; i++)
216 {
217 var selector = this.selectors[i];
218
219 for (var j = 0; j < nodes.length; j++)
220 {
221 var elements = nodes[j].querySelectorAll(selector);
222 var matched = false;
223
224 for (var k = 0; k < elements.length; k++)
225 {
226 // Only consider selectors that actually have an effect on the
227 // computed styles, and aren't overridden by rules with higher
228 // priority, or haven't been circumvented in a different way.
229 if (getComputedStyle(elements[k]).display == "none")
230 {
231 matchedSelectors.push(selector);
232 matched = true;
233 break;
234 }
235 }
236
237 if (matched)
238 break;
239 }
240 }
241
242 if (matchedSelectors.length > 0)
243 ext.backgroundPage.sendMessage({
244 type: "trace-elemhide",
245 selectors: matchedSelectors
246 });
247 },
248
249 onTimeout: function()
250 {
251 this.checkNodes(this.changedNodes);
252 this.changedNodes = [];
253 this.timeout = null;
254 },
255
256 observe: function(mutations)
257 {
258 // Forget previously changed nodes that are no longer in the DOM.
259 for (var i = 0; i < this.changedNodes.length; i++)
260 {
261 if (!this.document.contains(this.changedNodes[i]))
262 this.changedNodes.splice(i--, 1);
263 }
264
265 for (var j = 0; j < mutations.length; j++)
266 {
267 var mutation = mutations[j];
268 var node = mutation.target;
269
270 // Ignore mutations of nodes that aren't in the DOM anymore.
271 if (!this.document.contains(node))
272 continue;
273
274 // Since querySelectorAll() doesn't consider the root itself
275 // and since CSS selectors can also match siblings, we have
276 // to consider the parent node for attribute mutations.
277 if (mutation.type == "attributes")
278 node = node.parentNode;
279
280 var addNode = true;
281 for (var k = 0; k < this.changedNodes.length; k++)
282 {
283 var previouslyChangedNode = this.changedNodes[k];
284
285 // If we are already going to check an ancestor of this node,
286 // we can ignore this node, since it will be considered anyway
287 // when checking one of its ancestors.
288 if (previouslyChangedNode.contains(node))
289 {
290 addNode = false;
291 break;
292 }
293
294 // If this node is an ancestor of a node that previously changed,
295 // we can ignore that node, since it will be considered anyway
296 // when checking one of its ancestors.
297 if (node.contains(previouslyChangedNode))
298 this.changedNodes.splice(k--, 1);
299 }
300
301 if (addNode)
302 this.changedNodes.push(node);
303 }
304
305 // Check only nodes whose descendants have changed, and not more often
306 // than once a second. Otherwise large pages with a lot of DOM mutations
307 // (like YouTube) freeze when the devtools panel is active.
308 if (this.timeout == null)
309 this.timeout = setTimeout(this.onTimeout.bind(this), 1000);
310 },
311
312 trace: function()
313 {
314 this.checkNodes([this.document]);
315
316 this.observer.observe(
317 this.document,
318 {
319 childList: true,
320 attributes: true,
321 subtree: true
322 }
323 );
324 },
325
326 disconnect: function()
327 {
328 this.document.removeEventListener("DOMContentLoaded", this.trace);
329 this.observer.disconnect();
330 clearTimeout(this.timeout);
331 }
332 };
333
193 function reinjectRulesWhenRemoved(document, style) 334 function reinjectRulesWhenRemoved(document, style)
194 { 335 {
195 var MutationObserver = window.MutationObserver || window.WebKitMutationObserve r; 336 var MutationObserver = window.MutationObserver || window.WebKitMutationObserve r;
196 if (!MutationObserver) 337 if (!MutationObserver)
197 return; 338 return;
198 339
199 var observer = new MutationObserver(function(mutations) 340 var observer = new MutationObserver(function(mutations)
200 { 341 {
201 var isStyleRemoved = false; 342 var isStyleRemoved = false;
202 for (var i = 0; i < mutations.length; i++) 343 for (var i = 0; i < mutations.length; i++)
(...skipping 10 matching lines...) Expand all
213 observer.disconnect(); 354 observer.disconnect();
214 355
215 var n = document.styleSheets.length; 356 var n = document.styleSheets.length;
216 if (n == 0) 357 if (n == 0)
217 return; 358 return;
218 359
219 var stylesheet = document.styleSheets[n - 1]; 360 var stylesheet = document.styleSheets[n - 1];
220 ext.backgroundPage.sendMessage( 361 ext.backgroundPage.sendMessage(
221 {type: "get-selectors"}, 362 {type: "get-selectors"},
222 363
223 function(selectors) 364 function(response)
224 { 365 {
366 var selectors = response.selectors;
225 while (selectors.length > 0) 367 while (selectors.length > 0)
226 { 368 {
227 var selector = selectors.splice(0, SELECTOR_GROUP_SIZE).join(", "); 369 var selector = selectors.splice(0, SELECTOR_GROUP_SIZE).join(", ");
228 370
229 // Using non-standard addRule() here. This is the only way 371 // Using non-standard addRule() here. This is the only way
230 // to add rules at the end of a cross-origin stylesheet 372 // to add rules at the end of a cross-origin stylesheet
231 // because we don't know how many rules are already in there 373 // because we don't know how many rules are already in there
232 stylesheet.addRule(selector, "display: none !important;"); 374 stylesheet.addRule(selector, "display: none !important;");
233 } 375 }
234 } 376 }
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 } 420 }
279 421
280 return result; 422 return result;
281 } 423 }
282 424
283 function init(document) 425 function init(document)
284 { 426 {
285 var shadow = null; 427 var shadow = null;
286 var style = null; 428 var style = null;
287 var observer = null; 429 var observer = null;
430 var tracer = null;
288 var propertyFilters = new CSSPropertyFilters(window, addElemHideSelectors); 431 var propertyFilters = new CSSPropertyFilters(window, addElemHideSelectors);
289 432
290 // Use Shadow DOM if available to don't mess with web pages that rely on 433 // Use Shadow DOM if available to don't mess with web pages that rely on
291 // the order of their own <style> tags (#309). 434 // the order of their own <style> tags (#309).
292 // 435 //
293 // However, creating a shadow root breaks running CSS transitions. So we 436 // However, creating a shadow root breaks running CSS transitions. So we
294 // have to create the shadow root before transistions might start (#452). 437 // have to create the shadow root before transistions might start (#452).
295 // 438 //
296 // Also, using shadow DOM causes issues on some Google websites, 439 // Also, using shadow DOM causes issues on some Google websites,
297 // including Google Docs and Gmail (#1770, #2602). 440 // including Google Docs and Gmail (#1770, #2602).
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 490
348 var checkLoaded = function() 491 var checkLoaded = function()
349 { 492 {
350 if (!selectors || !CSSPropertyFiltersLoaded) 493 if (!selectors || !CSSPropertyFiltersLoaded)
351 return; 494 return;
352 495
353 if (observer) 496 if (observer)
354 observer.disconnect(); 497 observer.disconnect();
355 observer = null; 498 observer = null;
356 499
500 if (tracer)
501 tracer.disconnect();
502 tracer = null;
503
357 if (style && style.parentElement) 504 if (style && style.parentElement)
358 style.parentElement.removeChild(style); 505 style.parentElement.removeChild(style);
359 style = null; 506 style = null;
360 507
361 addElemHideSelectors(selectors); 508 addElemHideSelectors(selectors.selectors);
362 propertyFilters.apply(); 509 propertyFilters.apply();
510
511 if (selectors.trace)
512 tracer = new ElementHidingTracer(document, selectors.selectors);
363 }; 513 };
364 514
365 ext.backgroundPage.sendMessage({type: "get-selectors"}, function(response) 515 ext.backgroundPage.sendMessage({type: "get-selectors"}, function(response)
366 { 516 {
367 selectors = response; 517 selectors = response;
368 checkLoaded(); 518 checkLoaded();
369 }); 519 });
370 520
371 propertyFilters.load(function() 521 propertyFilters.load(function()
372 { 522 {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 }, true); 566 }, true);
417 567
418 return updateStylesheet; 568 return updateStylesheet;
419 } 569 }
420 570
421 if (document instanceof HTMLDocument) 571 if (document instanceof HTMLDocument)
422 { 572 {
423 checkSitekey(); 573 checkSitekey();
424 window.updateStylesheet = init(document); 574 window.updateStylesheet = init(document);
425 } 575 }
OLDNEW
« no previous file with comments | « dependencies ('k') | lib/devtools.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld