Fixes a regression where TreeOutline.findTreeElement would
[WebKit-https.git] / WebCore / page / inspector / treeoutline.js
index 1248055..5df0f7d 100644 (file)
@@ -243,6 +243,8 @@ TreeOutline.prototype.findTreeElement = function(representedObject, isAncestor,
         return null;
 
     if ("__treeElementIdentifier" in representedObject) {
+        // If this representedObject has a tree element identifier, and it is a known TreeElement
+        // in our tree we can just return that tree element.
         var elements = this._knownTreeElements[representedObject.__treeElementIdentifier];
         if (elements) {
             for (var i = 0; i < elements.length; ++i)
@@ -254,6 +256,8 @@ TreeOutline.prototype.findTreeElement = function(representedObject, isAncestor,
     if (!isAncestor || !(isAncestor instanceof Function) || !getParent || !(getParent instanceof Function))
         return null;
 
+    // The representedObject isn't know, so we start at the top of the tree and work down to find the first
+    // tree element that represents representedObject or one of its ancestors.
     var item;
     var found = false;
     for (var i = 0; i < this.children.length; ++i) {
@@ -267,6 +271,8 @@ TreeOutline.prototype.findTreeElement = function(representedObject, isAncestor,
     if (!found)
         return null;
 
+    // Make sure the item that we found is connected to the root of the tree.
+    // Build up a list of representedObject's ancestors that aren't already in our tree.
     var ancestors = [];
     var currentObject = representedObject;
     while (currentObject) {
@@ -276,13 +282,22 @@ TreeOutline.prototype.findTreeElement = function(representedObject, isAncestor,
         currentObject = getParent(currentObject);
     }
 
+    // For each of those ancestors we populate them to fill in the tree.
     for (var i = 0; i < ancestors.length; ++i) {
+        // Make sure we don't call findTreeElement with the same representedObject
+        // again, to prevent infinite recursion.
+        if (ancestors[i] === representedObject)
+            continue;
+        // FIXME: we could do something faster than findTreeElement since we will know the next
+        // ancestor exists in the tree.
         item = this.findTreeElement(ancestors[i], isAncestor, getParent);
-        if (ancestors[i] !== representedObject && item && item.onpopulate)
+        if (item && item.onpopulate)
             item.onpopulate(item);
     }
 
-    return item;
+    // Now that all the ancestors are populated, try to find the representedObject again. This time
+    // without the isAncestor and getParent functions to prevent an infinite recursion if it isn't found.
+    return this.findTreeElement(representedObject);
 }
 
 TreeOutline.prototype.treeElementFromPoint = function(x, y)
@@ -637,12 +652,23 @@ TreeElement.prototype.expand = function()
         this.onexpand(this);
 }
 
-TreeElement.prototype.expandRecursively = function()
+TreeElement.prototype.expandRecursively = function(maxDepth)
 {
     var item = this;
+    var info = {};
+    var depth = 0;
+
+    // The Inspector uses TreeOutlines to represents object properties, so recursive expansion
+    // in some case can be infinite, since JavaScript objects can hold circular references.
+    // So default to a recursion cap of 3 levels, since that gives fairly good results.
+    if (typeof maxDepth === "undefined" || typeof maxDepth === "null")
+        maxDepth = 3;
+
     while (item) {
-        item.expand();
-        item = item.traverseNextTreeElement(false, this);
+        if (depth < maxDepth)
+            item.expand();
+        item = item.traverseNextTreeElement(false, this, (depth >= maxDepth), info);
+        depth += info.depthChange;
     }
 }
 
@@ -702,14 +728,20 @@ TreeElement.prototype.deselect = function(supressOnDeselect)
         this.ondeselect(this);
 }
 
-TreeElement.prototype.traverseNextTreeElement = function(skipHidden, stayWithin, dontPopulate)
+TreeElement.prototype.traverseNextTreeElement = function(skipHidden, stayWithin, dontPopulate, info)
 {
     if (!dontPopulate && this.hasChildren && this.onpopulate)
         this.onpopulate(this);
 
+    if (info)
+        info.depthChange = 0;
+
     var element = skipHidden ? (this.revealed() ? this.children[0] : null) : this.children[0];
-    if (element && (!skipHidden || (skipHidden && this.expanded)))
+    if (element && (!skipHidden || (skipHidden && this.expanded))) {
+        if (info)
+            info.depthChange = 1;
         return element;
+    }
 
     if (this === stayWithin)
         return null;
@@ -719,8 +751,11 @@ TreeElement.prototype.traverseNextTreeElement = function(skipHidden, stayWithin,
         return element;
 
     element = this;
-    while (element && !element.root && !(skipHidden ? (element.revealed() ? element.nextSibling : null) : element.nextSibling) && element.parent !== stayWithin)
+    while (element && !element.root && !(skipHidden ? (element.revealed() ? element.nextSibling : null) : element.nextSibling) && element.parent !== stayWithin) {
+        if (info)
+            info.depthChange -= 1;
         element = element.parent;
+    }
 
     if (!element)
         return null;