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