Web Inspector: ES6: Show Symbol properties on Objects
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / ObjectTreeBaseTreeElement.js
1 /*
2  * Copyright (C) 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 WebInspector.ObjectTreeBaseTreeElement = class ObjectTreeBaseTreeElement extends WebInspector.GeneralTreeElement
27 {
28     constructor(representedObject, propertyPath, property)
29     {
30         console.assert(representedObject);
31         console.assert(propertyPath instanceof WebInspector.PropertyPath);
32         console.assert(!property || property instanceof WebInspector.PropertyDescriptor);
33
34         super(null, null, null, representedObject, false);
35
36         this._property = property;
37         this._propertyPath = propertyPath;
38
39         this.small = true;
40         this.toggleOnClick = true;
41         this.selectable = false;
42         this.tooltipHandledSeparately = true;
43     }
44
45     // Public
46
47     get property()
48     {
49         return this._property;
50     }
51
52     get propertyPath()
53     {
54         return this._propertyPath;
55     }
56
57     // Protected
58
59     oncontextmenu(event)
60     {
61         this._contextMenuHandler(event);
62     }
63
64     resolvedValue()
65     {
66         console.assert(this._property);
67         if (this._getterValue)
68             return this._getterValue;
69         if (this._property.hasValue())
70             return this._property.value;
71         return null;
72     }
73
74     resolvedValuePropertyPath()
75     {
76         console.assert(this._property);
77         if (this._getterValue)
78             return this._propertyPath.appendPropertyDescriptor(this._getterValue, this._property, WebInspector.PropertyPath.Type.Value);
79         if (this._property.hasValue())
80             return this._propertyPath.appendPropertyDescriptor(this._property.value, this._property, WebInspector.PropertyPath.Type.Value);
81         return null;
82     }
83
84     thisPropertyPath()
85     {
86         console.assert(this._property);
87         return this._propertyPath.appendPropertyDescriptor(null, this._property, this.propertyPathType());
88     }
89
90     hadError()
91     {
92         console.assert(this._property);
93         return this._property.wasThrown || this._getterHadError;
94     }
95
96     propertyPathType()
97     {
98         console.assert(this._property);
99         if (this._getterValue || this._property.hasValue())
100             return WebInspector.PropertyPath.Type.Value;
101         if (this._property.hasGetter())
102             return WebInspector.PropertyPath.Type.Getter;
103         if (this._property.hasSetter())
104             return WebInspector.PropertyPath.Type.Setter;
105         return WebInspector.PropertyPath.Type.Value;
106     }
107
108     propertyPathString(propertyPath)
109     {
110         if (propertyPath.isFullPathImpossible())
111             return WebInspector.UIString("Unable to determine path to property from root");
112
113         return propertyPath.displayPath(this.propertyPathType());
114     }
115
116     createGetterElement(interactive)
117     {
118         var getterElement = document.createElement("img");
119         getterElement.className = "getter";
120
121         if (!interactive) {
122             getterElement.classList.add("disabled");
123             getterElement.title = WebInspector.UIString("Getter");
124             return getterElement;
125         }
126
127         getterElement.title = WebInspector.UIString("Invoke getter");
128         getterElement.addEventListener("click", function(event) {
129             event.stopPropagation();
130             var lastNonPrototypeObject = this._propertyPath.lastNonPrototypeObject;
131             var getterObject = this._property.get;
132             lastNonPrototypeObject.invokeGetter(getterObject, function(error, result, wasThrown) {
133                 this._getterHadError = !!(error || wasThrown);
134                 this._getterValue = result;
135                 if (this.invokedGetter && typeof this.invokedGetter === "function")
136                     this.invokedGetter();
137             }.bind(this));
138         }.bind(this));
139
140         return getterElement;
141     }
142
143     createSetterElement(interactive)
144     {
145         var setterElement = document.createElement("img");
146         setterElement.className = "setter";
147         setterElement.title = WebInspector.UIString("Setter");
148
149         if (!interactive)
150             setterElement.classList.add("disabled");
151
152         return setterElement;
153     }
154
155     // Private
156
157     _logSymbolProperty()
158     {
159         var symbol = this._property.symbol;
160         if (!symbol)
161             return;
162
163         var text = WebInspector.UIString("Selected Symbol");
164         WebInspector.consoleLogViewController.appendImmediateExecutionWithResult(text, symbol);
165     }
166
167     _logValue(value)
168     {
169         var resolvedValue = value || this.resolvedValue();
170         if (!resolvedValue)
171             return;
172
173         var propertyPath = this.resolvedValuePropertyPath();
174         var isImpossible = propertyPath.isFullPathImpossible();
175         var text = isImpossible ? WebInspector.UIString("Selected Value") : propertyPath.displayPath(this.propertyPathType());
176
177         if (!isImpossible)
178             WebInspector.quickConsole.prompt.pushHistoryItem(text);
179
180         WebInspector.consoleLogViewController.appendImmediateExecutionWithResult(text, resolvedValue);
181     }
182
183     _contextMenuHandler(event)
184     {
185         var resolvedValue = this.resolvedValue();
186         if (!resolvedValue)
187             return;
188
189         var contextMenu = new WebInspector.ContextMenu(event);
190
191         if (this._property && this._property.symbol)
192             contextMenu.appendItem(WebInspector.UIString("Log Symbol"), this._logSymbolProperty.bind(this));
193
194         contextMenu.appendItem(WebInspector.UIString("Log Value"), this._logValue.bind(this));
195
196         var propertyPath = this.resolvedValuePropertyPath();
197         if (propertyPath && !propertyPath.isFullPathImpossible()) {
198             contextMenu.appendItem(WebInspector.UIString("Copy Path to Property"), function() {
199                 InspectorFrontendHost.copyText(propertyPath.displayPath(WebInspector.PropertyPath.Type.Value));
200             }.bind(this));
201         }
202
203         contextMenu.appendSeparator();
204
205         this._appendMenusItemsForObject(contextMenu, resolvedValue);
206
207         if (!contextMenu.isEmpty())
208             contextMenu.show();
209     }
210
211     _appendMenusItemsForObject(contextMenu, resolvedValue)
212     {
213         if (resolvedValue.type === "function") {
214             // FIXME: We should better handle bound functions.
215             if (!isFunctionStringNativeCode(resolvedValue.description)) {
216                 contextMenu.appendItem(WebInspector.UIString("Jump to Definition"), function() {
217                     DebuggerAgent.getFunctionDetails(resolvedValue.objectId, function(error, response) {
218                         if (error)
219                             return;
220
221                         var location = response.location;
222                         var sourceCode = WebInspector.debuggerManager.scriptForIdentifier(location.scriptId);
223                         if (!sourceCode)
224                             return;
225
226                         var sourceCodeLocation = sourceCode.createSourceCodeLocation(location.lineNumber, location.columnNumber || 0);
227                         WebInspector.resourceSidebarPanel.showSourceCodeLocation(sourceCodeLocation);
228                     });
229                 });
230             }
231             return;
232         }
233
234         if (resolvedValue.subtype === "node") {
235             contextMenu.appendItem(WebInspector.UIString("Reveal in DOM Tree"), function() {
236                 resolvedValue.pushNodeToFrontend(function(nodeId) {
237                     WebInspector.domTreeManager.inspectElement(nodeId);
238                 });
239             });
240             return;
241         }
242     }
243 };