Fix Bug 17815: Inspector's DOM tree should descend into subframes
authoraroben@apple.com <aroben@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Mar 2008 06:13:32 +0000 (06:13 +0000)
committeraroben@apple.com <aroben@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Mar 2008 06:13:32 +0000 (06:13 +0000)
        <http://bugs.webkit.org/show_bug.cgi?id=17815>

        Reviewed by Tim.

        * page/inspector/DocumentPanel.js:
        (WebInspector.DocumentPanel.revealNode): Changed to provide
        _isAncestorIncludingParentFramesWithinPanel and
        _parentNodeOrFrameElementWithinPanel for the isAncestor and getParent
        parameters to findTreeElement so that parent frames will be searched.
        (WebInspector.DocumentPanel.updateBreadcrumb):
          - Changed while loop to for loop
          - Use _parentNodeOrFrameElementWithinPanel instead of
            Node.parentNode to move to the next node
          - The loop now ends when we reach the DocumentPanel's document node
          - Traversal past other Document nodes is now allowed
          - We add the "start" class to the final crumb after the loop exits
        (WebInspector.DocumentPanel._getDocumentForNode): Added. Simple helper
        that returns the node itself if the node is a Document node, or the
        node's ownerDocument otherwise.
        (WebInspector.DocumentPanel._parentNodeOrFrameElementWithinPanel):
        Added. Returns the node's parent node or, in the case of a Document
        node, the node's window's owning frame element, but will not return a
        node that is in a parent frame of the DocumentPanel's Document.
        (WebInspector.DocumentPanel._isAncestorIncludingParentFramesWithinPanel):
        Added. Returns true if a is an ancestor of b if a is an ancestor of a
        frame element whose subframe(s) contain b.
        (WebInspector.DOMNodeTreeElement): We now consider ourselves to have
        children if we have a contentDocument.
        (WebInspector.DOMNodeTreeElement.onpopulate): Moved the appendChild
        loop into a function so that we can add both children of our
        contentDocument and children of our node to the tree.
        (WebInspector.DOMNodeTreeElement.ondblclick): Changed so that we get
        the rootDOMNode by traversing the tree outline hierarchy instead of
        the DOM hierarchy so that we can easily jump up to a parent frame.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@31025 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/page/inspector/DocumentPanel.js

index 6fe5b83..389e936 100644 (file)
@@ -1,5 +1,44 @@
 2008-03-12  Adam Roben  <aroben@apple.com>
 
+        Fix Bug 17815: Inspector's DOM tree should descend into subframes
+
+        <http://bugs.webkit.org/show_bug.cgi?id=17815>
+
+        Reviewed by Tim.
+
+        * page/inspector/DocumentPanel.js:
+        (WebInspector.DocumentPanel.revealNode): Changed to provide
+        _isAncestorIncludingParentFramesWithinPanel and
+        _parentNodeOrFrameElementWithinPanel for the isAncestor and getParent
+        parameters to findTreeElement so that parent frames will be searched.
+        (WebInspector.DocumentPanel.updateBreadcrumb):
+          - Changed while loop to for loop
+          - Use _parentNodeOrFrameElementWithinPanel instead of
+            Node.parentNode to move to the next node
+          - The loop now ends when we reach the DocumentPanel's document node
+          - Traversal past other Document nodes is now allowed
+          - We add the "start" class to the final crumb after the loop exits
+        (WebInspector.DocumentPanel._getDocumentForNode): Added. Simple helper
+        that returns the node itself if the node is a Document node, or the
+        node's ownerDocument otherwise.
+        (WebInspector.DocumentPanel._parentNodeOrFrameElementWithinPanel):
+        Added. Returns the node's parent node or, in the case of a Document
+        node, the node's window's owning frame element, but will not return a
+        node that is in a parent frame of the DocumentPanel's Document.
+        (WebInspector.DocumentPanel._isAncestorIncludingParentFramesWithinPanel):
+        Added. Returns true if a is an ancestor of b if a is an ancestor of a
+        frame element whose subframe(s) contain b.
+        (WebInspector.DOMNodeTreeElement): We now consider ourselves to have
+        children if we have a contentDocument.
+        (WebInspector.DOMNodeTreeElement.onpopulate): Moved the appendChild
+        loop into a function so that we can add both children of our
+        contentDocument and children of our node to the tree.
+        (WebInspector.DOMNodeTreeElement.ondblclick): Changed so that we get
+        the rootDOMNode by traversing the tree outline hierarchy instead of
+        the DOM hierarchy so that we can easily jump up to a parent frame.
+
+2008-03-12  Adam Roben  <aroben@apple.com>
+
         Update the styles/metrics panes and breadcrumb after editing DOM
         attributes
 
index a940ab6..93dd542 100644 (file)
@@ -162,7 +162,7 @@ WebInspector.DocumentPanel.prototype = {
 
     revealNode: function(node)
     {
-        var nodeItem = this.views.dom.treeOutline.findTreeElement(node, function(a, b) { return isAncestorNode.call(a, b); }, function(a) { return a.parentNode; });
+        var nodeItem = this.views.dom.treeOutline.findTreeElement(node, this._isAncestorIncludingParentFramesWithinPanel.bind(this), this._parentNodeOrFrameElementWithinPanel.bind(this));
         if (!nodeItem)
             return;
 
@@ -282,11 +282,13 @@ WebInspector.DocumentPanel.prototype = {
         };
 
         foundRoot = false;
-        var current = this.focusedDOMNode;
-        while (current) {
-            if (current.nodeType === Node.DOCUMENT_NODE)
+        for (var current = this.focusedDOMNode; current; current = this._parentNodeOrFrameElementWithinPanel(current)) {
+            if (current === this.resource.documentNode)
                 break;
 
+            if (current.nodeType === Node.DOCUMENT_NODE)
+                continue;
+
             if (current === this.rootDOMNode)
                 foundRoot = true;
 
@@ -372,13 +374,13 @@ WebInspector.DocumentPanel.prototype = {
                 crumb.addStyleClass("selected");
             if (!crumbs.childNodes.length)
                 crumb.addStyleClass("end");
-            if (current.parentNode.nodeType === Node.DOCUMENT_NODE)
-                crumb.addStyleClass("start");
 
             crumbs.appendChild(crumb);
-            current = current.parentNode;
         }
 
+        if (crumbs.hasChildNodes())
+            crumbs.lastChild.addStyleClass("start");
+
         this.updateBreadcrumbSizes();
     },
 
@@ -733,14 +735,49 @@ WebInspector.DocumentPanel.prototype = {
         this.updateBreadcrumbSizes();
 
         event.preventDefault();
-    }
+    },
+
+    _getDocumentForNode: function(node)
+    {
+        return node.nodeType == Node.DOCUMENT_NODE ? node : node.ownerDocument;
+    },
+
+    _parentNodeOrFrameElementWithinPanel: function(node)
+    {
+        var parent = node.parentNode;
+        if (parent)
+            return parent;
+
+        var document = this._getDocumentForNode(node);
+
+        if (document === this.resource.documentNode)
+            return undefined;
+
+        return document.defaultView.frameElement;
+    },
+
+    _isAncestorIncludingParentFramesWithinPanel: function(a, b)
+    {
+        for (var node = b; node; node = this._getDocumentForNode(node).defaultView.frameElement) {
+            if (isAncestorNode.call(a, node))
+                return true;
+
+            if (this._getDocumentForNode(node) === this.resource.documentNode) {
+                // We've gone as high in the frame hierarchy as we can without
+                // moving out of this DocumentPanel.
+                return false;
+            }
+        }
+
+        return false;
+    },
 }
 
 WebInspector.DocumentPanel.prototype.__proto__ = WebInspector.SourcePanel.prototype;
 
 WebInspector.DOMNodeTreeElement = function(node)
 {
-    var hasChildren = (Preferences.ignoreWhitespace ? (firstChildSkippingWhitespace.call(node) ? true : false) : node.hasChildNodes());
+    var hasChildren = node.contentDocument || (Preferences.ignoreWhitespace ? (firstChildSkippingWhitespace.call(node) ? true : false) : node.hasChildNodes());
     var titleInfo = nodeTitleInfo.call(node, hasChildren, WebInspector.linkifyURL);
 
     if (titleInfo.hasChildren) 
@@ -815,12 +852,21 @@ WebInspector.DOMNodeTreeElement.prototype = {
         this.removeChildren();
         this.whitespaceIgnored = Preferences.ignoreWhitespace;
 
-        var node = (Preferences.ignoreWhitespace ? firstChildSkippingWhitespace.call(this.representedObject) : this.representedObject.firstChild);
-        while (node) {
-            this.appendChild(new WebInspector.DOMNodeTreeElement(node));
-            node = Preferences.ignoreWhitespace ? nextSiblingSkippingWhitespace.call(node) : node.nextSibling;
+        var treeElement = this;
+        function appendChildrenOfNode(node)
+        {
+            var child = (Preferences.ignoreWhitespace ? firstChildSkippingWhitespace.call(node) : node.firstChild);
+            while (child) {
+                treeElement.appendChild(new WebInspector.DOMNodeTreeElement(child));
+                child = Preferences.ignoreWhitespace ? nextSiblingSkippingWhitespace.call(child) : child.nextSibling;
+            }
         }
 
+        if (this.representedObject.contentDocument)
+            appendChildrenOfNode(this.representedObject.contentDocument);
+
+        appendChildrenOfNode(this.representedObject);
+
         if (this.representedObject.nodeType == Node.ELEMENT_NODE) {
             var title = "<span class=\"webkit-html-tag close\">&lt;/" + this.representedObject.nodeName.toLowerCase().escapeHTML() + "&gt;</span>";
             var item = new TreeElement(title, this.representedObject, false);
@@ -875,7 +921,7 @@ WebInspector.DOMNodeTreeElement.prototype = {
             return;
 
         var panel = this.treeOutline.panel;
-        panel.rootDOMNode = this.representedObject.parentNode;
+        panel.rootDOMNode = this.parent.representedObject;
         panel.focusedDOMNode = this.representedObject;
 
         if (this.hasChildren && !this.expanded)