2 * Copyright (C) 2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
26 WebInspector.ObjectTreePropertyTreeElement = function(property, mode)
28 console.assert(property instanceof WebInspector.PropertyDescriptor);
30 this._property = property;
31 this._mode = mode || WebInspector.ObjectTreeView.Mode.Properties;
33 // FIXME: API Mode not turned on yet.
34 this._mode = WebInspector.ObjectTreeView.Mode.Properties;
36 TreeElement.call(this, "", null, false);
37 this.toggleOnClick = true;
38 this.selectable = false;
41 WebInspector.ObjectTreePropertyTreeElement.prototype = {
42 constructor: WebInspector.ObjectTreePropertyTreeElement,
43 __proto__: TreeElement.prototype,
49 return this._property;
54 onpopulate: function()
56 this._updateChildren();
61 this.listItemElement.classList.add("object-tree-property");
68 _updateTitle: function()
70 this.listItemElement.removeChildren();
72 if (this._mode === WebInspector.ObjectTreeView.Mode.Properties) {
73 this._updateTitlePropertyStyle();
74 this.hasChildren = this._property.hasValue() && this._property.value.hasChildren && !this._property.wasThrown;
76 this._updateTitleAPIStyle();
77 this.hasChildren = this._property.hasValue() && this._property.value.hasChildren && !this._property.wasThrown && this._property.name === "__proto__";
81 _updateTitlePropertyStyle: function()
84 var nameElement = document.createElement("span");
85 nameElement.className = "name";
86 nameElement.textContent = this._property.name;
88 // Property attributes.
89 if (this._mode === WebInspector.ObjectTreeView.Mode.Properties) {
90 if (!this._property.enumerable)
91 nameElement.classList.add("not-enumerable");
95 var separatorElement = document.createElement("span");
96 separatorElement.className = "separator";
97 separatorElement.textContent = ": ";
100 var valueOrGetterElement = document.createElement("span");
101 valueOrGetterElement.className = "value";
103 if (this._property.hasValue()) {
104 valueOrGetterElement.textContent = this._descriptionString();
105 valueOrGetterElement.classList.add(WebInspector.ObjectTreeView.classNameForObject(this._property.value));
106 // FIXME: Context Menu for Value. (See ObjectPropertiesSection).
107 // FIXME: Option+Click for Value.
109 console.assert(this._property.hasGetter());
110 valueOrGetterElement.textContent = "(...)";
111 // FIXME: Click to Populate Value.
112 // FIXME: Context Menu to Populate Value.
115 if (this._property.wasThrown)
116 valueOrGetterElement.classList.add("error");
118 this.listItemElement.appendChild(nameElement);
119 this.listItemElement.appendChild(separatorElement);
120 this.listItemElement.appendChild(valueOrGetterElement);
123 _updateTitleAPIStyle: function()
125 // Fixed value. Display like a property.
126 const propertyNamesToDisplayAsValues = ["__proto__", "constructor"];
127 if (propertyNamesToDisplayAsValues.contains(this._property.name) || (this._property.hasValue() && this._property.value.type !== "function")) {
128 this._updateTitlePropertyStyle();
132 // No API to display.
133 var isFunction = this._property.hasValue() && this._property.value.type === "function";
134 if (!isFunction && !this._property.hasGetter() && !this._property.hasSetter())
137 // Function / Getter / Setter.
138 var nameElement = document.createElement("span");
139 nameElement.className = "name";
140 nameElement.textContent = this._property.name;
141 this.listItemElement.appendChild(nameElement);
144 var paramElement = document.createElement("span");
145 paramElement.textContent = this._functionParameterString();
146 this.listItemElement.appendChild(paramElement);
149 if (this._property.hasGetter()) {
150 var icon = document.createElement("span");
151 icon.textContent += "[G]";
152 this.listItemElement.appendChild(icon);
154 if (this._property.hasSetter()) {
155 var icon = document.createElement("span");
156 icon.textContent += "[S]";
157 this.listItemElement.appendChild(icon);
161 _descriptionString: function()
163 var value = this._property.value;
164 var description = value.description;
167 if (this._property.wasThrown)
168 return "[Exception: " + description + "]";
170 // String: replace newlines as nice unicode symbols.
171 if (value.type === "string")
172 return "\"" + description.replace(/\n/g, "\u21B5").replace(/"/g, "\\\"") + "\"";
174 // Function: Collapse whitespace in function display strings.
175 if (value.type === "function")
176 return /.*/.exec(description)[0].replace(/ +$/g, "");
181 _functionParameterString: function()
183 console.assert(this._property.value.type === "function");
185 var match = this._property.value.description.match(/^function.*?(\([^)]+?\))/);
186 return match ? match[1] : "()";
189 _updateChildren: function()
191 if (this.children.length && !this.shouldRefreshChildren)
194 function callback(mode, properties)
196 this.removeChildren();
199 properties.sort(WebInspector.ObjectTreeView.ComparePropertyDescriptors);
200 for (var propertyDescriptor of properties)
201 this.appendChild(new WebInspector.ObjectTreePropertyTreeElement(propertyDescriptor, mode));
204 if (mode === WebInspector.ObjectTreeView.Mode.Properties) {
205 if (this._property.value.isCollectionType())
206 this.appendChild(new WebInspector.ObjectTreeCollectionTreeElement(this._property.value));
210 if (this._property.name === "__proto__")
211 this._property.value.getOwnPropertyDescriptors(callback.bind(this, WebInspector.ObjectTreeView.Mode.API));
213 this._property.value.getOwnAndGetterPropertyDescriptors(callback.bind(this, this._mode));