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 var asyncCheckbox = this.titleElement.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Async"), WebInspector.settings.enableAsyncStackTraces, true, undefined, WebInspector.UIString("Capture async stack traces")));
37 asyncCheckbox.classList.add("scripts-callstack-async");
38 asyncCheckbox.addEventListener("click", consumeEvent, false);
39 WebInspector.settings.enableAsyncStackTraces.addChangeListener(this._asyncStackTracesStateChanged, this);
42 WebInspector.CallStackSidebarPane.Events = {
43 CallFrameRestarted: "CallFrameRestarted",
44 CallFrameSelected: "CallFrameSelected"
47 WebInspector.CallStackSidebarPane.prototype = {
49 * @param {?Array.<!WebInspector.DebuggerModel.CallFrame>} callFrames
50 * @param {?WebInspector.DebuggerModel.StackTrace} asyncStackTrace
52 update: function(callFrames, asyncStackTrace)
54 this.bodyElement.removeChildren();
55 delete this._statusMessageElement;
56 /** @type {!Array.<!WebInspector.CallStackSidebarPane.Placard>} */
60 var infoElement = this.bodyElement.createChild("div", "info");
61 infoElement.textContent = WebInspector.UIString("Not Paused");
65 this._appendSidebarPlacards(callFrames);
67 while (asyncStackTrace) {
68 var title = asyncStackTrace.description;
70 title += " " + WebInspector.UIString("(async)");
72 title = WebInspector.UIString("Async Call");
73 var asyncPlacard = new WebInspector.Placard(title, "");
74 asyncPlacard.element.classList.add("placard-label");
75 this.bodyElement.appendChild(asyncPlacard.element);
76 this._appendSidebarPlacards(asyncStackTrace.callFrames, asyncPlacard);
77 asyncStackTrace = asyncStackTrace.asyncStackTrace;
82 * @param {!Array.<!WebInspector.DebuggerModel.CallFrame>} callFrames
83 * @param {!WebInspector.Placard=} asyncPlacard
85 _appendSidebarPlacards: function(callFrames, asyncPlacard)
87 for (var i = 0, n = callFrames.length; i < n; ++i) {
88 var placard = new WebInspector.CallStackSidebarPane.Placard(callFrames[i], asyncPlacard);
89 placard.element.addEventListener("click", this._placardSelected.bind(this, placard), false);
90 placard.element.addEventListener("contextmenu", this._placardContextMenu.bind(this, placard), true);
91 if (!i && asyncPlacard) {
92 asyncPlacard.element.addEventListener("click", this._placardSelected.bind(this, placard), false);
93 asyncPlacard.element.addEventListener("contextmenu", this._placardContextMenu.bind(this, placard), true);
95 this.placards.push(placard);
96 this.bodyElement.appendChild(placard.element);
101 * @param {!WebInspector.CallStackSidebarPane.Placard} placard
103 _placardContextMenu: function(placard, event)
105 var contextMenu = new WebInspector.ContextMenu(event);
107 if (!placard._callFrame.isAsync())
108 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Restart frame" : "Restart Frame"), this._restartFrame.bind(this, placard));
110 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy stack trace" : "Copy Stack Trace"), this._copyStackTrace.bind(this));
115 * @param {!WebInspector.CallStackSidebarPane.Placard} placard
117 _restartFrame: function(placard)
119 placard._callFrame.restart();
120 this.dispatchEventToListeners(WebInspector.CallStackSidebarPane.Events.CallFrameRestarted, placard._callFrame);
123 _asyncStackTracesStateChanged: function()
125 var enabled = WebInspector.settings.enableAsyncStackTraces.get();
126 if (!enabled && this.placards)
127 this._removeAsyncPlacards();
130 _removeAsyncPlacards: function()
132 var shouldSelectTopFrame = false;
133 var lastSyncPlacardIndex = -1;
134 for (var i = 0; i < this.placards.length; ++i) {
135 var placard = this.placards[i];
136 if (placard._asyncPlacard) {
137 if (placard.selected)
138 shouldSelectTopFrame = true;
139 placard._asyncPlacard.element.remove();
140 placard.element.remove();
142 lastSyncPlacardIndex = i;
145 this.placards.length = lastSyncPlacardIndex + 1;
146 if (shouldSelectTopFrame)
147 this._selectPlacardByIndex(0);
151 * @param {!WebInspector.DebuggerModel.CallFrame} x
153 setSelectedCallFrame: function(x)
155 for (var i = 0; i < this.placards.length; ++i) {
156 var placard = this.placards[i];
157 placard.selected = (placard._callFrame === x);
164 _selectNextCallFrameOnStack: function()
166 var index = this._selectedCallFrameIndex();
169 return this._selectPlacardByIndex(index + 1);
175 _selectPreviousCallFrameOnStack: function()
177 var index = this._selectedCallFrameIndex();
180 return this._selectPlacardByIndex(index - 1);
184 * @param {number} index
187 _selectPlacardByIndex: function(index)
189 if (index < 0 || index >= this.placards.length)
191 this._placardSelected(this.placards[index]);
198 _selectedCallFrameIndex: function()
200 var selectedCallFrame = WebInspector.debuggerModel.selectedCallFrame();
201 if (!selectedCallFrame)
203 for (var i = 0; i < this.placards.length; ++i) {
204 var placard = this.placards[i];
205 if (placard._callFrame === selectedCallFrame)
212 * @param {!WebInspector.CallStackSidebarPane.Placard} placard
214 _placardSelected: function(placard)
216 placard.element.scrollIntoViewIfNeeded();
217 this.dispatchEventToListeners(WebInspector.CallStackSidebarPane.Events.CallFrameSelected, placard._callFrame);
220 _copyStackTrace: function()
223 for (var i = 0; i < this.placards.length; ++i) {
224 if (i && this.placards[i]._asyncPlacard !== this.placards[i - 1]._asyncPlacard)
225 text += this.placards[i]._asyncPlacard.title + "\n";
226 text += this.placards[i].title + " (" + this.placards[i].subtitle + ")\n";
228 InspectorFrontendHost.copyText(text);
232 * @param {function(!Array.<!WebInspector.KeyboardShortcut.Descriptor>, function(?Event=):boolean)} registerShortcutDelegate
234 registerShortcuts: function(registerShortcutDelegate)
236 registerShortcutDelegate(WebInspector.ShortcutsScreen.SourcesPanelShortcuts.NextCallFrame, this._selectNextCallFrameOnStack.bind(this));
237 registerShortcutDelegate(WebInspector.ShortcutsScreen.SourcesPanelShortcuts.PrevCallFrame, this._selectPreviousCallFrameOnStack.bind(this));
241 * @param {!Element|string} status
243 setStatus: function(status)
245 if (!this._statusMessageElement)
246 this._statusMessageElement = this.bodyElement.createChild("div", "info");
247 if (typeof status === "string") {
248 this._statusMessageElement.textContent = status;
250 this._statusMessageElement.removeChildren();
251 this._statusMessageElement.appendChild(status);
255 _keyDown: function(event)
257 if (event.altKey || event.shiftKey || event.metaKey || event.ctrlKey)
259 if (event.keyIdentifier === "Up" && this._selectPreviousCallFrameOnStack() || event.keyIdentifier === "Down" && this._selectNextCallFrameOnStack())
263 __proto__: WebInspector.SidebarPane.prototype
268 * @extends {WebInspector.Placard}
269 * @param {!WebInspector.DebuggerModel.CallFrame} callFrame
270 * @param {!WebInspector.Placard=} asyncPlacard
272 WebInspector.CallStackSidebarPane.Placard = function(callFrame, asyncPlacard)
274 WebInspector.Placard.call(this, callFrame.functionName || WebInspector.UIString("(anonymous function)"), "");
275 callFrame.createLiveLocation(this._update.bind(this));
276 this._callFrame = callFrame;
277 this._asyncPlacard = asyncPlacard;
280 WebInspector.CallStackSidebarPane.Placard.prototype = {
282 * @param {!WebInspector.UILocation} uiLocation
284 _update: function(uiLocation)
286 this.subtitle = uiLocation.linkText().trimMiddle(100);
289 __proto__: WebInspector.Placard.prototype