Web Inspector: Create Separate Model and View Objects for RemoteObjects / ObjectPrevi...
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 19 Feb 2015 20:25:04 +0000 (20:25 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 19 Feb 2015 20:25:04 +0000 (20:25 +0000)
https://bugs.webkit.org/show_bug.cgi?id=141696

Reviewed by Timothy Hatcher.

Source/WebInspectorUI:

* UserInterface/Main.html:
Add new files.

* UserInterface/Models/CollectionEntry.js: Added.
(WebInspector.CollectionEntry):
(WebInspector.CollectionEntry.fromPayload):
(WebInspector.CollectionEntry.prototype.get key):
(WebInspector.CollectionEntry.prototype.get value):
* UserInterface/Models/CollectionEntryPreview.js: Added.
(WebInspector.CollectionEntryPreview):
(WebInspector.CollectionEntryPreview.fromPayload):
(WebInspector.CollectionEntryPreview.prototype.get keyPreview):
(WebInspector.CollectionEntryPreview.prototype.get valuePreview):
* UserInterface/Models/ObjectPreview.js: Added.
(WebInspector.ObjectPreview):
(WebInspector.ObjectPreview.fromPayload):
(WebInspector.ObjectPreview.prototype.get type):
(WebInspector.ObjectPreview.prototype.get subtype):
(WebInspector.ObjectPreview.prototype.get description):
(WebInspector.ObjectPreview.prototype.get lossless):
(WebInspector.ObjectPreview.prototype.get overflow):
(WebInspector.ObjectPreview.prototype.get properties):
(WebInspector.ObjectPreview.prototype.get entries):
* UserInterface/Models/PropertyPreview.js: Added.
(WebInspector.PropertyPreview):
(WebInspector.PropertyPreview.fromPayload):
(WebInspector.PropertyPreview.prototype.get name):
(WebInspector.PropertyPreview.prototype.get type):
(WebInspector.PropertyPreview.prototype.get subtype):
(WebInspector.PropertyPreview.prototype.get value):
(WebInspector.PropertyPreview.prototype.get valuePreview):
* UserInterface/Models/PropertyDescriptor.js: Added.
(WebInspector.PropertyDescriptor.fromPayload):
(WebInspector.PropertyDescriptor.prototype.get name):
(WebInspector.PropertyDescriptor.prototype.get value):
(WebInspector.PropertyDescriptor.prototype.get writable):
(WebInspector.PropertyDescriptor.prototype.get configurable):
(WebInspector.PropertyDescriptor.prototype.get enumerable):
(WebInspector.PropertyDescriptor.prototype.get isOwnProperty):
(WebInspector.PropertyDescriptor.prototype.get wasThrown):
(WebInspector.PropertyDescriptor.prototype.get isInternalProperty):
(WebInspector.PropertyDescriptor.prototype.hasValue):
(WebInspector.PropertyDescriptor.prototype.hasGetter):
(WebInspector.PropertyDescriptor.prototype.hasSetter):
New Model objects for different Protocol types.
The only customizations right now are compatibility modifications
and PropertyDescriptor's "hasValue", "hasGetter", and "hasSetter"
functions to return reliable checks based on the descriptors contents.

* UserInterface/Protocol/RemoteObject.js:
(WebInspector.RemoteObject):
(WebInspector.RemoteObject.fromPayload):
(WebInspector.RemoteObject.resolveNode):
(WebInspector.RemoteObject.prototype.get value):
(WebInspector.RemoteObject.prototype._isSymbol):
(WebInspector.RemoteObject.prototype.isCollectionType):
(WebInspector.RemoteObject.prototype.isWeakCollection):
(WebInspector.RemoteObject.prototype.getCollectionEntries):
(WebInspector.RemoteObject.prototype.arrayLength):
Clean up the existing code to enforce more checks and use our
style of member variables and public accessors.

(WebInspector.RemoteObject.prototype.getOwnPropertyDescriptors):
(WebInspector.RemoteObject.prototype.getOwnAndGetterPropertyDescriptors):
(WebInspector.RemoteObject.prototype.getAllPropertyDescriptors):
(WebInspector.RemoteObject.prototype.callback):
Provide a new way of getting properties that returns Model objects
instead of raw protocol types.

* UserInterface/Views/ConsoleMessageImpl.js:
(WebInspector.ConsoleMessageImpl.prototype._format):
(WebInspector.ConsoleMessageImpl.prototype._formatParameter):
(WebInspector.ConsoleMessageImpl.prototype._propertyPreviewElement):
(WebInspector.ConsoleMessageImpl.prototype._formatParameterAsNode):
(WebInspector.ConsoleMessageImpl.prototype._formatParameterAsTable):
(WebInspector.ConsoleMessageImpl.prototype._formatAsArrayEntry):
Always include a preview when possible. Now, when forced to be an object,
force expansion even if the preview is lossless.

(WebInspector.ConsoleMessageImpl.prototype._formatParameterAsObject):
Use an ObjectTreeView instead of ObjectPropertiesSection.

(WebInspector.ConsoleMessageImpl.prototype._appendPreview): Deleted.
(WebInspector.ConsoleMessageImpl.prototype._appendEntryPreviews): Deleted.
(WebInspector.ConsoleMessageImpl.prototype._appendPropertyPreviews): Deleted.
(WebInspector.ConsoleMessageImpl.prototype._appendValuePreview): Deleted.
This code is moved into ObjectPreviewView.

* UserInterface/Views/ObjectPropertiesSection.js:
(WebInspector.CollectionEntriesMainTreeElement.prototype.onexpand.callback):
(WebInspector.CollectionEntriesMainTreeElement.prototype.onexpand):
These types are now converted to Model types in Model objects, so do not do it here.

* UserInterface/Views/ObjectPreviewView.css: Added.
(.object-preview):
(.object-preview.lossless):
(.object-preview .name):
* UserInterface/Views/ObjectPreviewView.js: Added.
(WebInspector.ObjectPreviewView):
(WebInspector.ObjectPreviewView.prototype.get preview):
(WebInspector.ObjectPreviewView.prototype.get element):
(WebInspector.ObjectPreviewView.prototype.get mode):
(WebInspector.ObjectPreviewView.prototype.get lossless):
(WebInspector.ObjectPreviewView.prototype._numberOfPropertiesToShowInMode):
(WebInspector.ObjectPreviewView.prototype._appendPreview):
(WebInspector.ObjectPreviewView.prototype._appendEntryPreviews):
(WebInspector.ObjectPreviewView.prototype._appendPropertyPreviews):
(WebInspector.ObjectPreviewView.prototype._appendValuePreview):
(WebInspector.ObjectPreviewView.prototype._formattedObjectElementForPreview):
An ObjectPreviewView can create a full/brief view given a ObjectPreview.
The view will contain formatted values everywhere possible.

* UserInterface/Views/ObjectTreePropertyTreeElement.js: Added.
(WebInspector.ObjectTreePropertyTreeElement):
(WebInspector.ObjectTreePropertyTreeElement.prototype.get property):
(WebInspector.ObjectTreePropertyTreeElement.prototype.onpopulate):
(WebInspector.ObjectTreePropertyTreeElement.prototype.onattach):
(WebInspector.ObjectTreePropertyTreeElement.prototype._updateTitle):
(WebInspector.ObjectTreePropertyTreeElement.prototype._updateTitlePropertyStyle):
(WebInspector.ObjectTreePropertyTreeElement.prototype._updateTitleAPIStyle):
(WebInspector.ObjectTreePropertyTreeElement.prototype._descriptionString):
(WebInspector.ObjectTreePropertyTreeElement.prototype._functionParameterString):
(WebInspector.ObjectTreePropertyTreeElement.prototype.mode):
(WebInspector.ObjectTreePropertyTreeElement.prototype):
* UserInterface/Views/ObjectTreeView.js: Added.
(WebInspector.ObjectTreeView):
(WebInspector.ObjectTreeView.classNameForObject):
(WebInspector.ObjectTreeView.ComparePropertyDescriptors):
(WebInspector.ObjectTreeView.prototype.get object):
(WebInspector.ObjectTreeView.prototype.get element):
(WebInspector.ObjectTreeView.prototype.get expanded):
(WebInspector.ObjectTreeView.prototype.expand):
(WebInspector.ObjectTreeView.prototype.collapse):
(WebInspector.ObjectTreeView.prototype.update):
(WebInspector.ObjectTreeView.prototype._updateProperties):
(WebInspector.ObjectTreeView.prototype._handlePreviewOrTitleElementClick):
Re-implementation of ObjectPropertiesSection for our Model objects
without "Section" semantics / dependencies. An ObjectTree will creates
an expandable tree for a RemoteObject. The top level clickable item
will be an ObjectPreview if possible, otherwise just a title element.

* UserInterface/Views/ObjectTreeView.css: Added.
(.object-tree):
(.object-tree > .title):
(.object-tree > :matches(.title, .object-preview)::before):
(.object-tree.expanded > :matches(.title, .object-preview)::before):
(.object-tree.lossless-preview > :matches(.title, .object-preview)::before):
(.object-tree-outline):
(.object-tree.expanded > .object-tree-outline):
(.object-tree-outline li):
(.object-tree-outline li.parent):
(.object-tree-outline li.parent::before):
(.object-tree-outline li.parent.expanded::before):
(.object-tree-outline ol):
(.object-tree-outline ol.expanded):
(.object-tree-outline li .empty-message):
(.object-tree-property .name):
(.object-tree-property .name.not-enumerable):
(.object-tree-property .value.error):
(.formatted-object, .formatted-node, .formatted-error, .formatted-map, .formatted-set, .formatted-weakmap):
(.formatted-number):
(.formatted-string, .formatted-regexp):
(.formatted-string):
(.formatted-regexp):
(.formatted-symbol):
(.formatted-null, .formatted-undefined):
(.console-group-messages .object-tree:not(.lossless-preview)):
(.console-group-messages .object-tree:not(.lossless-preview) > :matches(.title, .object-preview)):
(.console-group-messages .object-tree:not(.lossless-preview) > :matches(.title, .object-preview)::before):
(.console-group-messages :matches(.console-formatted-object, .console-formatted-node, .console-formatted-error, .console-formatted-map, .console-formatted-set, .console-formatted-weakmap) .object-tree):
(.console-group-messages :matches(.console-formatted-object, .console-formatted-node, .console-formatted-error, .console-formatted-map, .console-formatted-set, .console-formatted-weakmap) .object-tree-outline):
All styles for ObjectTree / ObjectPreview. Independent from
other styles in the inspector. Most of this is a copy of
the styles applied to ObjectPropertiesSection, renamed.

* UserInterface/Views/ObjectTreeCollectionTreeElement.js: Added.
(WebInspector.ObjectTreeCollectionTreeElement):
(WebInspector.ObjectTreeCollectionTreeElement.propertyDescriptorForEntry):
(WebInspector.ObjectTreeCollectionTreeElement.prototype.get remoteObject):
(WebInspector.ObjectTreeCollectionTreeElement.prototype.onexpand.callback):
(WebInspector.ObjectTreeCollectionTreeElement.prototype.onexpand):
(WebInspector.ObjectTreeCollectionTreeElement.prototype.oncollapse):
(WebInspector.ObjectTreeCollectionTreeElement.prototype.ondetach):
(WebInspector.ObjectTreeCollectionTreeElement.prototype._trackWeakEntries):
(WebInspector.ObjectTreeCollectionTreeElement.prototype._untrackWeakEntries):
(WebInspector.ObjectTreeCollectionEntryTreeElement):
(WebInspector.ObjectTreeCollectionEntryTreeElement.prototype.onpopulate):
(WebInspector.ObjectTreeCollectionEntryTreeElement.prototype.onattach):
(WebInspector.ObjectTreeEmptyCollectionTreeElement):
Essentially a copy of ObjectPropertiesSection Collection handling using
the ObjectTree class names.

* UserInterface/Views/TreeOutlineDataGridSynchronizer.js:
Fix prototype typo.

LayoutTests:

* inspector/model/remote-object-expected.txt:
* inspector/model/remote-object-get-properties-expected.txt:
* inspector/model/remote-object-get-properties.html:
* inspector/model/remote-object-weak-collection-expected.txt:
* inspector/model/remote-object-weak-collection.html:
Update tests and results to use our Model objects and not
raw protocol types.

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

24 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/model/remote-object-expected.txt
LayoutTests/inspector/model/remote-object-get-properties-expected.txt
LayoutTests/inspector/model/remote-object-get-properties.html
LayoutTests/inspector/model/remote-object-weak-collection-expected.txt
LayoutTests/inspector/model/remote-object-weak-collection.html
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Models/CollectionEntry.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/CollectionEntryPreview.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/ObjectPreview.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/PropertyDescriptor.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/PropertyPreview.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js
Source/WebInspectorUI/UserInterface/Test.html
Source/WebInspectorUI/UserInterface/Views/ConsoleMessageImpl.js
Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.css [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/ObjectPropertiesSection.js
Source/WebInspectorUI/UserInterface/Views/ObjectTreeCollectionTreeElement.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.css [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/TreeOutlineDataGridSynchronizer.js

index 3177308..872d339 100644 (file)
@@ -1,3 +1,18 @@
+2015-02-19  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Create Separate Model and View Objects for RemoteObjects / ObjectPreview / PropertyDescriptor
+        https://bugs.webkit.org/show_bug.cgi?id=141696
+
+        Reviewed by Timothy Hatcher.
+
+        * inspector/model/remote-object-expected.txt:
+        * inspector/model/remote-object-get-properties-expected.txt:
+        * inspector/model/remote-object-get-properties.html:
+        * inspector/model/remote-object-weak-collection-expected.txt:
+        * inspector/model/remote-object-weak-collection.html:
+        Update tests and results to use our Model objects and not
+        raw protocol types.
+
 2015-02-19  Brent Fulgham  <bfulgham@apple.com>
 
         [Win] Disable media tests due to bot failures.
index 235a463..1e98d4f 100644 (file)
@@ -5,7 +5,7 @@ EXPRESSION: null
   "_type": "object",
   "_subtype": "null",
   "_description": "null",
-  "value": null
+  "_value": null
 }
 
 -----------------------------------------------------
@@ -36,7 +36,7 @@ EXPRESSION: true
 {
   "_type": "boolean",
   "_description": "true",
-  "value": true
+  "_value": true
 }
 
 -----------------------------------------------------
@@ -44,7 +44,7 @@ EXPRESSION: false
 {
   "_type": "boolean",
   "_description": "false",
-  "value": false
+  "_value": false
 }
 
 -----------------------------------------------------
@@ -52,7 +52,7 @@ EXPRESSION: 0
 {
   "_type": "number",
   "_description": "0",
-  "value": 0
+  "_value": 0
 }
 
 -----------------------------------------------------
@@ -60,7 +60,7 @@ EXPRESSION: -0
 {
   "_type": "number",
   "_description": "0",
-  "value": 0
+  "_value": 0
 }
 
 -----------------------------------------------------
@@ -68,7 +68,7 @@ EXPRESSION: 1
 {
   "_type": "number",
   "_description": "1",
-  "value": 1
+  "_value": 1
 }
 
 -----------------------------------------------------
@@ -76,7 +76,7 @@ EXPRESSION: -1
 {
   "_type": "number",
   "_description": "-1",
-  "value": -1
+  "_value": -1
 }
 
 -----------------------------------------------------
@@ -84,7 +84,7 @@ EXPRESSION: 1.234
 {
   "_type": "number",
   "_description": "1.234",
-  "value": 1.234
+  "_value": 1.234
 }
 
 -----------------------------------------------------
@@ -92,7 +92,7 @@ EXPRESSION: -1.234
 {
   "_type": "number",
   "_description": "-1.234",
-  "value": -1.234
+  "_value": -1.234
 }
 
 -----------------------------------------------------
@@ -100,7 +100,7 @@ EXPRESSION: 1e3
 {
   "_type": "number",
   "_description": "1000",
-  "value": 1000
+  "_value": 1000
 }
 
 -----------------------------------------------------
@@ -108,7 +108,7 @@ EXPRESSION: Number.MAX_VALUE
 {
   "_type": "number",
   "_description": "1.7976931348623157e+308",
-  "value": 1.7976931348623157e+308
+  "_value": 1.7976931348623157e+308
 }
 
 -----------------------------------------------------
@@ -116,7 +116,7 @@ EXPRESSION: Number.MIN_VALUE
 {
   "_type": "number",
   "_description": "5e-324",
-  "value": 5e-324
+  "_value": 5e-324
 }
 
 -----------------------------------------------------
@@ -124,7 +124,7 @@ EXPRESSION: NaN
 {
   "_type": "number",
   "_description": "NaN",
-  "value": null
+  "_value": null
 }
 
 -----------------------------------------------------
@@ -132,7 +132,7 @@ EXPRESSION: Infinity
 {
   "_type": "number",
   "_description": "Infinity",
-  "value": null
+  "_value": null
 }
 
 -----------------------------------------------------
@@ -140,7 +140,7 @@ EXPRESSION: ''
 {
   "_type": "string",
   "_description": "",
-  "value": ""
+  "_value": ""
 }
 
 -----------------------------------------------------
@@ -148,7 +148,7 @@ EXPRESSION: '"'
 {
   "_type": "string",
   "_description": "\"",
-  "value": "\""
+  "_value": "\""
 }
 
 -----------------------------------------------------
@@ -156,7 +156,7 @@ EXPRESSION: "'"
 {
   "_type": "string",
   "_description": "'",
-  "value": "'"
+  "_value": "'"
 }
 
 -----------------------------------------------------
@@ -164,7 +164,7 @@ EXPRESSION: 'string'
 {
   "_type": "string",
   "_description": "string",
-  "value": "string"
+  "_value": "string"
 }
 
 -----------------------------------------------------
@@ -172,7 +172,7 @@ EXPRESSION: 'Unicode…'
 {
   "_type": "string",
   "_description": "Unicode…",
-  "value": "Unicode…"
+  "_value": "Unicode…"
 }
 
 -----------------------------------------------------
@@ -180,7 +180,7 @@ EXPRESSION: 'I wish I had something to put here.'
 {
   "_type": "string",
   "_description": "I wish I had something to put here.",
-  "value": "I wish I had something to put here."
+  "_value": "I wish I had something to put here."
 }
 
 -----------------------------------------------------
@@ -255,38 +255,39 @@ EXPRESSION: / /
   "_objectId": "<filtered>",
   "_description": "/ /",
   "_preview": {
-    "type": "object",
-    "description": "/ /",
-    "lossless": true,
-    "subtype": "regexp",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "regexp",
+    "_description": "/ /",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "lastIndex",
-        "type": "number",
-        "value": "0"
+        "_name": "lastIndex",
+        "_type": "number",
+        "_value": "0"
       },
       {
-        "name": "global",
-        "type": "boolean",
-        "value": "false"
+        "_name": "global",
+        "_type": "boolean",
+        "_value": "false"
       },
       {
-        "name": "ignoreCase",
-        "type": "boolean",
-        "value": "false"
+        "_name": "ignoreCase",
+        "_type": "boolean",
+        "_value": "false"
       },
       {
-        "name": "multiline",
-        "type": "boolean",
-        "value": "false"
+        "_name": "multiline",
+        "_type": "boolean",
+        "_value": "false"
       },
       {
-        "name": "source",
-        "type": "string",
-        "value": " "
+        "_name": "source",
+        "_type": "string",
+        "_value": " "
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -298,38 +299,39 @@ EXPRESSION: /(?:)/
   "_objectId": "<filtered>",
   "_description": "/(?:)/",
   "_preview": {
-    "type": "object",
-    "description": "/(?:)/",
-    "lossless": true,
-    "subtype": "regexp",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "regexp",
+    "_description": "/(?:)/",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "lastIndex",
-        "type": "number",
-        "value": "0"
+        "_name": "lastIndex",
+        "_type": "number",
+        "_value": "0"
       },
       {
-        "name": "global",
-        "type": "boolean",
-        "value": "false"
+        "_name": "global",
+        "_type": "boolean",
+        "_value": "false"
       },
       {
-        "name": "ignoreCase",
-        "type": "boolean",
-        "value": "false"
+        "_name": "ignoreCase",
+        "_type": "boolean",
+        "_value": "false"
       },
       {
-        "name": "multiline",
-        "type": "boolean",
-        "value": "false"
+        "_name": "multiline",
+        "_type": "boolean",
+        "_value": "false"
       },
       {
-        "name": "source",
-        "type": "string",
-        "value": "(?:)"
+        "_name": "source",
+        "_type": "string",
+        "_value": "(?:)"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -341,38 +343,39 @@ EXPRESSION: /^r(e)g[e]{1,}x+/
   "_objectId": "<filtered>",
   "_description": "/^r(e)g[e]{1,}x+/",
   "_preview": {
-    "type": "object",
-    "description": "/^r(e)g[e]{1,}x+/",
-    "lossless": true,
-    "subtype": "regexp",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "regexp",
+    "_description": "/^r(e)g[e]{1,}x+/",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "lastIndex",
-        "type": "number",
-        "value": "0"
+        "_name": "lastIndex",
+        "_type": "number",
+        "_value": "0"
       },
       {
-        "name": "global",
-        "type": "boolean",
-        "value": "false"
+        "_name": "global",
+        "_type": "boolean",
+        "_value": "false"
       },
       {
-        "name": "ignoreCase",
-        "type": "boolean",
-        "value": "false"
+        "_name": "ignoreCase",
+        "_type": "boolean",
+        "_value": "false"
       },
       {
-        "name": "multiline",
-        "type": "boolean",
-        "value": "false"
+        "_name": "multiline",
+        "_type": "boolean",
+        "_value": "false"
       },
       {
-        "name": "source",
-        "type": "string",
-        "value": "^r(e)g[e]{1,}x+"
+        "_name": "source",
+        "_type": "string",
+        "_value": "^r(e)g[e]{1,}x+"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -384,38 +387,39 @@ EXPRESSION: /^r(e)g[e]{1,}x+/ig
   "_objectId": "<filtered>",
   "_description": "/^r(e)g[e]{1,}x+/gi",
   "_preview": {
-    "type": "object",
-    "description": "/^r(e)g[e]{1,}x+/gi",
-    "lossless": true,
-    "subtype": "regexp",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "regexp",
+    "_description": "/^r(e)g[e]{1,}x+/gi",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "lastIndex",
-        "type": "number",
-        "value": "0"
+        "_name": "lastIndex",
+        "_type": "number",
+        "_value": "0"
       },
       {
-        "name": "global",
-        "type": "boolean",
-        "value": "true"
+        "_name": "global",
+        "_type": "boolean",
+        "_value": "true"
       },
       {
-        "name": "ignoreCase",
-        "type": "boolean",
-        "value": "true"
+        "_name": "ignoreCase",
+        "_type": "boolean",
+        "_value": "true"
       },
       {
-        "name": "multiline",
-        "type": "boolean",
-        "value": "false"
+        "_name": "multiline",
+        "_type": "boolean",
+        "_value": "false"
       },
       {
-        "name": "source",
-        "type": "string",
-        "value": "^r(e)g[e]{1,}x+"
+        "_name": "source",
+        "_type": "string",
+        "_value": "^r(e)g[e]{1,}x+"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -427,38 +431,39 @@ EXPRESSION: new RegExp('')
   "_objectId": "<filtered>",
   "_description": "/(?:)/",
   "_preview": {
-    "type": "object",
-    "description": "/(?:)/",
-    "lossless": true,
-    "subtype": "regexp",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "regexp",
+    "_description": "/(?:)/",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "lastIndex",
-        "type": "number",
-        "value": "0"
+        "_name": "lastIndex",
+        "_type": "number",
+        "_value": "0"
       },
       {
-        "name": "global",
-        "type": "boolean",
-        "value": "false"
+        "_name": "global",
+        "_type": "boolean",
+        "_value": "false"
       },
       {
-        "name": "ignoreCase",
-        "type": "boolean",
-        "value": "false"
+        "_name": "ignoreCase",
+        "_type": "boolean",
+        "_value": "false"
       },
       {
-        "name": "multiline",
-        "type": "boolean",
-        "value": "false"
+        "_name": "multiline",
+        "_type": "boolean",
+        "_value": "false"
       },
       {
-        "name": "source",
-        "type": "string",
-        "value": "(?:)"
+        "_name": "source",
+        "_type": "string",
+        "_value": "(?:)"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -470,38 +475,39 @@ EXPRESSION: new RegExp('test', 'i')
   "_objectId": "<filtered>",
   "_description": "/test/i",
   "_preview": {
-    "type": "object",
-    "description": "/test/i",
-    "lossless": true,
-    "subtype": "regexp",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "regexp",
+    "_description": "/test/i",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "lastIndex",
-        "type": "number",
-        "value": "0"
+        "_name": "lastIndex",
+        "_type": "number",
+        "_value": "0"
       },
       {
-        "name": "global",
-        "type": "boolean",
-        "value": "false"
+        "_name": "global",
+        "_type": "boolean",
+        "_value": "false"
       },
       {
-        "name": "ignoreCase",
-        "type": "boolean",
-        "value": "true"
+        "_name": "ignoreCase",
+        "_type": "boolean",
+        "_value": "true"
       },
       {
-        "name": "multiline",
-        "type": "boolean",
-        "value": "false"
+        "_name": "multiline",
+        "_type": "boolean",
+        "_value": "false"
       },
       {
-        "name": "source",
-        "type": "string",
-        "value": "test"
+        "_name": "source",
+        "_type": "string",
+        "_value": "test"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -513,12 +519,13 @@ EXPRESSION: []
   "_objectId": "<filtered>",
   "_description": "Array[0]",
   "_preview": {
-    "type": "object",
-    "description": "Array[0]",
-    "lossless": true,
-    "subtype": "array",
-    "overflow": false,
-    "properties": []
+    "_type": "object",
+    "_subtype": "array",
+    "_description": "Array[0]",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [],
+    "_entries": null
   }
 }
 
@@ -530,23 +537,24 @@ EXPRESSION: [1, 2]
   "_objectId": "<filtered>",
   "_description": "Array[2]",
   "_preview": {
-    "type": "object",
-    "description": "Array[2]",
-    "lossless": true,
-    "subtype": "array",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "array",
+    "_description": "Array[2]",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "0",
-        "type": "number",
-        "value": "1"
+        "_name": "0",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "1",
-        "type": "number",
-        "value": "2"
+        "_name": "1",
+        "_type": "number",
+        "_value": "2"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -558,31 +566,32 @@ EXPRESSION: [[1],[2],[3]]
   "_objectId": "<filtered>",
   "_description": "Array[3]",
   "_preview": {
-    "type": "object",
-    "description": "Array[3]",
-    "lossless": false,
-    "subtype": "array",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "array",
+    "_description": "Array[3]",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "0",
-        "type": "object",
-        "subtype": "array",
-        "value": "Array[1]"
+        "_name": "0",
+        "_type": "object",
+        "_subtype": "array",
+        "_value": "Array[1]"
       },
       {
-        "name": "1",
-        "type": "object",
-        "subtype": "array",
-        "value": "Array[1]"
+        "_name": "1",
+        "_type": "object",
+        "_subtype": "array",
+        "_value": "Array[1]"
       },
       {
-        "name": "2",
-        "type": "object",
-        "subtype": "array",
-        "value": "Array[1]"
+        "_name": "2",
+        "_type": "object",
+        "_subtype": "array",
+        "_value": "Array[1]"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -594,39 +603,40 @@ EXPRESSION: [true, 1, 1.234, 'string', /regex/]
   "_objectId": "<filtered>",
   "_description": "Array[5]",
   "_preview": {
-    "type": "object",
-    "description": "Array[5]",
-    "lossless": false,
-    "subtype": "array",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "array",
+    "_description": "Array[5]",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "0",
-        "type": "boolean",
-        "value": "true"
+        "_name": "0",
+        "_type": "boolean",
+        "_value": "true"
       },
       {
-        "name": "1",
-        "type": "number",
-        "value": "1"
+        "_name": "1",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "2",
-        "type": "number",
-        "value": "1.234"
+        "_name": "2",
+        "_type": "number",
+        "_value": "1.234"
       },
       {
-        "name": "3",
-        "type": "string",
-        "value": "string"
+        "_name": "3",
+        "_type": "string",
+        "_value": "string"
       },
       {
-        "name": "4",
-        "type": "object",
-        "subtype": "regexp",
-        "value": "/regex/"
+        "_name": "4",
+        "_type": "object",
+        "_subtype": "regexp",
+        "_value": "/regex/"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -638,28 +648,29 @@ EXPRESSION: [{a:1}, {b:2}, {c:2}]
   "_objectId": "<filtered>",
   "_description": "Array[3]",
   "_preview": {
-    "type": "object",
-    "description": "Array[3]",
-    "lossless": false,
-    "subtype": "array",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "array",
+    "_description": "Array[3]",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "0",
-        "type": "object",
-        "value": "Object"
+        "_name": "0",
+        "_type": "object",
+        "_value": "Object"
       },
       {
-        "name": "1",
-        "type": "object",
-        "value": "Object"
+        "_name": "1",
+        "_type": "object",
+        "_value": "Object"
       },
       {
-        "name": "2",
-        "type": "object",
-        "value": "Object"
+        "_name": "2",
+        "_type": "object",
+        "_value": "Object"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -671,19 +682,20 @@ EXPRESSION: [[{a:1}, {b:2}, {c:2}]]
   "_objectId": "<filtered>",
   "_description": "Array[1]",
   "_preview": {
-    "type": "object",
-    "description": "Array[1]",
-    "lossless": false,
-    "subtype": "array",
-    "overflow": false,
-    "properties": [
-      {
-        "name": "0",
-        "type": "object",
-        "subtype": "array",
-        "value": "Array[3]"
+    "_type": "object",
+    "_subtype": "array",
+    "_description": "Array[1]",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "0",
+        "_type": "object",
+        "_subtype": "array",
+        "_value": "Array[3]"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -695,12 +707,13 @@ EXPRESSION: arr = []; arr.length = 100; arr
   "_objectId": "<filtered>",
   "_description": "Array[100]",
   "_preview": {
-    "type": "object",
-    "description": "Array[100]",
-    "lossless": true,
-    "subtype": "array",
-    "overflow": false,
-    "properties": []
+    "_type": "object",
+    "_subtype": "array",
+    "_description": "Array[100]",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [],
+    "_entries": null
   }
 }
 
@@ -712,513 +725,514 @@ EXPRESSION: arr = []; arr.length = 100; arr.fill(1)
   "_objectId": "<filtered>",
   "_description": "Array[100]",
   "_preview": {
-    "type": "object",
-    "description": "Array[100]",
-    "lossless": true,
-    "subtype": "array",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "array",
+    "_description": "Array[100]",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "0",
-        "type": "number",
-        "value": "1"
+        "_name": "0",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "1",
-        "type": "number",
-        "value": "1"
+        "_name": "1",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "2",
-        "type": "number",
-        "value": "1"
+        "_name": "2",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "3",
-        "type": "number",
-        "value": "1"
+        "_name": "3",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "4",
-        "type": "number",
-        "value": "1"
+        "_name": "4",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "5",
-        "type": "number",
-        "value": "1"
+        "_name": "5",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "6",
-        "type": "number",
-        "value": "1"
+        "_name": "6",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "7",
-        "type": "number",
-        "value": "1"
+        "_name": "7",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "8",
-        "type": "number",
-        "value": "1"
+        "_name": "8",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "9",
-        "type": "number",
-        "value": "1"
+        "_name": "9",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "10",
-        "type": "number",
-        "value": "1"
+        "_name": "10",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "11",
-        "type": "number",
-        "value": "1"
+        "_name": "11",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "12",
-        "type": "number",
-        "value": "1"
+        "_name": "12",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "13",
-        "type": "number",
-        "value": "1"
+        "_name": "13",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "14",
-        "type": "number",
-        "value": "1"
+        "_name": "14",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "15",
-        "type": "number",
-        "value": "1"
+        "_name": "15",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "16",
-        "type": "number",
-        "value": "1"
+        "_name": "16",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "17",
-        "type": "number",
-        "value": "1"
+        "_name": "17",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "18",
-        "type": "number",
-        "value": "1"
+        "_name": "18",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "19",
-        "type": "number",
-        "value": "1"
+        "_name": "19",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "20",
-        "type": "number",
-        "value": "1"
+        "_name": "20",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "21",
-        "type": "number",
-        "value": "1"
+        "_name": "21",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "22",
-        "type": "number",
-        "value": "1"
+        "_name": "22",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "23",
-        "type": "number",
-        "value": "1"
+        "_name": "23",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "24",
-        "type": "number",
-        "value": "1"
+        "_name": "24",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "25",
-        "type": "number",
-        "value": "1"
+        "_name": "25",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "26",
-        "type": "number",
-        "value": "1"
+        "_name": "26",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "27",
-        "type": "number",
-        "value": "1"
+        "_name": "27",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "28",
-        "type": "number",
-        "value": "1"
+        "_name": "28",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "29",
-        "type": "number",
-        "value": "1"
+        "_name": "29",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "30",
-        "type": "number",
-        "value": "1"
+        "_name": "30",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "31",
-        "type": "number",
-        "value": "1"
+        "_name": "31",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "32",
-        "type": "number",
-        "value": "1"
+        "_name": "32",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "33",
-        "type": "number",
-        "value": "1"
+        "_name": "33",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "34",
-        "type": "number",
-        "value": "1"
+        "_name": "34",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "35",
-        "type": "number",
-        "value": "1"
+        "_name": "35",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "36",
-        "type": "number",
-        "value": "1"
+        "_name": "36",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "37",
-        "type": "number",
-        "value": "1"
+        "_name": "37",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "38",
-        "type": "number",
-        "value": "1"
+        "_name": "38",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "39",
-        "type": "number",
-        "value": "1"
+        "_name": "39",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "40",
-        "type": "number",
-        "value": "1"
+        "_name": "40",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "41",
-        "type": "number",
-        "value": "1"
+        "_name": "41",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "42",
-        "type": "number",
-        "value": "1"
+        "_name": "42",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "43",
-        "type": "number",
-        "value": "1"
+        "_name": "43",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "44",
-        "type": "number",
-        "value": "1"
+        "_name": "44",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "45",
-        "type": "number",
-        "value": "1"
+        "_name": "45",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "46",
-        "type": "number",
-        "value": "1"
+        "_name": "46",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "47",
-        "type": "number",
-        "value": "1"
+        "_name": "47",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "48",
-        "type": "number",
-        "value": "1"
+        "_name": "48",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "49",
-        "type": "number",
-        "value": "1"
+        "_name": "49",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "50",
-        "type": "number",
-        "value": "1"
+        "_name": "50",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "51",
-        "type": "number",
-        "value": "1"
+        "_name": "51",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "52",
-        "type": "number",
-        "value": "1"
+        "_name": "52",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "53",
-        "type": "number",
-        "value": "1"
+        "_name": "53",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "54",
-        "type": "number",
-        "value": "1"
+        "_name": "54",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "55",
-        "type": "number",
-        "value": "1"
+        "_name": "55",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "56",
-        "type": "number",
-        "value": "1"
+        "_name": "56",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "57",
-        "type": "number",
-        "value": "1"
+        "_name": "57",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "58",
-        "type": "number",
-        "value": "1"
+        "_name": "58",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "59",
-        "type": "number",
-        "value": "1"
+        "_name": "59",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "60",
-        "type": "number",
-        "value": "1"
+        "_name": "60",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "61",
-        "type": "number",
-        "value": "1"
+        "_name": "61",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "62",
-        "type": "number",
-        "value": "1"
+        "_name": "62",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "63",
-        "type": "number",
-        "value": "1"
+        "_name": "63",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "64",
-        "type": "number",
-        "value": "1"
+        "_name": "64",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "65",
-        "type": "number",
-        "value": "1"
+        "_name": "65",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "66",
-        "type": "number",
-        "value": "1"
+        "_name": "66",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "67",
-        "type": "number",
-        "value": "1"
+        "_name": "67",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "68",
-        "type": "number",
-        "value": "1"
+        "_name": "68",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "69",
-        "type": "number",
-        "value": "1"
+        "_name": "69",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "70",
-        "type": "number",
-        "value": "1"
+        "_name": "70",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "71",
-        "type": "number",
-        "value": "1"
+        "_name": "71",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "72",
-        "type": "number",
-        "value": "1"
+        "_name": "72",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "73",
-        "type": "number",
-        "value": "1"
+        "_name": "73",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "74",
-        "type": "number",
-        "value": "1"
+        "_name": "74",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "75",
-        "type": "number",
-        "value": "1"
+        "_name": "75",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "76",
-        "type": "number",
-        "value": "1"
+        "_name": "76",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "77",
-        "type": "number",
-        "value": "1"
+        "_name": "77",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "78",
-        "type": "number",
-        "value": "1"
+        "_name": "78",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "79",
-        "type": "number",
-        "value": "1"
+        "_name": "79",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "80",
-        "type": "number",
-        "value": "1"
+        "_name": "80",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "81",
-        "type": "number",
-        "value": "1"
+        "_name": "81",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "82",
-        "type": "number",
-        "value": "1"
+        "_name": "82",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "83",
-        "type": "number",
-        "value": "1"
+        "_name": "83",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "84",
-        "type": "number",
-        "value": "1"
+        "_name": "84",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "85",
-        "type": "number",
-        "value": "1"
+        "_name": "85",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "86",
-        "type": "number",
-        "value": "1"
+        "_name": "86",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "87",
-        "type": "number",
-        "value": "1"
+        "_name": "87",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "88",
-        "type": "number",
-        "value": "1"
+        "_name": "88",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "89",
-        "type": "number",
-        "value": "1"
+        "_name": "89",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "90",
-        "type": "number",
-        "value": "1"
+        "_name": "90",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "91",
-        "type": "number",
-        "value": "1"
+        "_name": "91",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "92",
-        "type": "number",
-        "value": "1"
+        "_name": "92",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "93",
-        "type": "number",
-        "value": "1"
+        "_name": "93",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "94",
-        "type": "number",
-        "value": "1"
+        "_name": "94",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "95",
-        "type": "number",
-        "value": "1"
+        "_name": "95",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "96",
-        "type": "number",
-        "value": "1"
+        "_name": "96",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "97",
-        "type": "number",
-        "value": "1"
+        "_name": "97",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "98",
-        "type": "number",
-        "value": "1"
+        "_name": "98",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "99",
-        "type": "number",
-        "value": "1"
+        "_name": "99",
+        "_type": "number",
+        "_value": "1"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1230,18 +1244,19 @@ EXPRESSION: arr = []; arr.length = 100; arr[10] = 1; arr
   "_objectId": "<filtered>",
   "_description": "Array[100]",
   "_preview": {
-    "type": "object",
-    "description": "Array[100]",
-    "lossless": true,
-    "subtype": "array",
-    "overflow": false,
-    "properties": [
-      {
-        "name": "10",
-        "type": "number",
-        "value": "1"
+    "_type": "object",
+    "_subtype": "array",
+    "_description": "Array[100]",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "10",
+        "_type": "number",
+        "_value": "1"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1253,29 +1268,30 @@ EXPRESSION: a = null; (function() { a = arguments; })(1, '2', /3/); a
   "_objectId": "<filtered>",
   "_description": "Arguments[3]",
   "_preview": {
-    "type": "object",
-    "description": "Arguments[3]",
-    "lossless": false,
-    "subtype": "array",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "array",
+    "_description": "Arguments[3]",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "0",
-        "type": "number",
-        "value": "1"
+        "_name": "0",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "1",
-        "type": "string",
-        "value": "2"
+        "_name": "1",
+        "_type": "string",
+        "_value": "2"
       },
       {
-        "name": "2",
-        "type": "object",
-        "subtype": "regexp",
-        "value": "/3/"
+        "_name": "2",
+        "_type": "object",
+        "_subtype": "regexp",
+        "_value": "/3/"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1287,48 +1303,49 @@ EXPRESSION: new Int32Array(new ArrayBuffer(16))
   "_objectId": "<filtered>",
   "_description": "Int32Array[4]",
   "_preview": {
-    "type": "object",
-    "description": "Int32Array[4]",
-    "lossless": false,
-    "subtype": "array",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "array",
+    "_description": "Int32Array[4]",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "0",
-        "type": "number",
-        "value": "0"
+        "_name": "0",
+        "_type": "number",
+        "_value": "0"
       },
       {
-        "name": "1",
-        "type": "number",
-        "value": "0"
+        "_name": "1",
+        "_type": "number",
+        "_value": "0"
       },
       {
-        "name": "2",
-        "type": "number",
-        "value": "0"
+        "_name": "2",
+        "_type": "number",
+        "_value": "0"
       },
       {
-        "name": "3",
-        "type": "number",
-        "value": "0"
+        "_name": "3",
+        "_type": "number",
+        "_value": "0"
       },
       {
-        "name": "byteOffset",
-        "type": "number",
-        "value": "0"
+        "_name": "byteOffset",
+        "_type": "number",
+        "_value": "0"
       },
       {
-        "name": "byteLength",
-        "type": "number",
-        "value": "16"
+        "_name": "byteLength",
+        "_type": "number",
+        "_value": "16"
       },
       {
-        "name": "buffer",
-        "type": "object",
-        "value": "ArrayBuffer"
+        "_name": "buffer",
+        "_type": "object",
+        "_value": "ArrayBuffer"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1340,48 +1357,49 @@ EXPRESSION: var intArray = new Int32Array(new ArrayBuffer(16)); for (var i = 0;
   "_objectId": "<filtered>",
   "_description": "Int32Array[4]",
   "_preview": {
-    "type": "object",
-    "description": "Int32Array[4]",
-    "lossless": false,
-    "subtype": "array",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "array",
+    "_description": "Int32Array[4]",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "0",
-        "type": "number",
-        "value": "0"
+        "_name": "0",
+        "_type": "number",
+        "_value": "0"
       },
       {
-        "name": "1",
-        "type": "number",
-        "value": "1"
+        "_name": "1",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "2",
-        "type": "number",
-        "value": "2"
+        "_name": "2",
+        "_type": "number",
+        "_value": "2"
       },
       {
-        "name": "3",
-        "type": "number",
-        "value": "3"
+        "_name": "3",
+        "_type": "number",
+        "_value": "3"
       },
       {
-        "name": "byteOffset",
-        "type": "number",
-        "value": "0"
+        "_name": "byteOffset",
+        "_type": "number",
+        "_value": "0"
       },
       {
-        "name": "byteLength",
-        "type": "number",
-        "value": "16"
+        "_name": "byteLength",
+        "_type": "number",
+        "_value": "16"
       },
       {
-        "name": "buffer",
-        "type": "object",
-        "value": "ArrayBuffer"
+        "_name": "buffer",
+        "_type": "object",
+        "_value": "ArrayBuffer"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1392,10 +1410,12 @@ EXPRESSION: ({})
   "_objectId": "<filtered>",
   "_description": "Object",
   "_preview": {
-    "type": "object",
-    "description": "Object",
-    "lossless": true,
-    "properties": []
+    "_type": "object",
+    "_description": "Object",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [],
+    "_entries": null
   }
 }
 
@@ -1406,16 +1426,18 @@ EXPRESSION: ({a: 1})
   "_objectId": "<filtered>",
   "_description": "Object",
   "_preview": {
-    "type": "object",
-    "description": "Object",
-    "lossless": true,
-    "properties": [
-      {
-        "name": "a",
-        "type": "number",
-        "value": "1"
+    "_type": "object",
+    "_description": "Object",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "a",
+        "_type": "number",
+        "_value": "1"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1426,32 +1448,34 @@ EXPRESSION: ({a: 1, b: "string", c: /regex/, d: Symbol('sym')})
   "_objectId": "<filtered>",
   "_description": "Object",
   "_preview": {
-    "type": "object",
-    "description": "Object",
-    "lossless": false,
-    "properties": [
+    "_type": "object",
+    "_description": "Object",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "a",
-        "type": "number",
-        "value": "1"
+        "_name": "a",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "b",
-        "type": "string",
-        "value": "string"
+        "_name": "b",
+        "_type": "string",
+        "_value": "string"
       },
       {
-        "name": "c",
-        "type": "object",
-        "subtype": "regexp",
-        "value": "/regex/"
+        "_name": "c",
+        "_type": "object",
+        "_subtype": "regexp",
+        "_value": "/regex/"
       },
       {
-        "name": "d",
-        "type": "symbol",
-        "value": "Symbol(sym)"
+        "_name": "d",
+        "_type": "symbol",
+        "_value": "Symbol(sym)"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1462,29 +1486,31 @@ EXPRESSION: ({a:function a(){}, b:function b(){}, get getter(){}, set setter(v){
   "_objectId": "<filtered>",
   "_description": "Object",
   "_preview": {
-    "type": "object",
-    "description": "Object",
-    "lossless": false,
-    "properties": [
+    "_type": "object",
+    "_description": "Object",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "a",
-        "type": "function",
-        "value": ""
+        "_name": "a",
+        "_type": "function",
+        "_value": ""
       },
       {
-        "name": "b",
-        "type": "function",
-        "value": ""
+        "_name": "b",
+        "_type": "function",
+        "_value": ""
       },
       {
-        "name": "getter",
-        "type": "accessor"
+        "_name": "getter",
+        "_type": "accessor"
       },
       {
-        "name": "setter",
-        "type": "accessor"
+        "_name": "setter",
+        "_type": "accessor"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1495,10 +1521,12 @@ EXPRESSION: function Foo() {}; new Foo
   "_objectId": "<filtered>",
   "_description": "Foo",
   "_preview": {
-    "type": "object",
-    "description": "Foo",
-    "lossless": true,
-    "properties": []
+    "_type": "object",
+    "_description": "Foo",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [],
+    "_entries": null
   }
 }
 
@@ -1509,10 +1537,12 @@ EXPRESSION: var Foo2 = function() {}; new Foo2
   "_objectId": "<filtered>",
   "_description": "Foo2",
   "_preview": {
-    "type": "object",
-    "description": "Foo2",
-    "lossless": true,
-    "properties": []
+    "_type": "object",
+    "_description": "Foo2",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [],
+    "_entries": null
   }
 }
 
@@ -1523,10 +1553,12 @@ EXPRESSION: var namespace = {}; namespace.Foo3 = function() {}; new namespace.Fo
   "_objectId": "<filtered>",
   "_description": "Foo3",
   "_preview": {
-    "type": "object",
-    "description": "Foo3",
-    "lossless": true,
-    "properties": []
+    "_type": "object",
+    "_description": "Foo3",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [],
+    "_entries": null
   }
 }
 
@@ -1537,25 +1569,27 @@ EXPRESSION: function Bar() { this._x = 5 }; Bar.prototype = {constructor: Bar, g
   "_objectId": "<filtered>",
   "_description": "Bar",
   "_preview": {
-    "type": "object",
-    "description": "Bar",
-    "lossless": false,
-    "properties": [
+    "_type": "object",
+    "_description": "Bar",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "_x",
-        "type": "number",
-        "value": "5"
+        "_name": "_x",
+        "_type": "number",
+        "_value": "5"
       },
       {
-        "name": "constructor",
-        "type": "function",
-        "value": ""
+        "_name": "constructor",
+        "_type": "function",
+        "_value": ""
       },
       {
-        "name": "x",
-        "type": "accessor"
+        "_name": "x",
+        "_type": "accessor"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1566,16 +1600,18 @@ EXPRESSION: function Bar2() { this._x = 5 }; Bar.prototype = {get x() {return th
   "_objectId": "<filtered>",
   "_description": "Bar2",
   "_preview": {
-    "type": "object",
-    "description": "Bar2",
-    "lossless": true,
-    "properties": [
-      {
-        "name": "_x",
-        "type": "number",
-        "value": "5"
+    "_type": "object",
+    "_description": "Bar2",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "_x",
+        "_type": "number",
+        "_value": "5"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1586,38 +1622,39 @@ EXPRESSION: window.loadEvent
   "_objectId": "<filtered>",
   "_description": "Event",
   "_preview": {
-    "type": "object",
-    "description": "Event",
-    "lossless": false,
-    "properties": [
+    "_type": "object",
+    "_description": "Event",
+    "_lossless": false,
+    "_overflow": true,
+    "_properties": [
       {
-        "name": "clipboardData",
-        "type": "undefined",
-        "value": "undefined"
+        "_name": "clipboardData",
+        "_type": "undefined",
+        "_value": "undefined"
       },
       {
-        "name": "type",
-        "type": "string",
-        "value": "load"
+        "_name": "type",
+        "_type": "string",
+        "_value": "load"
       },
       {
-        "name": "target",
-        "type": "object",
-        "subtype": "node",
-        "value": "#document"
+        "_name": "target",
+        "_type": "object",
+        "_subtype": "node",
+        "_value": "#document"
       },
       {
-        "name": "currentTarget",
-        "type": "object",
-        "value": "Window"
+        "_name": "currentTarget",
+        "_type": "object",
+        "_value": "Window"
       },
       {
-        "name": "eventPhase",
-        "type": "number",
-        "value": "2"
+        "_name": "eventPhase",
+        "_type": "number",
+        "_value": "2"
       }
     ],
-    "overflow": true
+    "_entries": null
   }
 }
 
@@ -1628,16 +1665,18 @@ EXPRESSION: new ArrayBuffer(16)
   "_objectId": "<filtered>",
   "_description": "ArrayBuffer",
   "_preview": {
-    "type": "object",
-    "description": "ArrayBuffer",
-    "lossless": true,
-    "properties": [
-      {
-        "name": "byteLength",
-        "type": "number",
-        "value": "16"
+    "_type": "object",
+    "_description": "ArrayBuffer",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "byteLength",
+        "_type": "number",
+        "_value": "16"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1648,26 +1687,28 @@ EXPRESSION: new DataView(new ArrayBuffer(16))
   "_objectId": "<filtered>",
   "_description": "DataView",
   "_preview": {
-    "type": "object",
-    "description": "DataView",
-    "lossless": false,
-    "properties": [
+    "_type": "object",
+    "_description": "DataView",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "byteOffset",
-        "type": "number",
-        "value": "0"
+        "_name": "byteOffset",
+        "_type": "number",
+        "_value": "0"
       },
       {
-        "name": "byteLength",
-        "type": "number",
-        "value": "16"
+        "_name": "byteLength",
+        "_type": "number",
+        "_value": "16"
       },
       {
-        "name": "buffer",
-        "type": "object",
-        "value": "ArrayBuffer"
+        "_name": "buffer",
+        "_type": "object",
+        "_value": "ArrayBuffer"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1679,38 +1720,39 @@ EXPRESSION: document.body
   "_objectId": "<filtered>",
   "_description": "body",
   "_preview": {
-    "type": "object",
-    "description": "body",
-    "lossless": false,
-    "subtype": "node",
-    "overflow": true,
-    "properties": [
+    "_type": "object",
+    "_subtype": "node",
+    "_description": "body",
+    "_lossless": false,
+    "_overflow": true,
+    "_properties": [
       {
-        "name": "aLink",
-        "type": "string",
-        "value": ""
+        "_name": "aLink",
+        "_type": "string",
+        "_value": ""
       },
       {
-        "name": "background",
-        "type": "string",
-        "value": ""
+        "_name": "background",
+        "_type": "string",
+        "_value": ""
       },
       {
-        "name": "bgColor",
-        "type": "string",
-        "value": ""
+        "_name": "bgColor",
+        "_type": "string",
+        "_value": ""
       },
       {
-        "name": "link",
-        "type": "string",
-        "value": ""
+        "_name": "link",
+        "_type": "string",
+        "_value": ""
       },
       {
-        "name": "text",
-        "type": "string",
-        "value": ""
+        "_name": "text",
+        "_type": "string",
+        "_value": ""
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1722,38 +1764,39 @@ EXPRESSION: div = document.createElement('div'); div.className = 'foo bar'; div
   "_objectId": "<filtered>",
   "_description": "div.foo.bar",
   "_preview": {
-    "type": "object",
-    "description": "div.foo.bar",
-    "lossless": false,
-    "subtype": "node",
-    "overflow": true,
-    "properties": [
+    "_type": "object",
+    "_subtype": "node",
+    "_description": "div.foo.bar",
+    "_lossless": false,
+    "_overflow": true,
+    "_properties": [
       {
-        "name": "align",
-        "type": "string",
-        "value": ""
+        "_name": "align",
+        "_type": "string",
+        "_value": ""
       },
       {
-        "name": "title",
-        "type": "string",
-        "value": ""
+        "_name": "title",
+        "_type": "string",
+        "_value": ""
       },
       {
-        "name": "lang",
-        "type": "string",
-        "value": ""
+        "_name": "lang",
+        "_type": "string",
+        "_value": ""
       },
       {
-        "name": "translate",
-        "type": "boolean",
-        "value": "true"
+        "_name": "translate",
+        "_type": "boolean",
+        "_value": "true"
       },
       {
-        "name": "dir",
-        "type": "string",
-        "value": ""
+        "_name": "dir",
+        "_type": "string",
+        "_value": ""
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1765,38 +1808,39 @@ EXPRESSION: span = document.createElement('span'); span.id = 'foo'; span
   "_objectId": "<filtered>",
   "_description": "span#foo",
   "_preview": {
-    "type": "object",
-    "description": "span#foo",
-    "lossless": false,
-    "subtype": "node",
-    "overflow": true,
-    "properties": [
+    "_type": "object",
+    "_subtype": "node",
+    "_description": "span#foo",
+    "_lossless": false,
+    "_overflow": true,
+    "_properties": [
       {
-        "name": "title",
-        "type": "string",
-        "value": ""
+        "_name": "title",
+        "_type": "string",
+        "_value": ""
       },
       {
-        "name": "lang",
-        "type": "string",
-        "value": ""
+        "_name": "lang",
+        "_type": "string",
+        "_value": ""
       },
       {
-        "name": "translate",
-        "type": "boolean",
-        "value": "true"
+        "_name": "translate",
+        "_type": "boolean",
+        "_value": "true"
       },
       {
-        "name": "dir",
-        "type": "string",
-        "value": ""
+        "_name": "dir",
+        "_type": "string",
+        "_value": ""
       },
       {
-        "name": "tabIndex",
-        "type": "number",
-        "value": "-1"
+        "_name": "tabIndex",
+        "_type": "number",
+        "_value": "-1"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1808,38 +1852,39 @@ EXPRESSION: document.createTextNode('text')
   "_objectId": "<filtered>",
   "_description": "#text",
   "_preview": {
-    "type": "object",
-    "description": "#text",
-    "lossless": false,
-    "subtype": "node",
-    "overflow": true,
-    "properties": [
+    "_type": "object",
+    "_subtype": "node",
+    "_description": "#text",
+    "_lossless": false,
+    "_overflow": true,
+    "_properties": [
       {
-        "name": "wholeText",
-        "type": "string",
-        "value": "text"
+        "_name": "wholeText",
+        "_type": "string",
+        "_value": "text"
       },
       {
-        "name": "splitText",
-        "type": "function",
-        "value": ""
+        "_name": "splitText",
+        "_type": "function",
+        "_value": ""
       },
       {
-        "name": "replaceWholeText",
-        "type": "function",
-        "value": ""
+        "_name": "replaceWholeText",
+        "_type": "function",
+        "_value": ""
       },
       {
-        "name": "data",
-        "type": "string",
-        "value": "text"
+        "_name": "data",
+        "_type": "string",
+        "_value": "text"
       },
       {
-        "name": "length",
-        "type": "number",
-        "value": "4"
+        "_name": "length",
+        "_type": "number",
+        "_value": "4"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1851,41 +1896,42 @@ EXPRESSION: document.head.children
   "_objectId": "<filtered>",
   "_description": "HTMLCollection[3]",
   "_preview": {
-    "type": "object",
-    "description": "HTMLCollection[3]",
-    "lossless": false,
-    "subtype": "array",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "array",
+    "_description": "HTMLCollection[3]",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "0",
-        "type": "object",
-        "subtype": "node",
-        "value": "meta"
+        "_name": "0",
+        "_type": "object",
+        "_subtype": "node",
+        "_value": "meta"
       },
       {
-        "name": "1",
-        "type": "object",
-        "subtype": "node",
-        "value": "script"
+        "_name": "1",
+        "_type": "object",
+        "_subtype": "node",
+        "_value": "script"
       },
       {
-        "name": "2",
-        "type": "object",
-        "subtype": "node",
-        "value": "script"
+        "_name": "2",
+        "_type": "object",
+        "_subtype": "node",
+        "_value": "script"
       },
       {
-        "name": "item",
-        "type": "function",
-        "value": ""
+        "_name": "item",
+        "_type": "function",
+        "_value": ""
       },
       {
-        "name": "namedItem",
-        "type": "function",
-        "value": ""
+        "_name": "namedItem",
+        "_type": "function",
+        "_value": ""
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1897,41 +1943,42 @@ EXPRESSION: document.getElementsByClassName('my-test')
   "_objectId": "<filtered>",
   "_description": "NodeList[3]",
   "_preview": {
-    "type": "object",
-    "description": "NodeList[3]",
-    "lossless": false,
-    "subtype": "array",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "array",
+    "_description": "NodeList[3]",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "0",
-        "type": "object",
-        "subtype": "node",
-        "value": "p.my-test"
+        "_name": "0",
+        "_type": "object",
+        "_subtype": "node",
+        "_value": "p.my-test"
       },
       {
-        "name": "1",
-        "type": "object",
-        "subtype": "node",
-        "value": "p.my-test"
+        "_name": "1",
+        "_type": "object",
+        "_subtype": "node",
+        "_value": "p.my-test"
       },
       {
-        "name": "2",
-        "type": "object",
-        "subtype": "node",
-        "value": "p.my-test"
+        "_name": "2",
+        "_type": "object",
+        "_subtype": "node",
+        "_value": "p.my-test"
       },
       {
-        "name": "constructor",
-        "type": "object",
-        "value": "NodeListConstructor"
+        "_name": "constructor",
+        "_type": "object",
+        "_value": "NodeListConstructor"
       },
       {
-        "name": "item",
-        "type": "function",
-        "value": ""
+        "_name": "item",
+        "_type": "function",
+        "_value": ""
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1943,41 +1990,42 @@ EXPRESSION: document.querySelectorAll('.my-test')
   "_objectId": "<filtered>",
   "_description": "NodeList[3]",
   "_preview": {
-    "type": "object",
-    "description": "NodeList[3]",
-    "lossless": false,
-    "subtype": "array",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "array",
+    "_description": "NodeList[3]",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "0",
-        "type": "object",
-        "subtype": "node",
-        "value": "p.my-test"
+        "_name": "0",
+        "_type": "object",
+        "_subtype": "node",
+        "_value": "p.my-test"
       },
       {
-        "name": "1",
-        "type": "object",
-        "subtype": "node",
-        "value": "p.my-test"
+        "_name": "1",
+        "_type": "object",
+        "_subtype": "node",
+        "_value": "p.my-test"
       },
       {
-        "name": "2",
-        "type": "object",
-        "subtype": "node",
-        "value": "p.my-test"
+        "_name": "2",
+        "_type": "object",
+        "_subtype": "node",
+        "_value": "p.my-test"
       },
       {
-        "name": "constructor",
-        "type": "object",
-        "value": "NodeListConstructor"
+        "_name": "constructor",
+        "_type": "object",
+        "_value": "NodeListConstructor"
       },
       {
-        "name": "item",
-        "type": "function",
-        "value": ""
+        "_name": "item",
+        "_type": "function",
+        "_value": ""
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -1989,33 +2037,34 @@ EXPRESSION: error = null; try { [].x.x; } catch (e) { error = e; }; error
   "_objectId": "<filtered>",
   "_description": "TypeError: undefined is not an object (evaluating '[].x.x')",
   "_preview": {
-    "type": "object",
-    "description": "TypeError: undefined is not an object (evaluating '[].x.x')",
-    "lossless": true,
-    "subtype": "error",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "error",
+    "_description": "TypeError: undefined is not an object (evaluating '[].x.x')",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "message",
-        "type": "string",
-        "value": "undefined is not an object (evaluating '[].x.x')"
+        "_name": "message",
+        "_type": "string",
+        "_value": "undefined is not an object (evaluating '[].x.x')"
       },
       {
-        "name": "line",
-        "type": "number",
-        "value": "1"
+        "_name": "line",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "column",
-        "type": "number",
-        "value": "25"
+        "_name": "column",
+        "_type": "number",
+        "_value": "25"
       },
       {
-        "name": "stack",
-        "type": "string",
-        "value": "eval code\neval@[native code]\n_evaluateOn\n_evaluateAndWrap\nevaluate"
+        "_name": "stack",
+        "_type": "string",
+        "_value": "eval code\neval@[native code]\n_evaluateOn\n_evaluateAndWrap\nevaluate"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -2027,33 +2076,34 @@ EXPRESSION: error = null; try { eval('if()'); } catch (e) { error = e; }; error
   "_objectId": "<filtered>",
   "_description": "SyntaxError: Unexpected token ')'",
   "_preview": {
-    "type": "object",
-    "description": "SyntaxError: Unexpected token ')'",
-    "lossless": true,
-    "subtype": "error",
-    "overflow": false,
-    "properties": [
+    "_type": "object",
+    "_subtype": "error",
+    "_description": "SyntaxError: Unexpected token ')'",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
       {
-        "name": "message",
-        "type": "string",
-        "value": "Unexpected token ')'"
+        "_name": "message",
+        "_type": "string",
+        "_value": "Unexpected token ')'"
       },
       {
-        "name": "line",
-        "type": "number",
-        "value": "1"
+        "_name": "line",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "column",
-        "type": "number",
-        "value": "25"
+        "_name": "column",
+        "_type": "number",
+        "_value": "25"
       },
       {
-        "name": "stack",
-        "type": "string",
-        "value": "eval@[native code]\neval code\neval@[native code]\n_evaluateOn\n_evaluateAndWrap\nevaluate"
+        "_name": "stack",
+        "_type": "string",
+        "_value": "eval@[native code]\neval code\neval@[native code]\n_evaluateOn\n_evaluateAndWrap\nevaluate"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -2065,38 +2115,39 @@ EXPRESSION: error = null; try { document.createTextNode('').splitText(100); } ca
   "_objectId": "<filtered>",
   "_description": "Error: IndexSizeError: DOM Exception 1",
   "_preview": {
-    "type": "object",
-    "description": "Error: IndexSizeError: DOM Exception 1",
-    "lossless": false,
-    "subtype": "error",
-    "overflow": true,
-    "properties": [
+    "_type": "object",
+    "_subtype": "error",
+    "_description": "Error: IndexSizeError: DOM Exception 1",
+    "_lossless": false,
+    "_overflow": true,
+    "_properties": [
       {
-        "name": "code",
-        "type": "number",
-        "value": "1"
+        "_name": "code",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "name",
-        "type": "string",
-        "value": "IndexSizeError"
+        "_name": "name",
+        "_type": "string",
+        "_value": "IndexSizeError"
       },
       {
-        "name": "message",
-        "type": "string",
-        "value": "IndexSizeError: DOM Exception 1"
+        "_name": "message",
+        "_type": "string",
+        "_value": "IndexSizeError: DOM Exception 1"
       },
       {
-        "name": "line",
-        "type": "number",
-        "value": "1"
+        "_name": "line",
+        "_type": "number",
+        "_value": "1"
       },
       {
-        "name": "column",
-        "type": "number",
-        "value": "58"
+        "_name": "column",
+        "_type": "number",
+        "_value": "58"
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -2107,10 +2158,12 @@ EXPRESSION: Object.seal({})
   "_objectId": "<filtered>",
   "_description": "Object",
   "_preview": {
-    "type": "object",
-    "description": "Object",
-    "lossless": true,
-    "properties": []
+    "_type": "object",
+    "_description": "Object",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [],
+    "_entries": null
   }
 }
 
@@ -2121,10 +2174,12 @@ EXPRESSION: Object.freeze({})
   "_objectId": "<filtered>",
   "_description": "Object",
   "_preview": {
-    "type": "object",
-    "description": "Object",
-    "lossless": true,
-    "properties": []
+    "_type": "object",
+    "_description": "Object",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [],
+    "_entries": null
   }
 }
 
@@ -2136,13 +2191,13 @@ EXPRESSION: new Map
   "_objectId": "<filtered>",
   "_description": "Map",
   "_preview": {
-    "type": "object",
-    "description": "Map",
-    "lossless": true,
-    "subtype": "map",
-    "overflow": false,
-    "properties": [],
-    "entries": []
+    "_type": "object",
+    "_subtype": "map",
+    "_description": "Map",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [],
+    "_entries": []
   }
 }
 
@@ -2154,35 +2209,47 @@ EXPRESSION: map = new Map; map.set(1, 2); map.set('key', 'value'); map
   "_objectId": "<filtered>",
   "_description": "Map",
   "_preview": {
-    "type": "object",
-    "description": "Map",
-    "lossless": true,
-    "subtype": "map",
-    "overflow": false,
-    "properties": [],
-    "entries": [
-      {
-        "key": {
-          "type": "number",
-          "description": "1",
-          "lossless": true
+    "_type": "object",
+    "_subtype": "map",
+    "_description": "Map",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [],
+    "_entries": [
+      {
+        "_key": {
+          "_type": "number",
+          "_description": "1",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         },
-        "value": {
-          "type": "number",
-          "description": "2",
-          "lossless": true
+        "_value": {
+          "_type": "number",
+          "_description": "2",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         }
       },
       {
-        "key": {
-          "type": "string",
-          "description": "key",
-          "lossless": true
+        "_key": {
+          "_type": "string",
+          "_description": "key",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         },
-        "value": {
-          "type": "string",
-          "description": "value",
-          "lossless": true
+        "_value": {
+          "_type": "string",
+          "_description": "value",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         }
       }
     ]
@@ -2197,92 +2264,98 @@ EXPRESSION: map = new Map; map.set({a:1}, {b:2}); map.set(document.body, [1,2]);
   "_objectId": "<filtered>",
   "_description": "Map",
   "_preview": {
-    "type": "object",
-    "description": "Map",
-    "lossless": true,
-    "subtype": "map",
-    "overflow": false,
-    "properties": [],
-    "entries": [
-      {
-        "key": {
-          "type": "object",
-          "description": "Object",
-          "lossless": true,
-          "properties": [
+    "_type": "object",
+    "_subtype": "map",
+    "_description": "Map",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [],
+    "_entries": [
+      {
+        "_key": {
+          "_type": "object",
+          "_description": "Object",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": [
             {
-              "name": "a",
-              "type": "number",
-              "value": "1"
+              "_name": "a",
+              "_type": "number",
+              "_value": "1"
             }
-          ]
+          ],
+          "_entries": null
         },
-        "value": {
-          "type": "object",
-          "description": "Object",
-          "lossless": true,
-          "properties": [
+        "_value": {
+          "_type": "object",
+          "_description": "Object",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": [
             {
-              "name": "b",
-              "type": "number",
-              "value": "2"
+              "_name": "b",
+              "_type": "number",
+              "_value": "2"
             }
-          ]
+          ],
+          "_entries": null
         }
       },
       {
-        "key": {
-          "type": "object",
-          "description": "body",
-          "lossless": false,
-          "subtype": "node",
-          "overflow": true,
-          "properties": [
+        "_key": {
+          "_type": "object",
+          "_subtype": "node",
+          "_description": "body",
+          "_lossless": false,
+          "_overflow": true,
+          "_properties": [
             {
-              "name": "aLink",
-              "type": "string",
-              "value": ""
+              "_name": "aLink",
+              "_type": "string",
+              "_value": ""
             },
             {
-              "name": "background",
-              "type": "string",
-              "value": ""
+              "_name": "background",
+              "_type": "string",
+              "_value": ""
             },
             {
-              "name": "bgColor",
-              "type": "string",
-              "value": ""
+              "_name": "bgColor",
+              "_type": "string",
+              "_value": ""
             },
             {
-              "name": "link",
-              "type": "string",
-              "value": ""
+              "_name": "link",
+              "_type": "string",
+              "_value": ""
             },
             {
-              "name": "text",
-              "type": "string",
-              "value": ""
+              "_name": "text",
+              "_type": "string",
+              "_value": ""
             }
-          ]
+          ],
+          "_entries": null
         },
-        "value": {
-          "type": "object",
-          "description": "Array[2]",
-          "lossless": true,
-          "subtype": "array",
-          "overflow": false,
-          "properties": [
+        "_value": {
+          "_type": "object",
+          "_subtype": "array",
+          "_description": "Array[2]",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": [
             {
-              "name": "0",
-              "type": "number",
-              "value": "1"
+              "_name": "0",
+              "_type": "number",
+              "_value": "1"
             },
             {
-              "name": "1",
-              "type": "number",
-              "value": "2"
+              "_name": "1",
+              "_type": "number",
+              "_value": "2"
             }
-          ]
+          ],
+          "_entries": null
         }
       }
     ]
@@ -2297,71 +2370,101 @@ EXPRESSION: map = new Map; for (var i = 0; i <= 100; i++) map.set(i, i); map
   "_objectId": "<filtered>",
   "_description": "Map",
   "_preview": {
-    "type": "object",
-    "description": "Map",
-    "lossless": false,
-    "subtype": "map",
-    "overflow": true,
-    "properties": [],
-    "entries": [
-      {
-        "key": {
-          "type": "number",
-          "description": "0",
-          "lossless": true
+    "_type": "object",
+    "_subtype": "map",
+    "_description": "Map",
+    "_lossless": false,
+    "_overflow": true,
+    "_properties": [],
+    "_entries": [
+      {
+        "_key": {
+          "_type": "number",
+          "_description": "0",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         },
-        "value": {
-          "type": "number",
-          "description": "0",
-          "lossless": true
+        "_value": {
+          "_type": "number",
+          "_description": "0",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         }
       },
       {
-        "key": {
-          "type": "number",
-          "description": "1",
-          "lossless": true
+        "_key": {
+          "_type": "number",
+          "_description": "1",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         },
-        "value": {
-          "type": "number",
-          "description": "1",
-          "lossless": true
+        "_value": {
+          "_type": "number",
+          "_description": "1",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         }
       },
       {
-        "key": {
-          "type": "number",
-          "description": "2",
-          "lossless": true
+        "_key": {
+          "_type": "number",
+          "_description": "2",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         },
-        "value": {
-          "type": "number",
-          "description": "2",
-          "lossless": true
+        "_value": {
+          "_type": "number",
+          "_description": "2",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         }
       },
       {
-        "key": {
-          "type": "number",
-          "description": "3",
-          "lossless": true
+        "_key": {
+          "_type": "number",
+          "_description": "3",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         },
-        "value": {
-          "type": "number",
-          "description": "3",
-          "lossless": true
+        "_value": {
+          "_type": "number",
+          "_description": "3",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         }
       },
       {
-        "key": {
-          "type": "number",
-          "description": "4",
-          "lossless": true
+        "_key": {
+          "_type": "number",
+          "_description": "4",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         },
-        "value": {
-          "type": "number",
-          "description": "4",
-          "lossless": true
+        "_value": {
+          "_type": "number",
+          "_description": "4",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         }
       }
     ]
@@ -2376,44 +2479,47 @@ EXPRESSION: map = new WeakMap; strongKey = {id:1}; map.set(strongKey, [1,2]); ma
   "_objectId": "<filtered>",
   "_description": "WeakMap",
   "_preview": {
-    "type": "object",
-    "description": "WeakMap",
-    "lossless": true,
-    "subtype": "weakmap",
-    "overflow": false,
-    "properties": [],
-    "entries": [
-      {
-        "key": {
-          "type": "object",
-          "description": "Object",
-          "lossless": true,
-          "properties": [
+    "_type": "object",
+    "_subtype": "weakmap",
+    "_description": "WeakMap",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [],
+    "_entries": [
+      {
+        "_key": {
+          "_type": "object",
+          "_description": "Object",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": [
             {
-              "name": "id",
-              "type": "number",
-              "value": "1"
+              "_name": "id",
+              "_type": "number",
+              "_value": "1"
             }
-          ]
+          ],
+          "_entries": null
         },
-        "value": {
-          "type": "object",
-          "description": "Array[2]",
-          "lossless": true,
-          "subtype": "array",
-          "overflow": false,
-          "properties": [
+        "_value": {
+          "_type": "object",
+          "_subtype": "array",
+          "_description": "Array[2]",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": [
             {
-              "name": "0",
-              "type": "number",
-              "value": "1"
+              "_name": "0",
+              "_type": "number",
+              "_value": "1"
             },
             {
-              "name": "1",
-              "type": "number",
-              "value": "2"
+              "_name": "1",
+              "_type": "number",
+              "_value": "2"
             }
-          ]
+          ],
+          "_entries": null
         }
       }
     ]
@@ -2428,13 +2534,13 @@ EXPRESSION: new Set
   "_objectId": "<filtered>",
   "_description": "Set",
   "_preview": {
-    "type": "object",
-    "description": "Set",
-    "lossless": true,
-    "subtype": "set",
-    "overflow": false,
-    "properties": [],
-    "entries": []
+    "_type": "object",
+    "_subtype": "set",
+    "_description": "Set",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [],
+    "_entries": []
   }
 }
 
@@ -2446,32 +2552,41 @@ EXPRESSION: set = new Set; set.add(1); set.add(2); set.add('key'); set
   "_objectId": "<filtered>",
   "_description": "Set",
   "_preview": {
-    "type": "object",
-    "description": "Set",
-    "lossless": true,
-    "subtype": "set",
-    "overflow": false,
-    "properties": [],
-    "entries": [
-      {
-        "value": {
-          "type": "number",
-          "description": "1",
-          "lossless": true
+    "_type": "object",
+    "_subtype": "set",
+    "_description": "Set",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [],
+    "_entries": [
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "1",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         }
       },
       {
-        "value": {
-          "type": "number",
-          "description": "2",
-          "lossless": true
+        "_value": {
+          "_type": "number",
+          "_description": "2",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         }
       },
       {
-        "value": {
-          "type": "string",
-          "description": "key",
-          "lossless": true
+        "_value": {
+          "_type": "string",
+          "_description": "key",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         }
       }
     ]
@@ -2486,82 +2601,86 @@ EXPRESSION: set = new Set; set.add({a:1}); set.add(document.body); set.add([1,2]
   "_objectId": "<filtered>",
   "_description": "Set",
   "_preview": {
-    "type": "object",
-    "description": "Set",
-    "lossless": true,
-    "subtype": "set",
-    "overflow": false,
-    "properties": [],
-    "entries": [
-      {
-        "value": {
-          "type": "object",
-          "description": "Object",
-          "lossless": true,
-          "properties": [
+    "_type": "object",
+    "_subtype": "set",
+    "_description": "Set",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [],
+    "_entries": [
+      {
+        "_value": {
+          "_type": "object",
+          "_description": "Object",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": [
             {
-              "name": "a",
-              "type": "number",
-              "value": "1"
+              "_name": "a",
+              "_type": "number",
+              "_value": "1"
             }
-          ]
+          ],
+          "_entries": null
         }
       },
       {
-        "value": {
-          "type": "object",
-          "description": "body",
-          "lossless": false,
-          "subtype": "node",
-          "overflow": true,
-          "properties": [
+        "_value": {
+          "_type": "object",
+          "_subtype": "node",
+          "_description": "body",
+          "_lossless": false,
+          "_overflow": true,
+          "_properties": [
             {
-              "name": "aLink",
-              "type": "string",
-              "value": ""
+              "_name": "aLink",
+              "_type": "string",
+              "_value": ""
             },
             {
-              "name": "background",
-              "type": "string",
-              "value": ""
+              "_name": "background",
+              "_type": "string",
+              "_value": ""
             },
             {
-              "name": "bgColor",
-              "type": "string",
-              "value": ""
+              "_name": "bgColor",
+              "_type": "string",
+              "_value": ""
             },
             {
-              "name": "link",
-              "type": "string",
-              "value": ""
+              "_name": "link",
+              "_type": "string",
+              "_value": ""
             },
             {
-              "name": "text",
-              "type": "string",
-              "value": ""
+              "_name": "text",
+              "_type": "string",
+              "_value": ""
             }
-          ]
+          ],
+          "_entries": null
         }
       },
       {
-        "value": {
-          "type": "object",
-          "description": "Array[2]",
-          "lossless": true,
-          "subtype": "array",
-          "overflow": false,
-          "properties": [
+        "_value": {
+          "_type": "object",
+          "_subtype": "array",
+          "_description": "Array[2]",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": [
             {
-              "name": "0",
-              "type": "number",
-              "value": "1"
+              "_name": "0",
+              "_type": "number",
+              "_value": "1"
             },
             {
-              "name": "1",
-              "type": "number",
-              "value": "2"
+              "_name": "1",
+              "_type": "number",
+              "_value": "2"
             }
-          ]
+          ],
+          "_entries": null
         }
       }
     ]
@@ -2576,46 +2695,61 @@ EXPRESSION: set = new Set; for (var i = 0; i <= 100; i++) set.add(i); set
   "_objectId": "<filtered>",
   "_description": "Set",
   "_preview": {
-    "type": "object",
-    "description": "Set",
-    "lossless": false,
-    "subtype": "set",
-    "overflow": true,
-    "properties": [],
-    "entries": [
-      {
-        "value": {
-          "type": "number",
-          "description": "0",
-          "lossless": true
+    "_type": "object",
+    "_subtype": "set",
+    "_description": "Set",
+    "_lossless": false,
+    "_overflow": true,
+    "_properties": [],
+    "_entries": [
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "0",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         }
       },
       {
-        "value": {
-          "type": "number",
-          "description": "1",
-          "lossless": true
+        "_value": {
+          "_type": "number",
+          "_description": "1",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         }
       },
       {
-        "value": {
-          "type": "number",
-          "description": "2",
-          "lossless": true
+        "_value": {
+          "_type": "number",
+          "_description": "2",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         }
       },
       {
-        "value": {
-          "type": "number",
-          "description": "3",
-          "lossless": true
+        "_value": {
+          "_type": "number",
+          "_description": "3",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         }
       },
       {
-        "value": {
-          "type": "number",
-          "description": "4",
-          "lossless": true
+        "_value": {
+          "_type": "number",
+          "_description": "4",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
         }
       }
     ]
@@ -2629,17 +2763,19 @@ EXPRESSION: new Promise(function(){})
   "_objectId": "<filtered>",
   "_description": "Promise",
   "_preview": {
-    "type": "object",
-    "description": "Promise",
-    "lossless": true,
-    "properties": [
-      {
-        "name": "status",
-        "type": "string",
-        "value": "pending",
-        "internal": true
+    "_type": "object",
+    "_description": "Promise",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "status",
+        "_type": "string",
+        "_value": "pending",
+        "_internal": true
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -2650,23 +2786,25 @@ EXPRESSION: Promise.reject()
   "_objectId": "<filtered>",
   "_description": "Promise",
   "_preview": {
-    "type": "object",
-    "description": "Promise",
-    "lossless": true,
-    "properties": [
-      {
-        "name": "status",
-        "type": "string",
-        "value": "rejected",
-        "internal": true
-      },
-      {
-        "name": "result",
-        "type": "undefined",
-        "value": "undefined",
-        "internal": true
+    "_type": "object",
+    "_description": "Promise",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "status",
+        "_type": "string",
+        "_value": "rejected",
+        "_internal": true
+      },
+      {
+        "_name": "result",
+        "_type": "undefined",
+        "_value": "undefined",
+        "_internal": true
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -2677,23 +2815,25 @@ EXPRESSION: Promise.reject('result')
   "_objectId": "<filtered>",
   "_description": "Promise",
   "_preview": {
-    "type": "object",
-    "description": "Promise",
-    "lossless": true,
-    "properties": [
-      {
-        "name": "status",
-        "type": "string",
-        "value": "rejected",
-        "internal": true
-      },
-      {
-        "name": "result",
-        "type": "string",
-        "value": "result",
-        "internal": true
+    "_type": "object",
+    "_description": "Promise",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "status",
+        "_type": "string",
+        "_value": "rejected",
+        "_internal": true
+      },
+      {
+        "_name": "result",
+        "_type": "string",
+        "_value": "result",
+        "_internal": true
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -2704,23 +2844,25 @@ EXPRESSION: Promise.resolve()
   "_objectId": "<filtered>",
   "_description": "Promise",
   "_preview": {
-    "type": "object",
-    "description": "Promise",
-    "lossless": true,
-    "properties": [
-      {
-        "name": "status",
-        "type": "string",
-        "value": "resolved",
-        "internal": true
-      },
-      {
-        "name": "result",
-        "type": "undefined",
-        "value": "undefined",
-        "internal": true
+    "_type": "object",
+    "_description": "Promise",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "status",
+        "_type": "string",
+        "_value": "resolved",
+        "_internal": true
+      },
+      {
+        "_name": "result",
+        "_type": "undefined",
+        "_value": "undefined",
+        "_internal": true
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
@@ -2731,23 +2873,25 @@ EXPRESSION: Promise.resolve({result:1})
   "_objectId": "<filtered>",
   "_description": "Promise",
   "_preview": {
-    "type": "object",
-    "description": "Promise",
-    "lossless": false,
-    "properties": [
-      {
-        "name": "status",
-        "type": "string",
-        "value": "resolved",
-        "internal": true
-      },
-      {
-        "name": "result",
-        "type": "object",
-        "value": "Object",
-        "internal": true
+    "_type": "object",
+    "_description": "Promise",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "status",
+        "_type": "string",
+        "_value": "resolved",
+        "_internal": true
+      },
+      {
+        "_name": "result",
+        "_type": "object",
+        "_value": "Object",
+        "_internal": true
       }
-    ]
+    ],
+    "_entries": null
   }
 }
 
index fa31201..fb93bee 100644 (file)
@@ -128,15 +128,11 @@ ALL PROPERTIES:
     _bar
     _foo
     constructor
-    get getterProperty
-    set getterProperty
-    get foo
-    set foo
+    getterProperty
+    foo
     BAR_CONSTANT
-    get bar
-    set bar
-    get setterOnly
-    set setterOnly
+    bar
+    setterOnly
     toString
     toLocaleString
     valueOf
@@ -164,8 +160,7 @@ OWN AND GETTER PROPERTIES:
 
 ALL PROPERTIES:
     constructor
-    get badGetter
-    set badGetter
+    badGetter
     toString
     toLocaleString
     valueOf
@@ -233,10 +228,8 @@ description: function () {
 OWN PROPERTIES:
     name
     length
-    get arguments
-    set arguments
-    get caller
-    set caller
+    arguments
+    caller
     __proto__
     targetFunction
     boundThis
@@ -245,10 +238,8 @@ OWN PROPERTIES:
 OWN AND GETTER PROPERTIES:
     name
     length
-    get arguments
-    set arguments
-    get caller
-    set caller
+    arguments
+    caller
     __proto__
     targetFunction
     boundThis
@@ -257,10 +248,8 @@ OWN AND GETTER PROPERTIES:
 ALL PROPERTIES:
     name
     length
-    get arguments
-    set arguments
-    get caller
-    set caller
+    arguments
+    caller
     toString
     apply
     call
index 4301fe0..fc0e2e7 100644 (file)
@@ -79,26 +79,26 @@ function test()
             if (remoteObject.subtype)
                 InspectorTest.log("subtype: " + remoteObject.subtype);
             InspectorTest.log("description: " + remoteObject.description);
-            remoteObject.getOwnProperties(function(properties) {
+            remoteObject.getOwnPropertyDescriptors(function(properties) {
                 InspectorTest.log("\nOWN PROPERTIES:");
                 for (var property of properties) {
-                    InspectorTest.assert(property instanceof WebInspector.RemoteObjectProperty);
+                    InspectorTest.assert(property instanceof WebInspector.PropertyDescriptor);
                     InspectorTest.log("    " + property.name);
                 }
             });
 
-            remoteObject.getOwnAndGetterProperties(function(properties) {
+            remoteObject.getOwnAndGetterPropertyDescriptors(function(properties) {
                 InspectorTest.log("\nOWN AND GETTER PROPERTIES:");
                 for (var property of properties) {
-                    InspectorTest.assert(property instanceof WebInspector.RemoteObjectProperty);
+                    InspectorTest.assert(property instanceof WebInspector.PropertyDescriptor);
                     InspectorTest.log("    " + property.name);
                 }
             });
 
-            remoteObject.getAllProperties(function(properties) {
+            remoteObject.getAllPropertyDescriptors(function(properties) {
                 InspectorTest.log("\nALL PROPERTIES:");
                 for (var property of properties) {
-                    InspectorTest.assert(property instanceof WebInspector.RemoteObjectProperty);
+                    InspectorTest.assert(property instanceof WebInspector.PropertyDescriptor);
                     InspectorTest.log("    " + property.name);
                 }
 
index c3424f0..dbcd375 100644 (file)
@@ -9,53 +9,59 @@ EXPRESSION: weakMap.set(strongKey1, 1); weakMap.set(strongKey2, 2); weakMap
 ENTRIES:
 [
   {
-    "key": {
-      "type": "object",
-      "objectId": "<filtered>",
-      "className": "Object",
-      "description": "Object",
-      "preview": {
-        "type": "object",
-        "description": "Object",
-        "lossless": true,
-        "properties": [
+    "_key": {
+      "_type": "object",
+      "_objectId": "<filtered>",
+      "_description": "Object",
+      "_hasChildren": true,
+      "_preview": {
+        "_type": "object",
+        "_description": "Object",
+        "_lossless": true,
+        "_overflow": false,
+        "_properties": [
           {
-            "name": "id",
-            "type": "number",
-            "value": "1"
+            "_name": "id",
+            "_type": "number",
+            "_value": "1"
           }
-        ]
+        ],
+        "_entries": null
       }
     },
-    "value": {
-      "type": "number",
-      "value": 1,
-      "description": "1"
+    "_value": {
+      "_type": "number",
+      "_description": "1",
+      "_hasChildren": false,
+      "_value": 1
     }
   },
   {
-    "key": {
-      "type": "object",
-      "objectId": "<filtered>",
-      "className": "Object",
-      "description": "Object",
-      "preview": {
-        "type": "object",
-        "description": "Object",
-        "lossless": true,
-        "properties": [
+    "_key": {
+      "_type": "object",
+      "_objectId": "<filtered>",
+      "_description": "Object",
+      "_hasChildren": true,
+      "_preview": {
+        "_type": "object",
+        "_description": "Object",
+        "_lossless": true,
+        "_overflow": false,
+        "_properties": [
           {
-            "name": "id",
-            "type": "number",
-            "value": "2"
+            "_name": "id",
+            "_type": "number",
+            "_value": "2"
           }
-        ]
+        ],
+        "_entries": null
       }
     },
-    "value": {
-      "type": "number",
-      "value": 2,
-      "description": "2"
+    "_value": {
+      "_type": "number",
+      "_description": "2",
+      "_hasChildren": false,
+      "_value": 2
     }
   }
 ]
@@ -65,28 +71,31 @@ EXPRESSION: delete window.strongKey1; weakMap
 ENTRIES:
 [
   {
-    "key": {
-      "type": "object",
-      "objectId": "<filtered>",
-      "className": "Object",
-      "description": "Object",
-      "preview": {
-        "type": "object",
-        "description": "Object",
-        "lossless": true,
-        "properties": [
+    "_key": {
+      "_type": "object",
+      "_objectId": "<filtered>",
+      "_description": "Object",
+      "_hasChildren": true,
+      "_preview": {
+        "_type": "object",
+        "_description": "Object",
+        "_lossless": true,
+        "_overflow": false,
+        "_properties": [
           {
-            "name": "id",
-            "type": "number",
-            "value": "2"
+            "_name": "id",
+            "_type": "number",
+            "_value": "2"
           }
-        ]
+        ],
+        "_entries": null
       }
     },
-    "value": {
-      "type": "number",
-      "value": 2,
-      "description": "2"
+    "_value": {
+      "_type": "number",
+      "_description": "2",
+      "_hasChildren": false,
+      "_value": 2
     }
   }
 ]
@@ -96,28 +105,31 @@ EXPRESSION: weakMap.set({id:3}, 3); weakMap.set({id:4}, 4); weakMap
 ENTRIES:
 [
   {
-    "key": {
-      "type": "object",
-      "objectId": "<filtered>",
-      "className": "Object",
-      "description": "Object",
-      "preview": {
-        "type": "object",
-        "description": "Object",
-        "lossless": true,
-        "properties": [
+    "_key": {
+      "_type": "object",
+      "_objectId": "<filtered>",
+      "_description": "Object",
+      "_hasChildren": true,
+      "_preview": {
+        "_type": "object",
+        "_description": "Object",
+        "_lossless": true,
+        "_overflow": false,
+        "_properties": [
           {
-            "name": "id",
-            "type": "number",
-            "value": "2"
+            "_name": "id",
+            "_type": "number",
+            "_value": "2"
           }
-        ]
+        ],
+        "_entries": null
       }
     },
-    "value": {
-      "type": "number",
-      "value": 2,
-      "description": "2"
+    "_value": {
+      "_type": "number",
+      "_description": "2",
+      "_hasChildren": false,
+      "_value": 2
     }
   }
 ]
index 2076454..102bd23 100644 (file)
@@ -32,7 +32,7 @@ function test()
 
     function remoteObjectJSONFilter(key, value)
     {
-        if (key === "objectId")
+        if (key === "_objectId")
             return "<filtered>";
 
         return value;
@@ -59,6 +59,8 @@ function test()
                 remoteObject.getCollectionEntries(0, 100, function(entries) {
                     InspectorTest.log("ENTRIES:");
                     entries.sort(function(a, b) { return a.value.value - b.value.value; });
+                    for (var entry of entries)
+                        InspectorTest.assert(entry instanceof WebInspector.CollectionEntry);
                     InspectorTest.log(JSON.stringify(entries, remoteObjectJSONFilter, "  "));
                     remoteObject.releaseWeakCollectionEntries();
                     runNextStep();
index 31ae44e..511628e 100644 (file)
@@ -1,5 +1,209 @@
 2015-02-19  Joseph Pecoraro  <pecoraro@apple.com>
 
+        Web Inspector: Create Separate Model and View Objects for RemoteObjects / ObjectPreview / PropertyDescriptor
+        https://bugs.webkit.org/show_bug.cgi?id=141696
+
+        Reviewed by Timothy Hatcher.
+
+        * UserInterface/Main.html:
+        Add new files.
+
+        * UserInterface/Models/CollectionEntry.js: Added.
+        (WebInspector.CollectionEntry):
+        (WebInspector.CollectionEntry.fromPayload):
+        (WebInspector.CollectionEntry.prototype.get key):
+        (WebInspector.CollectionEntry.prototype.get value):
+        * UserInterface/Models/CollectionEntryPreview.js: Added.
+        (WebInspector.CollectionEntryPreview):
+        (WebInspector.CollectionEntryPreview.fromPayload):
+        (WebInspector.CollectionEntryPreview.prototype.get keyPreview):
+        (WebInspector.CollectionEntryPreview.prototype.get valuePreview):
+        * UserInterface/Models/ObjectPreview.js: Added.
+        (WebInspector.ObjectPreview):
+        (WebInspector.ObjectPreview.fromPayload):
+        (WebInspector.ObjectPreview.prototype.get type):
+        (WebInspector.ObjectPreview.prototype.get subtype):
+        (WebInspector.ObjectPreview.prototype.get description):
+        (WebInspector.ObjectPreview.prototype.get lossless):
+        (WebInspector.ObjectPreview.prototype.get overflow):
+        (WebInspector.ObjectPreview.prototype.get properties):
+        (WebInspector.ObjectPreview.prototype.get entries):
+        * UserInterface/Models/PropertyPreview.js: Added.
+        (WebInspector.PropertyPreview):
+        (WebInspector.PropertyPreview.fromPayload):
+        (WebInspector.PropertyPreview.prototype.get name):
+        (WebInspector.PropertyPreview.prototype.get type):
+        (WebInspector.PropertyPreview.prototype.get subtype):
+        (WebInspector.PropertyPreview.prototype.get value):
+        (WebInspector.PropertyPreview.prototype.get valuePreview):
+        * UserInterface/Models/PropertyDescriptor.js: Added.
+        (WebInspector.PropertyDescriptor.fromPayload):
+        (WebInspector.PropertyDescriptor.prototype.get name):
+        (WebInspector.PropertyDescriptor.prototype.get value):
+        (WebInspector.PropertyDescriptor.prototype.get writable):
+        (WebInspector.PropertyDescriptor.prototype.get configurable):
+        (WebInspector.PropertyDescriptor.prototype.get enumerable):
+        (WebInspector.PropertyDescriptor.prototype.get isOwnProperty):
+        (WebInspector.PropertyDescriptor.prototype.get wasThrown):
+        (WebInspector.PropertyDescriptor.prototype.get isInternalProperty):
+        (WebInspector.PropertyDescriptor.prototype.hasValue):
+        (WebInspector.PropertyDescriptor.prototype.hasGetter):
+        (WebInspector.PropertyDescriptor.prototype.hasSetter):
+        New Model objects for different Protocol types.
+        The only customizations right now are compatibility modifications
+        and PropertyDescriptor's "hasValue", "hasGetter", and "hasSetter"
+        functions to return reliable checks based on the descriptors contents.
+
+        * UserInterface/Protocol/RemoteObject.js:
+        (WebInspector.RemoteObject):
+        (WebInspector.RemoteObject.fromPayload):
+        (WebInspector.RemoteObject.resolveNode):
+        (WebInspector.RemoteObject.prototype.get value):
+        (WebInspector.RemoteObject.prototype._isSymbol):
+        (WebInspector.RemoteObject.prototype.isCollectionType):
+        (WebInspector.RemoteObject.prototype.isWeakCollection):
+        (WebInspector.RemoteObject.prototype.getCollectionEntries):
+        (WebInspector.RemoteObject.prototype.arrayLength):
+        Clean up the existing code to enforce more checks and use our
+        style of member variables and public accessors.
+
+        (WebInspector.RemoteObject.prototype.getOwnPropertyDescriptors):
+        (WebInspector.RemoteObject.prototype.getOwnAndGetterPropertyDescriptors):
+        (WebInspector.RemoteObject.prototype.getAllPropertyDescriptors):
+        (WebInspector.RemoteObject.prototype.callback):
+        Provide a new way of getting properties that returns Model objects
+        instead of raw protocol types.
+
+        * UserInterface/Views/ConsoleMessageImpl.js:
+        (WebInspector.ConsoleMessageImpl.prototype._format):
+        (WebInspector.ConsoleMessageImpl.prototype._formatParameter):
+        (WebInspector.ConsoleMessageImpl.prototype._propertyPreviewElement):
+        (WebInspector.ConsoleMessageImpl.prototype._formatParameterAsNode):
+        (WebInspector.ConsoleMessageImpl.prototype._formatParameterAsTable):
+        (WebInspector.ConsoleMessageImpl.prototype._formatAsArrayEntry):
+        Always include a preview when possible. Now, when forced to be an object,
+        force expansion even if the preview is lossless.
+
+        (WebInspector.ConsoleMessageImpl.prototype._formatParameterAsObject):
+        Use an ObjectTreeView instead of ObjectPropertiesSection.
+
+        (WebInspector.ConsoleMessageImpl.prototype._appendPreview): Deleted.
+        (WebInspector.ConsoleMessageImpl.prototype._appendEntryPreviews): Deleted.
+        (WebInspector.ConsoleMessageImpl.prototype._appendPropertyPreviews): Deleted.
+        (WebInspector.ConsoleMessageImpl.prototype._appendValuePreview): Deleted.
+        This code is moved into ObjectPreviewView.
+
+
+        * UserInterface/Views/ObjectPropertiesSection.js:
+        (WebInspector.CollectionEntriesMainTreeElement.prototype.onexpand.callback):
+        (WebInspector.CollectionEntriesMainTreeElement.prototype.onexpand):
+        These types are now converted to Model types in Model objects, so do not do it here.
+
+        * UserInterface/Views/ObjectPreviewView.css: Added.
+        (.object-preview):
+        (.object-preview.lossless):
+        (.object-preview .name):
+        * UserInterface/Views/ObjectPreviewView.js: Added.
+        (WebInspector.ObjectPreviewView):
+        (WebInspector.ObjectPreviewView.prototype.get preview):
+        (WebInspector.ObjectPreviewView.prototype.get element):
+        (WebInspector.ObjectPreviewView.prototype.get mode):
+        (WebInspector.ObjectPreviewView.prototype.get lossless):
+        (WebInspector.ObjectPreviewView.prototype._numberOfPropertiesToShowInMode):
+        (WebInspector.ObjectPreviewView.prototype._appendPreview):
+        (WebInspector.ObjectPreviewView.prototype._appendEntryPreviews):
+        (WebInspector.ObjectPreviewView.prototype._appendPropertyPreviews):
+        (WebInspector.ObjectPreviewView.prototype._appendValuePreview):
+        (WebInspector.ObjectPreviewView.prototype._formattedObjectElementForPreview):
+        An ObjectPreviewView can create a full/brief view given a ObjectPreview.
+        The view will contain formatted values everywhere possible.
+
+        * UserInterface/Views/ObjectTreePropertyTreeElement.js: Added.
+        (WebInspector.ObjectTreePropertyTreeElement):
+        (WebInspector.ObjectTreePropertyTreeElement.prototype.get property):
+        (WebInspector.ObjectTreePropertyTreeElement.prototype.onpopulate):
+        (WebInspector.ObjectTreePropertyTreeElement.prototype.onattach):
+        (WebInspector.ObjectTreePropertyTreeElement.prototype._updateTitle):
+        (WebInspector.ObjectTreePropertyTreeElement.prototype._updateTitlePropertyStyle):
+        (WebInspector.ObjectTreePropertyTreeElement.prototype._updateTitleAPIStyle):
+        (WebInspector.ObjectTreePropertyTreeElement.prototype._descriptionString):
+        (WebInspector.ObjectTreePropertyTreeElement.prototype._functionParameterString):
+        (WebInspector.ObjectTreePropertyTreeElement.prototype.mode):
+        (WebInspector.ObjectTreePropertyTreeElement.prototype):
+        * UserInterface/Views/ObjectTreeView.js: Added.
+        (WebInspector.ObjectTreeView):
+        (WebInspector.ObjectTreeView.classNameForObject):
+        (WebInspector.ObjectTreeView.ComparePropertyDescriptors):
+        (WebInspector.ObjectTreeView.prototype.get object):
+        (WebInspector.ObjectTreeView.prototype.get element):
+        (WebInspector.ObjectTreeView.prototype.get expanded):
+        (WebInspector.ObjectTreeView.prototype.expand):
+        (WebInspector.ObjectTreeView.prototype.collapse):
+        (WebInspector.ObjectTreeView.prototype.update):
+        (WebInspector.ObjectTreeView.prototype._updateProperties):
+        (WebInspector.ObjectTreeView.prototype._handlePreviewOrTitleElementClick):
+        Re-implementation of ObjectPropertiesSection for our Model objects
+        without "Section" semantics / dependencies. An ObjectTree will creates
+        an expandable tree for a RemoteObject. The top level clickable item
+        will be an ObjectPreview if possible, otherwise just a title element.
+
+        * UserInterface/Views/ObjectTreeView.css: Added.
+        (.object-tree):
+        (.object-tree > .title):
+        (.object-tree > :matches(.title, .object-preview)::before):
+        (.object-tree.expanded > :matches(.title, .object-preview)::before):
+        (.object-tree.lossless-preview > :matches(.title, .object-preview)::before):
+        (.object-tree-outline):
+        (.object-tree.expanded > .object-tree-outline):
+        (.object-tree-outline li):
+        (.object-tree-outline li.parent):
+        (.object-tree-outline li.parent::before):
+        (.object-tree-outline li.parent.expanded::before):
+        (.object-tree-outline ol):
+        (.object-tree-outline ol.expanded):
+        (.object-tree-outline li .empty-message):
+        (.object-tree-property .name):
+        (.object-tree-property .name.not-enumerable):
+        (.object-tree-property .value.error):
+        (.formatted-object, .formatted-node, .formatted-error, .formatted-map, .formatted-set, .formatted-weakmap):
+        (.formatted-number):
+        (.formatted-string, .formatted-regexp):
+        (.formatted-string):
+        (.formatted-regexp):
+        (.formatted-symbol):
+        (.formatted-null, .formatted-undefined):
+        (.console-group-messages .object-tree:not(.lossless-preview)):
+        (.console-group-messages .object-tree:not(.lossless-preview) > :matches(.title, .object-preview)):
+        (.console-group-messages .object-tree:not(.lossless-preview) > :matches(.title, .object-preview)::before):
+        (.console-group-messages :matches(.console-formatted-object, .console-formatted-node, .console-formatted-error, .console-formatted-map, .console-formatted-set, .console-formatted-weakmap) .object-tree):
+        (.console-group-messages :matches(.console-formatted-object, .console-formatted-node, .console-formatted-error, .console-formatted-map, .console-formatted-set, .console-formatted-weakmap) .object-tree-outline):
+        All styles for ObjectTree / ObjectPreview. Independent from
+        other styles in the inspector. Most of this is a copy of
+        the styles applied to ObjectPropertiesSection, renamed.
+
+
+        * UserInterface/Views/ObjectTreeCollectionTreeElement.js: Added.
+        (WebInspector.ObjectTreeCollectionTreeElement):
+        (WebInspector.ObjectTreeCollectionTreeElement.propertyDescriptorForEntry):
+        (WebInspector.ObjectTreeCollectionTreeElement.prototype.get remoteObject):
+        (WebInspector.ObjectTreeCollectionTreeElement.prototype.onexpand.callback):
+        (WebInspector.ObjectTreeCollectionTreeElement.prototype.onexpand):
+        (WebInspector.ObjectTreeCollectionTreeElement.prototype.oncollapse):
+        (WebInspector.ObjectTreeCollectionTreeElement.prototype.ondetach):
+        (WebInspector.ObjectTreeCollectionTreeElement.prototype._trackWeakEntries):
+        (WebInspector.ObjectTreeCollectionTreeElement.prototype._untrackWeakEntries):
+        (WebInspector.ObjectTreeCollectionEntryTreeElement):
+        (WebInspector.ObjectTreeCollectionEntryTreeElement.prototype.onpopulate):
+        (WebInspector.ObjectTreeCollectionEntryTreeElement.prototype.onattach):
+        (WebInspector.ObjectTreeEmptyCollectionTreeElement):
+        Essentially a copy of ObjectPropertiesSection Collection handling using
+        the ObjectTree class names.
+
+        * UserInterface/Views/TreeOutlineDataGridSynchronizer.js:
+        Fix prototype typo.
+
+2015-02-19  Joseph Pecoraro  <pecoraro@apple.com>
+
         Web Inspector: DOMTree / Node Details Sidebar do not update as <input> content changes
         https://bugs.webkit.org/show_bug.cgi?id=141790
 
index 46f31a1..f667eeb 100644 (file)
@@ -96,6 +96,8 @@
     <link rel="stylesheet" href="Views/NavigationSidebarPanel.css">
     <link rel="stylesheet" href="Views/NetworkTimelineOverviewGraph.css">
     <link rel="stylesheet" href="Views/NetworkTimelineView.css">
+    <link rel="stylesheet" href="Views/ObjectPreviewView.css">
+    <link rel="stylesheet" href="Views/ObjectTreeView.css">
     <link rel="stylesheet" href="Views/OverviewTimelineView.css">
     <link rel="stylesheet" href="Views/PathComponentIcons.css">
     <link rel="stylesheet" href="Views/Popover.css">
     <script src="Models/CSSStyleDeclaration.js"></script>
     <script src="Models/CSSStyleSheet.js"></script>
     <script src="Models/CallFrame.js"></script>
+    <script src="Models/CollectionEntry.js"></script>
+    <script src="Models/CollectionEntryPreview.js"></script>
     <script src="Models/Color.js"></script>
     <script src="Models/ContentFlow.js"></script>
     <script src="Models/CookieStorageObject.js"></script>
     <script src="Models/LazySourceCodeLocation.js"></script>
     <script src="Models/LogObject.js"></script>
     <script src="Models/NetworkTimeline.js"></script>
+    <script src="Models/ObjectPreview.js"></script>
     <script src="Models/Probe.js"></script>
     <script src="Models/ProbeSet.js"></script>
     <script src="Models/ProbeSetDataFrame.js"></script>
     <script src="Models/Profile.js"></script>
     <script src="Models/ProfileNode.js"></script>
     <script src="Models/ProfileNodeCall.js"></script>
+    <script src="Models/PropertyDescriptor.js"></script>
+    <script src="Models/PropertyPreview.js"></script>    
     <script src="Models/ReplayDashboard.js"></script>
     <script src="Models/ReplaySession.js"></script>
     <script src="Models/ReplaySessionSegment.js"></script>
     <script src="Views/NavigationBar.js"></script>
     <script src="Views/NetworkTimelineOverviewGraph.js"></script>
     <script src="Views/NetworkTimelineView.js"></script>
+    <script src="Views/ObjectPreviewView.js"></script>
     <script src="Views/ObjectPropertiesSection.js"></script>
+    <script src="Views/ObjectTreeCollectionTreeElement.js"></script>
+    <script src="Views/ObjectTreePropertyTreeElement.js"></script>
+    <script src="Views/ObjectTreeView.js"></script>
     <script src="Views/OverviewTimelineView.js"></script>
     <script src="Views/Popover.js"></script>
     <script src="Views/ProbeDetailsSidebarPanel.js"></script>
diff --git a/Source/WebInspectorUI/UserInterface/Models/CollectionEntry.js b/Source/WebInspectorUI/UserInterface/Models/CollectionEntry.js
new file mode 100644 (file)
index 0000000..1dbb36d
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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.CollectionEntry = function(key, value)
+{
+    WebInspector.Object.call(this);
+
+    console.assert(value instanceof WebInspector.RemoteObject);
+    console.assert(!key || key instanceof WebInspector.RemoteObject);
+
+    this._key = key;
+    this._value = value;
+};
+
+// Runtime.CollectionEntry.
+WebInspector.CollectionEntry.fromPayload = function(payload)
+{
+    if (payload.key)
+        payload.key = WebInspector.RemoteObject.fromPayload(payload.key);
+    if (payload.value)
+        payload.value = WebInspector.RemoteObject.fromPayload(payload.value);
+
+    return new WebInspector.CollectionEntry(payload.key, payload.value);
+};
+
+WebInspector.CollectionEntry.prototype = {
+    constructor: WebInspector.CollectionEntry,
+    __proto__: WebInspector.Object.prototype,
+
+    // Public
+
+    get key()
+    {
+        return this._key;
+    },
+
+    get value()
+    {
+        return this._value;
+    }
+};
diff --git a/Source/WebInspectorUI/UserInterface/Models/CollectionEntryPreview.js b/Source/WebInspectorUI/UserInterface/Models/CollectionEntryPreview.js
new file mode 100644 (file)
index 0000000..dd3afbc
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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.CollectionEntryPreview = function(keyPreview, valuePreview)
+{
+    WebInspector.Object.call(this);
+
+    console.assert(valuePreview instanceof WebInspector.ObjectPreview);
+    console.assert(!keyPreview || keyPreview instanceof WebInspector.ObjectPreview);
+
+    this._key = keyPreview;
+    this._value = valuePreview;
+};
+
+// Runtime.EntryPreview.
+WebInspector.CollectionEntryPreview.fromPayload = function(payload)
+{
+    if (payload.key)
+        payload.key = WebInspector.ObjectPreview.fromPayload(payload.key);
+    if (payload.value)
+        payload.value = WebInspector.ObjectPreview.fromPayload(payload.value);
+
+    return new WebInspector.CollectionEntryPreview(payload.key, payload.value);
+};
+
+WebInspector.CollectionEntryPreview.prototype = {
+    constructor: WebInspector.CollectionEntryPreview,
+    __proto__: WebInspector.Object.prototype,
+
+    // Public
+
+    get keyPreview()
+    {
+        return this._key;
+    },
+
+    get valuePreview()
+    {
+        return this._value;
+    }
+};
diff --git a/Source/WebInspectorUI/UserInterface/Models/ObjectPreview.js b/Source/WebInspectorUI/UserInterface/Models/ObjectPreview.js
new file mode 100644 (file)
index 0000000..f96b83b
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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.ObjectPreview = function(type, subtype, description, lossless, overflow, properties, entries)
+{
+    WebInspector.Object.call(this);
+
+    console.assert(type);
+    console.assert(typeof lossless === "boolean");
+    console.assert(!properties || !properties.length || properties[0] instanceof WebInspector.PropertyPreview);
+    console.assert(!entries || !entries.length || entries[0] instanceof WebInspector.CollectionEntryPreview);
+
+    this._type = type;
+    this._subtype = subtype;
+    this._description = description || "";
+    this._lossless = lossless;
+    this._overflow = overflow || false;
+
+    this._properties = properties || null;
+    this._entries = entries || null;
+};
+
+// Runtime.ObjectPreview.
+WebInspector.ObjectPreview.fromPayload = function(payload)
+{
+    if (payload.properties)
+        payload.properties = payload.properties.map(function(property) { return WebInspector.PropertyPreview.fromPayload(property); });
+    if (payload.entries)
+        payload.entries = payload.entries.map(function(entry) { return WebInspector.CollectionEntryPreview.fromPayload(entry); });
+
+    return new WebInspector.ObjectPreview(payload.type, payload.subtype, payload.description, payload.lossless, payload.overflow, payload.properties, payload.entries);
+};
+
+WebInspector.ObjectPreview.prototype = {
+    constructor: WebInspector.ObjectPreview,
+    __proto__: WebInspector.Object.prototype,
+
+    // Public
+
+    get type()
+    {
+        return this._type;
+    },
+
+    get subtype()
+    {
+        return this._subtype;
+    },
+
+    get description()
+    {
+        return this._description;
+    },
+
+    get lossless()
+    {
+        return this._lossless;
+    },
+
+    get overflow()
+    {
+        return this._overflow;
+    },
+
+    get propertyPreviews()
+    {
+        return this._properties;
+    },
+
+    get collectionEntryPreviews()
+    {
+        return this._entries;
+    }
+};
diff --git a/Source/WebInspectorUI/UserInterface/Models/PropertyDescriptor.js b/Source/WebInspectorUI/UserInterface/Models/PropertyDescriptor.js
new file mode 100644 (file)
index 0000000..9fef369
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * 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.PropertyDescriptor = function(descriptor, isOwnProperty, wasThrown, isInternalProperty)
+{
+    WebInspector.Object.call(this);
+
+    console.assert(descriptor);
+    console.assert(descriptor.name);
+    console.assert(!descriptor.value || descriptor.value instanceof WebInspector.RemoteObject);
+    console.assert(!descriptor.get || descriptor.get instanceof WebInspector.RemoteObject);
+    console.assert(!descriptor.set || descriptor.set instanceof WebInspector.RemoteObject);
+
+    this._name = descriptor.name;
+    this._value = descriptor.value;
+    this._hasValue = "value" in descriptor;
+    this._get = descriptor.get;
+    this._set = descriptor.set;
+
+    this._writable = descriptor.writable || false;
+    this._configurable = descriptor.configurable || false;
+    this._enumerable = descriptor.enumerable || false;
+
+    this._own = isOwnProperty || false;
+    this._wasThrown = wasThrown || false;
+    this._internal = isInternalProperty || false;
+};
+
+// Runtime.PropertyDescriptor or Runtime.InternalPropertyDescriptor.
+WebInspector.PropertyDescriptor.fromPayload = function(payload)
+{
+    if (payload.value)
+        payload.value = WebInspector.RemoteObject.fromPayload(payload.value);
+    if (payload.get)
+        payload.get = WebInspector.RemoteObject.fromPayload(payload.get);
+    if (payload.set)
+        payload.set = WebInspector.RemoteObject.fromPayload(payload.set);
+
+    if (payload.internal) {
+        console.assert(payload.value);
+        payload.writable = payload.configurable = payload.enumerable = false;
+        payload.isOwn = true;
+    }
+
+    return new WebInspector.PropertyDescriptor(payload, payload.isOwn, payload.wasThrown, payload.internal);
+};
+
+WebInspector.PropertyDescriptor.prototype = {
+    constructor: WebInspector.PropertyDescriptor,
+    __proto__: WebInspector.Object.prototype,
+
+    // Public
+
+    get name()
+    {
+        return this._name;
+    },
+
+    get value()
+    {
+        return this._value;
+    },
+
+    get get()
+    {
+        return this._get;
+    },
+
+    get set()
+    {
+        return this._set;
+    },
+
+    get writable()
+    {
+        return this._writable;
+    },
+
+    get configurable()
+    {
+        return this._configurable;
+    },
+
+    get enumerable()
+    {
+        return this._enumerable;
+    },
+
+    get isOwnProperty()
+    {
+        return this._own;
+    },
+
+    get wasThrown()
+    {
+        return this._wasThrown;
+    },
+
+    get isInternalProperty()
+    {
+        return this._internal;
+    },
+
+    hasValue: function()
+    {
+        return this._hasValue;
+    },
+
+    hasGetter: function()
+    {
+        return this._get && this._get.type === "function";
+    },
+
+    hasSetter: function()
+    {
+        return this._set && this._set.type === "function";
+    }
+};
diff --git a/Source/WebInspectorUI/UserInterface/Models/PropertyPreview.js b/Source/WebInspectorUI/UserInterface/Models/PropertyPreview.js
new file mode 100644 (file)
index 0000000..1f804ad
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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.PropertyPreview = function(name, type, subtype, value, valuePreview, isInternalProperty)
+{
+    WebInspector.Object.call(this);
+
+    console.assert(name);
+    console.assert(type);
+    console.assert(!value || typeof value === "string");
+    console.assert(!valuePreview || valuePreview instanceof WebInspector.ObjectPreview);
+
+    this._name = name;
+    this._type = type;
+    this._subtype = subtype;
+    this._value = value;
+    this._valuePreview = valuePreview;
+    this._internal = isInternalProperty;
+};
+
+// Runtime.PropertyPreview.
+WebInspector.PropertyPreview.fromPayload = function(payload)
+{
+    if (payload.valuePreview)
+        payload.valuePreview = WebInspector.ObjectPreview.fromPayload(payload.valuePreview);
+
+    return new WebInspector.PropertyPreview(payload.name, payload.type, payload.subtype, payload.value, payload.valuePreview, payload.internal);
+};
+
+WebInspector.PropertyPreview.prototype = {
+    constructor: WebInspector.PropertyPreview,
+    __proto__: WebInspector.Object.prototype,
+
+    // Public
+
+    get name()
+    {
+        return this._name;
+    },
+
+    get type()
+    {
+        return this._type;
+    },
+
+    get subtype()
+    {
+        return this._subtype;
+    },
+
+    get value()
+    {
+        return this._value;
+    },
+
+    get valuePreview()
+    {
+        return this._valuePreview;
+    },
+
+    get internal()
+    {
+        return this._internal;
+    }
+};
index 7e46373..b0eb66c 100644 (file)
 
 WebInspector.RemoteObject = function(objectId, type, subtype, value, description, preview)
 {
+    // No superclass.
+
+    console.assert(type);
+    console.assert(!preview || preview instanceof WebInspector.ObjectPreview);
+
     this._type = type;
     this._subtype = subtype;
+
     if (objectId) {
-        // handle
+        // Object or Symbol.
+        console.assert(!subtype || typeof subtype === "string");
+        console.assert(!description || typeof description === "string");
+        console.assert(!value);
+
         this._objectId = objectId;
         this._description = description;
         this._hasChildren = type !== "symbol";
         this._preview = preview;
     } else {
-        // Primitive or null object.
+        // Primitive or null.
         console.assert(type !== "object" || value === null);
+        console.assert(!preview);
+
         this._description = description || (value + "");
         this._hasChildren = false;
-        this.value = value;
+        this._value = value;
     }
 };
 
@@ -52,10 +64,27 @@ WebInspector.RemoteObject.fromPrimitiveValue = function(value)
     return new WebInspector.RemoteObject(undefined, typeof value, undefined, value);
 };
 
+WebInspector.RemoteObject.fromPayload = function(payload)
+{
+    console.assert(typeof payload === "object", "Remote object payload should only be an object");
+
+    if (payload.preview) {
+        // COMPATIBILITY (iOS 8): iOS 7 and 8 did not have type/subtype/description on
+        // Runtime.ObjectPreview. Copy them over from the RemoteObject.
+        if (!payload.preview.type) {
+            payload.preview.type = obj.type;
+            payload.preview.subtype = obj.subtype;
+            payload.preview.description = obj.description;
+        }
+        payload.preview = WebInspector.ObjectPreview.fromPayload(payload.preview);
+    }
+
+    return new WebInspector.RemoteObject(payload.objectId, payload.type, payload.subtype, payload.value, payload.description, payload.preview);
+};
+
 WebInspector.RemoteObject.resolveNode = function(node, objectGroup, callback)
 {
-    function mycallback(error, object)
-    {
+    DOMAgent.resolveNode(node.id, objectGroup, function(error, object) {
         if (!callback)
             return;
 
@@ -63,15 +92,7 @@ WebInspector.RemoteObject.resolveNode = function(node, objectGroup, callback)
             callback(null);
         else
             callback(WebInspector.RemoteObject.fromPayload(object));
-    }
-    DOMAgent.resolveNode(node.id, objectGroup, mycallback);
-};
-
-WebInspector.RemoteObject.fromPayload = function(payload)
-{
-    console.assert(typeof payload === "object", "Remote object payload should only be an object");
-
-    return new WebInspector.RemoteObject(payload.objectId, payload.type, payload.subtype, payload.value, payload.description, payload.preview);
+    });
 };
 
 WebInspector.RemoteObject.type = function(remoteObject)
@@ -87,6 +108,8 @@ WebInspector.RemoteObject.type = function(remoteObject)
 };
 
 WebInspector.RemoteObject.prototype = {
+    constructor: WebInspector.RemoteObject,
+
     get objectId()
     {
         return this._objectId;
@@ -112,11 +135,84 @@ WebInspector.RemoteObject.prototype = {
         return this._hasChildren;
     },
 
+    get value()
+    {
+        return this._value;
+    },
+
     get preview()
     {
         return this._preview;
     },
 
+    getOwnPropertyDescriptors: function(callback)
+    {
+        this._getPropertyDescriptors(true, false, callback);
+    },
+
+    getOwnAndGetterPropertyDescriptors: function(callback)
+    {
+        this._getPropertyDescriptors(false, true, callback);
+    },
+
+    getAllPropertyDescriptors: function(callback)
+    {
+        this._getPropertyDescriptors(false, false, callback);
+    },
+
+    _getPropertyDescriptors: function(ownProperties, ownAndGetterProperties, callback)
+    {
+        if (!this._objectId || this._isSymbol()) {
+            callback([]);
+            return;
+        }
+
+        function remoteObjectBinder(error, properties, internalProperties)
+        {
+            if (error) {
+                callback(null);
+                return;
+            }
+
+            if (internalProperties)
+                properties = properties.concat(internalProperties);
+
+            var descriptors = properties.map(function(payload) {
+                return WebInspector.PropertyDescriptor.fromPayload(payload);
+            });
+
+            callback(descriptors);
+        }
+
+        // COMPATIBILITY (iOS 8): RuntimeAgent.getProperties did not support ownerAndGetterProperties.
+        // Here we do our best to reimplement it by getting all properties and reducing them down.
+        if (ownAndGetterProperties && !RuntimeAgent.getProperties.supports("ownAndGetterProperties")) {
+            RuntimeAgent.getProperties(this._objectId, function(error, allProperties) {
+                var ownOrGetterPropertiesList = [];
+                if (allProperties) {
+                    for (var property of allProperties) {
+                        if (property.isOwn || property.get || property.name === "__proto__") {
+                            // Own property or getter property in prototype chain.
+                            ownOrGetterPropertiesList.push(property);
+                        } else if (property.value && property.name !== property.name.toUpperCase()) {
+                            var type = property.value.type;
+                            if (type && type !== "function" && property.name !== "constructor") {
+                                // Possible native binding getter property converted to a value. Also, no CONSTANT name style and not "constructor".
+                                ownOrGetterPropertiesList.push(property);
+                            }
+                        }
+                    }
+                }
+                remoteObjectBinder(error, ownOrGetterPropertiesList);
+            });
+            return;
+        }
+
+        RuntimeAgent.getProperties(this._objectId, ownProperties, ownAndGetterProperties, remoteObjectBinder);
+    },
+
+    // FIXME: Phase out these functions. They return RemoteObjectProperty instead of PropertyDescriptors.
+
     getOwnProperties: function(callback)
     {
         this._getProperties(true, false, callback);
@@ -146,7 +242,7 @@ WebInspector.RemoteObject.prototype = {
                 return;
             }
 
-            // FIXME: We should display Internal Properties visually distinct. For now treat as non-enumerable own properties.
+            // FIXME: WebInspector.PropertyDescriptor instead of RemoteObjectProperty.
             if (internalProperties) {
                 properties = properties.concat(internalProperties.map(function(descriptor) {
                     descriptor.writable = false;
@@ -191,7 +287,7 @@ WebInspector.RemoteObject.prototype = {
                     }
                 }
                 remoteObjectBinder(error, ownOrGetterPropertiesList);
-            }); 
+            });
             return;
         }
 
@@ -237,17 +333,17 @@ WebInspector.RemoteObject.prototype = {
 
     _isSymbol: function()
     {
-        return this.type === "symbol";
+        return this._type === "symbol";
     },
 
     isCollectionType: function()
     {
-        return this.subtype === "map" || this.subtype === "set" || this.subtype === "weakmap";
+        return this._subtype === "map" || this._subtype === "set" || this._subtype === "weakmap";
     },
 
     isWeakCollection: function()
     {
-        return this.subtype === "weakmap";
+        return this._subtype === "weakmap";
     },
 
     getCollectionEntries: function(start, numberToFetch, callback)
@@ -260,11 +356,12 @@ WebInspector.RemoteObject.prototype = {
         console.assert(this.isCollectionType());
 
         // WeakMaps are not ordered. We should never send a non-zero start.
-        console.assert((this.subtype === "weakmap" && start === 0) || this.subtype !== "weakmap");
+        console.assert((this._subtype === "weakmap" && start === 0) || this._subtype !== "weakmap");
 
         var objectGroup = this.isWeakCollection() ? this._weakCollectionObjectGroup() : "";
 
         RuntimeAgent.getCollectionEntries(this._objectId, objectGroup, start, numberToFetch, function(error, entries) {
+            entries = entries.map(function(entry) { return WebInspector.CollectionEntry.fromPayload(entry); });
             callback(entries);
         });
     },
@@ -311,12 +408,13 @@ WebInspector.RemoteObject.prototype = {
 
     arrayLength: function()
     {
-        if (this.subtype !== "array")
+        if (this._subtype !== "array")
             return 0;
 
         var matches = this._description.match(/\[([0-9]+)\]/);
         if (!matches)
             return 0;
+
         return parseInt(matches[1], 10);
     },
 
index 7d4bb55..d3f3459 100644 (file)
@@ -67,9 +67,6 @@
     <script src="Models/TimelineRecord.js"></script>
 
     <script src="Models/Breakpoint.js"></script>
-    <script src="Models/CallFrame.js"></script>
-    <script src="Models/Color.js"></script>
-    <script src="Models/ContentFlow.js"></script>
     <script src="Models/CSSCompletions.js"></script>
     <script src="Models/CSSKeywordCompletions.js"></script>
     <script src="Models/CSSProperty.js"></script>
     <script src="Models/CSSSelector.js"></script>
     <script src="Models/CSSStyleDeclaration.js"></script>
     <script src="Models/CSSStyleSheet.js"></script>
+    <script src="Models/CallFrame.js"></script>
+    <script src="Models/CollectionEntry.js"></script>
+    <script src="Models/Color.js"></script>
+    <script src="Models/ContentFlow.js"></script>
     <script src="Models/DOMNode.js"></script>
     <script src="Models/DOMNodeStyles.js"></script>
     <script src="Models/DOMStorageObject.js"></script>
     <script src="Models/DOMTree.js"></script>
+    <script src="Models/CollectionEntryPreview.js"></script>
     <script src="Models/ExecutionContext.js"></script>
     <script src="Models/ExecutionContextList.js"></script>
     <script src="Models/Frame.js"></script>
@@ -91,6 +93,7 @@
     <script src="Models/LayoutTimelineRecord.js"></script>
     <script src="Models/LazySourceCodeLocation.js"></script>
     <script src="Models/NetworkTimeline.js"></script>
+    <script src="Models/ObjectPreview.js"></script>
     <script src="Models/Probe.js"></script>
     <script src="Models/ProbeSet.js"></script>
     <script src="Models/ProbeSetDataFrame.js"></script>
     <script src="Models/Profile.js"></script>
     <script src="Models/ProfileNode.js"></script>
     <script src="Models/ProfileNodeCall.js"></script>
+    <script src="Models/PropertyDescriptor.js"></script>
+    <script src="Models/PropertyPreview.js"></script>
     <script src="Models/ReplaySession.js"></script>
     <script src="Models/ReplaySessionSegment.js"></script>
     <script src="Models/Resource.js"></script>
index e58f31c..e3a0ae9 100644 (file)
@@ -247,7 +247,7 @@ WebInspector.ConsoleMessageImpl.prototype = {
                 span.textContent = parameters[i].description;
                 formattedResult.appendChild(span);
             } else
-                formattedResult.appendChild(this._formatParameter(parameters[i], false, true));
+                formattedResult.appendChild(this._formatParameter(parameters[i], false));
 
             if (i < parameters.length - 1 && !this._isExpandable(parameters[i]))
                 formattedResult.appendChild(document.createTextNode(" "));
@@ -266,7 +266,7 @@ WebInspector.ConsoleMessageImpl.prototype = {
         return remoteObject.hasChildren;
     },
 
-    _formatParameter: function(output, forceObjectFormat, includePreview)
+    _formatParameter: function(output, forceObjectFormat)
     {
         var type;
         if (forceObjectFormat)
@@ -288,7 +288,7 @@ WebInspector.ConsoleMessageImpl.prototype = {
         if (this._isExpandable(output))
             span.classList.add("expandable");
 
-        formatter.call(this, output, span, includePreview);
+        formatter.call(this, output, span, forceObjectFormat);
         return span;
     },
 
@@ -297,123 +297,21 @@ WebInspector.ConsoleMessageImpl.prototype = {
         elem.appendChild(document.createTextNode(val));
     },
 
-    _formatParameterAsObject: function(obj, elem, includePreview)
+    _formatParameterAsObject: function(obj, elem, forceExpansion)
     {
-        var titleElement = document.createElement("span");
-        if (includePreview && obj.preview) {
-            titleElement.classList.add("console-object-preview");
-
-            // COMPATIBILITY (iOS 8): iOS 7 and 8 did not have type/subtype/description on
-            // Runtime.ObjectPreview. Copy them over from the RemoteObject.
-            var preview = obj.preview;
-            if (!preview.type) {
-                preview.type = obj.type;
-                preview.subtype = obj.subtype;
-                preview.description = obj.description;
-            }
-
-            var lossless = this._appendPreview(titleElement, preview);
-            if (lossless) {
-                titleElement.classList.add("console-object-preview-lossless");
-                elem.appendChild(titleElement);
-                return;
-            }
-        } else
-            titleElement.appendChild(document.createTextNode(obj.description || ""));
-
-        var section = new WebInspector.ObjectPropertiesSection(obj, titleElement);
-        elem.appendChild(section.element);
-    },
-
-    _appendPreview: function(element, preview)
-    {
-        if (preview.type === "object" && preview.subtype !== "null" && preview.subtype !== "array") {
-            var previewObjectNameElement = document.createElement("span");
-            previewObjectNameElement.classList.add("console-object-preview-name");
-            if (preview.description === "Object")
-                previewObjectNameElement.classList.add("console-object-preview-name-Object");
-
-            previewObjectNameElement.textContent = preview.description + " ";
-            element.appendChild(previewObjectNameElement);
-        }
-
-        var bodyElement = element.createChild("span", "console-object-preview-body");
-        if (preview.entries)
-            return this._appendEntryPreviews(bodyElement, preview);
-        if (preview.properties)
-            return this._appendPropertyPreviews(bodyElement, preview);
-        return this._appendValuePreview(bodyElement, preview);
-    },
-
-    _appendEntryPreviews: function(element, preview)
-    {
-        var lossless = preview.lossless && !preview.properties.length;
-
-        element.appendChild(document.createTextNode("{"));
-
-        for (var i = 0; i < preview.entries.length; ++i) {
-            if (i > 0)
-                element.appendChild(document.createTextNode(", "));
-
-            var entry = preview.entries[i];
-            if (entry.key) {
-                this._appendPreview(element, entry.key);
-                element.appendChild(document.createTextNode(" => "));
-            }
-
-            this._appendPreview(element, entry.value);
-        }
-
-        if (preview.overflow)
-            element.createChild("span").textContent = "\u2026";
-        element.appendChild(document.createTextNode("}"));
-
-        return lossless;
-    },
-
-    _appendPropertyPreviews: function(element, preview)
-    {
-        var isArray = preview.subtype === "array";
-
-        element.appendChild(document.createTextNode(isArray ? "[" : "{"));
-
-        for (var i = 0; i < preview.properties.length; ++i) {
-            var property = preview.properties[i];
-
-            // FIXME: Better handle getter/setter accessors. Should we show getters in previews?
-            if (property.type === "accessor")
-                continue;
-
-            // Constructor name is often already visible, so don't show it as a property.
-            if (property.name === "constructor")
-                continue;
-
-            if (i > 0)
-                element.appendChild(document.createTextNode(", "));
-
-            if (!isArray || property.name != i) {
-                element.createChild("span", "name").textContent = property.name;
-                element.appendChild(document.createTextNode(": "));
-            }
-
-            element.appendChild(this._propertyPreviewElement(property));
-        }
-
-        if (preview.overflow)
-            element.createChild("span").textContent = "\u2026";
-
-        element.appendChild(document.createTextNode(isArray ? "]" : "}"));
-
-        return preview.lossless;
+        var objectTree = new WebInspector.ObjectTreeView(obj, WebInspector.ObjectTreeView.Mode.Properties, forceExpansion);
+        elem.appendChild(objectTree.element);
     },
 
     _propertyPreviewElement: function(property)
     {
+        // FIXME: Used by console.table. We should be able to eliminate this in favor of ObjectPreview.
+
         var span = document.createElement("span");
-        span.classList.add("console-formatted-" + property.type);
+        span.classList.add(WebInspector.ObjectTreeView.classNameForObject(property));
 
         if (property.type === "string") {
-            span.textContent = "\"" + property.value.replace(/\n/g, "\u21B5") + "\"";
+            span.textContent = "\"" + property.value.replace(/\n/g, "\u21B5").replace(/"/g, "\\\"") + "\"";
             return span;
         }
 
@@ -422,22 +320,10 @@ WebInspector.ConsoleMessageImpl.prototype = {
             return span;
         }
 
-        if (property.type === "object") {
-            if (property.subtype === "node")
-                span.classList.add("console-formatted-preview-node");
-            else if (property.subtype === "regexp")
-                span.classList.add("console-formatted-regexp");
-        }
-
         span.textContent = property.value;
         return span;
     },
 
-    _appendValuePreview: function(element, preview)
-    {
-        element.appendChild(document.createTextNode(preview.description));
-    },
-
     _formatParameterAsNode: function(object, elem)
     {
         function printNode(nodeId)
@@ -445,7 +331,7 @@ WebInspector.ConsoleMessageImpl.prototype = {
             if (!nodeId) {
                 // Sometimes DOM is loaded after the sync message is being formatted, so we get no
                 // nodeId here. So we fall back to object formatting here.
-                this._formatParameterAsObject(object, elem, false);
+                this._formatParameterAsObject(object, elem, true);
                 return;
             }
             var treeOutline = new WebInspector.DOMTreeOutline(false, false, true);
@@ -571,7 +457,7 @@ WebInspector.ConsoleMessageImpl.prototype = {
 
         // If lossless or not table data, output the object so full data can be gotten.
         if (!preview.lossless || !flatValues.length) {
-            element.appendChild(this._formatParameter(table, true, false));
+            element.appendChild(this._formatParameter(table, true));
             if (!flatValues.length)
                 return element;
         }
@@ -589,10 +475,10 @@ WebInspector.ConsoleMessageImpl.prototype = {
         var span = document.createElement("span");
         span.className = "console-formatted-string source-code";
         span.appendChild(document.createTextNode("\""));
-        span.appendChild(WebInspector.linkifyStringAsFragment(output.description));
+        span.appendChild(WebInspector.linkifyStringAsFragment(output.description.replace(/"/g, "\\\"")));
         span.appendChild(document.createTextNode("\""));
 
-        elem.classList.remove("console-formatted-string");        
+        elem.classList.remove("console-formatted-string");
         elem.appendChild(span);
     },
 
@@ -644,7 +530,7 @@ WebInspector.ConsoleMessageImpl.prototype = {
     _formatAsArrayEntry: function(output)
     {
         // Prevent infinite expansion of cross-referencing arrays.
-        return this._formatParameter(output, output.subtype && output.subtype === "array", false);
+        return this._formatParameter(output, output.subtype && output.subtype === "array");
     },
 
     _formatWithSubstitutionString: function(parameters, formattedResult)
@@ -653,7 +539,7 @@ WebInspector.ConsoleMessageImpl.prototype = {
 
         function parameterFormatter(force, obj)
         {
-            return this._formatParameter(obj, force, false);
+            return this._formatParameter(obj, force);
         }
 
         function stringFormatter(obj)
diff --git a/Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.css b/Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.css
new file mode 100644 (file)
index 0000000..8631852
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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-preview {
+    font-style: italic;
+}
+
+.object-preview.lossless {
+    font-style: normal;
+}
+
+.object-preview .name {
+    color: rgb(136, 19, 145);
+}
diff --git a/Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.js b/Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.js
new file mode 100644 (file)
index 0000000..2ed0630
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * 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.ObjectPreviewView = function(preview, mode)
+{
+    WebInspector.Object.call(this);
+
+    console.assert(preview instanceof WebInspector.ObjectPreview);
+
+    this._preview = preview;
+    this._mode = mode || WebInspector.ObjectPreviewView.Mode.Full;
+
+    this._element = document.createElement("span");
+    this._element.className = "object-preview";
+    this._lossless = this._appendPreview(this._element, this._preview);
+
+    if (this._lossless)
+        this._element.classList.add("lossless");
+};
+
+WebInspector.ObjectPreviewView.Mode = {
+    Brief: Symbol("object-preview-brief"),
+    Full: Symbol("object-preview-full"),
+};
+
+WebInspector.ObjectPreviewView.prototype = {
+    constructor: WebInspector.ObjectPreviewView,
+    __proto__: WebInspector.Object,
+
+    // Public
+
+    get preview()
+    {
+        return this._preview;
+    },
+
+    get element()
+    {
+        return this._element;
+    },
+
+    get mode()
+    {
+        return this._mode;
+    },
+
+    get lossless()
+    {
+        return this._lossless;
+    },
+
+    // Private
+
+    _numberOfPropertiesToShowInMode: function()
+    {
+        return this._mode === WebInspector.ObjectPreviewView.Mode.Brief ? 3 : Infinity;
+    },
+
+    _appendPreview: function(element, preview)
+    {
+        // Class name for non-array object types.
+        if (preview.type === "object" && preview.subtype !== "null" && preview.subtype !== "array" && preview.description !== "Object") {
+            var nameElement = element.appendChild(document.createElement("span"));
+            nameElement.className = "object-preview-name";
+            nameElement.textContent = preview.description + " ";
+        }
+
+        // Content.
+        var bodyElement = element.appendChild(document.createElement("span"));
+        bodyElement.className = "object-preview-body";
+        if (preview.collectionEntryPreviews)
+            return this._appendEntryPreviews(bodyElement, preview);
+        if (preview.propertyPreviews)
+            return this._appendPropertyPreviews(bodyElement, preview);
+        return this._appendValuePreview(bodyElement, preview);
+    },
+
+    _appendEntryPreviews: function(element, preview)
+    {
+        var lossless = preview.lossless && !preview.propertyPreviews.length;
+
+        element.appendChild(document.createTextNode("{"));
+
+        var limit = Math.min(preview.collectionEntryPreviews.length, this._numberOfPropertiesToShowInMode());
+        for (var i = 0; i < limit; ++i) {
+            if (i > 0)
+                element.appendChild(document.createTextNode(", "));
+
+            var entry = preview.collectionEntryPreviews[i];
+            if (entry.keyPreview) {
+                this._appendPreview(element, entry.keyPreview);
+                element.appendChild(document.createTextNode(" => "));
+            }
+
+            this._appendPreview(element, entry.valuePreview);
+        }
+
+        if (preview.overflow)
+            element.appendChild(document.createTextNode("\u2026"));
+        element.appendChild(document.createTextNode("}"));
+
+        return lossless;
+    },
+
+    _appendPropertyPreviews: function(element, preview)
+    {
+        var isArray = preview.subtype === "array";
+
+        element.appendChild(document.createTextNode(isArray ? "[" : "{"));
+
+        var numberAdded = 0;
+        var limit = this._numberOfPropertiesToShowInMode();
+        for (var i = 0; i < preview.propertyPreviews.length && numberAdded < limit; ++i) {
+            var property = preview.propertyPreviews[i];
+
+            // FIXME: Better handle getter/setter accessors. Should we show getters in previews?
+            if (property.type === "accessor")
+                continue;
+
+            // Constructor name is often already visible, so don't show it as a property.
+            if (property.name === "constructor")
+                continue;
+
+            if (numberAdded++ > 0)
+                element.appendChild(document.createTextNode(", "));
+
+            if (!isArray || property.name != i) {
+                var nameElement = element.appendChild(document.createElement("span"));
+                nameElement.className = "name";
+                nameElement.textContent = property.name;
+                element.appendChild(document.createTextNode(": "));
+            }
+
+            element.appendChild(this._formattedObjectElementForPreview(property, property.value));
+        }
+
+        if (preview.overflow)
+            element.appendChild(document.createTextNode("\u2026"));
+
+        element.appendChild(document.createTextNode(isArray ? "]" : "}"));
+
+        return preview.lossless;
+    },
+
+    _appendValuePreview: function(element, preview)
+    {
+        element.appendChild(this._formattedObjectElementForPreview(preview, preview.description));
+        return true;
+    },
+
+    _formattedObjectElementForPreview: function(propertyPreviewOrObjectPreview, value)
+    {
+        var span = document.createElement("span");
+        span.classList.add(WebInspector.ObjectTreeView.classNameForObject(propertyPreviewOrObjectPreview));
+
+        if (propertyPreviewOrObjectPreview.type === "string") {
+            span.textContent = "\"" + value.replace(/\n/g, "\u21B5").replace(/"/g, "\\\"") + "\"";
+            return span;
+        }
+
+        if (propertyPreviewOrObjectPreview.type === "function") {
+            span.textContent = "function";
+            return span;
+        }
+
+        span.textContent = value;
+        return span;
+    }
+};
index 1c55e68..7948822 100644 (file)
@@ -207,7 +207,7 @@ WebInspector.ObjectPropertyTreeElement.prototype = {
         if (this.property.wasThrown)
             this.valueElement.textContent = "[Exception: " + description + "]";
         else if (this.property.value.type === "string" && typeof description === "string") {
-            this.valueElement.textContent = "\"" + description.replace(/\n/g, "\u21B5") + "\"";
+            this.valueElement.textContent = "\"" + description.replace(/\n/g, "\u21B5").replace(/"/g, "\\\"") + "\"";
             this.valueElement._originalTextContent = "\"" + description + "\"";
         } else if (this.property.value.type === "function" && typeof description === "string") {
             this.valueElement.textContent = /.*/.exec(description)[0].replace(/ +$/g, "");
@@ -404,7 +404,7 @@ WebInspector.CollectionEntriesMainTreeElement.prototype = {
                 else {
                     this.appendChild(new WebInspector.ObjectPropertyTreeElement({
                         name: "" + i,
-                        value: WebInspector.RemoteObject.fromPayload(entry.value),
+                        value: entry.value,
                         enumerable: true,
                         writable: false,
                     }));
@@ -472,8 +472,8 @@ WebInspector.CollectionEntryTreeElement = function(entry, index)
     console.assert(entry);
 
     this._name = "" + index;
-    this._key = WebInspector.RemoteObject.fromPayload(entry.key);
-    this._value = WebInspector.RemoteObject.fromPayload(entry.value);
+    this._key = entry.key;
+    this._value = entry.value;
 
     this.toggleOnClick = true;
     this.selectable = false;
diff --git a/Source/WebInspectorUI/UserInterface/Views/ObjectTreeCollectionTreeElement.js b/Source/WebInspectorUI/UserInterface/Views/ObjectTreeCollectionTreeElement.js
new file mode 100644 (file)
index 0000000..5481e94
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * 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
+};
diff --git a/Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.js b/Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.js
new file mode 100644 (file)
index 0000000..10ec67c
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * 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.ObjectTreePropertyTreeElement = function(property, mode)
+{
+    console.assert(property instanceof WebInspector.PropertyDescriptor);
+
+    this._property = property;
+    this._mode = mode || WebInspector.ObjectTreeView.Mode.Properties;
+
+    // FIXME: API Mode not turned on yet.
+    this._mode = WebInspector.ObjectTreeView.Mode.Properties;
+
+    TreeElement.call(this, "", null, false);
+    this.toggleOnClick = true;
+    this.selectable = false;
+};
+
+WebInspector.ObjectTreePropertyTreeElement.prototype = {
+    constructor: WebInspector.ObjectTreePropertyTreeElement,
+    __proto__: TreeElement.prototype,
+
+    // Public
+
+    get property()
+    {
+        return this._property;
+    },
+
+    // Protected
+
+    onpopulate: function()
+    {
+        this._updateChildren();
+    },
+
+    onattach: function()
+    {
+        this.listItemElement.classList.add("object-tree-property");
+
+        this._updateTitle();
+    },
+
+    // Private
+
+    _updateTitle: function()
+    {
+        this.listItemElement.removeChildren();
+
+        if (this._mode === WebInspector.ObjectTreeView.Mode.Properties) {
+            this._updateTitlePropertyStyle();
+            this.hasChildren = this._property.hasValue() && this._property.value.hasChildren && !this._property.wasThrown;
+        } else {
+            this._updateTitleAPIStyle();
+            this.hasChildren = this._property.hasValue() && this._property.value.hasChildren && !this._property.wasThrown && this._property.name === "__proto__";
+        }
+    },
+
+    _updateTitlePropertyStyle: function()
+    {
+        // Property name.
+        var nameElement = document.createElement("span");
+        nameElement.className = "name";
+        nameElement.textContent = this._property.name;
+
+        // Property attributes.
+        if (this._mode === WebInspector.ObjectTreeView.Mode.Properties) {
+            if (!this._property.enumerable)
+                nameElement.classList.add("not-enumerable");
+        }
+
+        // Separator.
+        var separatorElement = document.createElement("span");
+        separatorElement.className = "separator";
+        separatorElement.textContent = ": ";
+
+        // Value / Getter.
+        var valueOrGetterElement = document.createElement("span");
+        valueOrGetterElement.className = "value";
+
+        if (this._property.hasValue()) {
+            valueOrGetterElement.textContent = this._descriptionString();
+            valueOrGetterElement.classList.add(WebInspector.ObjectTreeView.classNameForObject(this._property.value));
+            // FIXME: Context Menu for Value. (See ObjectPropertiesSection).
+            // FIXME: Option+Click for Value.
+        } else {
+            console.assert(this._property.hasGetter());
+            valueOrGetterElement.textContent = "(...)";
+            // FIXME: Click to Populate Value.
+            // FIXME: Context Menu to Populate Value.
+        }
+
+        if (this._property.wasThrown)
+            valueOrGetterElement.classList.add("error");
+
+        this.listItemElement.appendChild(nameElement);
+        this.listItemElement.appendChild(separatorElement);
+        this.listItemElement.appendChild(valueOrGetterElement);
+    },
+
+    _updateTitleAPIStyle: function()
+    {
+        // Fixed value. Display like a property.
+        const propertyNamesToDisplayAsValues = ["__proto__", "constructor"];
+        if (propertyNamesToDisplayAsValues.contains(this._property.name) || (this._property.hasValue() && this._property.value.type !== "function")) {
+            this._updateTitlePropertyStyle();
+            return;
+        }
+
+        // No API to display.
+        var isFunction = this._property.hasValue() && this._property.value.type === "function";
+        if (!isFunction && !this._property.hasGetter() && !this._property.hasSetter())
+            return;
+
+        // Function / Getter / Setter.
+        var nameElement = document.createElement("span");
+        nameElement.className = "name";
+        nameElement.textContent = this._property.name;
+        this.listItemElement.appendChild(nameElement);
+
+        if (isFunction) {
+            var paramElement = document.createElement("span");
+            paramElement.textContent = this._functionParameterString();
+            this.listItemElement.appendChild(paramElement);
+        }
+
+        if (this._property.hasGetter()) {
+            var icon = document.createElement("span");
+            icon.textContent += "[G]";
+            this.listItemElement.appendChild(icon);
+        }
+        if (this._property.hasSetter()) {
+            var icon = document.createElement("span");
+            icon.textContent += "[S]";
+            this.listItemElement.appendChild(icon);
+        }
+    },
+
+    _descriptionString: function()
+    {
+        var value = this._property.value;
+        var description = value.description;
+
+        // Exception.
+        if (this._property.wasThrown)
+            return "[Exception: " + description + "]";
+
+        // String: replace newlines as nice unicode symbols.
+        if (value.type === "string")
+            return "\"" + description.replace(/\n/g, "\u21B5").replace(/"/g, "\\\"") + "\"";
+
+        // Function: Collapse whitespace in function display strings.
+        if (value.type === "function")
+            return /.*/.exec(description)[0].replace(/ +$/g, "");
+
+        return description;
+    },
+
+    _functionParameterString: function()
+    {
+        console.assert(this._property.value.type === "function");
+
+        var match = this._property.value.description.match(/^function.*?(\([^)]+?\))/);
+        return match ? match[1] : "()";
+    },
+
+    _updateChildren: function()
+    {
+        if (this.children.length && !this.shouldRefreshChildren)
+            return;
+
+        function callback(mode, properties)
+        {
+            this.removeChildren();
+
+            if (properties) {
+                properties.sort(WebInspector.ObjectTreeView.ComparePropertyDescriptors);
+                for (var propertyDescriptor of properties)
+                    this.appendChild(new WebInspector.ObjectTreePropertyTreeElement(propertyDescriptor, mode));
+            }
+
+            if (mode === WebInspector.ObjectTreeView.Mode.Properties) {
+                if (this._property.value.isCollectionType())
+                    this.appendChild(new WebInspector.ObjectTreeCollectionTreeElement(this._property.value));
+            }
+        };
+
+        if (this._property.name === "__proto__")
+            this._property.value.getOwnPropertyDescriptors(callback.bind(this, WebInspector.ObjectTreeView.Mode.API));
+        else
+            this._property.value.getOwnAndGetterPropertyDescriptors(callback.bind(this, this._mode));
+    }
+};
diff --git a/Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.css b/Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.css
new file mode 100644 (file)
index 0000000..a8dfd51
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * 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 {
+    position: relative;
+}
+
+.object-tree > .title {
+    color: black;
+    padding: 0 8px 0 18px;
+    min-height: 18px;
+    white-space: nowrap;
+    background-origin: padding;
+    background-clip: padding;
+}
+
+.object-tree > :matches(.title, .object-preview)::before {
+    position: absolute;
+    top: 5px;
+    left: 7px;
+
+    width: 8px;
+    height: 8px;
+
+    background-image: -webkit-canvas(disclosure-triangle-tiny-closed-normal);
+    background-size: 8px 8px;
+    background-repeat: no-repeat;
+
+    content: "";
+}
+
+.object-tree.expanded > :matches(.title, .object-preview)::before {
+    background-image: -webkit-canvas(disclosure-triangle-tiny-open-normal);
+}
+
+.object-tree.lossless-preview > :matches(.title, .object-preview)::before {
+    background: none;
+    width: 0px;
+}
+
+.object-tree-outline {
+    display: none;
+}
+
+.object-tree.expanded > .object-tree-outline {
+    display: block;
+    padding-left: 16px;
+}
+
+.object-tree-outline {
+    margin: 0;
+    padding: 0 6px 2px;
+    list-style: none;
+    min-height: 18px;
+    outline: none;
+}
+
+.object-tree-outline li {
+    margin-left: 12px;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    overflow: hidden;
+    -webkit-user-select: text;
+    cursor: default;
+}
+
+.object-tree-outline li.parent {
+    margin-left: 1px;
+}
+
+.object-tree-outline li.parent::before {
+    float: left;
+
+    content: "";
+
+    background-image: -webkit-canvas(disclosure-triangle-tiny-closed-normal);
+    background-size: 8px 8px;
+    background-repeat: no-repeat;
+
+    width: 8px;
+    height: 8px;
+
+    margin-top: 3px;
+    padding-right: 2px;
+}
+
+.object-tree-outline li.parent.expanded::before {
+    background-image: -webkit-canvas(disclosure-triangle-tiny-open-normal);
+}
+
+.object-tree-outline ol {
+    display: none;
+    margin: 0;
+    -webkit-padding-start: 12px;
+    list-style: none;
+}
+
+.object-tree-outline ol.expanded {
+    display: block;
+}
+
+.object-tree-outline li .empty-message {
+    padding-top: 0;
+    padding-bottom: 0;
+    color: rgb(60%, 60%, 60%);
+}
+
+/* Property Colors */
+
+.object-tree-property .name {
+    color: rgb(136, 19, 145);
+}
+
+.object-tree-property .name.not-enumerable {
+    opacity: 0.6;
+}
+
+.object-tree-property .value.error {
+    color: red;
+}
+
+
+/* Object Tree Type Colors */
+
+.formatted-object, .formatted-node, .formatted-error, .formatted-map, .formatted-set, .formatted-weakmap {
+    position: relative;
+    display: inline-block;
+    vertical-align: top;
+    color: black;
+}
+
+.formatted-number {
+    color: rgb(28, 0, 207);
+}
+
+.formatted-string, .formatted-regexp {
+    white-space: pre;
+}
+
+.formatted-string {
+    color: rgb(196, 26, 22);
+}
+
+.formatted-regexp {
+    color: rgb(255, 88, 0);
+}
+
+.formatted-symbol {
+    color: rgb(63, 169, 156);
+}
+
+.formatted-null, .formatted-undefined {
+    color: rgb(128, 128, 128);
+}
+
+
+/* Console Overrides */
+
+.console-group-messages .object-tree:not(.lossless-preview) {
+    margin: 0 0 0 12px !important;
+}
+
+.console-group-messages .object-tree:not(.lossless-preview) > :matches(.title, .object-preview) {
+    padding: 0 8px 0 0;
+}
+
+.console-group-messages .object-tree:not(.lossless-preview) > :matches(.title, .object-preview)::before {
+    top: 2px;
+    left: 1px;
+}
+
+/* FIXME: Transitioning the console over to formatted-object */
+.console-group-messages :matches(.formatted-object, .formatted-node, .formatted-error, .formatted-map, .formatted-set, .formatted-weakmap) .object-tree,
+.console-group-messages :matches(.console-formatted-object, .console-formatted-node, .console-formatted-error, .console-formatted-map, .console-formatted-set, .console-formatted-weakmap) .object-tree {
+    position: static;
+}
+
+.console-group-messages :matches(.formatted-object, .formatted-node, .formatted-error, .formatted-map, .formatted-set, .formatted-weakmap) .object-tree-outline,
+.console-group-messages :matches(.console-formatted-object, .console-formatted-node, .console-formatted-error, .console-formatted-map, .console-formatted-set, .console-formatted-weakmap) .object-tree-outline {
+    padding-left: 0 !important;
+}
diff --git a/Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.js b/Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.js
new file mode 100644 (file)
index 0000000..33f64d8
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * 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.ObjectTreeView = function(object, mode, forceExpanding)
+{
+    WebInspector.Object.call(this);
+
+    console.assert(object instanceof WebInspector.RemoteObject);
+
+    this._object = object;
+    this._mode = mode || WebInspector.ObjectTreeView.Mode.Properties;
+    this._expanded = false;
+    this._hasLosslessPreview = false;
+
+    this._element = document.createElement("div");
+    this._element.className = "object-tree";
+
+    if (this._object.preview) {
+        var previewView = new WebInspector.ObjectPreviewView(this._object.preview);
+        this._previewElement = previewView.element;
+        this._previewElement.addEventListener("click", this._handlePreviewOrTitleElementClick.bind(this));
+        this._element.appendChild(this._previewElement);
+
+        if (previewView.lossless && !forceExpanding) {
+            this._hasLosslessPreview = true;
+            this.element.classList.add("lossless-preview");
+        }
+    }
+
+    this._titleElement = document.createElement("span");
+    this._titleElement.className = "title";
+    this._titleElement.textContent = this._object.description || "";
+    this._titleElement.addEventListener("click", this._handlePreviewOrTitleElementClick.bind(this));
+    this._element.appendChild(this._titleElement);
+
+    if (this._object.preview)
+        this._titleElement.hidden = true;
+
+    this._outlineElement = document.createElement("ol");
+    this._outlineElement.className = "object-tree-outline";
+    this._outline = new TreeOutline(this._outlineElement);
+    this._element.appendChild(this._outlineElement);
+
+    // FIXME: Support editable ObjectTrees.
+};
+
+WebInspector.ObjectTreeView.Mode = {
+    Properties: Symbol("object-tree-properties"),
+    API: Symbol("object-tree-api"),
+};
+
+WebInspector.ObjectTreeView.classNameForObject = function(object)
+{
+    return "formatted-" + (object.subtype ? object.subtype : object.type);
+}
+
+WebInspector.ObjectTreeView.ComparePropertyDescriptors = function(propertyA, propertyB)
+{
+    var a = propertyA.name;
+    var b = propertyB.name;
+
+    // Put __proto__ at the bottom.
+    if (a === "__proto__")
+        return 1;
+    if (b === "__proto__")
+        return -1;
+
+    // Put internal properties at the top.
+    if (a.isInternalProperty && !b.isInternalProperty)
+        return -1;
+    if (b.isInternalProperty && !a.isInternalProperty)
+        return 1;
+
+    // if used elsewhere make sure to
+    //  - convert a and b to strings (not needed here, properties are all strings)
+    //  - check if a == b (not needed here, no two properties can be the same)
+
+    var diff = 0;
+    var chunk = /^\d+|^\D+/;
+    var chunka, chunkb, anum, bnum;
+    while (diff === 0) {
+        if (!a && b)
+            return -1;
+        if (!b && a)
+            return 1;
+        chunka = a.match(chunk)[0];
+        chunkb = b.match(chunk)[0];
+        anum = !isNaN(chunka);
+        bnum = !isNaN(chunkb);
+        if (anum && !bnum)
+            return -1;
+        if (bnum && !anum)
+            return 1;
+        if (anum && bnum) {
+            diff = chunka - chunkb;
+            if (diff === 0 && chunka.length !== chunkb.length) {
+                if (!+chunka && !+chunkb) // chunks are strings of all 0s (special case)
+                    return chunka.length - chunkb.length;
+                else
+                    return chunkb.length - chunka.length;
+            }
+        } else if (chunka !== chunkb)
+            return (chunka < chunkb) ? -1 : 1;
+        a = a.substring(chunka.length);
+        b = b.substring(chunkb.length);
+    }
+    return diff;
+};
+
+WebInspector.ObjectTreeView.prototype = {
+    constructor: WebInspector.ObjectTreeView,
+    __proto__: WebInspector.Object,
+
+    // Public
+
+    get object()
+    {
+        return this._object;
+    },
+
+    get element()
+    {
+        return this._element;
+    },
+
+    get expanded()
+    {
+        return this._expanded;
+    },
+
+    expand: function()
+    {
+        if (this._expanded)
+            return;
+
+        this._expanded = true;
+        this._element.classList.add("expanded");
+
+        if (this._previewElement) {
+            this._previewElement.hidden = true;
+            this._titleElement.hidden = false;
+        }
+
+        this.update();
+    },
+
+    collapse: function()
+    {
+        if (!this._expanded)
+            return;
+
+        this._expanded = false;
+        this._element.classList.remove("expanded");
+
+        if (this._previewElement) {
+            this._previewElement.hidden = false;
+            this._titleElement.hidden = true;
+        }
+    },
+
+    // Protected
+
+    update: function()
+    {
+        this._object.getOwnAndGetterPropertyDescriptors(this._updateProperties.bind(this));
+    },
+
+    // Private
+
+    _updateProperties: function(properties)
+    {
+        properties.sort(WebInspector.ObjectTreeView.ComparePropertyDescriptors);
+
+        this._outline.removeChildren();
+
+        for (var propertyDescriptor of properties)
+            this._outline.appendChild(new WebInspector.ObjectTreePropertyTreeElement(propertyDescriptor, this._mode));
+
+        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");;
+            this._outline.appendChild(new TreeElement(emptyMessageElement, null, false));
+        }
+    },
+
+    _handlePreviewOrTitleElementClick: function(event)
+    {
+        if (this._hasLosslessPreview)
+            return;
+
+        if (!this._expanded)
+            this.expand();
+        else
+            this.collapse();
+
+        event.stopPropagation();
+    }
+};
index 391f9e1..391fd50 100644 (file)
@@ -88,7 +88,7 @@ WebInspector.TreeOutlineDataGridSynchronizer = function(treeOutline, dataGrid, d
 
 WebInspector.TreeOutlineDataGridSynchronizer.prototype = {
     constructor: WebInspector.TreeOutlineDataGridSynchronizer,
-    __proto__: WebInspector.Object,
+    __proto__: WebInspector.Object.prototype,
 
     // Public