c2f6d4df14cb8955ea179872ba57b29d6fa531c4
[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     _logValue(value)
158     {
159         var resolvedValue = value || this.resolvedValue();
160         if (!resolvedValue)
161             return;
162
163         var propertyPath = this.resolvedValuePropertyPath();
164         var isImpossible = propertyPath.isFullPathImpossible();
165         var text = isImpossible ? WebInspector.UIString("Selected Value") : propertyPath.displayPath(this.propertyPathType());
166
167         if (!isImpossible)
168             WebInspector.quickConsole.prompt.pushHistoryItem(text);
169
170         WebInspector.consoleLogViewController.appendImmediateExecutionWithResult(text, resolvedValue);
171     }
172
173     _contextMenuHandler(event)
174     {
175         var resolvedValue = this.resolvedValue();
176         if (!resolvedValue)
177             return;
178
179         var contextMenu = new WebInspector.ContextMenu(event);
180         contextMenu.appendItem(WebInspector.UIString("Log Value"), this._logValue.bind(this));
181
182         var propertyPath = this.resolvedValuePropertyPath();
183         if (propertyPath && !propertyPath.isFullPathImpossible()) {
184             contextMenu.appendItem(WebInspector.UIString("Copy Path to Property"), function() {
185                 InspectorFrontendHost.copyText(propertyPath.displayPath(WebInspector.PropertyPath.Type.Value));
186             }.bind(this));
187         }
188
189         contextMenu.appendSeparator();
190
191         this._appendMenusItemsForObject(contextMenu, resolvedValue);
192
193         if (!contextMenu.isEmpty())
194             contextMenu.show();
195     }
196
197     _appendMenusItemsForObject(contextMenu, resolvedValue)
198     {
199         if (resolvedValue.type === "function") {
200             // FIXME: We should better handle bound functions.
201             if (!isFunctionStringNativeCode(resolvedValue.description)) {
202                 contextMenu.appendItem(WebInspector.UIString("Jump to Definition"), function() {
203                     DebuggerAgent.getFunctionDetails(resolvedValue.objectId, function(error, response) {
204                         if (error)
205                             return;
206
207                         var location = response.location;
208                         var sourceCode = WebInspector.debuggerManager.scriptForIdentifier(location.scriptId);
209                         if (!sourceCode)
210                             return;
211
212                         var sourceCodeLocation = sourceCode.createSourceCodeLocation(location.lineNumber, location.columnNumber || 0);
213                         WebInspector.resourceSidebarPanel.showSourceCodeLocation(sourceCodeLocation);
214                     });
215                 });
216             }
217             return;
218         }
219
220         if (resolvedValue.subtype === "node") {
221             contextMenu.appendItem(WebInspector.UIString("Reveal in DOM Tree"), function() {
222                 resolvedValue.pushNodeToFrontend(function(nodeId) {
223                     WebInspector.domTreeManager.inspectElement(nodeId);
224                 });
225             });
226             return;
227         }
228     }
229 };