Title: [180713] trunk/Source/WebInspectorUI
Revision
180713
Author
joep...@webkit.org
Date
2015-02-26 17:15:15 -0800 (Thu, 26 Feb 2015)

Log Message

Web Inspector: New ObjectTree UI for Arrays / Maps / Sets
https://bugs.webkit.org/show_bug.cgi?id=142037

Reviewed by Timothy Hatcher.

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Main.html:
Miscellaneous changes.

* UserInterface/Models/PropertyDescriptor.js:
(WebInspector.PropertyDescriptor.prototype.isIndexProperty):
Useful for quickly checking if this property is numeric and possibly
an array index.

* UserInterface/Models/PropertyPath.js:
(WebInspector.PropertyPath.prototype.appendMapKey):
(WebInspector.PropertyPath.prototype.appendMapValue):
(WebInspector.PropertyPath.prototype.appendSetIndex):
Be specific about property paths into maps / sets. Note that a map
value may be displayable if the key is simple.

* UserInterface/Protocol/RemoteObject.js:
(WebInspector.RemoteObject.prototype.hasValue):
A simple value RemoteObject may have the value "undefined". So provide
a falsey proof helper that actually checks if we have a value.

(WebInspector.RemoteObject.prototype.isArray):
(WebInspector.RemoteObject.prototype.backendGetOwnPropertyDescriptor):
(WebInspector.RemoteObject.prototype.wrappedCallback):
(WebInspector.RemoteObject.prototype.getOwnPropertyDescriptor):
Currently backend APIs exist only to get all properties. In the case
of collections, we often want to get only one property (__proto__).
This is a simple implementation on top of callFunctionOn.

* UserInterface/Views/ConsoleMessageImpl.js:
(WebInspector.ConsoleMessageImpl.prototype._formatParameterAsObject):
(WebInspector.ConsoleMessageImpl.prototype._formatParameterAsArray):
(WebInspector.ConsoleMessageImpl.prototype.appendUndefined): Deleted.
(WebInspector.ConsoleMessageImpl.prototype._printArray): Deleted.
(WebInspector.ConsoleMessageImpl.prototype._formatAsArrayEntry): Deleted.
Simplify array formatted to just use an ObjectTreeView. Add fixmes
that we should seed the ObjectTreeView with a starting property path.

* UserInterface/Views/FormattedValue.css:
(.formatted-node > ol):
Sometimes, a node's display was getting overridden by various console styles.
Force a node to always display block. We may be able to remove this later.

* UserInterface/Views/FormattedValue.js:
(WebInspector.FormattedValue.createObjectTreeOrFormattedValueForRemoteObject):
Helper for formatting a node / object / value more easily. This
is used by all collection types.

* UserInterface/Views/ObjectPreviewView.js:
(WebInspector.ObjectPreviewView.prototype._appendPropertyPreviews):
We lost the nice sparse array support when switching to the new preview path,
we should add it back.

* UserInterface/Views/ObjectTreeArrayIndexTreeElement.css:
(.object-tree-array-index):
(.object-tree-array-index > .titles):
(.object-tree-array-index > .icon):
(.object-tree-array-index .index-name):
(.object-tree-array-index .index-value .object-tree):
(.object-tree-array-index .index-value .object-tree .object-tree-outline):
(.object-tree-property + ol .object-tree-array-index):
New styles specific to array index tree elements.

* UserInterface/Views/ObjectTreeMapEntryTreeElement.css:
(.object-tree-array-index.object-tree-map-entry > .titles > .title > .index-name):
(.object-tree-map-entry.key):
(.object-tree-map-entry.key:first-of-type):
(.object-tree-map-entry):
New styles specific to map key/value tree elements.

* UserInterface/Views/ObjectTreeCollectionTreeElement.js: Removed.
Remove old collection implementation.

* UserInterface/Views/ObjectTreeArrayIndexTreeElement.js: Added.
(WebInspector.ObjectTreeArrayIndexTreeElement):
(WebInspector.ObjectTreeArrayIndexTreeElement.prototype.get property):
(WebInspector.ObjectTreeArrayIndexTreeElement.prototype._resolvedValue):
(WebInspector.ObjectTreeArrayIndexTreeElement.prototype._propertyPathType):
(WebInspector.ObjectTreeArrayIndexTreeElement.prototype._resolvedValuePropertyPath):
(WebInspector.ObjectTreeArrayIndexTreeElement.prototype._thisPropertyPath):
(WebInspector.ObjectTreeArrayIndexTreeElement.prototype._propertyPathString):
(WebInspector.ObjectTreeArrayIndexTreeElement.prototype._updateTitle):
(WebInspector.ObjectTreeArrayIndexTreeElement.prototype._titleFragment):
(WebInspector.ObjectTreeArrayIndexTreeElement.prototype._createInteractiveGetterElement.):
(WebInspector.ObjectTreeArrayIndexTreeElement.prototype._createReadOnlyIconElement):
Index followed by formatted value. Unfortunately a page can hack up an array
with getter properties, so also support getter values in an array. This ends
up copying a lot of ObjectTreePropertyTreeElement as a result.

* UserInterface/Views/ObjectTreeMapEntryTreeElement.js: Added.
(WebInspector.ObjectTreeMapEntryTreeElement):
(WebInspector.ObjectTreeMapEntryTreeElement.prototype.get object):
(WebInspector.ObjectTreeMapEntryTreeElement.prototype._propertyPathString):
(WebInspector.ObjectTreeMapEntryTreeElement.prototype._titleFragment):
(WebInspector.ObjectTreeMapKeyTreeElement):
(WebInspector.ObjectTreeMapKeyTreeElement.prototype.displayPropertyName):
(WebInspector.ObjectTreeMapKeyTreeElement.prototype.resolvedValuePropertyPath):
(WebInspector.ObjectTreeMapValueTreeElement):
(WebInspector.ObjectTreeMapValueTreeElement.prototype.displayPropertyName):
(WebInspector.ObjectTreeMapValueTreeElement.prototype.resolvedValuePropertyPath):
Key/value followed by formatted value.

* UserInterface/Views/ObjectTreeSetIndexTreeElement.js: Added.
(WebInspector.ObjectTreeSetIndexTreeElement):
(WebInspector.ObjectTreeSetIndexTreeElement.prototype.get object):
(WebInspector.ObjectTreeSetIndexTreeElement.prototype._resolvedValuePropertyPath):
(WebInspector.ObjectTreeSetIndexTreeElement.prototype._titleFragment):
Dot followed by formatted value.

* UserInterface/Views/ObjectTreePropertyTreeElement.css:
(.object-tree-property > .titles):
Reformat.

* UserInterface/Views/ObjectTreeView.css:
(.object-tree-property :matches(.formatted-string, .formatted-regexp)):
Upgrade generic styles.

* UserInterface/Views/ObjectTreePropertyTreeElement.js:
(WebInspector.ObjectTreePropertyTreeElement.prototype._resolvedValue):
(WebInspector.ObjectTreePropertyTreeElement.prototype._resolvedValuePropertyPath):
(WebInspector.ObjectTreePropertyTreeElement.prototype._updateChildren):
(WebInspector.ObjectTreePropertyTreeElement.prototype._updateChildrenInternal):
(WebInspector.ObjectTreePropertyTreeElement.prototype._updateEntries):
(WebInspector.ObjectTreePropertyTreeElement.prototype._updateProperties):
* UserInterface/Views/ObjectTreeView.js:
(WebInspector.ObjectTreeView):
(WebInspector.ObjectTreeView.emptyMessageElement):
(WebInspector.ObjectTreeView.prototype.expand):
(WebInspector.ObjectTreeView.prototype.collapse):
(WebInspector.ObjectTreeView.prototype.update):
(WebInspector.ObjectTreeView.prototype._updateChildren):
(WebInspector.ObjectTreeView.prototype._updateEntries):
(WebInspector.ObjectTreeView.prototype._updateProperties):
(WebInspector.ObjectTreeView.prototype._handlePreviewOrTitleElementClick):
Both ObjectTreeView and ObjectTreePropertyTreeElement will fetch only collection
entries or properties depending on the type of the object being expanded.

(WebInspector.ObjectTreeView.prototype._trackWeakEntries):
(WebInspector.ObjectTreeView.prototype._untrackWeakEntries):
Allow WeakMap entries to be Garbage Collected when the ObjectTreeView
collapses or the console is cleared. FIXME for handling sub-tree WeakMaps.

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/Source/WebInspectorUI/ChangeLog (180712 => 180713)


--- trunk/Source/WebInspectorUI/ChangeLog	2015-02-27 01:04:19 UTC (rev 180712)
+++ trunk/Source/WebInspectorUI/ChangeLog	2015-02-27 01:15:15 UTC (rev 180713)
@@ -1,3 +1,152 @@
+2015-02-26  Joseph Pecoraro  <pecor...@apple.com>
+
+        Web Inspector: New ObjectTree UI for Arrays / Maps / Sets
+        https://bugs.webkit.org/show_bug.cgi?id=142037
+
+        Reviewed by Timothy Hatcher.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * UserInterface/Main.html:
+        Miscellaneous changes.
+
+        * UserInterface/Models/PropertyDescriptor.js:
+        (WebInspector.PropertyDescriptor.prototype.isIndexProperty):
+        Useful for quickly checking if this property is numeric and possibly
+        an array index.
+
+        * UserInterface/Models/PropertyPath.js:
+        (WebInspector.PropertyPath.prototype.appendMapKey):
+        (WebInspector.PropertyPath.prototype.appendMapValue):
+        (WebInspector.PropertyPath.prototype.appendSetIndex):
+        Be specific about property paths into maps / sets. Note that a map
+        value may be displayable if the key is simple.
+
+        * UserInterface/Protocol/RemoteObject.js:
+        (WebInspector.RemoteObject.prototype.hasValue):
+        A simple value RemoteObject may have the value "undefined". So provide
+        a falsey proof helper that actually checks if we have a value.
+
+        (WebInspector.RemoteObject.prototype.isArray):
+        (WebInspector.RemoteObject.prototype.backendGetOwnPropertyDescriptor):
+        (WebInspector.RemoteObject.prototype.wrappedCallback):
+        (WebInspector.RemoteObject.prototype.getOwnPropertyDescriptor):
+        Currently backend APIs exist only to get all properties. In the case
+        of collections, we often want to get only one property (__proto__).
+        This is a simple implementation on top of callFunctionOn.
+
+        * UserInterface/Views/ConsoleMessageImpl.js:
+        (WebInspector.ConsoleMessageImpl.prototype._formatParameterAsObject):
+        (WebInspector.ConsoleMessageImpl.prototype._formatParameterAsArray):
+        (WebInspector.ConsoleMessageImpl.prototype.appendUndefined): Deleted.
+        (WebInspector.ConsoleMessageImpl.prototype._printArray): Deleted.
+        (WebInspector.ConsoleMessageImpl.prototype._formatAsArrayEntry): Deleted.
+        Simplify array formatted to just use an ObjectTreeView. Add fixmes
+        that we should seed the ObjectTreeView with a starting property path.
+
+        * UserInterface/Views/FormattedValue.css:
+        (.formatted-node > ol):
+        Sometimes, a node's display was getting overridden by various console styles.
+        Force a node to always display block. We may be able to remove this later.
+
+        * UserInterface/Views/FormattedValue.js:
+        (WebInspector.FormattedValue.createObjectTreeOrFormattedValueForRemoteObject):
+        Helper for formatting a node / object / value more easily. This
+        is used by all collection types.
+
+        * UserInterface/Views/ObjectPreviewView.js:
+        (WebInspector.ObjectPreviewView.prototype._appendPropertyPreviews):
+        We lost the nice sparse array support when switching to the new preview path,
+        we should add it back.
+
+        * UserInterface/Views/ObjectTreeArrayIndexTreeElement.css:
+        (.object-tree-array-index):
+        (.object-tree-array-index > .titles):
+        (.object-tree-array-index > .icon):
+        (.object-tree-array-index .index-name):
+        (.object-tree-array-index .index-value .object-tree):
+        (.object-tree-array-index .index-value .object-tree .object-tree-outline):
+        (.object-tree-property + ol .object-tree-array-index):
+        New styles specific to array index tree elements.
+
+        * UserInterface/Views/ObjectTreeMapEntryTreeElement.css:
+        (.object-tree-array-index.object-tree-map-entry > .titles > .title > .index-name):
+        (.object-tree-map-entry.key):
+        (.object-tree-map-entry.key:first-of-type):
+        (.object-tree-map-entry):
+        New styles specific to map key/value tree elements.
+
+        * UserInterface/Views/ObjectTreeCollectionTreeElement.js: Removed.
+        Remove old collection implementation.
+
+        * UserInterface/Views/ObjectTreeArrayIndexTreeElement.js: Added.
+        (WebInspector.ObjectTreeArrayIndexTreeElement):
+        (WebInspector.ObjectTreeArrayIndexTreeElement.prototype.get property):
+        (WebInspector.ObjectTreeArrayIndexTreeElement.prototype._resolvedValue):
+        (WebInspector.ObjectTreeArrayIndexTreeElement.prototype._propertyPathType):
+        (WebInspector.ObjectTreeArrayIndexTreeElement.prototype._resolvedValuePropertyPath):
+        (WebInspector.ObjectTreeArrayIndexTreeElement.prototype._thisPropertyPath):
+        (WebInspector.ObjectTreeArrayIndexTreeElement.prototype._propertyPathString):
+        (WebInspector.ObjectTreeArrayIndexTreeElement.prototype._updateTitle):
+        (WebInspector.ObjectTreeArrayIndexTreeElement.prototype._titleFragment):
+        (WebInspector.ObjectTreeArrayIndexTreeElement.prototype._createInteractiveGetterElement.):
+        (WebInspector.ObjectTreeArrayIndexTreeElement.prototype._createReadOnlyIconElement):
+        Index followed by formatted value. Unfortunately a page can hack up an array
+        with getter properties, so also support getter values in an array. This ends
+        up copying a lot of ObjectTreePropertyTreeElement as a result.
+
+        * UserInterface/Views/ObjectTreeMapEntryTreeElement.js: Added.
+        (WebInspector.ObjectTreeMapEntryTreeElement):
+        (WebInspector.ObjectTreeMapEntryTreeElement.prototype.get object):
+        (WebInspector.ObjectTreeMapEntryTreeElement.prototype._propertyPathString):
+        (WebInspector.ObjectTreeMapEntryTreeElement.prototype._titleFragment):
+        (WebInspector.ObjectTreeMapKeyTreeElement):
+        (WebInspector.ObjectTreeMapKeyTreeElement.prototype.displayPropertyName):
+        (WebInspector.ObjectTreeMapKeyTreeElement.prototype.resolvedValuePropertyPath):
+        (WebInspector.ObjectTreeMapValueTreeElement):
+        (WebInspector.ObjectTreeMapValueTreeElement.prototype.displayPropertyName):
+        (WebInspector.ObjectTreeMapValueTreeElement.prototype.resolvedValuePropertyPath):
+        Key/value followed by formatted value.
+
+        * UserInterface/Views/ObjectTreeSetIndexTreeElement.js: Added.
+        (WebInspector.ObjectTreeSetIndexTreeElement):
+        (WebInspector.ObjectTreeSetIndexTreeElement.prototype.get object):
+        (WebInspector.ObjectTreeSetIndexTreeElement.prototype._resolvedValuePropertyPath):
+        (WebInspector.ObjectTreeSetIndexTreeElement.prototype._titleFragment):
+        Dot followed by formatted value.
+
+        * UserInterface/Views/ObjectTreePropertyTreeElement.css:
+        (.object-tree-property > .titles):
+        Reformat.
+
+        * UserInterface/Views/ObjectTreeView.css:
+        (.object-tree-property :matches(.formatted-string, .formatted-regexp)):
+        Upgrade generic styles.
+
+        * UserInterface/Views/ObjectTreePropertyTreeElement.js:
+        (WebInspector.ObjectTreePropertyTreeElement.prototype._resolvedValue):
+        (WebInspector.ObjectTreePropertyTreeElement.prototype._resolvedValuePropertyPath):
+        (WebInspector.ObjectTreePropertyTreeElement.prototype._updateChildren):
+        (WebInspector.ObjectTreePropertyTreeElement.prototype._updateChildrenInternal):
+        (WebInspector.ObjectTreePropertyTreeElement.prototype._updateEntries):
+        (WebInspector.ObjectTreePropertyTreeElement.prototype._updateProperties):
+        * UserInterface/Views/ObjectTreeView.js:
+        (WebInspector.ObjectTreeView):
+        (WebInspector.ObjectTreeView.emptyMessageElement):
+        (WebInspector.ObjectTreeView.prototype.expand):
+        (WebInspector.ObjectTreeView.prototype.collapse):
+        (WebInspector.ObjectTreeView.prototype.update):
+        (WebInspector.ObjectTreeView.prototype._updateChildren):
+        (WebInspector.ObjectTreeView.prototype._updateEntries):
+        (WebInspector.ObjectTreeView.prototype._updateProperties):
+        (WebInspector.ObjectTreeView.prototype._handlePreviewOrTitleElementClick):
+        Both ObjectTreeView and ObjectTreePropertyTreeElement will fetch only collection
+        entries or properties depending on the type of the object being expanded.
+
+        (WebInspector.ObjectTreeView.prototype._trackWeakEntries):
+        (WebInspector.ObjectTreeView.prototype._untrackWeakEntries):
+        Allow WeakMap entries to be Garbage Collected when the ObjectTreeView
+        collapses or the console is cleared. FIXME for handling sub-tree WeakMaps.
+
 2015-02-26  Brent Fulgham  <bfulg...@apple.com>
 
         [Win] Make build logs more legible by reducing noise

Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (180712 => 180713)


--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2015-02-27 01:04:19 UTC (rev 180712)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2015-02-27 01:15:15 UTC (rev 180713)
@@ -307,12 +307,14 @@
 localizedStrings["No Box Model Information"] = "No Box Model Information";
 localizedStrings["No Call Frames"] = "No Call Frames";
 localizedStrings["No Child Layers"] = "No Child Layers";
+localizedStrings["No Entries."] = "No Entries.";
 localizedStrings["No Event Listeners"] = "No Event Listeners";
 localizedStrings["No Filter Results"] = "No Filter Results";
 localizedStrings["No Layer Available"] = "No Layer Available";
 localizedStrings["No Parameters"] = "No Parameters";
 localizedStrings["No Properties"] = "No Properties";
 localizedStrings["No Properties \u2014 Click to Edit"] = "No Properties \u2014 Click to Edit";
+localizedStrings["No Properties."] = "No Properties.";
 localizedStrings["No Query Parameters"] = "No Query Parameters";
 localizedStrings["No Request Headers"] = "No Request Headers";
 localizedStrings["No Response Headers"] = "No Response Headers";
@@ -481,7 +483,8 @@
 localizedStrings["XHR"] = "XHR";
 localizedStrings["XHRs"] = "XHRs";
 localizedStrings["Yes"] = "Yes";
+localizedStrings["key"] = "key";
 localizedStrings["line "] = "line ";
 localizedStrings["originally %s"] = "originally %s";
-localizedStrings["undefined \xD7 %d"] = "undefined \xD7 %d";
+localizedStrings["value"] = "value";
 localizedStrings[" %s  Profile Recorded"] = " %s  Profile Recorded";

Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (180712 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Main.html	2015-02-27 01:04:19 UTC (rev 180712)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html	2015-02-27 01:15:15 UTC (rev 180713)
@@ -99,6 +99,8 @@
     <link rel="stylesheet" href=""
     <link rel="stylesheet" href=""
     <link rel="stylesheet" href=""
+    <link rel="stylesheet" href=""
+    <link rel="stylesheet" href=""
     <link rel="stylesheet" href=""
     <link rel="stylesheet" href=""
     <link rel="stylesheet" href=""
@@ -420,8 +422,10 @@
     <script src=""
     <script src=""
     <script src=""
-    <script src=""
+    <script src=""
+    <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/PropertyDescriptor.js (180712 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Models/PropertyDescriptor.js	2015-02-27 01:04:19 UTC (rev 180712)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/PropertyDescriptor.js	2015-02-27 01:15:15 UTC (rev 180713)
@@ -142,5 +142,10 @@
     hasSetter: function()
     {
         return this._set && this._set.type === "function";
-    }
+    },
+
+    isIndexProperty: function()
+    {
+        return !isNaN(Number(this._name));
+    },
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/PropertyPath.js (180712 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Models/PropertyPath.js	2015-02-27 01:04:19 UTC (rev 180712)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/PropertyPath.js	2015-02-27 01:15:15 UTC (rev 180713)
@@ -44,10 +44,11 @@
 };
 
 WebInspector.PropertyPath.SpecialPathComponent = {
-    CollectionIndex: "@collection[?]",
     InternalPropertyName: "@internal",
     SymbolPropertyName: "@symbol",
-    GetterPropertyName: "@getter",
+    MapKey: "@mapkey",
+    MapValue: "@mapvalue",
+    SetIndex: "@setindex",
 };
 
 WebInspector.PropertyPath.Type = {
@@ -200,12 +201,36 @@
         return new WebInspector.PropertyPath(object, component, this);
     },
 
-    appendCollectionIndex: function(object)
+    appendMapKey: function(object)
     {
-        var component = WebInspector.PropertyPath.SpecialPathComponent.CollectionIndex;
+        var component = WebInspector.PropertyPath.SpecialPathComponent.MapKey;
         return new WebInspector.PropertyPath(object, component, this);
     },
 
+    appendMapValue: function(object, keyObject)
+    {
+        console.assert(!keyObject || keyObject instanceof WebInspector.RemoteObject);
+
+        if (keyObject && keyObject.hasValue()) {
+            if (keyObject.type === "string") {
+                var component = ".get(" + doubleQuotedString(keyObject.description) + ")";
+                return new WebInspector.PropertyPath(object, component, this);                
+            }
+
+            var component = ".get(" + keyObject.description + ")";
+            return new WebInspector.PropertyPath(object, component, this);                
+        }
+            
+        var component = WebInspector.PropertyPath.SpecialPathComponent.MapValue;
+        return new WebInspector.PropertyPath(object, component, this);
+    },
+
+    appendSetIndex: function(object)
+    {
+        var component = WebInspector.PropertyPath.SpecialPathComponent.SetIndex;
+        return new WebInspector.PropertyPath(object, component, this);
+    },
+    
     appendPropertyDescriptor: function(object, descriptor, type)
     {
         if (descriptor.isInternalProperty)

Modified: trunk/Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js (180712 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js	2015-02-27 01:04:19 UTC (rev 180712)
+++ trunk/Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js	2015-02-27 01:15:15 UTC (rev 180713)
@@ -145,6 +145,11 @@
         return this._preview;
     },
 
+    hasValue: function()
+    {
+        return "_value" in this;
+    },
+
     getOwnPropertyDescriptors: function(callback)
     {
         this._getPropertyDescriptors(true, callback);
@@ -350,6 +355,11 @@
         return this._type === "symbol";
     },
 
+    isArray: function()
+    {
+        return this._subtype === "array";
+    },
+
     isCollectionType: function()
     {
         return this._subtype === "map" || this._subtype === "set" || this._subtype === "weakmap";
@@ -439,6 +449,32 @@
         this.callFunction(backendInvokeGetter, [getterRemoteObject], true, callback);
     },
 
+    getOwnPropertyDescriptor: function(propertyName, callback)
+    {
+        if (!RuntimeAgent.getOwnPropertyDescriptor) {
+            function backendGetOwnPropertyDescriptor(propertyName)
+            {
+                return this[propertyName];
+            }
+
+            function wrappedCallback(error, result, wasThrown)
+            {
+                if (error || wasThrown || !(result instanceof WebInspector.RemoteObject)) {
+                    callback(null);
+                    return;
+                }
+
+                var fakeDescriptor = {name: propertyName, value: result, writable: true, configurable: true, enumerable: false};
+                var fakePropertyDescriptor = new WebInspector.PropertyDescriptor(fakeDescriptor, true, false, false, false);
+                callback(fakePropertyDescriptor);
+            }
+
+            this.callFunction(backendGetOwnPropertyDescriptor, [propertyName], false, wrappedCallback);
+        }
+
+        // FIXME: Implement a real getOwnPropertyDescriptor?
+    },
+
     release: function()
     {
         RuntimeAgent.releaseObject(this._objectId);

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageImpl.js (180712 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageImpl.js	2015-02-27 01:04:19 UTC (rev 180712)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageImpl.js	2015-02-27 01:15:15 UTC (rev 180713)
@@ -296,7 +296,8 @@
 
     _formatParameterAsObject: function(obj, elem, forceExpansion)
     {
-        var objectTree = new WebInspector.ObjectTreeView(obj, WebInspector.ObjectTreeView.Mode.Properties, forceExpansion);
+        // FIXME: Intialize component with "$n" instead of "obj". Or, an existing property path.
+        var objectTree = new WebInspector.ObjectTreeView(obj, WebInspector.ObjectTreeView.Mode.Properties, null, forceExpansion);
         elem.appendChild(objectTree.element);
     },
 
@@ -314,8 +315,9 @@
 
     _formatParameterAsArray: function(arr, elem)
     {
-        // FIXME: Array previews look poor. Keep doing what we currently do for arrays.
-        arr.deprecatedGetOwnProperties(this._printArray.bind(this, arr, elem));
+        // FIXME: Intialize component with "$n" instead of "obj". Or, an existing property path.
+        var objectTree = new WebInspector.ObjectTreeView(arr, WebInspector.ObjectTreeView.Mode.Properties);
+        elem.appendChild(objectTree.element);
     },
 
     _userProvidedColumnNames: function(columnNamesArgument)
@@ -439,57 +441,6 @@
         return element;
     },
 
-    _printArray: function(array, elem, properties)
-    {
-        if (!properties)
-            return;
-
-        var elements = [];
-        for (var i = 0; i < properties.length; ++i) {
-            var property = properties[i];
-            var name = property.name;
-            if (!isNaN(name))
-                elements[name] = this._formatAsArrayEntry(property.value);
-        }
-
-        elem.appendChild(document.createTextNode("["));
-        var lastNonEmptyIndex = -1;
-
-        function appendUndefined(elem, index)
-        {
-            if (index - lastNonEmptyIndex <= 1)
-                return;
-            var span = elem.createChild("span", "formatted-undefined");
-            span.textContent = WebInspector.UIString("undefined × %d").format(index - lastNonEmptyIndex - 1);
-        }
-
-        var length = array.arrayLength();
-        for (var i = 0; i < length; ++i) {
-            var element = elements[i];
-            if (!element)
-                continue;
-
-            if (i - lastNonEmptyIndex > 1) {
-                appendUndefined(elem, i);
-                elem.appendChild(document.createTextNode(", "));
-            }
-
-            elem.appendChild(element);
-            lastNonEmptyIndex = i;
-            if (i < length - 1)
-                elem.appendChild(document.createTextNode(", "));
-        }
-        appendUndefined(elem, length);
-
-        elem.appendChild(document.createTextNode("]"));
-    },
-
-    _formatAsArrayEntry: function(output)
-    {
-        // Prevent infinite expansion of cross-referencing arrays.
-        return this._formatParameter(output, output.subtype && output.subtype === "array");
-    },
-
     _formatWithSubstitutionString: function(parameters, formattedResult)
     {
         var formatters = {};

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/FormattedValue.css (180712 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Views/FormattedValue.css	2015-02-27 01:04:19 UTC (rev 180712)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/FormattedValue.css	2015-02-27 01:15:15 UTC (rev 180713)
@@ -30,6 +30,10 @@
     color: black;
 }
 
+.formatted-node > ol {
+    display: block !important;
+}
+
 .formatted-number {
     color: rgb(28, 0, 207);
 }

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/FormattedValue.js (180712 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Views/FormattedValue.js	2015-02-27 01:04:19 UTC (rev 180712)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/FormattedValue.js	2015-02-27 01:15:15 UTC (rev 180713)
@@ -111,3 +111,16 @@
 {
     return WebInspector.FormattedValue.createElementForTypesAndValue(propertyPreview.type, propertyPreview.subtype, propertyPreview.value, true, false);
 };
+
+WebInspector.FormattedValue.createObjectTreeOrFormattedValueForRemoteObject = function(object, propertyPath)
+{
+    if (object.subtype === "node")
+        return WebInspector.FormattedValue.createElementForNode(object);
+
+    if (object.type === "object") {
+        var objectTree = new WebInspector.ObjectTreeView(object, WebInspector.ObjectTreeView.Mode.Properties, propertyPath);
+        return objectTree.element;
+    }
+
+    return WebInspector.FormattedValue.createElementForRemoteObject(object);
+};

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.js (180712 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.js	2015-02-27 01:04:19 UTC (rev 180712)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.js	2015-02-27 01:15:15 UTC (rev 180713)
@@ -171,6 +171,7 @@
         if (preview.subtype === "date")
             return !preview.propertyPreviews.length;
 
+        // FIXME: Array previews should have better sparse support: (undefined × 10).
         var isArray = preview.subtype === "array";
 
         element.appendChild(document.createTextNode(isArray ? "[" : "{"));

Copied: trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeArrayIndexTreeElement.css (from rev 180712, trunk/Source/WebInspectorUI/UserInterface/Views/FormattedValue.css) (0 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeArrayIndexTreeElement.css	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeArrayIndexTreeElement.css	2015-02-27 01:15:15 UTC (rev 180713)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 Apple 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+.object-tree-array-index {
+    position: relative;
+    left: -12px;
+    margin-top: 2px;
+    margin-bottom: 1px;
+}
+
+.object-tree-array-index > .disclosure-button,
+.object-tree-array-index > .icon {
+    display: none;
+}
+
+.object-tree-array-index .index-name {
+    font-family: -webkit-system-font, sans-serif;
+    font-size: 11px;
+    vertical-align: top;
+    color: hsla(0, 0%, 0%, 0.33);
+
+    position:relative;
+    top: -1px;
+
+    display: inline-block;
+    width: 22px;
+    text-align: center;
+}
+
+/* FIXME: Should this be all the time? */
+.object-tree-array-index .index-value .object-tree {
+    display: inline-block;
+}
+
+/* An array inside an array we should reduce the padding-start. */
+.object-tree-array-index .index-value .object-tree .object-tree-outline {
+    -webkit-padding-start: 6px;
+}
+
+/* An array inside an ObjectTreePropertyTreeElement needs more left shift */
+.object-tree-property + ol .object-tree-array-index {
+    left: -18px;
+}

Added: trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeArrayIndexTreeElement.js (0 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeArrayIndexTreeElement.js	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeArrayIndexTreeElement.js	2015-02-27 01:15:15 UTC (rev 180713)
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2015 Apple 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+// FIXME: This should share more code with ObjectTreePropertyTreeElement.
+
+WebInspector.ObjectTreeArrayIndexTreeElement = function(property, propertyPath)
+{
+    console.assert(property instanceof WebInspector.PropertyDescriptor);
+    console.assert(propertyPath instanceof WebInspector.PropertyPath);
+    console.assert(property.isIndexProperty(), "ArrayIndexTreeElement expects numeric property names");
+
+    this._property = property;
+    this._propertyPath = propertyPath;
+
+    var classNames = ["object-tree-property", "object-tree-array-index"];
+    if (!this._property.hasValue())
+        classNames.push("accessor");
+
+    WebInspector.GeneralTreeElement.call(this, classNames, this._titleFragment(), null, this._property, false);
+
+    this.small = true;
+    this.toggleOnClick = false;
+    this.selectable = false;
+    this.tooltipHandledSeparately = true;
+    this.hasChildren = false;
+};
+
+WebInspector.ObjectTreeArrayIndexTreeElement.prototype = {
+    constructor: WebInspector.ObjectTreeArrayIndexTreeElement,
+    __proto__: WebInspector.GeneralTreeElement.prototype,
+
+    // Public
+
+    get property()
+    {
+        return this._property;
+    },
+
+    // Private
+
+    _resolvedValue: function()
+    {
+        if (this._getterValue)
+            return this._getterValue;
+        if (this._property.hasValue())
+            return this._property.value;
+        return null;
+    },
+
+    _propertyPathType: function()
+    {
+        if (this._getterValue || this._property.hasValue())
+            return WebInspector.PropertyPath.Type.Value;
+        if (this._property.hasGetter())
+            return WebInspector.PropertyPath.Type.Getter;
+        if (this._property.hasSetter())
+            return WebInspector.PropertyPath.Type.Setter;
+        return WebInspector.PropertyPath.Type.Value;
+    },
+
+    _resolvedValuePropertyPath: function()
+    {
+        if (this._getterValue)
+            return this._propertyPath.appendPropertyDescriptor(this._getterValue, this._property, WebInspector.PropertyPath.Type.Value);
+        if (this._property.hasValue())
+            return this._propertyPath.appendPropertyDescriptor(this._property.value, this._property, WebInspector.PropertyPath.Type.Value);
+        return null;
+    },
+
+    _thisPropertyPath: function()
+    {
+        return this._propertyPath.appendPropertyDescriptor(null, this._property, this._propertyPathType());
+    },
+
+    _propertyPathString: function(propertyPath)
+    {
+        if (propertyPath.isFullPathImpossible())
+            return WebInspector.UIString("Unable to determine path to property from root");
+
+        return propertyPath.displayPath(this._propertyPathType());
+    },
+
+    _updateTitle: function()
+    {
+        this.mainTitle = this._titleFragment();
+
+        if (this._getterValue)
+            this.removeClassName("accessor");
+
+        this._updateHasChildren();
+    },
+
+    _titleFragment: function()
+    {
+        var container = document.createDocumentFragment();
+
+        // Array index name.
+        var nameElement = container.appendChild(document.createElement("span"));
+        nameElement.className = "index-name";
+        nameElement.textContent = this._property.name;
+        nameElement.title = this._propertyPathString(this._thisPropertyPath());
+
+        // Value.
+        var valueElement = container.appendChild(document.createElement("span"));
+        valueElement.className = "index-value";
+
+        var resolvedValue = this._resolvedValue();
+        if (resolvedValue)
+            valueElement.appendChild(WebInspector.FormattedValue.createObjectTreeOrFormattedValueForRemoteObject(resolvedValue, this._resolvedValuePropertyPath()));
+        else {
+            if (this._property.hasGetter())
+                container.appendChild(this._createInteractiveGetterElement());
+            if (!this._property.hasSetter())
+                container.appendChild(this._createReadOnlyIconElement());
+            // FIXME: What if just a setter?
+        }
+
+        valueElement.classList.add("value");
+        if (this._property.wasThrown || this._getterHadError)
+            valueElement.classList.add("error");
+
+        return container;
+    },
+
+    _createInteractiveGetterElement: function()
+    {
+        var getterElement = document.createElement("img");
+        getterElement.className = "getter";
+        getterElement.title = WebInspector.UIString("Invoke getter");
+
+        getterElement.addEventListener("click", function(event) {
+            event.stopPropagation();
+            var lastNonPrototypeObject = this._propertyPath.lastNonPrototypeObject;
+            var getterObject = this._property.get;
+            lastNonPrototypeObject.invokeGetter(getterObject, function(error, result, wasThrown) {
+                this._getterHadError = !!(error || wasThrown);
+                this._getterValue = result;
+                this._updateTitle();
+            }.bind(this));
+        }.bind(this));
+
+        return getterElement;
+    },
+
+    _createReadOnlyIconElement: function()
+    {
+        var readOnlyElement = document.createElement("img");
+        readOnlyElement.className = "read-only";
+        readOnlyElement.title = WebInspector.UIString("Read only");
+        return readOnlyElement;
+    },
+};

Deleted: trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeCollectionTreeElement.js (180712 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeCollectionTreeElement.js	2015-02-27 01:04:19 UTC (rev 180712)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeCollectionTreeElement.js	2015-02-27 01:15:15 UTC (rev 180713)
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2015 Apple 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. AND ITS CONTRIBUTORS ``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 ITS 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.ObjectTreeCollectionTreeElement = function(remoteObject)
-{
-    console.assert(remoteObject instanceof WebInspector.RemoteObject);
-
-    this._remoteObject = remoteObject;
-    this._requestingEntries = false;
-    this._trackingEntries = false;
-
-    TreeElement.call(this, "<entries>", null, false);
-    this.toggleOnClick = true;
-    this.selectable = false;
-    this.hasChildren = true;
-    this.expand();
-
-    // FIXME: When a parent TreeElement is collapsed, we do not get a chance
-    // to releaseWeakCollectionEntries. We should.
-};
-
-WebInspector.ObjectTreeCollectionTreeElement.propertyDescriptorForEntry = function(name, value)
-{
-    var descriptor = {name: name, value: value, enumerable: true, writable: false};
-    return new WebInspector.PropertyDescriptor(descriptor, true, false, false);
-}
-
-WebInspector.ObjectTreeCollectionTreeElement.prototype = {
-    constructor: WebInspector.ObjectTreeCollectionTreeElement,
-    __proto__: TreeElement.prototype,
-
-    // Public
-
-    get remoteObject()
-    {
-        return this._remoteObject;
-    },
-
-    // Protected
-
-    onexpand: function()
-    {
-        if (this.children.length && !this.shouldRefreshChildren)
-            return;
-
-        if (this._requestingEntries)
-            return;
-
-        this._requestingEntries = true;
-
-        function callback(entries) {
-            this._requestingEntries = false;
-
-            this.removeChildren();
-
-            if (!entries || !entries.length) {
-                this.appendChild(new WebInspector.ObjectTreeEmptyCollectionTreeElement);
-                return;
-            }
-
-            this._trackWeakEntries();
-
-            for (var i = 0; i < entries.length; ++i) {
-                var entry = entries[i];
-                if (entry.key)
-                    this.appendChild(new WebInspector.ObjectTreeCollectionEntryTreeElement(entry, i));
-                else {
-                    var propertyDescriptor = WebInspector.ObjectTreeCollectionTreeElement.propertyDescriptorForEntry("" + i, entry.value);
-                    this.appendChild(new WebInspector.ObjectTreePropertyTreeElement(propertyDescriptor));
-                }
-            }
-        }
-
-        this._remoteObject.getCollectionEntries(0, 100, callback.bind(this));
-    },
-
-    oncollapse: function()
-    {
-        this._untrackWeakEntries();
-    },
-
-    ondetach: function()
-    {
-        this._untrackWeakEntries();
-    },
-
-    // Private.
-
-    _trackWeakEntries: function()
-    {
-        if (!this._remoteObject.isWeakCollection())
-            return;
-
-        if (this._trackingEntries)
-            return;
-
-        this._trackingEntries = true;
-
-        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.Cleared, this._untrackWeakEntries, this);
-        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.ActiveLogCleared, this._untrackWeakEntries, this);
-        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.SessionStarted, this._untrackWeakEntries, this);
-    },
-
-    _untrackWeakEntries: function()
-    {
-        if (!this._remoteObject.isWeakCollection())
-            return;
-
-        if (!this._trackingEntries)
-            return;
-
-        this._trackingEntries = false;
-
-        this._remoteObject.releaseWeakCollectionEntries();
-
-        WebInspector.logManager.removeEventListener(WebInspector.LogManager.Event.Cleared, this._untrackWeakEntries, this);
-        WebInspector.logManager.removeEventListener(WebInspector.LogManager.Event.ActiveLogCleared, this._untrackWeakEntries, this);
-        WebInspector.logManager.removeEventListener(WebInspector.LogManager.Event.SessionStarted, this._untrackWeakEntries, this);
-
-        this.removeChildren();
-
-        if (this.expanded)
-            this.collapse();
-    },
-};
-
-WebInspector.ObjectTreeCollectionEntryTreeElement = function(entry, index)
-{
-    console.assert(entry instanceof WebInspector.CollectionEntry);
-    console.assert(entry.key instanceof WebInspector.RemoteObject);
-    console.assert(entry.value instanceof WebInspector.RemoteObject);
-
-    this._name = "" + index;
-    this._key = entry.key;
-    this._value = entry.value;
-
-    TreeElement.call(this, "", null, false);
-    this.toggleOnClick = true;
-    this.selectable = false;
-    this.hasChildren = true;
-}
-
-WebInspector.ObjectTreeCollectionEntryTreeElement.prototype = {
-    constructor: WebInspector.ObjectTreeCollectionEntryTreeElement,
-    __proto__: TreeElement.prototype,
-
-    // Protected
-
-    onpopulate: function()
-    {
-        if (this.children.length && !this.shouldRefreshChildren)
-            return;
-
-        var keyPropertyDescriptor = WebInspector.ObjectTreeCollectionTreeElement.propertyDescriptorForEntry("key", this._key);
-        this.appendChild(new WebInspector.ObjectTreePropertyTreeElement(keyPropertyDescriptor));
-
-        var valuePropertyDescriptor = WebInspector.ObjectTreeCollectionTreeElement.propertyDescriptorForEntry("value", this._value);
-        this.appendChild(new WebInspector.ObjectTreePropertyTreeElement(valuePropertyDescriptor));
-    },
-
-    onattach: function()
-    {
-        var nameElement = document.createElement("span");
-        nameElement.className = "name";
-        nameElement.textContent = "" + this._name;
-
-        var separatorElement = document.createElement("span");
-        separatorElement.className = "separator";
-        separatorElement.textContent = ": ";
-
-        var valueElement = document.createElement("span");
-        valueElement.className = "value";
-        valueElement.textContent = "{" + this._key.description + " => " + this._value.description + "}";
-
-        this.listItemElement.classList.add("object-tree-property");
-
-        this.listItemElement.removeChildren();
-        this.listItemElement.appendChild(nameElement);
-        this.listItemElement.appendChild(separatorElement);
-        this.listItemElement.appendChild(valueElement);
-    }
-};
-
-WebInspector.ObjectTreeEmptyCollectionTreeElement = function()
-{
-    TreeElement.call(this, WebInspector.UIString("Empty Collection"), null, false);
-    this.selectable = false;
-}
-
-WebInspector.ObjectTreeEmptyCollectionTreeElement.prototype = {
-    constructor: WebInspector.ObjectTreeEmptyCollectionTreeElement,
-    __proto__: TreeElement.prototype
-};

Copied: trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeMapEntryTreeElement.css (from rev 180712, trunk/Source/WebInspectorUI/UserInterface/Views/FormattedValue.css) (0 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeMapEntryTreeElement.css	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeMapEntryTreeElement.css	2015-02-27 01:15:15 UTC (rev 180713)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015 Apple 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+.object-tree-array-index.object-tree-map-entry > .titles > .title > .index-name {
+    width: 37px;
+    text-align: right;
+    margin-right: 5px;
+}
+
+.object-tree-map-entry.key {
+    border-top: 1px solid hsl(0, 0%, 96%);
+}
+
+.object-tree-map-entry.key:first-of-type {
+    border-top: none;
+}
+
+.object-tree-map-entry {
+    padding-top: 2px;
+    padding-bottom: 2px;
+}

Added: trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeMapEntryTreeElement.js (0 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeMapEntryTreeElement.js	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeMapEntryTreeElement.js	2015-02-27 01:15:15 UTC (rev 180713)
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2015 Apple 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. AND ITS CONTRIBUTORS ``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 ITS 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.ObjectTreeMapEntryTreeElement = function(object, propertyPath)
+{
+    console.assert(object instanceof WebInspector.RemoteObject);
+    console.assert(propertyPath instanceof WebInspector.PropertyPath);
+
+    this._object = object;
+    this._propertyPath = propertyPath;
+
+    // Treat the same as an array-index just with different strings and widths.
+    WebInspector.GeneralTreeElement.call(this, ["object-tree-array-index", "object-tree-map-entry"], this._titleFragment(), null, this._object, false);
+
+    this.small = true;
+    this.toggleOnClick = false;
+    this.selectable = false;
+    this.tooltipHandledSeparately = true;
+    this.hasChildren = false;
+};
+
+WebInspector.ObjectTreeMapEntryTreeElement.prototype = {
+    constructor: WebInspector.ObjectTreeMapEntryTreeElement,
+    __proto__: WebInspector.GeneralTreeElement.prototype,
+
+    // Public
+
+    get object()
+    {
+        return this._object;
+    },
+
+    // Private
+
+    _propertyPathString: function(propertyPath)
+    {
+        if (propertyPath.isFullPathImpossible())
+            return WebInspector.UIString("Unable to determine path to property from root");
+
+        return propertyPath.displayPath(WebInspector.PropertyPath.Type.Value);
+    },
+
+    _titleFragment: function()
+    {
+        var container = document.createDocumentFragment();
+
+        var propertyPath = this.resolvedValuePropertyPath();
+
+        // Index name.
+        var nameElement = container.appendChild(document.createElement("span"));
+        nameElement.className = "index-name";
+        nameElement.textContent = this.displayPropertyName();
+        nameElement.title = this._propertyPathString(propertyPath);
+
+        // Value.
+        var valueElement = container.appendChild(document.createElement("span"));
+        valueElement.className = "index-value";
+        valueElement.appendChild(WebInspector.FormattedValue.createObjectTreeOrFormattedValueForRemoteObject(this._object, propertyPath));
+
+        return container;
+    }
+};
+
+
+WebInspector.ObjectTreeMapKeyTreeElement = function(object, propertyPath)
+{
+    WebInspector.ObjectTreeMapEntryTreeElement.call(this, object, propertyPath);
+    this.addClassName("key");
+}
+
+WebInspector.ObjectTreeMapKeyTreeElement.prototype = {
+    constructor: WebInspector.ObjectTreeMapKeyTreeElement,
+    __proto__: WebInspector.ObjectTreeMapEntryTreeElement.prototype,
+
+    // Protected
+
+    displayPropertyName: function()
+    {
+        return WebInspector.UIString("key");
+    },
+
+    resolvedValuePropertyPath: function()
+    {
+        return this._propertyPath.appendMapKey(this._object);
+    }
+};
+
+
+WebInspector.ObjectTreeMapValueTreeElement = function(object, propertyPath, key)
+{
+    this._key = key;
+    WebInspector.ObjectTreeMapEntryTreeElement.call(this, object, propertyPath);
+    this.addClassName("value");
+}
+
+WebInspector.ObjectTreeMapValueTreeElement.prototype = {
+    constructor: WebInspector.ObjectTreeMapValueTreeElement,
+    __proto__: WebInspector.ObjectTreeMapEntryTreeElement.prototype,
+
+    // Protected
+
+    displayPropertyName: function()
+    {
+        return WebInspector.UIString("value");
+    },
+
+    resolvedValuePropertyPath: function()
+    {
+        return this._propertyPath.appendMapValue(this._object, this._key);
+    }
+};

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.css (180712 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.css	2015-02-27 01:04:19 UTC (rev 180712)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.css	2015-02-27 01:15:15 UTC (rev 180713)
@@ -27,6 +27,16 @@
     margin-top: 1px;
 }
 
+.object-tree-property > .titles {
+    position: relative;
+    top: 2px;
+    line-height: normal;
+    padding-bottom: 1px;
+    text-overflow: ellipsis;
+    overflow: hidden;
+    white-space: nowrap;
+}
+
 .object-tree-property > .disclosure-button {
     float: left;
 
@@ -160,20 +170,6 @@
     margin-left: 3px;
 }
 
-.object-tree-property :matches(.formatted-string, .formatted-regexp) {
-    white-space: nowrap;
-}
-
 .object-tree-property .value.error {
     color: red;
 }
-
-.object-tree-property > .titles {
-    position: relative;
-    top: 2px;
-    line-height: normal;
-    padding-bottom: 1px;
-    text-overflow: ellipsis;
-    overflow: hidden;
-    white-space: nowrap;
-}

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.js (180712 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.js	2015-02-27 01:04:19 UTC (rev 180712)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.js	2015-02-27 01:15:15 UTC (rev 180713)
@@ -94,10 +94,8 @@
     {
         if (this._getterValue)
             return this._getterValue;
-
         if (this._property.hasValue())
             return this._property.value;
-
         return null;
     },
 
@@ -116,10 +114,8 @@
     {
         if (this._getterValue)
             return this._propertyPath.appendPropertyDescriptor(this._getterValue, this._property, WebInspector.PropertyPath.Type.Value);
-
         if (this._property.hasValue())
             return this._propertyPath.appendPropertyDescriptor(this._property.value, this._property, WebInspector.PropertyPath.Type.Value);
-
         return null;
     },
 
@@ -391,48 +387,84 @@
             return;
 
         var resolvedValue = this._resolvedValue();
-        var resolvedValuePropertyPath = this._resolvedValuePropertyPath();
+        if (resolvedValue.isCollectionType() && this._mode === WebInspector.ObjectTreeView.Mode.Properties)
+            resolvedValue.getCollectionEntries(0, 100, this._updateChildrenInternal.bind(this, this._updateEntries, this._mode));
+        else if (this._property.name === "__proto__")
+            resolvedValue.getOwnPropertyDescriptors(this._updateChildrenInternal.bind(this, this._updateProperties, WebInspector.ObjectTreeView.Mode.API));
+        else
+            resolvedValue.getDisplayablePropertyDescriptors(this._updateChildrenInternal.bind(this, this._updateProperties, this._mode));
+    },
 
-        function callback(mode, properties)
-        {
-            this.removeChildren();
+    _updateChildrenInternal: function(handler, mode, list)
+    {
+        this.removeChildren();
 
-            if (!properties) {
-                var errorMessageElement = document.createElement("div");
-                errorMessageElement.className = "empty-message";
-                errorMessageElement.textContent = WebInspector.UIString("Could not fetch properties. Object may no longer exist.");;
-                this.appendChild(new TreeElement(errorMessageElement, null, false));
-                return;
-            }
+        if (!list) {
+            var errorMessageElement = WebInspector.ObjectTreeView.emptyMessageElement(WebInspector.UIString("Could not fetch properties. Object may no longer exist."));
+            this.appendChild(new TreeElement(errorMessageElement, null, false));
+            return;
+        }
 
-            var prototypeName = undefined;
-            if (this._property.name === "__proto__") {
-                if (resolvedValue.description)
-                    prototypeName = this._sanitizedPrototypeString(resolvedValue);
-            }
+        handler.call(this, list, this._resolvedValuePropertyPath(), mode);
+    },
 
-            var isAPI = mode === WebInspector.ObjectTreeView.Mode.API;
+    _updateEntries: function(entries, propertyPath, mode)
+    {
+        for (var entry of entries) {
+            if (entry.key) {
+                this.appendChild(new WebInspector.ObjectTreeMapKeyTreeElement(entry.key, propertyPath));
+                this.appendChild(new WebInspector.ObjectTreeMapValueTreeElement(entry.value, propertyPath, entry.key));
+            } else
+                this.appendChild(new WebInspector.ObjectTreeSetIndexTreeElement(entry.value, propertyPath));
+        }
 
-            properties.sort(WebInspector.ObjectTreeView.ComparePropertyDescriptors);
-            for (var propertyDescriptor of properties) {
-                // FIXME: If this is a pure API ObjectTree, we should show the native getters.
-                // For now, just skip native binding getters in API mode, since we likely
-                // already showed them in the Properties section.
-                if (isAPI && propertyDescriptor.nativeGetter)
-                    continue;
-                this.appendChild(new WebInspector.ObjectTreePropertyTreeElement(propertyDescriptor, resolvedValuePropertyPath, mode, prototypeName));
-            }
+        if (!this.children.length) {
+            var emptyMessageElement = WebInspector.ObjectTreeView.emptyMessageElement(WebInspector.UIString("No Entries."));
+            this.appendChild(new TreeElement(emptyMessageElement, null, false));
+        }
 
-            // FIXME: Re-enable Collection Entries with new UI.
-            // if (mode === WebInspector.ObjectTreeView.Mode.Properties) {
-            //     if (resolvedValue.isCollectionType())
-            //         this.appendChild(new WebInspector.ObjectTreeCollectionTreeElement(resolvedValue));
-            // }
-        };
+        // Show the prototype so users can see the API.
+        var resolvedValue = this._resolvedValue();
+        resolvedValue.getOwnPropertyDescriptor("__proto__", function(propertyDescriptor) {
+            if (propertyDescriptor)
+                this.appendChild(new WebInspector.ObjectTreePropertyTreeElement(propertyDescriptor, propertyPath, mode));
+        }.bind(this));
+    },
 
-        if (this._property.name === "__proto__")
-            resolvedValue.getOwnPropertyDescriptors(callback.bind(this, WebInspector.ObjectTreeView.Mode.API));
-        else
-            resolvedValue.getDisplayablePropertyDescriptors(callback.bind(this, this._mode));
-    },
+    _updateProperties: function(properties, propertyPath, mode)
+    {
+        properties.sort(WebInspector.ObjectTreeView.ComparePropertyDescriptors);
+
+        var resolvedValue = this._resolvedValue();
+        var isArray = resolvedValue.isArray();
+        var isPropertyMode = mode === WebInspector.ObjectTreeView.Mode.Properties || this._getterValue;
+        var isAPI = mode === WebInspector.ObjectTreeView.Mode.API;
+
+        var prototypeName = undefined;
+        if (this._property.name === "__proto__") {
+            if (resolvedValue.description)
+                prototypeName = this._sanitizedPrototypeString(resolvedValue);
+        }
+
+        for (var propertyDescriptor of properties) {
+            // FIXME: If this is a pure API ObjectTree, we should show the native getters.
+            // For now, just skip native binding getters in API mode, since we likely
+            // already showed them in the Properties section.
+            if (isAPI && propertyDescriptor.nativeGetter)
+                continue;
+            
+            if (isArray && isPropertyMode) {
+                if (propertyDescriptor.isIndexProperty())
+                    this.appendChild(new WebInspector.ObjectTreeArrayIndexTreeElement(propertyDescriptor, propertyPath));
+                else if (propertyDescriptor.name === "__proto__")
+                    this.appendChild(new WebInspector.ObjectTreePropertyTreeElement(propertyDescriptor, propertyPath, mode, prototypeName));
+            } else
+                this.appendChild(new WebInspector.ObjectTreePropertyTreeElement(propertyDescriptor, propertyPath, mode, prototypeName));
+        }
+
+        if (!this.children.length) {
+            var emptyMessageElement = WebInspector.ObjectTreeView.emptyMessageElement(WebInspector.UIString("No Properties."));
+            this.appendChild(new TreeElement(emptyMessageElement, null, false));
+        }
+    }
 };

Added: trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeSetIndexTreeElement.js (0 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeSetIndexTreeElement.js	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeSetIndexTreeElement.js	2015-02-27 01:15:15 UTC (rev 180713)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 Apple 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. AND ITS CONTRIBUTORS ``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 ITS 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.ObjectTreeSetIndexTreeElement = function(object, propertyPath)
+{
+    console.assert(object instanceof WebInspector.RemoteObject);
+
+    this._object = object;
+    this._propertyPath = propertyPath;
+
+    // Treat the same as an array-index just with a different character.
+    WebInspector.GeneralTreeElement.call(this, ["object-tree-array-index"], this._titleFragment(), null, this._object, false);
+
+    this.small = true;
+    this.toggleOnClick = false;
+    this.selectable = false;
+    this.tooltipHandledSeparately = true;
+    this.hasChildren = false;
+};
+
+WebInspector.ObjectTreeSetIndexTreeElement.prototype = {
+    constructor: WebInspector.ObjectTreeSetIndexTreeElement,
+    __proto__: WebInspector.GeneralTreeElement.prototype,
+
+    // Public
+
+    get object()
+    {
+        return this._object;
+    },
+
+    // Private
+
+    _resolvedValuePropertyPath: function()
+    {
+        return this._propertyPath.appendSetIndex(this._object);
+    },
+
+    _titleFragment: function()
+    {
+        var container = document.createDocumentFragment();
+
+        // Set bullet.
+        var nameElement = container.appendChild(document.createElement("span"));
+        nameElement.className = "index-name";
+        nameElement.textContent = "\u2022";
+        nameElement.title = WebInspector.UIString("Unable to determine path to property from root");
+
+        // Value.
+        var valueElement = container.appendChild(document.createElement("span"));
+        valueElement.className = "index-value";
+        valueElement.appendChild(WebInspector.FormattedValue.createObjectTreeOrFormattedValueForRemoteObject(this._object, this._resolvedValuePropertyPath()));
+
+        return container;
+    }
+};

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.css (180712 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.css	2015-02-27 01:04:19 UTC (rev 180712)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.css	2015-02-27 01:15:15 UTC (rev 180713)
@@ -105,3 +105,7 @@
     font-family: sans-serif;
     font-size: 12px;
 }
+
+.object-tree-property :matches(.formatted-string, .formatted-regexp) {
+    white-space: nowrap;
+}

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.js (180712 => 180713)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.js	2015-02-27 01:04:19 UTC (rev 180712)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.js	2015-02-27 01:15:15 UTC (rev 180713)
@@ -23,17 +23,24 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.ObjectTreeView = function(object, mode, forceExpanding)
+WebInspector.ObjectTreeView = function(object, mode, propertyPath, forceExpanding)
 {
     WebInspector.Object.call(this);
 
     console.assert(object instanceof WebInspector.RemoteObject);
+    console.assert(!propertyPath || propertyPath instanceof WebInspector.PropertyPath);
 
     this._object = object;
     this._mode = mode || WebInspector.ObjectTreeView.Mode.Properties;
+    this._propertyPath = propertyPath || new WebInspector.PropertyPath(this._object, "obj");
     this._expanded = false;
     this._hasLosslessPreview = false;
 
+    // If ObjectTree is used outside of the console, we do not know when to release
+    // WeakMap entries. Currently collapse would work. For the console, we can just
+    // listen for console clear events. Currently all ObjectTrees are in the console.
+    this._inConsole = true;
+
     this._element = document.createElement("div");
     this._element.className = "object-tree";
 
@@ -62,6 +69,14 @@
     // FIXME: Support editable ObjectTrees.
 };
 
+WebInspector.ObjectTreeView.emptyMessageElement = function(message)
+{
+    var emptyMessageElement = document.createElement("div");
+    emptyMessageElement.className = "empty-message";
+    emptyMessageElement.textContent = message;
+    return emptyMessageElement;
+};
+
 WebInspector.ObjectTreeView.Mode = {
     Properties: Symbol("object-tree-properties"),
     API: Symbol("object-tree-api"),
@@ -152,6 +167,8 @@
         if (this._previewView)
             this._previewView.showTitle();
 
+        this._trackWeakEntries();
+
         this.update();
     },
 
@@ -165,47 +182,76 @@
 
         if (this._previewView)
             this._previewView.showPreview();
+
+        this._untrackWeakEntries();
     },
 
     // Protected
 
     update: function()
     {
-        this._object.getDisplayablePropertyDescriptors(this._updateProperties.bind(this));
+        if (this._object.isCollectionType() && this._mode === WebInspector.ObjectTreeView.Mode.Properties)
+            this._object.getCollectionEntries(0, 100, this._updateChildren.bind(this, this._updateEntries));
+        else
+            this._object.getDisplayablePropertyDescriptors(this._updateChildren.bind(this, this._updateProperties));
     },
 
     // Private
 
-    _updateProperties: function(properties)
+    _updateChildren: function(handler, list)
     {
         this._outline.removeChildren();
 
-        if (!properties) {
-            var errorMessageElement = document.createElement("div");
-            errorMessageElement.className = "empty-message";
-            errorMessageElement.textContent = WebInspector.UIString("Could not fetch properties. Object may no longer exist.");;
+        if (!list) {
+            var errorMessageElement = WebInspector.ObjectTreeView.emptyMessageElement(WebInspector.UIString("Could not fetch properties. Object may no longer exist."));
             this._outline.appendChild(new TreeElement(errorMessageElement, null, false));
             return;
         }
 
+        handler.call(this, list, this._propertyPath);
+    },
+
+    _updateEntries: function(entries, propertyPath)
+    {
+        for (var entry of entries) {
+            if (entry.key) {
+                this._outline.appendChild(new WebInspector.ObjectTreeMapKeyTreeElement(entry.key, propertyPath));
+                this._outline.appendChild(new WebInspector.ObjectTreeMapValueTreeElement(entry.value, propertyPath, entry.key));
+            } else
+                this._outline.appendChild(new WebInspector.ObjectTreeSetIndexTreeElement(entry.value, propertyPath));
+        }
+
+        if (!this._outline.children.length) {
+            var emptyMessageElement = WebInspector.ObjectTreeView.emptyMessageElement(WebInspector.UIString("No Entries."));
+            this._outline.appendChild(new TreeElement(emptyMessageElement, null, false));
+        }
+
+        // Show the prototype so users can see the API.
+        this._object.getOwnPropertyDescriptor("__proto__", function(propertyDescriptor) {
+            if (propertyDescriptor)
+                this._outline.appendChild(new WebInspector.ObjectTreePropertyTreeElement(propertyDescriptor, propertyPath, this._mode));
+        }.bind(this));
+    },
+
+    _updateProperties: function(properties, propertyPath)
+    {
         properties.sort(WebInspector.ObjectTreeView.ComparePropertyDescriptors);
 
-        // FIXME: Intialize component with "$n" instead of "obj".
-        var rootPropertyPath = new WebInspector.PropertyPath(this._object, "obj");
+        var isArray = this._object.isArray();
+        var isPropertyMode = this._mode === WebInspector.ObjectTreeView.Mode.Properties;
 
-        for (var propertyDescriptor of properties)
-            this._outline.appendChild(new WebInspector.ObjectTreePropertyTreeElement(propertyDescriptor, rootPropertyPath, this._mode));
+        for (var propertyDescriptor of properties) {
+            if (isArray && isPropertyMode) {
+                if (propertyDescriptor.isIndexProperty())
+                    this._outline.appendChild(new WebInspector.ObjectTreeArrayIndexTreeElement(propertyDescriptor, propertyPath));
+                else if (propertyDescriptor.name === "__proto__")
+                    this._outline.appendChild(new WebInspector.ObjectTreePropertyTreeElement(propertyDescriptor, propertyPath, this._mode));
+            } else
+                this._outline.appendChild(new WebInspector.ObjectTreePropertyTreeElement(propertyDescriptor, propertyPath, this._mode));
+        }
 
-        // FIXME: Re-enable Collection Entries with new UI.
-        // if (this._mode === WebInspector.ObjectTreeView.Mode.Properties) {
-        //     if (this._object.isCollectionType())
-        //         this._outline.appendChild(new WebInspector.ObjectTreeCollectionTreeElement(this._object));
-        // }
-
         if (!this._outline.children.length) {
-            var emptyMessageElement = document.createElement("div");
-            emptyMessageElement.className = "empty-message";
-            emptyMessageElement.textContent = WebInspector.UIString("No Properties");;
+            var emptyMessageElement = WebInspector.ObjectTreeView.emptyMessageElement(WebInspector.UIString("No Properties."));
             this._outline.appendChild(new TreeElement(emptyMessageElement, null, false));
         }
     },
@@ -221,5 +267,45 @@
             this.collapse();
 
         event.stopPropagation();
-    }
+    },
+
+    _trackWeakEntries: function()
+    {
+        if (this._trackingEntries)
+            return;
+
+        if (!this._object.isWeakCollection())
+            return;
+
+        this._trackingEntries = true;
+
+        if (this._inConsole) {
+            WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.Cleared, this._untrackWeakEntries, this);
+            WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.ActiveLogCleared, this._untrackWeakEntries, this);
+            WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.SessionStarted, this._untrackWeakEntries, this);
+        }
+    },
+
+    _untrackWeakEntries: function()
+    {
+        if (!this._trackingEntries)
+            return;
+
+        if (!this._object.isWeakCollection())
+            return;
+
+        this._trackingEntries = false;
+
+        this._object.releaseWeakCollectionEntries();
+
+        if (this._inConsole) {
+            WebInspector.logManager.removeEventListener(WebInspector.LogManager.Event.Cleared, this._untrackWeakEntries, this);
+            WebInspector.logManager.removeEventListener(WebInspector.LogManager.Event.ActiveLogCleared, this._untrackWeakEntries, this);
+            WebInspector.logManager.removeEventListener(WebInspector.LogManager.Event.SessionStarted, this._untrackWeakEntries, this);
+        }
+
+        // FIXME: This only tries to release weak entries if this object was a WeakMap.
+        // If there was a WeakMap expanded in a sub-object, we will never release those values.
+        // Should we attempt walking the entire tree and release weak collections?
+    },
 };
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to