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

Side by Side Diff: include.preload.js

Issue 29370970: [adblockpluschrome] Issue 3596 - Added support for CSS property filters to devtools panel (Closed)
Patch Set: Use map instead of object Created Feb. 7, 2017, 11:58 a.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 | 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 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 try 185 try
186 { 186 {
187 return element.contentDocument; 187 return element.contentDocument;
188 } 188 }
189 catch (e) 189 catch (e)
190 { 190 {
191 return null; 191 return null;
192 } 192 }
193 } 193 }
194 194
195 function ElementHidingTracer(selectors) 195 function ElementHidingTracer()
196 { 196 {
197 this.selectors = selectors; 197 this.filters = new Map();
198 198
199 this.changedNodes = []; 199 this.changedNodes = [];
200 this.timeout = null; 200 this.timeout = null;
201 this.started = false;
201 202
202 this.observer = new MutationObserver(this.observe.bind(this)); 203 this.observer = new MutationObserver(this.observe.bind(this));
203 this.trace = this.trace.bind(this); 204 this.trace = this.trace.bind(this);
204
205 if (document.readyState == "loading")
206 document.addEventListener("DOMContentLoaded", this.trace);
207 else
208 this.trace();
209 } 205 }
210 ElementHidingTracer.prototype = { 206 ElementHidingTracer.prototype = {
211 checkNodes: function(nodes) 207 start: function()
212 { 208 {
213 var matchedSelectors = []; 209 let _start = () => {
210 this.trace();
211 this.started = true;
212 };
214 213
215 // Find all selectors that match any hidden element inside the given nodes. 214 if (document.readyState == "loading")
216 for (var i = 0; i < this.selectors.length; i++) 215 document.addEventListener("DOMContentLoaded", _start);
216 else
217 _start();
218 },
219
220 addFilters: function(filters)
221 {
222 if (this.started)
223 window.setTimeout(() => {
224 this.checkNodes([document], filters);
225 }, 0);
226
227 for (let [key, value] of filters)
217 { 228 {
218 var selector = this.selectors[i]; 229 if (!this.filters.has(key))
230 this.filters.set(key, []);
231 Array.prototype.push.apply(this.filters.get(key), value);
232 }
233 },
219 234
220 for (var j = 0; j < nodes.length; j++) 235 checkNodes: function(nodes, filters)
236 {
237 let matchedFilters = [];
238
239 for (let [filter, selectors] of filters)
240 {
241 for (let i = 0; i < selectors.length; i++)
221 { 242 {
222 var elements = nodes[j].querySelectorAll(selector); 243 for (var j = 0; j < nodes.length; j++)
223 var matched = false; 244 {
245 var elements = nodes[j].querySelectorAll(selectors[i]);
246 var matched = false;
224 247
225 for (var k = 0; k < elements.length; k++) 248 for (var k = 0; k < elements.length; k++)
226 {
227 // Only consider selectors that actually have an effect on the
228 // computed styles, and aren't overridden by rules with higher
229 // priority, or haven't been circumvented in a different way.
230 if (getComputedStyle(elements[k]).display == "none")
231 { 249 {
232 matchedSelectors.push(selector); 250 // Only consider selectors that actually have an effect on the
233 matched = true; 251 // computed styles, and aren't overridden by rules with higher
252 // priority, or haven't been circumvented in a different way.
253 if (getComputedStyle(elements[k]).display == "none")
254 {
255 matchedFilters.push(filter.replace(/^.*?##/, ""));
256 matched = true;
257 break;
258 }
259 }
260
261 if (matched)
234 break; 262 break;
235 }
236 } 263 }
237
238 if (matched)
239 break;
240 } 264 }
241 } 265 }
242 266
243 if (matchedSelectors.length > 0) 267 if (matchedFilters.length > 0)
244 ext.backgroundPage.sendMessage({ 268 ext.backgroundPage.sendMessage({
245 type: "devtools.traceElemHide", 269 type: "devtools.traceElemHide",
246 selectors: matchedSelectors 270 selectors: matchedFilters
247 }); 271 });
248 }, 272 },
249 273
250 onTimeout: function() 274 onTimeout: function()
251 { 275 {
252 this.checkNodes(this.changedNodes); 276 this.checkNodes(this.changedNodes, this.filters);
253 this.changedNodes = []; 277 this.changedNodes = [];
254 this.timeout = null; 278 this.timeout = null;
255 }, 279 },
256 280
257 observe: function(mutations) 281 observe: function(mutations)
258 { 282 {
259 // Forget previously changed nodes that are no longer in the DOM. 283 // Forget previously changed nodes that are no longer in the DOM.
260 for (var i = 0; i < this.changedNodes.length; i++) 284 for (var i = 0; i < this.changedNodes.length; i++)
261 { 285 {
262 if (!document.contains(this.changedNodes[i])) 286 if (!document.contains(this.changedNodes[i]))
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 329
306 // Check only nodes whose descendants have changed, and not more often 330 // Check only nodes whose descendants have changed, and not more often
307 // than once a second. Otherwise large pages with a lot of DOM mutations 331 // than once a second. Otherwise large pages with a lot of DOM mutations
308 // (like YouTube) freeze when the devtools panel is active. 332 // (like YouTube) freeze when the devtools panel is active.
309 if (this.timeout == null) 333 if (this.timeout == null)
310 this.timeout = setTimeout(this.onTimeout.bind(this), 1000); 334 this.timeout = setTimeout(this.onTimeout.bind(this), 1000);
311 }, 335 },
312 336
313 trace: function() 337 trace: function()
314 { 338 {
315 this.checkNodes([document]); 339 this.checkNodes([document], this.filters);
316 340
317 this.observer.observe( 341 this.observer.observe(
318 document, 342 document,
319 { 343 {
320 childList: true, 344 childList: true,
321 attributes: true, 345 attributes: true,
322 subtree: true 346 subtree: true
323 } 347 }
324 ); 348 );
325 }, 349 },
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
483 var shadow = shadowRoot(this); 507 var shadow = shadowRoot(this);
484 return shadow == ourShadowRoot ? null : shadow; 508 return shadow == ourShadowRoot ? null : shadow;
485 } 509 }
486 }); 510 });
487 }, null); 511 }, null);
488 } 512 }
489 513
490 return shadow; 514 return shadow;
491 }, 515 },
492 516
493 addSelectors: function(selectors) 517 addSelectors: function(filters)
494 { 518 {
495 if (selectors.length == 0) 519 if (!filters)
496 return; 520 return;
497 521
522 if (this.tracer)
523 this.tracer.addFilters(filters);
524
525 let selectors = [];
526 for (let filterSelectors of filters.values())
527 {
528 for (let i = 0; i < filterSelectors.length; i++)
529 selectors.push(filterSelectors[i]);
530 }
531
498 if (!this.style) 532 if (!this.style)
499 { 533 {
500 // Create <style> element lazily, only if we add styles. Add it to 534 // Create <style> element lazily, only if we add styles. Add it to
501 // the shadow DOM if possible. Otherwise fallback to the <head> or 535 // the shadow DOM if possible. Otherwise fallback to the <head> or
502 // <html> element. If we have injected a style element before that 536 // <html> element. If we have injected a style element before that
503 // has been removed (the sheet property is null), create a new one. 537 // has been removed (the sheet property is null), create a new one.
504 this.style = document.createElement("style"); 538 this.style = document.createElement("style");
505 (this.shadow || document.head 539 (this.shadow || document.head
506 || document.documentElement).appendChild(this.style); 540 || document.documentElement).appendChild(this.style);
507 541
(...skipping 29 matching lines...) Expand all
537 { 571 {
538 var selector = selectors.slice(i, i + this.selectorGroupSize).join(", "); 572 var selector = selectors.slice(i, i + this.selectorGroupSize).join(", ");
539 this.style.sheet.insertRule(selector + "{display: none !important;}", 573 this.style.sheet.insertRule(selector + "{display: none !important;}",
540 this.style.sheet.cssRules.length); 574 this.style.sheet.cssRules.length);
541 } 575 }
542 }, 576 },
543 577
544 apply: function() 578 apply: function()
545 { 579 {
546 var selectors = null; 580 var selectors = null;
547 var elemHideEmulationLoaded = false;
548 581
549 var checkLoaded = function() 582 var checkLoaded = function()
550 { 583 {
551 if (!selectors || !elemHideEmulationLoaded)
552 return;
553
554 if (this.tracer) 584 if (this.tracer)
555 this.tracer.disconnect(); 585 this.tracer.disconnect();
556 this.tracer = null; 586 this.tracer = null;
557 587
588 if (selectors.trace)
589 this.tracer = new ElementHidingTracer();
590
558 if (this.style && this.style.parentElement) 591 if (this.style && this.style.parentElement)
559 this.style.parentElement.removeChild(this.style); 592 this.style.parentElement.removeChild(this.style);
560 this.style = null; 593 this.style = null;
561 594
562 this.addSelectors(selectors.selectors); 595 if (selectors.selectors)
596 {
597 let filters = new Map();
598 for (let i = 0; i < selectors.selectors.length; i++)
599 filters.set(selectors.selectors[i], [selectors.selectors[i]]);
600 this.addSelectors(filters);
601 }
563 this.elemHideEmulation.apply(); 602 this.elemHideEmulation.apply();
564 603
565 if (selectors.trace) 604 if (this.tracer)
566 this.tracer = new ElementHidingTracer(selectors.selectors); 605 this.tracer.start();
567 }.bind(this); 606 }.bind(this);
568 607
569 ext.backgroundPage.sendMessage({type: "get-selectors"}, function(response) 608 ext.backgroundPage.sendMessage({type: "get-selectors"}, response =>
570 { 609 {
571 selectors = response; 610 selectors = response;
572 checkLoaded(); 611 this.elemHideEmulation.load(checkLoaded);
573 });
574
575 this.elemHideEmulation.load(function()
576 {
577 elemHideEmulationLoaded = true;
578 checkLoaded();
579 }); 612 });
580 } 613 }
581 }; 614 };
582 615
583 if (document instanceof HTMLDocument) 616 if (document instanceof HTMLDocument)
584 { 617 {
585 checkSitekey(); 618 checkSitekey();
586 wrapWebSocket(); 619 wrapWebSocket();
587 620
588 var elemhide = new ElemHide(); 621 var elemhide = new ElemHide();
589 elemhide.apply(); 622 elemhide.apply();
590 623
591 document.addEventListener("error", function(event) 624 document.addEventListener("error", function(event)
592 { 625 {
593 checkCollapse(event.target); 626 checkCollapse(event.target);
594 }, true); 627 }, true);
595 628
596 document.addEventListener("load", function(event) 629 document.addEventListener("load", function(event)
597 { 630 {
598 var element = event.target; 631 var element = event.target;
599 if (/^i?frame$/.test(element.localName)) 632 if (/^i?frame$/.test(element.localName))
600 checkCollapse(element); 633 checkCollapse(element);
601 }, true); 634 }, true);
602 } 635 }
OLDNEW
« no previous file with comments | « no previous file | lib/devtools.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld