| Index: include.preload.js | 
| diff --git a/include.preload.js b/include.preload.js | 
| index 86e52c32afceb894f6591a84b0eca3b1842383ce..5814884c969f8d495ca3c0bc58a1d0466a832b58 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(); | 
| 
 
Sebastian Noack
2017/02/09 11:07:39
Why to use a a Map object? It seems the logic woul
 
wspee
2017/02/10 10:46:46
If you have information that are are dependent fro
 
Sebastian Noack
2017/02/10 14:52:55
I'd generally agree, that data that have a mutual
 
 | 
| 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() | 
| { | 
| - var matchedSelectors = []; | 
| + let _start = () => { | 
| + this.trace(); | 
| + this.started = true; | 
| + }; | 
| + | 
| + if (document.readyState == "loading") | 
| + document.addEventListener("DOMContentLoaded", _start); | 
| + else | 
| + _start(); | 
| + }, | 
| - // Find all selectors that match any hidden element inside the given nodes. | 
| - for (var i = 0; i < this.selectors.length; i++) | 
| + addFilters: function(filters) | 
| + { | 
| + if (this.started) | 
| + window.setTimeout(() => { | 
| + this.checkNodes([document], filters); | 
| + }, 0); | 
| + | 
| + 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 selector of selectors) | 
| + { | 
| + for (let node of nodes) | 
| { | 
| - // 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") | 
| + let elements = node.querySelectorAll(selector); | 
| + let matched = false; | 
| + | 
| + for (let element of elements) | 
| { | 
| - 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(element).display == "none") | 
| + { | 
| + matchedFilters.push(filter.replace(/^.*?##/, "")); | 
| + matched = true; | 
| 
 
Sebastian Noack
2017/02/09 11:07:39
It seems, the "match" variable would be unnecessar
 
wspee
2017/02/10 10:46:46
Done.
 
 | 
| + 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,28 @@ ElemHide.prototype = { | 
| return shadow; | 
| }, | 
| - addSelectors: function(selectors) | 
| + addSelectors: function(selectors, filters) | 
| { | 
| - if (selectors.length == 0) | 
| + if (!selectors) | 
| 
 
Sebastian Noack
2017/02/09 11:07:39
Why did you change this line? Note that an empty a
 
wspee
2017/02/10 10:46:46
Done.
 
 | 
| return; | 
| + if (this.tracer) | 
| + { | 
| + let tracedFilters = new Map(); | 
| + for (let i = 0; i < selectors.length; i++) | 
| + { | 
| + let filterKey = filters ? filters[i] : selectors[i]; | 
| + let tracedFilter = tracedFilters.get(filterKey); | 
| + if (!tracedFilter) | 
| + { | 
| + tracedFilter = []; | 
| + tracedFilters.set(filterKey, tracedFilter); | 
| + } | 
| + tracedFilter.push(selectors[i]); | 
| + } | 
| + this.tracer.addFilters(tracedFilters); | 
| + } | 
| + | 
| if (!this.style) | 
| { | 
| // Create <style> element lazily, only if we add styles. Add it to | 
| @@ -544,38 +585,33 @@ 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) | 
| + this.addSelectors(selectors.selectors); | 
| + | 
| 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); | 
| }); | 
| } | 
| }; |