2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * @extends {WebInspector.SidebarPane}
30 WebInspector.CallStackSidebarPane = function()
32 WebInspector.SidebarPane.call(this, WebInspector.UIString("Call Stack"));
33 this.bodyElement.addEventListener("keydown", this._keyDown.bind(this), true);
34 this.bodyElement.tabIndex = 0;
36 if (WebInspector.experimentsSettings.asyncStackTraces.isEnabled()) {
37 var asyncCheckbox = this.titleElement.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Async"), WebInspector.settings.enableAsyncStackTraces, true, undefined, WebInspector.UIString("Capture async stack traces")));
38 asyncCheckbox.classList.add("scripts-callstack-async");
39 asyncCheckbox.addEventListener("click", consumeEvent, false);
40 WebInspector.settings.enableAsyncStackTraces.addChangeListener(this._asyncStackTracesStateChanged, this);
44 WebInspector.CallStackSidebarPane.Events = {
45 CallFrameRestarted: "CallFrameRestarted",
46 CallFrameSelected: "CallFrameSelected"
49 WebInspector.CallStackSidebarPane.prototype = {
51 * @param {?Array.<!WebInspector.DebuggerModel.CallFrame>} callFrames
52 * @param {?WebInspector.DebuggerModel.StackTrace} asyncStackTrace
54 update: function(callFrames, asyncStackTrace)
56 this.bodyElement.removeChildren();
57 delete this._statusMessageElement;
58 /** @type {!Array.<!WebInspector.CallStackSidebarPane.Placard>} */
62 var infoElement = this.bodyElement.createChild("div", "info");
63 infoElement.textContent = WebInspector.UIString("Not Paused");
67 this._appendSidebarPlacards(callFrames);
69 while (asyncStackTrace) {
70 var title = asyncStackTrace.description;
72 title += " " + WebInspector.UIString("(async)");
74 title = WebInspector.UIString("Async Call");
75 var asyncPlacard = new WebInspector.Placard(title, "");
76 asyncPlacard.element.classList.add("placard-label");
77 this.bodyElement.appendChild(asyncPlacard.element);
78 this._appendSidebarPlacards(asyncStackTrace.callFrames, asyncPlacard);
79 asyncStackTrace = asyncStackTrace.asyncStackTrace;
84 * @param {!Array.<!WebInspector.DebuggerModel.CallFrame>} callFrames
85 * @param {!WebInspector.Placard=} asyncPlacard
87 _appendSidebarPlacards: function(callFrames, asyncPlacard)
89 for (var i = 0, n = callFrames.length; i < n; ++i) {
90 var placard = new WebInspector.CallStackSidebarPane.Placard(callFrames[i], asyncPlacard);
91 placard.element.addEventListener("click", this._placardSelected.bind(this, placard), false);
92 placard.element.addEventListener("contextmenu", this._placardContextMenu.bind(this, placard), true);
93 if (!i && asyncPlacard) {
94 asyncPlacard.element.addEventListener("click", this._placardSelected.bind(this, placard), false);
95 asyncPlacard.element.addEventListener("contextmenu", this._placardContextMenu.bind(this, placard), true);
97 this.placards.push(placard);
98 this.bodyElement.appendChild(placard.element);
103 * @param {!WebInspector.CallStackSidebarPane.Placard} placard
105 _placardContextMenu: function(placard, event)
107 var contextMenu = new WebInspector.ContextMenu(event);
109 if (!placard._callFrame.isAsync())
110 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Restart frame" : "Restart Frame"), this._restartFrame.bind(this, placard));
112 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy stack trace" : "Copy Stack Trace"), this._copyStackTrace.bind(this));
117 * @param {!WebInspector.CallStackSidebarPane.Placard} placard
119 _restartFrame: function(placard)
121 placard._callFrame.restart();
122 this.dispatchEventToListeners(WebInspector.CallStackSidebarPane.Events.CallFrameRestarted, placard._callFrame);
125 _asyncStackTracesStateChanged: function()
127 var enabled = WebInspector.settings.enableAsyncStackTraces.get();
128 if (!enabled && this.placards)
129 this._removeAsyncPlacards();
132 _removeAsyncPlacards: function()
134 var shouldSelectTopFrame = false;
135 var lastSyncPlacardIndex = -1;
136 for (var i = 0; i < this.placards.length; ++i) {
137 var placard = this.placards[i];
138 if (placard._asyncPlacard) {
139 if (placard.selected)
140 shouldSelectTopFrame = true;
141 placard._asyncPlacard.element.remove();
142 placard.element.remove();
144 lastSyncPlacardIndex = i;
147 this.placards.length = lastSyncPlacardIndex + 1;
148 if (shouldSelectTopFrame)
149 this._selectPlacardByIndex(0);
153 * @param {!WebInspector.DebuggerModel.CallFrame} x
155 setSelectedCallFrame: function(x)
157 for (var i = 0; i < this.placards.length; ++i) {
158 var placard = this.placards[i];
159 placard.selected = (placard._callFrame === x);
166 _selectNextCallFrameOnStack: function()
168 var index = this._selectedCallFrameIndex();
171 return this._selectPlacardByIndex(index + 1);
177 _selectPreviousCallFrameOnStack: function()
179 var index = this._selectedCallFrameIndex();
182 return this._selectPlacardByIndex(index - 1);
186 * @param {number} index
189 _selectPlacardByIndex: function(index)
191 if (index < 0 || index >= this.placards.length)
193 this._placardSelected(this.placards[index]);
200 _selectedCallFrameIndex: function()
202 var selectedCallFrame = WebInspector.debuggerModel.selectedCallFrame();
203 if (!selectedCallFrame)
205 for (var i = 0; i < this.placards.length; ++i) {
206 var placard = this.placards[i];
207 if (placard._callFrame === selectedCallFrame)
214 * @param {!WebInspector.CallStackSidebarPane.Placard} placard
216 _placardSelected: function(placard)
218 placard.element.scrollIntoViewIfNeeded();
219 this.dispatchEventToListeners(WebInspector.CallStackSidebarPane.Events.CallFrameSelected, placard._callFrame);
222 _copyStackTrace: function()
225 for (var i = 0; i < this.placards.length; ++i) {
226 if (i && this.placards[i]._asyncPlacard !== this.placards[i - 1]._asyncPlacard)
227 text += this.placards[i]._asyncPlacard.title + "\n";
228 text += this.placards[i].title + " (" + this.placards[i].subtitle + ")\n";
230 InspectorFrontendHost.copyText(text);
234 * @param {function(!Array.<!WebInspector.KeyboardShortcut.Descriptor>, function(?Event=):boolean)} registerShortcutDelegate
236 registerShortcuts: function(registerShortcutDelegate)
238 registerShortcutDelegate(WebInspector.ShortcutsScreen.SourcesPanelShortcuts.NextCallFrame, this._selectNextCallFrameOnStack.bind(this));
239 registerShortcutDelegate(WebInspector.ShortcutsScreen.SourcesPanelShortcuts.PrevCallFrame, this._selectPreviousCallFrameOnStack.bind(this));
243 * @param {!Element|string} status
245 setStatus: function(status)
247 if (!this._statusMessageElement)
248 this._statusMessageElement = this.bodyElement.createChild("div", "info");
249 if (typeof status === "string") {
250 this._statusMessageElement.textContent = status;
252 this._statusMessageElement.removeChildren();
253 this._statusMessageElement.appendChild(status);
257 _keyDown: function(event)
259 if (event.altKey || event.shiftKey || event.metaKey || event.ctrlKey)
261 if (event.keyIdentifier === "Up" && this._selectPreviousCallFrameOnStack() || event.keyIdentifier === "Down" && this._selectNextCallFrameOnStack())
265 __proto__: WebInspector.SidebarPane.prototype
270 * @extends {WebInspector.Placard}
271 * @param {!WebInspector.DebuggerModel.CallFrame} callFrame
272 * @param {!WebInspector.Placard=} asyncPlacard
274 WebInspector.CallStackSidebarPane.Placard = function(callFrame, asyncPlacard)
276 WebInspector.Placard.call(this, callFrame.functionName || WebInspector.UIString("(anonymous function)"), "");
277 callFrame.createLiveLocation(this._update.bind(this));
278 this._callFrame = callFrame;
279 this._asyncPlacard = asyncPlacard;
282 WebInspector.CallStackSidebarPane.Placard.prototype = {
284 * @param {!WebInspector.UILocation} uiLocation
286 _update: function(uiLocation)
288 this.subtitle = uiLocation.linkText().trimMiddle(100);
291 __proto__: WebInspector.Placard.prototype