Web Inspector: Scopes sidebar should use new ObjectTreeView and not ObjectPropertiesS...
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 Mar 2015 18:30:47 +0000 (18:30 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 Mar 2015 18:30:47 +0000 (18:30 +0000)
https://bugs.webkit.org/show_bug.cgi?id=142808

Reviewed by Timothy Hatcher.

* UserInterface/Models/PropertyPath.js:
(WebInspector.PropertyPath):
(WebInspector.PropertyPath.emptyPropertyPathForScope):
Allow a special property empty path for "Scopes". This way for a
"<scopeObject>.property" we can show just the tooltip "property".

* UserInterface/Views/ObjectTreeView.css:
(.object-tree.properties-only > :matches(.title, .object-preview)):
(.object-tree.properties-only .object-tree-outline):
(.object-tree.properties-only .object-tree-property .property-name):
Tweak styles for only properties view, which won't have a top-level
preview and doesn't fade out enumerable properties.

* UserInterface/Views/ObjectTreeView.js:
(WebInspector.ObjectTreeView.prototype.get treeOutline):
Access the TreeOutline.

(WebInspector.ObjectTreeView.prototype.showOnlyProperties):
Properties only view modifies the display slightly.

(WebInspector.ObjectTreeView.prototype.appendExtraPropertyDescriptor):
(WebInspector.ObjectTreeView.prototype._updateProperties):
Allow the client to add its own property descriptors to display
as a property in this ObjectTreeView.

* UserInterface/Views/ScopeChainDetailsSidebarPanel.js:
(WebInspector.ScopeChainDetailsSidebarPanel.prototype.refresh):
Switch to using an ObjectTreeView.

(WebInspector.ScopeChainDetailsSidebarPanel.prototype._propertyPathIdentifierForTreeElement):
(WebInspector.ScopeChainDetailsSidebarPanel.prototype._objectTreeAddHandler):
(WebInspector.ScopeChainDetailsSidebarPanel.prototype._objectTreeExpandHandler):
(WebInspector.ScopeChainDetailsSidebarPanel.prototype._objectTreeCollapseHandler):
Keep track of what properties were expanded so we can auto-expand
them again when the sidebar refreshes.

* UserInterface/Main.html:
* UserInterface/Views/ScopeVariableTreeElement.js: Removed.
* WebInspectorUI.vcxproj/WebInspectorUI.vcxproj:
* WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters:
Remove the now unused ScopeVariableTreeElement.js.

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

Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Models/PropertyPath.js
Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.css
Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.js
Source/WebInspectorUI/UserInterface/Views/ScopeChainDetailsSidebarPanel.js
Source/WebInspectorUI/UserInterface/Views/ScopeVariableTreeElement.js [deleted file]
Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj
Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters

index 1bb3562..98f6242 100644 (file)
@@ -1,3 +1,52 @@
+2015-03-18  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Scopes sidebar should use new ObjectTreeView and not ObjectPropertiesSection
+        https://bugs.webkit.org/show_bug.cgi?id=142808
+
+        Reviewed by Timothy Hatcher.
+
+        * UserInterface/Models/PropertyPath.js:
+        (WebInspector.PropertyPath):
+        (WebInspector.PropertyPath.emptyPropertyPathForScope):
+        Allow a special property empty path for "Scopes". This way for a
+        "<scopeObject>.property" we can show just the tooltip "property".
+
+        * UserInterface/Views/ObjectTreeView.css:
+        (.object-tree.properties-only > :matches(.title, .object-preview)):
+        (.object-tree.properties-only .object-tree-outline):
+        (.object-tree.properties-only .object-tree-property .property-name):
+        Tweak styles for only properties view, which won't have a top-level
+        preview and doesn't fade out enumerable properties.
+
+        * UserInterface/Views/ObjectTreeView.js:
+        (WebInspector.ObjectTreeView.prototype.get treeOutline):
+        Access the TreeOutline.
+
+        (WebInspector.ObjectTreeView.prototype.showOnlyProperties):
+        Properties only view modifies the display slightly.
+
+        (WebInspector.ObjectTreeView.prototype.appendExtraPropertyDescriptor):
+        (WebInspector.ObjectTreeView.prototype._updateProperties):
+        Allow the client to add its own property descriptors to display
+        as a property in this ObjectTreeView.
+
+        * UserInterface/Views/ScopeChainDetailsSidebarPanel.js:
+        (WebInspector.ScopeChainDetailsSidebarPanel.prototype.refresh):
+        Switch to using an ObjectTreeView.
+
+        (WebInspector.ScopeChainDetailsSidebarPanel.prototype._propertyPathIdentifierForTreeElement):
+        (WebInspector.ScopeChainDetailsSidebarPanel.prototype._objectTreeAddHandler):
+        (WebInspector.ScopeChainDetailsSidebarPanel.prototype._objectTreeExpandHandler):
+        (WebInspector.ScopeChainDetailsSidebarPanel.prototype._objectTreeCollapseHandler):
+        Keep track of what properties were expanded so we can auto-expand
+        them again when the sidebar refreshes.
+
+        * UserInterface/Main.html:
+        * UserInterface/Views/ScopeVariableTreeElement.js: Removed.
+        * WebInspectorUI.vcxproj/WebInspectorUI.vcxproj:
+        * WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters:
+        Remove the now unused ScopeVariableTreeElement.js.
+
 2015-03-17  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Debugger Sidebar Icons Misaligned
index d93be67..f200447 100644 (file)
     <script src="Views/ScopeBar.js"></script>
     <script src="Views/ScopeBarItem.js"></script>
     <script src="Views/ScopeChainDetailsSidebarPanel.js"></script>
-    <script src="Views/ScopeVariableTreeElement.js"></script>
     <script src="Views/ScriptContentView.js"></script>
     <script src="Views/ScriptTimelineDataGrid.js"></script>
     <script src="Views/ScriptTimelineDataGridNode.js"></script>
index e1be4e7..06919f7 100644 (file)
@@ -38,7 +38,7 @@ WebInspector.PropertyPath = function(object, pathComponent, parent, isPrototype)
         throw new Error("Attempted to append to a PropertyPath with null object.");
 
     this._object = object;
-    this._pathComponent = pathComponent || null;
+    this._pathComponent = typeof pathComponent === "string" ? pathComponent : null;
     this._parent = parent || null;
     this._isPrototype = isPrototype || false;
 };
@@ -49,6 +49,7 @@ WebInspector.PropertyPath.SpecialPathComponent = {
     MapKey: "@mapkey",
     MapValue: "@mapvalue",
     SetIndex: "@setindex",
+    EmptyPathComponentForScope: "",
 };
 
 WebInspector.PropertyPath.Type = {
@@ -57,6 +58,11 @@ WebInspector.PropertyPath.Type = {
     Setter: "setter",
 };
 
+WebInspector.PropertyPath.emptyPropertyPathForScope = function(object)
+{
+    return new WebInspector.PropertyPath(object, WebInspector.PropertyPath.SpecialPathComponent.EmptyPathComponentForScope);
+}
+
 WebInspector.PropertyPath.prototype = {
     constructor: WebInspector.PropertyPath,
     __proto__: WebInspector.Object.prototype,
@@ -148,6 +154,11 @@ WebInspector.PropertyPath.prototype = {
         return !this._parent;
     },
 
+    isScope()
+    {
+        return this._pathComponent === WebInspector.PropertyPath.SpecialPathComponent.EmptyPathComponentForScope;
+    },
+
     isPathComponentImpossible()
     {
         return this._pathComponent && this._pathComponent.startsWith("@");
@@ -167,6 +178,10 @@ WebInspector.PropertyPath.prototype = {
     appendPropertyName(object, propertyName)
     {
         var isPrototype = propertyName === "__proto__";
+
+        if (this.isScope())
+            return new WebInspector.PropertyPath(object, propertyName, this, isPrototype);
+
         var component = this._canPropertyNameBeDotAccess(propertyName) ? "." + propertyName : "[" + doubleQuotedString(propertyName) + "]";
         return new WebInspector.PropertyPath(object, component, this, isPrototype);
     },
index a1e5eff..47d4d26 100644 (file)
     background-image: -webkit-canvas(navigation-sidebar-panel-disclosure-triangle-open-normal);
 }
 
+.object-tree.properties-only > :matches(.title, .object-preview) {
+    display: none;
+}
+
 .object-tree.expanded .object-preview {
     font-style: normal;
 }
     outline: none;
 }
 
+.object-tree.properties-only .object-tree-outline {
+    padding-left: 0;
+}
+
+.object-tree.properties-only .object-tree-property .property-name {
+    opacity: 1;
+}
+
 .object-tree-outline li {
     white-space: nowrap;
     text-overflow: ellipsis;
index 8d70501..67ea725 100644 (file)
@@ -151,6 +151,11 @@ WebInspector.ObjectTreeView.prototype = {
         return this._element;
     },
 
+    get treeOutline()
+    {
+        return this._outline;
+    },
+
     get expanded()
     {
         return this._expanded;
@@ -186,6 +191,13 @@ WebInspector.ObjectTreeView.prototype = {
         this._untrackWeakEntries();
     },
 
+    showOnlyProperties()
+    {
+        this._inConsole = false;
+
+        this._element.classList.add("properties-only");
+    },
+
     appendTitleSuffix(suffixElement)
     {
         if (this._previewView)
@@ -194,6 +206,14 @@ WebInspector.ObjectTreeView.prototype = {
             this._titleElement.appendChild(suffixElement);
     },
 
+    appendExtraPropertyDescriptor(propertyDescriptor)
+    {
+        if (!this._extraProperties)
+            this._extraProperties = [];
+
+        this._extraProperties.push(propertyDescriptor);
+    },
+
     // Protected
 
     update()
@@ -243,6 +263,9 @@ WebInspector.ObjectTreeView.prototype = {
 
     _updateProperties(properties, propertyPath)
     {
+        if (this._extraProperties)
+            properties = properties.concat(this._extraProperties);
+
         properties.sort(WebInspector.ObjectTreeView.ComparePropertyDescriptors);
 
         var isArray = this._object.isArray();
index f452aa2..c2cbc01 100644 (file)
@@ -33,13 +33,15 @@ WebInspector.ScopeChainDetailsSidebarPanel = function()
     WebInspector.runtimeManager.addEventListener(WebInspector.RuntimeManager.Event.DidEvaluate, this.needsRefresh, this);
 };
 
+WebInspector.ScopeChainDetailsSidebarPanel.autoExpandProperties = new Set;
+
 WebInspector.ScopeChainDetailsSidebarPanel.prototype = {
     constructor: WebInspector.ScopeChainDetailsSidebarPanel,
     __proto__: WebInspector.DetailsSidebarPanel.prototype,
 
     // Public
 
-    inspect: function(objects)
+    inspect(objects)
     {
         // Convert to a single item array if needed.
         if (!(objects instanceof Array))
@@ -75,7 +77,7 @@ WebInspector.ScopeChainDetailsSidebarPanel.prototype = {
         this.needsRefresh();
     },
 
-    refresh: function()
+    refresh()
     {
         var callFrame = this.callFrame;
         if (!callFrame)
@@ -93,7 +95,7 @@ WebInspector.ScopeChainDetailsSidebarPanel.prototype = {
             var scope = scopeChain[i];
 
             var title = null;
-            var extraProperties = null;
+            var extraPropertyDescriptor = null;
             var collapsedByDefault = false;
             var dontHighlightNonEnumerableProperties = true;
 
@@ -108,7 +110,7 @@ WebInspector.ScopeChainDetailsSidebarPanel.prototype = {
                     title = WebInspector.UIString("Local Variables");
 
                     if (callFrame.thisObject)
-                        extraProperties = [new WebInspector.RemoteObjectProperty("this", callFrame.thisObject)];
+                        extraPropertyDescriptor = new WebInspector.PropertyDescriptor({name: "this", value: callFrame.thisObject});
                     break;
 
                 case WebInspector.ScopeChainNode.Type.Closure:
@@ -144,12 +146,21 @@ WebInspector.ScopeChainDetailsSidebarPanel.prototype = {
 
             var detailsSectionIdentifier = scope.type + "-" + sectionCountByType[scope.type];
 
-            var section = new WebInspector.ObjectPropertiesSection(scope.object, null, null, null, true, extraProperties, WebInspector.ScopeVariableTreeElement);
-            section.dontHighlightNonEnumerablePropertiesAtTopLevel = dontHighlightNonEnumerableProperties;
-            section.__propertyIdentifierPrefix = detailsSectionIdentifier;
+            var scopePropertyPath = WebInspector.PropertyPath.emptyPropertyPathForScope(scope.object);
+            var objectTree = new WebInspector.ObjectTreeView(scope.object, WebInspector.ObjectTreeView.Mode.Properties, scopePropertyPath);
+
+            objectTree.showOnlyProperties();
+
+            if (extraPropertyDescriptor)
+                objectTree.appendExtraPropertyDescriptor(extraPropertyDescriptor);
+
+            var treeOutline = objectTree.treeOutline;
+            treeOutline.onadd = this._objectTreeAddHandler.bind(this, detailsSectionIdentifier);
+            treeOutline.onexpand = this._objectTreeExpandHandler.bind(this, detailsSectionIdentifier);
+            treeOutline.oncollapse = this._objectTreeCollapseHandler.bind(this, detailsSectionIdentifier);
 
             var detailsSection = new WebInspector.DetailsSection(detailsSectionIdentifier, title, null, null, collapsedByDefault);
-            detailsSection.groups[0].rows = [new WebInspector.DetailsSectionPropertiesRow(section)];
+            detailsSection.groups[0].rows = [new WebInspector.DetailsSectionPropertiesRow(objectTree)];
             detailsSections.push(detailsSection);
         }
 
@@ -170,10 +181,51 @@ WebInspector.ScopeChainDetailsSidebarPanel.prototype = {
         // We need a timeout in place in case there are long running, pending backend dispatches. This can happen
         // if the debugger is paused in code that was executed from the console. The console will be waiting for
         // the result of the execution and without a timeout we would never update the scope variables.
-        var timeout = setTimeout(delayedWork.bind(this), 50);
+        var delay = WebInspector.ScopeChainDetailsSidebarPanel.autoExpandProperties.size === 0 ? 50 : 250;
+        var timeout = setTimeout(delayedWork.bind(this), delay);
 
-        // Since ObjectPropertiesSection populates asynchronously, we want to wait to replace the existing content
+        // Since ObjectTreeView populates asynchronously, we want to wait to replace the existing content
         // until after all the pending asynchronous requests are completed. This prevents severe flashing while stepping.
         InspectorBackend.runAfterPendingDispatches(delayedWork.bind(this));
+    },
+
+    _propertyPathIdentifierForTreeElement(identifier, objectPropertyTreeElement)
+    {
+        if (!objectPropertyTreeElement.property)
+            return null;
+
+        var propertyPath = objectPropertyTreeElement.thisPropertyPath();
+        if (propertyPath.isFullPathImpossible())
+            return null;
+
+        return identifier + "-" + propertyPath.fullPath;
+    },
+
+    _objectTreeAddHandler(identifier, treeElement)
+    {
+        var propertyPathIdentifier = this._propertyPathIdentifierForTreeElement(identifier, treeElement);
+        if (!propertyPathIdentifier)
+            return;
+
+        if (WebInspector.ScopeChainDetailsSidebarPanel.autoExpandProperties.has(propertyPathIdentifier))
+            treeElement.expand();
+    },
+
+    _objectTreeExpandHandler(identifier, treeElement)
+    {
+        var propertyPathIdentifier = this._propertyPathIdentifierForTreeElement(identifier, treeElement);
+        if (!propertyPathIdentifier)
+            return;
+
+        WebInspector.ScopeChainDetailsSidebarPanel.autoExpandProperties.add(propertyPathIdentifier);
+    },
+
+    _objectTreeCollapseHandler(identifier, treeElement)
+    {
+        var propertyPathIdentifier = this._propertyPathIdentifierForTreeElement(identifier, treeElement);
+        if (!propertyPathIdentifier)
+            return;
+
+        WebInspector.ScopeChainDetailsSidebarPanel.autoExpandProperties.delete(propertyPathIdentifier);
     }
 };
diff --git a/Source/WebInspectorUI/UserInterface/Views/ScopeVariableTreeElement.js b/Source/WebInspectorUI/UserInterface/Views/ScopeVariableTreeElement.js
deleted file mode 100644 (file)
index 0ee2320..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2008, 2013 Apple Inc. All Rights Reserved.
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.ScopeVariableTreeElement = function(property)
-{
-    WebInspector.ObjectPropertyTreeElement.call(this, property);
-};
-
-WebInspector.ScopeVariableTreeElement._expandedProperties = {};
-
-WebInspector.ScopeVariableTreeElement.prototype = {
-    constructor: WebInspector.ScopeVariableTreeElement,
-
-    // Public
-
-    onattach: function()
-    {
-        WebInspector.ObjectPropertyTreeElement.prototype.onattach.call(this);
-
-        if (this.hasChildren && this.constructor._expandedProperties.hasOwnProperty(this.propertyIdentifier))
-            this.expand();
-    },
-
-    onexpand: function()
-    {
-        this.constructor._expandedProperties[this.propertyIdentifier] = true;
-    },
-
-    oncollapse: function()
-    {
-        delete this.constructor._expandedProperties[this.propertyIdentifier];
-    },
-
-    get propertyIdentifier()
-    {
-        if ("_propertyIdentifier" in this)
-            return this._propertyIdentifier;
-
-        var section = this.treeOutline.section;
-        this._propertyIdentifier = (section.__propertyIdentifierPrefix ? section.__propertyIdentifierPrefix + "-" : "") + this.propertyPath;
-        return this._propertyIdentifier;
-    },
-
-    get propertyPath()
-    {
-        if ("_propertyPath" in this)
-            return this._propertyPath;
-
-        var current = this;
-        var result;
-
-        do {
-            if (current.property) {
-                if (result)
-                    result = current.property.name + "." + result;
-                else
-                    result = current.property.name;
-            }
-
-            current = current.parent;
-        } while (current && !current.root);
-
-        this._propertyPath = result;
-        return result;
-    }
-};
-
-WebInspector.ScopeVariableTreeElement.prototype.__proto__ = WebInspector.ObjectPropertyTreeElement.prototype;
index c00d0f2..eb4c8f6 100644 (file)
     <None Include="..\UserInterface\ScopeBarItem.js" />
     <None Include="..\UserInterface\ScopeChainDetailsSidebarPanel.js" />
     <None Include="..\UserInterface\ScopeChainNode.js" />
-    <None Include="..\UserInterface\ScopeVariableTreeElement.js" />
     <None Include="..\UserInterface\Script.js" />
     <None Include="..\UserInterface\ScriptContentView.css" />
     <None Include="..\UserInterface\ScriptContentView.js" />
index b1c79dd..916dc22 100644 (file)
     <None Include="..\UserInterface\ScopeChainNode.js">
       <Filter>UserInterface</Filter>
     </None>
-    <None Include="..\UserInterface\ScopeVariableTreeElement.js">
-      <Filter>UserInterface</Filter>
-    </None>
     <None Include="..\UserInterface\Script.js">
       <Filter>UserInterface</Filter>
     </None>