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