fe8c6c0c9baa6be2456efce15c995d0c370f21fa
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / ScopeChainDetailsSidebarPanel.js
1 /*
2  * Copyright (C) 2013 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.ScopeChainDetailsSidebarPanel = function()
27 {
28     WebInspector.DetailsSidebarPanel.call(this, "scope-chain", WebInspector.UIString("Scope Chain"), WebInspector.UIString("Scope Chain"), "Images/NavigationItemVariable.svg", "5");
29
30     this._callFrame = null;
31
32     // Update on console prompt eval as objects in the scope chain may have changed.
33     WebInspector.runtimeManager.addEventListener(WebInspector.RuntimeManager.Event.DidEvaluate, this.needsRefresh, this);
34 };
35
36 WebInspector.ScopeChainDetailsSidebarPanel.prototype = {
37     constructor: WebInspector.ScopeChainDetailsSidebarPanel,
38
39     // Public
40
41     inspect: function(objects)
42     {
43         // Convert to a single item array if needed.
44         if (!(objects instanceof Array))
45             objects = [objects];
46
47         var callFrameToInspect = null;
48
49         // Iterate over the objects to find a WebInspector.CallFrame to inspect.
50         for (var i = 0; i < objects.length; ++i) {
51             if (!(objects[i] instanceof WebInspector.CallFrame))
52                 continue;
53             callFrameToInspect = objects[i];
54             break;
55         }
56
57         this.callFrame = callFrameToInspect;
58
59         return !!this.callFrame;
60     },
61
62     get callFrame()
63     {
64         return this._callFrame;
65     },
66
67     set callFrame(callFrame)
68     {
69         if (callFrame === this._callFrame)
70             return;
71
72         this._callFrame = callFrame;
73
74         this.needsRefresh();
75     },
76
77     refresh: function()
78     {
79         var callFrame = this.callFrame;
80         if (!callFrame)
81             return;
82
83         var detailsSections = [];
84         var foundLocalScope = false;
85
86         var sectionCountByType = {};
87         for (var type in WebInspector.ScopeChainNode.Type)
88             sectionCountByType[WebInspector.ScopeChainNode.Type[type]] = 0;
89
90         var scopeChain = callFrame.scopeChain;
91         for (var i = 0; i < scopeChain.length; ++i) {
92             var scope = scopeChain[i];
93
94             var title = null;
95             var extraProperties = null;
96             var collapsedByDefault = false;
97             var dontHighlightNonEnumerableProperties = true;
98
99             ++sectionCountByType[scope.type];
100
101             switch (scope.type) {
102                 case WebInspector.ScopeChainNode.Type.Local:
103                     foundLocalScope = true;
104                     collapsedByDefault = false;
105                     dontHighlightNonEnumerableProperties = true;
106
107                     title = WebInspector.UIString("Local Variables");
108
109                     if (callFrame.thisObject)
110                         extraProperties = [new WebInspector.RemoteObjectProperty("this", callFrame.thisObject)];
111                     break;
112
113                 case WebInspector.ScopeChainNode.Type.Closure:
114                     title = WebInspector.UIString("Closure Variables");
115                     dontHighlightNonEnumerableProperties = true;
116                     collapsedByDefault = false;
117                     break;
118
119                 case WebInspector.ScopeChainNode.Type.Catch:
120                     title = WebInspector.UIString("Catch Variables");
121                     dontHighlightNonEnumerableProperties = true;
122                     collapsedByDefault = false;
123                     break;
124
125                 case WebInspector.ScopeChainNode.Type.FunctionName:
126                     title = WebInspector.UIString("Function Name Variable");
127                     dontHighlightNonEnumerableProperties = true;
128                     collapsedByDefault = true;
129                     break;
130
131                 case WebInspector.ScopeChainNode.Type.With:
132                     title = WebInspector.UIString("With Object Properties");
133                     collapsedByDefault = foundLocalScope;
134                     dontHighlightNonEnumerableProperties = false;
135                     break;
136
137                 case WebInspector.ScopeChainNode.Type.Global:
138                     title = WebInspector.UIString("Global Variables");
139                     dontHighlightNonEnumerableProperties = false;
140                     collapsedByDefault = true;
141                     break;
142             }
143
144             var detailsSectionIdentifier = scope.type + "-" + sectionCountByType[scope.type];
145
146             var section = new WebInspector.ObjectPropertiesSection(scope.object, null, null, null, true, extraProperties, WebInspector.ScopeVariableTreeElement);
147             section.dontHighlightNonEnumerablePropertiesAtTopLevel = dontHighlightNonEnumerableProperties;
148             section.__propertyIdentifierPrefix = detailsSectionIdentifier;
149
150             var detailsSection = new WebInspector.DetailsSection(detailsSectionIdentifier, title, null, null, collapsedByDefault);
151             detailsSection.groups[0].rows = [new WebInspector.DetailsSectionPropertiesRow(section)];
152             detailsSections.push(detailsSection);
153         }
154
155         function delayedWork()
156         {
157             // Clear the timeout so we don't update the interface twice.
158             clearTimeout(timeout);
159
160             // Bail if the call frame changed while we were waiting for the async response.
161             if (this.callFrame !== callFrame)
162                 return;
163
164             this.element.removeChildren();
165             for (var i = 0; i < detailsSections.length; ++i)
166                 this.element.appendChild(detailsSections[i].element);
167         }
168
169         // We need a timeout in place in case there are long running, pending backend dispatches. This can happen
170         // if the debugger is paused in code that was executed from the console. The console will be waiting for
171         // the result of the execution and without a timeout we would never update the scope variables.
172         var timeout = setTimeout(delayedWork.bind(this), 50);
173
174         // Since ObjectPropertiesSection populates asynchronously, we want to wait to replace the existing content
175         // until after all the pending asynchronous requests are completed. This prevents severe flashing while stepping.
176         InspectorBackend.runAfterPendingDispatches(delayedWork.bind(this));
177     }
178 };
179
180 WebInspector.ScopeChainDetailsSidebarPanel.prototype.__proto__ = WebInspector.DetailsSidebarPanel.prototype;