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

Unified 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.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « dependencies ('k') | lib/devtools.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: include.preload.js
===================================================================
--- a/include.preload.js
+++ b/include.preload.js
@@ -190,6 +190,147 @@
}
}
+function ElementHidingTracer(document, selectors)
+{
+ this.document = document;
+ this.selectors = selectors;
+
+ this.changedNodes = [];
+ this.timeout = null;
+
+ 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)
+ {
+ var matchedSelectors = [];
+
+ // Find all selectors that match any hidden element inside the given nodes.
+ for (var i = 0; i < this.selectors.length; i++)
+ {
+ var selector = this.selectors[i];
+
+ for (var j = 0; j < nodes.length; j++)
+ {
+ var elements = nodes[j].querySelectorAll(selector);
+ var matched = false;
+
+ for (var k = 0; k < elements.length; k++)
+ {
+ // 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")
+ {
+ matchedSelectors.push(selector);
+ matched = true;
+ break;
+ }
+ }
+
+ if (matched)
+ break;
+ }
+ }
+
+ if (matchedSelectors.length > 0)
+ ext.backgroundPage.sendMessage({
+ type: "trace-elemhide",
+ selectors: matchedSelectors
+ });
+ },
+
+ onTimeout: function()
+ {
+ this.checkNodes(this.changedNodes);
+ this.changedNodes = [];
+ this.timeout = null;
+ },
+
+ observe: function(mutations)
+ {
+ // Forget previously changed nodes that are no longer in the DOM.
+ for (var i = 0; i < this.changedNodes.length; i++)
+ {
+ if (!this.document.contains(this.changedNodes[i]))
+ this.changedNodes.splice(i--, 1);
+ }
+
+ for (var j = 0; j < mutations.length; j++)
+ {
+ var mutation = mutations[j];
+ var node = mutation.target;
+
+ // Ignore mutations of nodes that aren't in the DOM anymore.
+ if (!this.document.contains(node))
+ continue;
+
+ // Since querySelectorAll() doesn't consider the root itself
+ // and since CSS selectors can also match siblings, we have
+ // to consider the parent node for attribute mutations.
+ if (mutation.type == "attributes")
+ node = node.parentNode;
+
+ var addNode = true;
+ for (var k = 0; k < this.changedNodes.length; k++)
+ {
+ var previouslyChangedNode = this.changedNodes[k];
+
+ // If we are already going to check an ancestor of this node,
+ // we can ignore this node, since it will be considered anyway
+ // when checking one of its ancestors.
+ if (previouslyChangedNode.contains(node))
+ {
+ addNode = false;
+ break;
+ }
+
+ // If this node is an ancestor of a node that previously changed,
+ // we can ignore that node, since it will be considered anyway
+ // when checking one of its ancestors.
+ if (node.contains(previouslyChangedNode))
+ this.changedNodes.splice(k--, 1);
+ }
+
+ if (addNode)
+ this.changedNodes.push(node);
+ }
+
+ // Check only nodes whose descendants have changed, and not more often
+ // than once a second. Otherwise large pages with a lot of DOM mutations
+ // (like YouTube) freeze when the devtools panel is active.
+ if (this.timeout == null)
+ this.timeout = setTimeout(this.onTimeout.bind(this), 1000);
+ },
+
+ trace: function()
+ {
+ this.checkNodes([this.document]);
+
+ this.observer.observe(
+ this.document,
+ {
+ childList: true,
+ attributes: true,
+ subtree: true
+ }
+ );
+ },
+
+ disconnect: function()
+ {
+ this.document.removeEventListener("DOMContentLoaded", this.trace);
+ this.observer.disconnect();
+ clearTimeout(this.timeout);
+ }
+};
+
function reinjectRulesWhenRemoved(document, style)
{
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
@@ -220,8 +361,9 @@
ext.backgroundPage.sendMessage(
{type: "get-selectors"},
- function(selectors)
+ function(response)
{
+ var selectors = response.selectors;
while (selectors.length > 0)
{
var selector = selectors.splice(0, SELECTOR_GROUP_SIZE).join(", ");
@@ -285,6 +427,7 @@
var shadow = null;
var style = null;
var observer = null;
+ var tracer = null;
var propertyFilters = new CSSPropertyFilters(window, addElemHideSelectors);
// Use Shadow DOM if available to don't mess with web pages that rely on
@@ -354,12 +497,19 @@
observer.disconnect();
observer = null;
+ if (tracer)
+ tracer.disconnect();
+ tracer = null;
+
if (style && style.parentElement)
style.parentElement.removeChild(style);
style = null;
- addElemHideSelectors(selectors);
+ addElemHideSelectors(selectors.selectors);
propertyFilters.apply();
+
+ if (selectors.trace)
+ tracer = new ElementHidingTracer(document, selectors.selectors);
};
ext.backgroundPage.sendMessage({type: "get-selectors"}, function(response)
« no previous file with comments | « dependencies ('k') | lib/devtools.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld