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: Rebased and fixed various issues Created March 12, 2015, 3:32 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 | « chrome/ext/devtools.js ('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
@@ -104,6 +104,139 @@
return !("isFrameWithoutContentScript" in contentDocument.defaultView);
}
+function traceHiddenElements(document, selectors)
+{
+ var changedNodes = [];
+ var timeout = null;
+
+ var checkNodes = function(nodes)
+ {
+ var matchedSelectors = [];
+
+ // Find all selectors that match any hidden element inside the given nodes.
+ for (var i = 0; i < selectors.length; i++)
+ {
+ var selector = 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});
+ };
+
+ var observer = new MutationObserver(function(mutations)
+ {
+ // Forget previously changed nodes that are no longer in the DOM.
+ for (var i = 0; i < changedNodes.length; i++)
+ {
+ if (!document.contains(changedNodes[i]))
+ 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 (!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 < changedNodes.length; k++)
+ {
+ var previouslyChangedNode = 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))
+ changedNodes.splice(k--, 1);
+ }
+
+ if (addNode)
+ 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 (!timeout)
+ {
+ timeout = setTimeout(function()
+ {
+ checkNodes(changedNodes);
+ changedNodes = [];
+ timeout = null;
+ }, 1000);
+ }
+ });
+
+ var startTracing = function()
+ {
+ checkNodes([document]);
+
+ observer.observe(
+ document,
+ {
+ childList: true,
+ attributes: true,
+ subtree: true
+ }
+ );
+ };
+
+ var stopTracing = function()
+ {
+ document.removeEventListener("DOMContentLoaded", startTracing);
+ observer.disconnect();
+ clearTimeout(timeout);
+ };
+
+ if (document.readyState == "loading")
+ document.addEventListener("DOMContentLoaded", startTracing);
+ else
+ startTracing();
+
+ return stopTracing;
+}
+
function reinjectRulesWhenRemoved(document, style)
{
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
@@ -134,8 +267,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(", ");
@@ -190,7 +324,9 @@
{
var shadow = null;
var style = null;
- var observer = null;
+
+ var reinjectObserver = null;
+ var stopTracing = null;
// Use Shadow DOM if available to don't mess with web pages that rely on
// the order of their own <style> tags (#309).
@@ -208,12 +344,18 @@
var updateStylesheet = function(reinject)
{
- ext.backgroundPage.sendMessage({type: "get-selectors"}, function(selectors)
+ ext.backgroundPage.sendMessage({type: "get-selectors"}, function(response)
{
- if (observer)
+ if (reinjectObserver)
{
- observer.disconnect();
- observer = null;
+ reinjectObserver.disconnect();
+ reinjectObserver = null;
+ }
+
+ if (stopTracing)
+ {
+ stopTracing();
+ stopTracing = null;
}
if (style && style.parentElement)
@@ -222,6 +364,7 @@
style = null;
}
+ var selectors = response.selectors;
if (selectors.length > 0)
{
// Create <style> element lazily, only if we add styles. Add it to
@@ -250,9 +393,12 @@
var selector = selectors.splice(0, SELECTOR_GROUP_SIZE).join(", ");
style.sheet.insertRule(selector + " { display: none !important; }", i);
}
+
+ reinjectObserver = reinjectRulesWhenRemoved(document, style);
+
+ if (response.trace)
+ stopTracing = traceHiddenElements(document, response.selectors);
}
-
- observer = reinjectRulesWhenRemoved(document, style);
}
});
};
« no previous file with comments | « chrome/ext/devtools.js ('k') | lib/devtools.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld