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