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 issues in content script breaking element hide tracing Created Jan. 30, 2016, 6:19 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
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++)
kzar 2016/01/31 13:33:51 Nit: Could you use `for ... of ...` for these loop
Sebastian Noack 2016/02/02 10:39:52 This is a content script. So there is no jsHydra m
kzar 2016/02/02 15:42:09 Acknowledged.
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({type: "trace-elemhide", selectors: matched Selectors});
kzar 2016/01/31 13:33:51 Nit: Mind wrapping this long line?
Sebastian Noack 2016/02/02 10:39:52 Done.
244 },
245
246 onTimeout: function()
247 {
248 this.checkNodes(this.changedNodes);
249 this.changedNodes = [];
250 this.timeout = null;
251 },
252
253 observe: function(mutations)
254 {
255 // Forget previously changed nodes that are no longer in the DOM.
256 for (var i = 0; i < this.changedNodes.length; i++)
257 {
258 if (!this.document.contains(this.changedNodes[i]))
259 this.changedNodes.splice(i--, 1);
260 }
261
262 for (var j = 0; j < mutations.length; j++)
263 {
264 var mutation = mutations[j];
265 var node = mutation.target;
266
267 // Ignore mutations of nodes that aren't in the DOM anymore.
268 if (!this.document.contains(node))
269 continue;
270
271 // Since querySelectorAll() doesn't consider the root itself
272 // and since CSS selectors can also match siblings, we have
273 // to consider the parent node for attribute mutations.
274 if (mutation.type == "attributes")
275 node = node.parentNode;
276
277 var addNode = true;
278 for (var k = 0; k < this.changedNodes.length; k++)
279 {
280 var previouslyChangedNode = this.changedNodes[k];
281
282 // If we are already going to check an ancestor of this node,
283 // we can ignore this node, since it will be considered anyway
284 // when checking one of its ancestors.
285 if (previouslyChangedNode.contains(node))
286 {
287 addNode = false;
288 break;
289 }
290
291 // If this node is an ancestor of a node that previously changed,
292 // we can ignore that node, since it will be considered anyway
293 // when checking one of its ancestors.
294 if (node.contains(previouslyChangedNode))
295 this.changedNodes.splice(k--, 1);
296 }
297
298 if (addNode)
299 this.changedNodes.push(node);
300 }
301
302 // Check only nodes whose descendants have changed, and not more often
303 // than once a second. Otherwise large pages with a lot of DOM mutations
304 // (like YouTube) freeze when the devtools panel is active.
305 if (this.timeout == null)
306 this.timeout = setTimeout(this.onTimeout.bind(this), 1000);
307 },
308
309 trace: function()
310 {
311 this.checkNodes([this.document]);
312
313 this.observer.observe(
314 this.document,
315 {
316 childList: true,
317 attributes: true,
318 subtree: true
319 }
320 );
321 },
322
323 disconnect: function()
324 {
325 this.document.removeEventListener("DOMContentLoaded", this.trace);
326 this.observer.disconnect();
327 clearTimeout(this.timeout);
328 }
329 };
330
193 function reinjectRulesWhenRemoved(document, style) 331 function reinjectRulesWhenRemoved(document, style)
194 { 332 {
195 var MutationObserver = window.MutationObserver || window.WebKitMutationObserve r; 333 var MutationObserver = window.MutationObserver || window.WebKitMutationObserve r;
196 if (!MutationObserver) 334 if (!MutationObserver)
197 return; 335 return;
198 336
199 var observer = new MutationObserver(function(mutations) 337 var observer = new MutationObserver(function(mutations)
200 { 338 {
201 var isStyleRemoved = false; 339 var isStyleRemoved = false;
202 for (var i = 0; i < mutations.length; i++) 340 for (var i = 0; i < mutations.length; i++)
(...skipping 10 matching lines...) Expand all
213 observer.disconnect(); 351 observer.disconnect();
214 352
215 var n = document.styleSheets.length; 353 var n = document.styleSheets.length;
216 if (n == 0) 354 if (n == 0)
217 return; 355 return;
218 356
219 var stylesheet = document.styleSheets[n - 1]; 357 var stylesheet = document.styleSheets[n - 1];
220 ext.backgroundPage.sendMessage( 358 ext.backgroundPage.sendMessage(
221 {type: "get-selectors"}, 359 {type: "get-selectors"},
222 360
223 function(selectors) 361 function(response)
224 { 362 {
363 var selectors = response.selectors;
225 while (selectors.length > 0) 364 while (selectors.length > 0)
226 { 365 {
227 var selector = selectors.splice(0, SELECTOR_GROUP_SIZE).join(", "); 366 var selector = selectors.splice(0, SELECTOR_GROUP_SIZE).join(", ");
228 367
229 // Using non-standard addRule() here. This is the only way 368 // Using non-standard addRule() here. This is the only way
230 // to add rules at the end of a cross-origin stylesheet 369 // to add rules at the end of a cross-origin stylesheet
231 // because we don't know how many rules are already in there 370 // because we don't know how many rules are already in there
232 stylesheet.addRule(selector, "display: none !important;"); 371 stylesheet.addRule(selector, "display: none !important;");
233 } 372 }
234 } 373 }
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 } 417 }
279 418
280 return result; 419 return result;
281 } 420 }
282 421
283 function init(document) 422 function init(document)
284 { 423 {
285 var shadow = null; 424 var shadow = null;
286 var style = null; 425 var style = null;
287 var observer = null; 426 var observer = null;
427 var tracer = null;
288 var propertyFilters = new CSSPropertyFilters(window, addElemHideSelectors); 428 var propertyFilters = new CSSPropertyFilters(window, addElemHideSelectors);
289 429
290 // Use Shadow DOM if available to don't mess with web pages that rely on 430 // Use Shadow DOM if available to don't mess with web pages that rely on
291 // the order of their own <style> tags (#309). 431 // the order of their own <style> tags (#309).
292 // 432 //
293 // However, creating a shadow root breaks running CSS transitions. So we 433 // However, creating a shadow root breaks running CSS transitions. So we
294 // have to create the shadow root before transistions might start (#452). 434 // have to create the shadow root before transistions might start (#452).
295 // 435 //
296 // Also, using shadow DOM causes issues on some Google websites, 436 // Also, using shadow DOM causes issues on some Google websites,
297 // including Google Docs and Gmail (#1770, #2602). 437 // including Google Docs and Gmail (#1770, #2602).
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 487
348 var checkLoaded = function() 488 var checkLoaded = function()
349 { 489 {
350 if (!selectors || !CSSPropertyFiltersLoaded) 490 if (!selectors || !CSSPropertyFiltersLoaded)
351 return; 491 return;
352 492
353 if (observer) 493 if (observer)
354 observer.disconnect(); 494 observer.disconnect();
355 observer = null; 495 observer = null;
356 496
497 if (tracer)
498 tracer.disconnect();
499 tracer = null;
500
357 if (style && style.parentElement) 501 if (style && style.parentElement)
358 style.parentElement.removeChild(style); 502 style.parentElement.removeChild(style);
359 style = null; 503 style = null;
360 504
361 addElemHideSelectors(selectors); 505 addElemHideSelectors(selectors.selectors);
362 propertyFilters.apply(); 506 propertyFilters.apply();
507
508 if (selectors.trace)
509 tracer = new ElementHidingTracer(document, selectors.selectors);
363 }; 510 };
364 511
365 ext.backgroundPage.sendMessage({type: "get-selectors"}, function(response) 512 ext.backgroundPage.sendMessage({type: "get-selectors"}, function(response)
366 { 513 {
367 selectors = response; 514 selectors = response;
368 checkLoaded(); 515 checkLoaded();
369 }); 516 });
370 517
371 propertyFilters.load(function() 518 propertyFilters.load(function()
372 { 519 {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 }, true); 563 }, true);
417 564
418 return updateStylesheet; 565 return updateStylesheet;
419 } 566 }
420 567
421 if (document instanceof HTMLDocument) 568 if (document instanceof HTMLDocument)
422 { 569 {
423 checkSitekey(); 570 checkSitekey();
424 window.updateStylesheet = init(document); 571 window.updateStylesheet = init(document);
425 } 572 }
OLDNEW

Powered by Google App Engine
This is Rietveld