| Index: include.preload.js |
| diff --git a/include.preload.js b/include.preload.js |
| index 86e52c32afceb894f6591a84b0eca3b1842383ce..eb5610ca33cf8402ebea7c23f6d65f68c95c1b6c 100644 |
| --- a/include.preload.js |
| +++ b/include.preload.js |
| @@ -192,64 +192,88 @@ function getContentDocument(element) |
| } |
| } |
| -function ElementHidingTracer(selectors) |
| +function ElementHidingTracer() |
| { |
| - this.selectors = selectors; |
| + this.filters = new Map(); |
| this.changedNodes = []; |
| this.timeout = null; |
| + this.started = false; |
| this.observer = new MutationObserver(this.observe.bind(this)); |
| this.trace = this.trace.bind(this); |
| - |
| - if (document.readyState == "loading") |
| - document.addEventListener("DOMContentLoaded", this.trace); |
| - else |
| - this.trace(); |
| } |
| ElementHidingTracer.prototype = { |
| - checkNodes: function(nodes) |
| + start: function() |
| + { |
| + let _start = () => { |
| + this.trace(); |
| + this.started = true; |
| + }; |
| + |
| + if (document.readyState == "loading") |
| + document.addEventListener("DOMContentLoaded", _start); |
| + else |
| + _start(); |
| + }, |
| + |
| + addFilters: function(filters) |
| { |
| - var matchedSelectors = []; |
| + if (this.started) |
| + window.setTimeout(() => { |
| + this.checkNodes([document], filters); |
| + }, 0); |
| - // Find all selectors that match any hidden element inside the given nodes. |
| - for (var i = 0; i < this.selectors.length; i++) |
| + for (let [key, value] of filters) |
| { |
| - var selector = this.selectors[i]; |
| + if (!this.filters.has(key)) |
| + this.filters.set(key, []); |
| + Array.prototype.push.apply(this.filters.get(key), value); |
| + } |
| + }, |
| - for (var j = 0; j < nodes.length; j++) |
| - { |
| - var elements = nodes[j].querySelectorAll(selector); |
| - var matched = false; |
| + checkNodes: function(nodes, filters) |
| + { |
| + let matchedFilters = []; |
| - for (var k = 0; k < elements.length; k++) |
| + for (let [filter, selectors] of filters) |
| + { |
| + for (let i = 0; i < selectors.length; i++) |
| + { |
| + for (var j = 0; j < nodes.length; j++) |
| { |
| - // Only consider selectors that actually have an effect on the |
| - // computed styles, and aren't overridden by rules with higher |
| - // priority, or haven't been circumvented in a different way. |
| - if (getComputedStyle(elements[k]).display == "none") |
| + var elements = nodes[j].querySelectorAll(selectors[i]); |
| + var matched = false; |
| + |
| + for (var k = 0; k < elements.length; k++) |
| { |
| - matchedSelectors.push(selector); |
| - matched = true; |
| - break; |
| + // Only consider selectors that actually have an effect on the |
| + // computed styles, and aren't overridden by rules with higher |
| + // priority, or haven't been circumvented in a different way. |
| + if (getComputedStyle(elements[k]).display == "none") |
| + { |
| + matchedFilters.push(filter.replace(/^.*?##/, "")); |
| + matched = true; |
| + break; |
| + } |
| } |
| - } |
| - if (matched) |
| - break; |
| + if (matched) |
| + break; |
| + } |
| } |
| } |
| - if (matchedSelectors.length > 0) |
| + if (matchedFilters.length > 0) |
| ext.backgroundPage.sendMessage({ |
| type: "devtools.traceElemHide", |
| - selectors: matchedSelectors |
| + selectors: matchedFilters |
| }); |
| }, |
| onTimeout: function() |
| { |
| - this.checkNodes(this.changedNodes); |
| + this.checkNodes(this.changedNodes, this.filters); |
| this.changedNodes = []; |
| this.timeout = null; |
| }, |
| @@ -312,7 +336,7 @@ ElementHidingTracer.prototype = { |
| trace: function() |
| { |
| - this.checkNodes([document]); |
| + this.checkNodes([document], this.filters); |
| this.observer.observe( |
| document, |
| @@ -490,11 +514,21 @@ ElemHide.prototype = { |
| return shadow; |
| }, |
| - addSelectors: function(selectors) |
| + addSelectors: function(filters) |
| { |
| - if (selectors.length == 0) |
| + if (!filters) |
| return; |
| + if (this.tracer) |
| + this.tracer.addFilters(filters); |
| + |
| + let selectors = []; |
| + for (let filterSelectors of filters.values()) |
| + { |
| + for (let i = 0; i < filterSelectors.length; i++) |
| + selectors.push(filterSelectors[i]); |
| + } |
| + |
| if (!this.style) |
| { |
| // Create <style> element lazily, only if we add styles. Add it to |
| @@ -544,38 +578,37 @@ ElemHide.prototype = { |
| apply: function() |
| { |
| var selectors = null; |
| - var elemHideEmulationLoaded = false; |
| var checkLoaded = function() |
| { |
| - if (!selectors || !elemHideEmulationLoaded) |
| - return; |
| - |
| if (this.tracer) |
| this.tracer.disconnect(); |
| this.tracer = null; |
| + if (selectors.trace) |
| + this.tracer = new ElementHidingTracer(); |
| + |
| if (this.style && this.style.parentElement) |
| this.style.parentElement.removeChild(this.style); |
| this.style = null; |
| - this.addSelectors(selectors.selectors); |
| + if (selectors.selectors) |
| + { |
| + let filters = new Map(); |
| + for (let i = 0; i < selectors.selectors.length; i++) |
| + filters.set(selectors.selectors[i], [selectors.selectors[i]]); |
| + this.addSelectors(filters); |
| + } |
| this.elemHideEmulation.apply(); |
| - if (selectors.trace) |
| - this.tracer = new ElementHidingTracer(selectors.selectors); |
| + if (this.tracer) |
| + this.tracer.start(); |
| }.bind(this); |
| - ext.backgroundPage.sendMessage({type: "get-selectors"}, function(response) |
| + ext.backgroundPage.sendMessage({type: "get-selectors"}, response => |
| { |
| selectors = response; |
| - checkLoaded(); |
| - }); |
| - |
| - this.elemHideEmulation.load(function() |
| - { |
| - elemHideEmulationLoaded = true; |
| - checkLoaded(); |
| + this.elemHideEmulation.load(checkLoaded); |
| }); |
| } |
| }; |