OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. | 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
11 * documentation and/or other materials provided with the distribution. | 11 * documentation and/or other materials provided with the distribution. |
12 * | 12 * |
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 */ | 24 */ |
25 | |
26 /** | 25 /** |
27 * @constructor | |
28 * @extends {WebInspector.SimpleView} | |
29 * @implements {WebInspector.ContextFlavorListener} | 26 * @implements {WebInspector.ContextFlavorListener} |
| 27 * @unrestricted |
30 */ | 28 */ |
31 WebInspector.CallStackSidebarPane = function() | 29 WebInspector.CallStackSidebarPane = class extends WebInspector.SimpleView { |
32 { | 30 constructor() { |
33 WebInspector.SimpleView.call(this, WebInspector.UIString("Call Stack")); | 31 super(WebInspector.UIString('Call Stack')); |
34 this.element.addEventListener("keydown", this._keyDown.bind(this), true); | 32 this.element.addEventListener('keydown', this._keyDown.bind(this), true); |
35 this.element.tabIndex = 0; | 33 this.element.tabIndex = 0; |
36 this.callFrameList = new WebInspector.UIList(); | 34 this.callFrameList = new WebInspector.UIList(); |
37 this.callFrameList.show(this.element); | 35 this.callFrameList.show(this.element); |
38 this._linkifier = new WebInspector.Linkifier(); | 36 this._linkifier = new WebInspector.Linkifier(); |
39 WebInspector.moduleSetting("enableAsyncStackTraces").addChangeListener(this.
_asyncStackTracesStateChanged, this); | 37 WebInspector.moduleSetting('enableAsyncStackTraces').addChangeListener(this.
_asyncStackTracesStateChanged, this); |
40 WebInspector.moduleSetting("skipStackFramesPattern").addChangeListener(this.
_update, this); | 38 WebInspector.moduleSetting('skipStackFramesPattern').addChangeListener(this.
_update, this); |
41 /** @type {!Array<!WebInspector.CallStackSidebarPane.CallFrame>} */ | 39 /** @type {!Array<!WebInspector.CallStackSidebarPane.CallFrame>} */ |
42 this.callFrames = []; | 40 this.callFrames = []; |
43 this._locationPool = new WebInspector.LiveLocationPool(); | 41 this._locationPool = new WebInspector.LiveLocationPool(); |
44 this._update(); | 42 this._update(); |
| 43 } |
| 44 |
| 45 /** |
| 46 * @override |
| 47 * @param {?Object} object |
| 48 */ |
| 49 flavorChanged(object) { |
| 50 this._update(); |
| 51 } |
| 52 |
| 53 _update() { |
| 54 var details = WebInspector.context.flavor(WebInspector.DebuggerPausedDetails
); |
| 55 |
| 56 this.callFrameList.detach(); |
| 57 this.callFrameList.clear(); |
| 58 this._linkifier.reset(); |
| 59 this.element.removeChildren(); |
| 60 this._locationPool.disposeAll(); |
| 61 |
| 62 this.callFrameList.show(this.element); |
| 63 delete this._hiddenCallFramesMessageElement; |
| 64 this.callFrames = []; |
| 65 this._hiddenCallFrames = 0; |
| 66 |
| 67 if (!details) { |
| 68 var infoElement = this.element.createChild('div', 'gray-info-message'); |
| 69 infoElement.textContent = WebInspector.UIString('Not Paused'); |
| 70 WebInspector.context.setFlavor(WebInspector.DebuggerModel.CallFrame, null)
; |
| 71 return; |
| 72 } |
| 73 this._debuggerModel = details.debuggerModel; |
| 74 var asyncStackTrace = details.asyncStackTrace; |
| 75 |
| 76 this._appendSidebarCallFrames(this._callFramesFromDebugger(details.callFrame
s)); |
| 77 var topStackHidden = (this._hiddenCallFrames === this.callFrames.length); |
| 78 |
| 79 var peviousStackTrace = details.callFrames; |
| 80 while (asyncStackTrace) { |
| 81 var title = ''; |
| 82 if (asyncStackTrace.description === 'async function') { |
| 83 var lastPreviousFrame = peviousStackTrace[peviousStackTrace.length - 1]; |
| 84 var topFrame = asyncStackTrace.callFrames[0]; |
| 85 var lastPreviousFrameName = WebInspector.beautifyFunctionName(lastPrevio
usFrame.functionName); |
| 86 var topFrameName = WebInspector.beautifyFunctionName(topFrame.functionNa
me); |
| 87 title = topFrameName + ' awaits ' + lastPreviousFrameName; |
| 88 } else { |
| 89 title = WebInspector.asyncStackTraceLabel(asyncStackTrace.description); |
| 90 } |
| 91 var asyncCallFrame = new WebInspector.UIList.Item(title, '', true); |
| 92 asyncCallFrame.setHoverable(false); |
| 93 asyncCallFrame.element.addEventListener( |
| 94 'contextmenu', this._asyncCallFrameContextMenu.bind(this, this.callFra
mes.length), true); |
| 95 this._appendSidebarCallFrames( |
| 96 this._callFramesFromRuntime(asyncStackTrace.callFrames, asyncCallFrame
), asyncCallFrame); |
| 97 peviousStackTrace = asyncStackTrace.callFrames; |
| 98 asyncStackTrace = asyncStackTrace.parent; |
| 99 } |
| 100 |
| 101 if (topStackHidden) |
| 102 this._revealHiddenCallFrames(); |
| 103 if (this._hiddenCallFrames) { |
| 104 var element = createElementWithClass('div', 'hidden-callframes-message'); |
| 105 if (this._hiddenCallFrames === 1) |
| 106 element.textContent = WebInspector.UIString('1 stack frame is hidden (bl
ack-boxed).'); |
| 107 else |
| 108 element.textContent = |
| 109 WebInspector.UIString('%d stack frames are hidden (black-boxed).', t
his._hiddenCallFrames); |
| 110 element.createTextChild(' '); |
| 111 var showAllLink = element.createChild('span', 'link'); |
| 112 showAllLink.textContent = WebInspector.UIString('Show'); |
| 113 showAllLink.addEventListener('click', this._revealHiddenCallFrames.bind(th
is), false); |
| 114 this.element.insertBefore(element, this.element.firstChild); |
| 115 this._hiddenCallFramesMessageElement = element; |
| 116 } |
| 117 this._selectNextVisibleCallFrame(0); |
| 118 this.revealView(); |
| 119 } |
| 120 |
| 121 /** |
| 122 * @param {!Array.<!WebInspector.DebuggerModel.CallFrame>} callFrames |
| 123 * @return {!Array<!WebInspector.CallStackSidebarPane.CallFrame>} |
| 124 */ |
| 125 _callFramesFromDebugger(callFrames) { |
| 126 var callFrameItems = []; |
| 127 for (var i = 0, n = callFrames.length; i < n; ++i) { |
| 128 var callFrame = callFrames[i]; |
| 129 var callFrameItem = new WebInspector.CallStackSidebarPane.CallFrame( |
| 130 callFrame.functionName, callFrame.location(), this._linkifier, callFra
me, this._locationPool); |
| 131 callFrameItem.element.addEventListener('click', this._callFrameSelected.bi
nd(this, callFrameItem), false); |
| 132 callFrameItems.push(callFrameItem); |
| 133 } |
| 134 return callFrameItems; |
| 135 } |
| 136 |
| 137 /** |
| 138 * @param {!Array<!RuntimeAgent.CallFrame>} callFrames |
| 139 * @param {!WebInspector.UIList.Item} asyncCallFrameItem |
| 140 * @return {!Array<!WebInspector.CallStackSidebarPane.CallFrame>} |
| 141 */ |
| 142 _callFramesFromRuntime(callFrames, asyncCallFrameItem) { |
| 143 var callFrameItems = []; |
| 144 for (var i = 0, n = callFrames.length; i < n; ++i) { |
| 145 var callFrame = callFrames[i]; |
| 146 var location = new WebInspector.DebuggerModel.Location( |
| 147 this._debuggerModel, callFrame.scriptId, callFrame.lineNumber, callFra
me.columnNumber); |
| 148 var callFrameItem = new WebInspector.CallStackSidebarPane.CallFrame( |
| 149 callFrame.functionName, location, this._linkifier, null, this._locatio
nPool, asyncCallFrameItem); |
| 150 callFrameItem.element.addEventListener('click', this._asyncCallFrameClicke
d.bind(this, callFrameItem), false); |
| 151 callFrameItems.push(callFrameItem); |
| 152 } |
| 153 return callFrameItems; |
| 154 } |
| 155 |
| 156 /** |
| 157 * @param {!Array.<!WebInspector.CallStackSidebarPane.CallFrame>} callFrames |
| 158 * @param {!WebInspector.UIList.Item=} asyncCallFrameItem |
| 159 */ |
| 160 _appendSidebarCallFrames(callFrames, asyncCallFrameItem) { |
| 161 if (asyncCallFrameItem) |
| 162 this.callFrameList.addItem(asyncCallFrameItem); |
| 163 |
| 164 var allCallFramesHidden = true; |
| 165 for (var i = 0, n = callFrames.length; i < n; ++i) { |
| 166 var callFrameItem = callFrames[i]; |
| 167 callFrameItem.element.addEventListener('contextmenu', this._callFrameConte
xtMenu.bind(this, callFrameItem), true); |
| 168 this.callFrames.push(callFrameItem); |
| 169 |
| 170 if (WebInspector.blackboxManager.isBlackboxedRawLocation(callFrameItem._lo
cation)) { |
| 171 callFrameItem.setHidden(true); |
| 172 callFrameItem.setDimmed(true); |
| 173 ++this._hiddenCallFrames; |
| 174 } else { |
| 175 this.callFrameList.addItem(callFrameItem); |
| 176 allCallFramesHidden = false; |
| 177 } |
| 178 } |
| 179 if (allCallFramesHidden && asyncCallFrameItem) { |
| 180 asyncCallFrameItem.setHidden(true); |
| 181 asyncCallFrameItem.element.remove(); |
| 182 } |
| 183 } |
| 184 |
| 185 _revealHiddenCallFrames() { |
| 186 if (!this._hiddenCallFrames) |
| 187 return; |
| 188 this._hiddenCallFrames = 0; |
| 189 this.callFrameList.clear(); |
| 190 for (var i = 0; i < this.callFrames.length; ++i) { |
| 191 var callFrame = this.callFrames[i]; |
| 192 if (callFrame._asyncCallFrame) { |
| 193 callFrame._asyncCallFrame.setHidden(false); |
| 194 if (i && callFrame._asyncCallFrame !== this.callFrames[i - 1]._asyncCall
Frame) |
| 195 this.callFrameList.addItem(callFrame._asyncCallFrame); |
| 196 } |
| 197 callFrame.setHidden(false); |
| 198 this.callFrameList.addItem(callFrame); |
| 199 } |
| 200 if (this._hiddenCallFramesMessageElement) { |
| 201 this._hiddenCallFramesMessageElement.remove(); |
| 202 delete this._hiddenCallFramesMessageElement; |
| 203 } |
| 204 } |
| 205 |
| 206 /** |
| 207 * @param {!WebInspector.CallStackSidebarPane.CallFrame} callFrame |
| 208 * @param {!Event} event |
| 209 */ |
| 210 _callFrameContextMenu(callFrame, event) { |
| 211 var contextMenu = new WebInspector.ContextMenu(event); |
| 212 var debuggerCallFrame = callFrame._debuggerCallFrame; |
| 213 if (debuggerCallFrame) |
| 214 contextMenu.appendItem( |
| 215 WebInspector.UIString.capitalize('Restart ^frame'), debuggerCallFrame.
restart.bind(debuggerCallFrame)); |
| 216 |
| 217 contextMenu.appendItem(WebInspector.UIString.capitalize('Copy ^stack ^trace'
), this._copyStackTrace.bind(this)); |
| 218 |
| 219 var uiLocation = WebInspector.debuggerWorkspaceBinding.rawLocationToUILocati
on(callFrame._location); |
| 220 this.appendBlackboxURLContextMenuItems(contextMenu, uiLocation.uiSourceCode)
; |
| 221 |
| 222 contextMenu.show(); |
| 223 } |
| 224 |
| 225 /** |
| 226 * @param {number} index |
| 227 * @param {!Event} event |
| 228 */ |
| 229 _asyncCallFrameContextMenu(index, event) { |
| 230 for (; index < this.callFrames.length; ++index) { |
| 231 var callFrame = this.callFrames[index]; |
| 232 if (!callFrame.isHidden()) { |
| 233 this._callFrameContextMenu(callFrame, event); |
| 234 break; |
| 235 } |
| 236 } |
| 237 } |
| 238 |
| 239 /** |
| 240 * @param {!WebInspector.ContextMenu} contextMenu |
| 241 * @param {!WebInspector.UISourceCode} uiSourceCode |
| 242 */ |
| 243 appendBlackboxURLContextMenuItems(contextMenu, uiSourceCode) { |
| 244 var binding = WebInspector.persistence.binding(uiSourceCode); |
| 245 if (binding) |
| 246 uiSourceCode = binding.network; |
| 247 if (uiSourceCode.project().type() === WebInspector.projectTypes.FileSystem) |
| 248 return; |
| 249 var canBlackbox = WebInspector.blackboxManager.canBlackboxUISourceCode(uiSou
rceCode); |
| 250 var isBlackboxed = WebInspector.blackboxManager.isBlackboxedUISourceCode(uiS
ourceCode); |
| 251 var isContentScript = uiSourceCode.project().type() === WebInspector.project
Types.ContentScripts; |
| 252 |
| 253 var manager = WebInspector.blackboxManager; |
| 254 if (canBlackbox) { |
| 255 if (isBlackboxed) |
| 256 contextMenu.appendItem( |
| 257 WebInspector.UIString.capitalize('Stop ^blackboxing'), |
| 258 manager.unblackboxUISourceCode.bind(manager, uiSourceCode)); |
| 259 else |
| 260 contextMenu.appendItem( |
| 261 WebInspector.UIString.capitalize('Blackbox ^script'), |
| 262 manager.blackboxUISourceCode.bind(manager, uiSourceCode)); |
| 263 } |
| 264 if (isContentScript) { |
| 265 if (isBlackboxed) |
| 266 contextMenu.appendItem( |
| 267 WebInspector.UIString.capitalize('Stop blackboxing ^all ^content ^sc
ripts'), |
| 268 manager.blackboxContentScripts.bind(manager)); |
| 269 else |
| 270 contextMenu.appendItem( |
| 271 WebInspector.UIString.capitalize('Blackbox ^all ^content ^scripts'), |
| 272 manager.unblackboxContentScripts.bind(manager)); |
| 273 } |
| 274 } |
| 275 |
| 276 _asyncStackTracesStateChanged() { |
| 277 var enabled = WebInspector.moduleSetting('enableAsyncStackTraces').get(); |
| 278 if (!enabled && this.callFrames) |
| 279 this._removeAsyncCallFrames(); |
| 280 } |
| 281 |
| 282 _removeAsyncCallFrames() { |
| 283 var shouldSelectTopFrame = false; |
| 284 var lastSyncCallFrameIndex = -1; |
| 285 for (var i = 0; i < this.callFrames.length; ++i) { |
| 286 var callFrame = this.callFrames[i]; |
| 287 if (callFrame._asyncCallFrame) { |
| 288 if (callFrame.isSelected()) |
| 289 shouldSelectTopFrame = true; |
| 290 callFrame._asyncCallFrame.element.remove(); |
| 291 callFrame.element.remove(); |
| 292 } else { |
| 293 lastSyncCallFrameIndex = i; |
| 294 } |
| 295 } |
| 296 this.callFrames.length = lastSyncCallFrameIndex + 1; |
| 297 if (shouldSelectTopFrame) |
| 298 this._selectNextVisibleCallFrame(0); |
| 299 } |
| 300 |
| 301 /** |
| 302 * @return {boolean} |
| 303 */ |
| 304 _selectNextCallFrameOnStack() { |
| 305 var index = this._selectedCallFrameIndex(); |
| 306 if (index === -1) |
| 307 return false; |
| 308 return this._selectNextVisibleCallFrame(index + 1); |
| 309 } |
| 310 |
| 311 /** |
| 312 * @return {boolean} |
| 313 */ |
| 314 _selectPreviousCallFrameOnStack() { |
| 315 var index = this._selectedCallFrameIndex(); |
| 316 if (index === -1) |
| 317 return false; |
| 318 return this._selectNextVisibleCallFrame(index - 1, true); |
| 319 } |
| 320 |
| 321 /** |
| 322 * @param {number} index |
| 323 * @param {boolean=} backward |
| 324 * @return {boolean} |
| 325 */ |
| 326 _selectNextVisibleCallFrame(index, backward) { |
| 327 while (0 <= index && index < this.callFrames.length) { |
| 328 var callFrame = this.callFrames[index]; |
| 329 if (!callFrame.isHidden() && !callFrame.isLabel() && !callFrame._asyncCall
Frame) { |
| 330 this._callFrameSelected(callFrame); |
| 331 return true; |
| 332 } |
| 333 index += backward ? -1 : 1; |
| 334 } |
| 335 return false; |
| 336 } |
| 337 |
| 338 /** |
| 339 * @return {number} |
| 340 */ |
| 341 _selectedCallFrameIndex() { |
| 342 if (!this._debuggerModel) |
| 343 return -1; |
| 344 var selectedCallFrame = this._debuggerModel.selectedCallFrame(); |
| 345 if (!selectedCallFrame) |
| 346 return -1; |
| 347 for (var i = 0; i < this.callFrames.length; ++i) { |
| 348 if (this.callFrames[i]._debuggerCallFrame === selectedCallFrame) |
| 349 return i; |
| 350 } |
| 351 return -1; |
| 352 } |
| 353 |
| 354 /** |
| 355 * @param {!WebInspector.CallStackSidebarPane.CallFrame} callFrameItem |
| 356 */ |
| 357 _asyncCallFrameClicked(callFrameItem) { |
| 358 var uiLocation = WebInspector.debuggerWorkspaceBinding.rawLocationToUILocati
on(callFrameItem._location); |
| 359 WebInspector.Revealer.reveal(uiLocation); |
| 360 } |
| 361 |
| 362 /** |
| 363 * @param {!WebInspector.CallStackSidebarPane.CallFrame} selectedCallFrame |
| 364 */ |
| 365 _callFrameSelected(selectedCallFrame) { |
| 366 selectedCallFrame.element.scrollIntoViewIfNeeded(); |
| 367 var callFrame = selectedCallFrame._debuggerCallFrame; |
| 368 |
| 369 for (var i = 0; i < this.callFrames.length; ++i) { |
| 370 var callFrameItem = this.callFrames[i]; |
| 371 callFrameItem.setSelected(callFrameItem === selectedCallFrame); |
| 372 if (callFrameItem.isSelected() && callFrameItem.isHidden()) |
| 373 this._revealHiddenCallFrames(); |
| 374 } |
| 375 |
| 376 var oldCallFrame = WebInspector.context.flavor(WebInspector.DebuggerModel.Ca
llFrame); |
| 377 if (oldCallFrame === callFrame) { |
| 378 var uiLocation = WebInspector.debuggerWorkspaceBinding.rawLocationToUILoca
tion(callFrame.location()); |
| 379 WebInspector.Revealer.reveal(uiLocation); |
| 380 return; |
| 381 } |
| 382 |
| 383 WebInspector.context.setFlavor(WebInspector.DebuggerModel.CallFrame, callFra
me); |
| 384 callFrame.debuggerModel.setSelectedCallFrame(callFrame); |
| 385 } |
| 386 |
| 387 _copyStackTrace() { |
| 388 var text = ''; |
| 389 var lastCallFrame = null; |
| 390 for (var i = 0; i < this.callFrames.length; ++i) { |
| 391 var callFrame = this.callFrames[i]; |
| 392 if (callFrame.isHidden()) |
| 393 continue; |
| 394 if (lastCallFrame && callFrame._asyncCallFrame !== lastCallFrame._asyncCal
lFrame) |
| 395 text += callFrame._asyncCallFrame.title() + '\n'; |
| 396 text += callFrame.title() + ' (' + callFrame.subtitle() + ')\n'; |
| 397 lastCallFrame = callFrame; |
| 398 } |
| 399 InspectorFrontendHost.copyText(text); |
| 400 } |
| 401 |
| 402 /** |
| 403 * @param {function(!Array.<!WebInspector.KeyboardShortcut.Descriptor>, functi
on(!Event=):boolean)} registerShortcutDelegate |
| 404 */ |
| 405 registerShortcuts(registerShortcutDelegate) { |
| 406 registerShortcutDelegate( |
| 407 WebInspector.ShortcutsScreen.SourcesPanelShortcuts.NextCallFrame, this._
selectNextCallFrameOnStack.bind(this)); |
| 408 registerShortcutDelegate( |
| 409 WebInspector.ShortcutsScreen.SourcesPanelShortcuts.PrevCallFrame, |
| 410 this._selectPreviousCallFrameOnStack.bind(this)); |
| 411 } |
| 412 |
| 413 _keyDown(event) { |
| 414 if (event.altKey || event.shiftKey || event.metaKey || event.ctrlKey) |
| 415 return; |
| 416 if (event.key === 'ArrowUp' && this._selectPreviousCallFrameOnStack() || |
| 417 event.key === 'ArrowDown' && this._selectNextCallFrameOnStack()) |
| 418 event.consume(true); |
| 419 } |
45 }; | 420 }; |
46 | 421 |
47 WebInspector.CallStackSidebarPane.prototype = { | |
48 /** | |
49 * @override | |
50 * @param {?Object} object | |
51 */ | |
52 flavorChanged: function(object) | |
53 { | |
54 this._update(); | |
55 }, | |
56 | |
57 _update: function() | |
58 { | |
59 var details = WebInspector.context.flavor(WebInspector.DebuggerPausedDet
ails); | |
60 | |
61 this.callFrameList.detach(); | |
62 this.callFrameList.clear(); | |
63 this._linkifier.reset(); | |
64 this.element.removeChildren(); | |
65 this._locationPool.disposeAll(); | |
66 | |
67 this.callFrameList.show(this.element); | |
68 delete this._hiddenCallFramesMessageElement; | |
69 this.callFrames = []; | |
70 this._hiddenCallFrames = 0; | |
71 | |
72 if (!details) { | |
73 var infoElement = this.element.createChild("div", "gray-info-message
"); | |
74 infoElement.textContent = WebInspector.UIString("Not Paused"); | |
75 WebInspector.context.setFlavor(WebInspector.DebuggerModel.CallFrame,
null); | |
76 return; | |
77 } | |
78 this._debuggerModel = details.debuggerModel; | |
79 var asyncStackTrace = details.asyncStackTrace; | |
80 | |
81 this._appendSidebarCallFrames(this._callFramesFromDebugger(details.callF
rames)); | |
82 var topStackHidden = (this._hiddenCallFrames === this.callFrames.length)
; | |
83 | |
84 var peviousStackTrace = details.callFrames; | |
85 while (asyncStackTrace) { | |
86 var title = ""; | |
87 if (asyncStackTrace.description === "async function") { | |
88 var lastPreviousFrame = peviousStackTrace[peviousStackTrace.leng
th - 1]; | |
89 var topFrame = asyncStackTrace.callFrames[0]; | |
90 var lastPreviousFrameName = WebInspector.beautifyFunctionName(la
stPreviousFrame.functionName); | |
91 var topFrameName = WebInspector.beautifyFunctionName(topFrame.fu
nctionName); | |
92 title = topFrameName + " awaits " + lastPreviousFrameName; | |
93 } else { | |
94 title = WebInspector.asyncStackTraceLabel(asyncStackTrace.descri
ption); | |
95 } | |
96 var asyncCallFrame = new WebInspector.UIList.Item(title, "", true); | |
97 asyncCallFrame.setHoverable(false); | |
98 asyncCallFrame.element.addEventListener("contextmenu", this._asyncCa
llFrameContextMenu.bind(this, this.callFrames.length), true); | |
99 this._appendSidebarCallFrames(this._callFramesFromRuntime(asyncStack
Trace.callFrames, asyncCallFrame), asyncCallFrame); | |
100 peviousStackTrace = asyncStackTrace.callFrames; | |
101 asyncStackTrace = asyncStackTrace.parent; | |
102 } | |
103 | |
104 if (topStackHidden) | |
105 this._revealHiddenCallFrames(); | |
106 if (this._hiddenCallFrames) { | |
107 var element = createElementWithClass("div", "hidden-callframes-messa
ge"); | |
108 if (this._hiddenCallFrames === 1) | |
109 element.textContent = WebInspector.UIString("1 stack frame is hi
dden (black-boxed)."); | |
110 else | |
111 element.textContent = WebInspector.UIString("%d stack frames are
hidden (black-boxed).", this._hiddenCallFrames); | |
112 element.createTextChild(" "); | |
113 var showAllLink = element.createChild("span", "link"); | |
114 showAllLink.textContent = WebInspector.UIString("Show"); | |
115 showAllLink.addEventListener("click", this._revealHiddenCallFrames.b
ind(this), false); | |
116 this.element.insertBefore(element, this.element.firstChild); | |
117 this._hiddenCallFramesMessageElement = element; | |
118 } | |
119 this._selectNextVisibleCallFrame(0); | |
120 this.revealView(); | |
121 }, | |
122 | |
123 /** | |
124 * @param {!Array.<!WebInspector.DebuggerModel.CallFrame>} callFrames | |
125 * @return {!Array<!WebInspector.CallStackSidebarPane.CallFrame>} | |
126 */ | |
127 _callFramesFromDebugger: function(callFrames) | |
128 { | |
129 var callFrameItems = []; | |
130 for (var i = 0, n = callFrames.length; i < n; ++i) { | |
131 var callFrame = callFrames[i]; | |
132 var callFrameItem = new WebInspector.CallStackSidebarPane.CallFrame(
callFrame.functionName, callFrame.location(), this._linkifier, callFrame, this._
locationPool); | |
133 callFrameItem.element.addEventListener("click", this._callFrameSelec
ted.bind(this, callFrameItem), false); | |
134 callFrameItems.push(callFrameItem); | |
135 } | |
136 return callFrameItems; | |
137 }, | |
138 | |
139 /** | |
140 * @param {!Array<!RuntimeAgent.CallFrame>} callFrames | |
141 * @param {!WebInspector.UIList.Item} asyncCallFrameItem | |
142 * @return {!Array<!WebInspector.CallStackSidebarPane.CallFrame>} | |
143 */ | |
144 _callFramesFromRuntime: function(callFrames, asyncCallFrameItem) | |
145 { | |
146 var callFrameItems = []; | |
147 for (var i = 0, n = callFrames.length; i < n; ++i) { | |
148 var callFrame = callFrames[i]; | |
149 var location = new WebInspector.DebuggerModel.Location(this._debugge
rModel, callFrame.scriptId, callFrame.lineNumber, callFrame.columnNumber); | |
150 var callFrameItem = new WebInspector.CallStackSidebarPane.CallFrame(
callFrame.functionName, location, this._linkifier, null, this._locationPool, asy
ncCallFrameItem); | |
151 callFrameItem.element.addEventListener("click", this._asyncCallFrame
Clicked.bind(this, callFrameItem), false); | |
152 callFrameItems.push(callFrameItem); | |
153 } | |
154 return callFrameItems; | |
155 }, | |
156 | |
157 /** | |
158 * @param {!Array.<!WebInspector.CallStackSidebarPane.CallFrame>} callFrames | |
159 * @param {!WebInspector.UIList.Item=} asyncCallFrameItem | |
160 */ | |
161 _appendSidebarCallFrames: function(callFrames, asyncCallFrameItem) | |
162 { | |
163 if (asyncCallFrameItem) | |
164 this.callFrameList.addItem(asyncCallFrameItem); | |
165 | |
166 var allCallFramesHidden = true; | |
167 for (var i = 0, n = callFrames.length; i < n; ++i) { | |
168 var callFrameItem = callFrames[i]; | |
169 callFrameItem.element.addEventListener("contextmenu", this._callFram
eContextMenu.bind(this, callFrameItem), true); | |
170 this.callFrames.push(callFrameItem); | |
171 | |
172 if (WebInspector.blackboxManager.isBlackboxedRawLocation(callFrameIt
em._location)) { | |
173 callFrameItem.setHidden(true); | |
174 callFrameItem.setDimmed(true); | |
175 ++this._hiddenCallFrames; | |
176 } else { | |
177 this.callFrameList.addItem(callFrameItem); | |
178 allCallFramesHidden = false; | |
179 } | |
180 } | |
181 if (allCallFramesHidden && asyncCallFrameItem) { | |
182 asyncCallFrameItem.setHidden(true); | |
183 asyncCallFrameItem.element.remove(); | |
184 } | |
185 }, | |
186 | |
187 _revealHiddenCallFrames: function() | |
188 { | |
189 if (!this._hiddenCallFrames) | |
190 return; | |
191 this._hiddenCallFrames = 0; | |
192 this.callFrameList.clear(); | |
193 for (var i = 0; i < this.callFrames.length; ++i) { | |
194 var callFrame = this.callFrames[i]; | |
195 if (callFrame._asyncCallFrame) { | |
196 callFrame._asyncCallFrame.setHidden(false); | |
197 if (i && callFrame._asyncCallFrame !== this.callFrames[i - 1]._a
syncCallFrame) | |
198 this.callFrameList.addItem(callFrame._asyncCallFrame); | |
199 } | |
200 callFrame.setHidden(false); | |
201 this.callFrameList.addItem(callFrame); | |
202 } | |
203 if (this._hiddenCallFramesMessageElement) { | |
204 this._hiddenCallFramesMessageElement.remove(); | |
205 delete this._hiddenCallFramesMessageElement; | |
206 } | |
207 }, | |
208 | |
209 /** | |
210 * @param {!WebInspector.CallStackSidebarPane.CallFrame} callFrame | |
211 * @param {!Event} event | |
212 */ | |
213 _callFrameContextMenu: function(callFrame, event) | |
214 { | |
215 var contextMenu = new WebInspector.ContextMenu(event); | |
216 var debuggerCallFrame = callFrame._debuggerCallFrame; | |
217 if (debuggerCallFrame) | |
218 contextMenu.appendItem(WebInspector.UIString.capitalize("Restart ^fr
ame"), debuggerCallFrame.restart.bind(debuggerCallFrame)); | |
219 | |
220 contextMenu.appendItem(WebInspector.UIString.capitalize("Copy ^stack ^tr
ace"), this._copyStackTrace.bind(this)); | |
221 | |
222 var uiLocation = WebInspector.debuggerWorkspaceBinding.rawLocationToUILo
cation(callFrame._location); | |
223 this.appendBlackboxURLContextMenuItems(contextMenu, uiLocation.uiSourceC
ode); | |
224 | |
225 contextMenu.show(); | |
226 }, | |
227 | |
228 /** | |
229 * @param {number} index | |
230 * @param {!Event} event | |
231 */ | |
232 _asyncCallFrameContextMenu: function(index, event) | |
233 { | |
234 for (; index < this.callFrames.length; ++index) { | |
235 var callFrame = this.callFrames[index]; | |
236 if (!callFrame.isHidden()) { | |
237 this._callFrameContextMenu(callFrame, event); | |
238 break; | |
239 } | |
240 } | |
241 }, | |
242 | |
243 /** | |
244 * @param {!WebInspector.ContextMenu} contextMenu | |
245 * @param {!WebInspector.UISourceCode} uiSourceCode | |
246 */ | |
247 appendBlackboxURLContextMenuItems: function(contextMenu, uiSourceCode) | |
248 { | |
249 var binding = WebInspector.persistence.binding(uiSourceCode); | |
250 if (binding) | |
251 uiSourceCode = binding.network; | |
252 if (uiSourceCode.project().type() === WebInspector.projectTypes.FileSyst
em) | |
253 return; | |
254 var canBlackbox = WebInspector.blackboxManager.canBlackboxUISourceCode(u
iSourceCode); | |
255 var isBlackboxed = WebInspector.blackboxManager.isBlackboxedUISourceCode
(uiSourceCode); | |
256 var isContentScript = uiSourceCode.project().type() === WebInspector.pro
jectTypes.ContentScripts; | |
257 | |
258 var manager = WebInspector.blackboxManager; | |
259 if (canBlackbox) { | |
260 if (isBlackboxed) | |
261 contextMenu.appendItem(WebInspector.UIString.capitalize("Stop ^b
lackboxing"), manager.unblackboxUISourceCode.bind(manager, uiSourceCode)); | |
262 else | |
263 contextMenu.appendItem(WebInspector.UIString.capitalize("Blackbo
x ^script"), manager.blackboxUISourceCode.bind(manager, uiSourceCode)); | |
264 } | |
265 if (isContentScript) { | |
266 if (isBlackboxed) | |
267 contextMenu.appendItem(WebInspector.UIString.capitalize("Stop bl
ackboxing ^all ^content ^scripts"), manager.blackboxContentScripts.bind(manager)
); | |
268 else | |
269 contextMenu.appendItem(WebInspector.UIString.capitalize("Blackbo
x ^all ^content ^scripts"), manager.unblackboxContentScripts.bind(manager)); | |
270 } | |
271 }, | |
272 | |
273 _asyncStackTracesStateChanged: function() | |
274 { | |
275 var enabled = WebInspector.moduleSetting("enableAsyncStackTraces").get()
; | |
276 if (!enabled && this.callFrames) | |
277 this._removeAsyncCallFrames(); | |
278 }, | |
279 | |
280 _removeAsyncCallFrames: function() | |
281 { | |
282 var shouldSelectTopFrame = false; | |
283 var lastSyncCallFrameIndex = -1; | |
284 for (var i = 0; i < this.callFrames.length; ++i) { | |
285 var callFrame = this.callFrames[i]; | |
286 if (callFrame._asyncCallFrame) { | |
287 if (callFrame.isSelected()) | |
288 shouldSelectTopFrame = true; | |
289 callFrame._asyncCallFrame.element.remove(); | |
290 callFrame.element.remove(); | |
291 } else { | |
292 lastSyncCallFrameIndex = i; | |
293 } | |
294 } | |
295 this.callFrames.length = lastSyncCallFrameIndex + 1; | |
296 if (shouldSelectTopFrame) | |
297 this._selectNextVisibleCallFrame(0); | |
298 }, | |
299 | |
300 /** | |
301 * @return {boolean} | |
302 */ | |
303 _selectNextCallFrameOnStack: function() | |
304 { | |
305 var index = this._selectedCallFrameIndex(); | |
306 if (index === -1) | |
307 return false; | |
308 return this._selectNextVisibleCallFrame(index + 1); | |
309 }, | |
310 | |
311 /** | |
312 * @return {boolean} | |
313 */ | |
314 _selectPreviousCallFrameOnStack: function() | |
315 { | |
316 var index = this._selectedCallFrameIndex(); | |
317 if (index === -1) | |
318 return false; | |
319 return this._selectNextVisibleCallFrame(index - 1, true); | |
320 }, | |
321 | |
322 /** | |
323 * @param {number} index | |
324 * @param {boolean=} backward | |
325 * @return {boolean} | |
326 */ | |
327 _selectNextVisibleCallFrame: function(index, backward) | |
328 { | |
329 while (0 <= index && index < this.callFrames.length) { | |
330 var callFrame = this.callFrames[index]; | |
331 if (!callFrame.isHidden() && !callFrame.isLabel() && !callFrame._asy
ncCallFrame) { | |
332 this._callFrameSelected(callFrame); | |
333 return true; | |
334 } | |
335 index += backward ? -1 : 1; | |
336 } | |
337 return false; | |
338 }, | |
339 | |
340 /** | |
341 * @return {number} | |
342 */ | |
343 _selectedCallFrameIndex: function() | |
344 { | |
345 if (!this._debuggerModel) | |
346 return -1; | |
347 var selectedCallFrame = this._debuggerModel.selectedCallFrame(); | |
348 if (!selectedCallFrame) | |
349 return -1; | |
350 for (var i = 0; i < this.callFrames.length; ++i) { | |
351 if (this.callFrames[i]._debuggerCallFrame === selectedCallFrame) | |
352 return i; | |
353 } | |
354 return -1; | |
355 }, | |
356 | |
357 /** | |
358 * @param {!WebInspector.CallStackSidebarPane.CallFrame} callFrameItem | |
359 */ | |
360 _asyncCallFrameClicked: function(callFrameItem) | |
361 { | |
362 var uiLocation = WebInspector.debuggerWorkspaceBinding.rawLocationToUILo
cation(callFrameItem._location); | |
363 WebInspector.Revealer.reveal(uiLocation); | |
364 }, | |
365 | |
366 /** | |
367 * @param {!WebInspector.CallStackSidebarPane.CallFrame} selectedCallFrame | |
368 */ | |
369 _callFrameSelected: function(selectedCallFrame) | |
370 { | |
371 selectedCallFrame.element.scrollIntoViewIfNeeded(); | |
372 var callFrame = selectedCallFrame._debuggerCallFrame; | |
373 | |
374 for (var i = 0; i < this.callFrames.length; ++i) { | |
375 var callFrameItem = this.callFrames[i]; | |
376 callFrameItem.setSelected(callFrameItem === selectedCallFrame); | |
377 if (callFrameItem.isSelected() && callFrameItem.isHidden()) | |
378 this._revealHiddenCallFrames(); | |
379 } | |
380 | |
381 var oldCallFrame = WebInspector.context.flavor(WebInspector.DebuggerMode
l.CallFrame); | |
382 if (oldCallFrame === callFrame) { | |
383 var uiLocation = WebInspector.debuggerWorkspaceBinding.rawLocationTo
UILocation(callFrame.location()); | |
384 WebInspector.Revealer.reveal(uiLocation); | |
385 return; | |
386 } | |
387 | |
388 WebInspector.context.setFlavor(WebInspector.DebuggerModel.CallFrame, cal
lFrame); | |
389 callFrame.debuggerModel.setSelectedCallFrame(callFrame); | |
390 }, | |
391 | |
392 _copyStackTrace: function() | |
393 { | |
394 var text = ""; | |
395 var lastCallFrame = null; | |
396 for (var i = 0; i < this.callFrames.length; ++i) { | |
397 var callFrame = this.callFrames[i]; | |
398 if (callFrame.isHidden()) | |
399 continue; | |
400 if (lastCallFrame && callFrame._asyncCallFrame !== lastCallFrame._as
yncCallFrame) | |
401 text += callFrame._asyncCallFrame.title() + "\n"; | |
402 text += callFrame.title() + " (" + callFrame.subtitle() + ")\n"; | |
403 lastCallFrame = callFrame; | |
404 } | |
405 InspectorFrontendHost.copyText(text); | |
406 }, | |
407 | |
408 /** | |
409 * @param {function(!Array.<!WebInspector.KeyboardShortcut.Descriptor>, func
tion(!Event=):boolean)} registerShortcutDelegate | |
410 */ | |
411 registerShortcuts: function(registerShortcutDelegate) | |
412 { | |
413 registerShortcutDelegate(WebInspector.ShortcutsScreen.SourcesPanelShortc
uts.NextCallFrame, this._selectNextCallFrameOnStack.bind(this)); | |
414 registerShortcutDelegate(WebInspector.ShortcutsScreen.SourcesPanelShortc
uts.PrevCallFrame, this._selectPreviousCallFrameOnStack.bind(this)); | |
415 }, | |
416 | |
417 _keyDown: function(event) | |
418 { | |
419 if (event.altKey || event.shiftKey || event.metaKey || event.ctrlKey) | |
420 return; | |
421 if (event.key === "ArrowUp" && this._selectPreviousCallFrameOnStack() ||
event.key === "ArrowDown" && this._selectNextCallFrameOnStack()) | |
422 event.consume(true); | |
423 }, | |
424 | |
425 __proto__: WebInspector.SimpleView.prototype | |
426 }; | |
427 | |
428 /** | 422 /** |
429 * @constructor | 423 * @unrestricted |
430 * @extends {WebInspector.UIList.Item} | |
431 * @param {string} functionName | |
432 * @param {!WebInspector.DebuggerModel.Location} location | |
433 * @param {!WebInspector.Linkifier} linkifier | |
434 * @param {?WebInspector.DebuggerModel.CallFrame} debuggerCallFrame | |
435 * @param {!WebInspector.LiveLocationPool} locationPool | |
436 * @param {!WebInspector.UIList.Item=} asyncCallFrame | |
437 */ | 424 */ |
438 WebInspector.CallStackSidebarPane.CallFrame = function(functionName, location, l
inkifier, debuggerCallFrame, locationPool, asyncCallFrame) | 425 WebInspector.CallStackSidebarPane.CallFrame = class extends WebInspector.UIList.
Item { |
439 { | 426 /** |
440 WebInspector.UIList.Item.call(this, WebInspector.beautifyFunctionName(functi
onName), ""); | 427 * @param {string} functionName |
| 428 * @param {!WebInspector.DebuggerModel.Location} location |
| 429 * @param {!WebInspector.Linkifier} linkifier |
| 430 * @param {?WebInspector.DebuggerModel.CallFrame} debuggerCallFrame |
| 431 * @param {!WebInspector.LiveLocationPool} locationPool |
| 432 * @param {!WebInspector.UIList.Item=} asyncCallFrame |
| 433 */ |
| 434 constructor(functionName, location, linkifier, debuggerCallFrame, locationPool
, asyncCallFrame) { |
| 435 super(WebInspector.beautifyFunctionName(functionName), ''); |
441 this._location = location; | 436 this._location = location; |
442 this._debuggerCallFrame = debuggerCallFrame; | 437 this._debuggerCallFrame = debuggerCallFrame; |
443 this._asyncCallFrame = asyncCallFrame; | 438 this._asyncCallFrame = asyncCallFrame; |
444 WebInspector.debuggerWorkspaceBinding.createCallFrameLiveLocation(location,
this._update.bind(this), locationPool); | 439 WebInspector.debuggerWorkspaceBinding.createCallFrameLiveLocation(location,
this._update.bind(this), locationPool); |
| 440 } |
| 441 |
| 442 /** |
| 443 * @param {!WebInspector.LiveLocation} liveLocation |
| 444 */ |
| 445 _update(liveLocation) { |
| 446 var uiLocation = liveLocation.uiLocation(); |
| 447 if (!uiLocation) |
| 448 return; |
| 449 var text = uiLocation.linkText(); |
| 450 this.setSubtitle(text.trimMiddle(30)); |
| 451 this.subtitleElement.title = text; |
| 452 } |
445 }; | 453 }; |
446 | |
447 WebInspector.CallStackSidebarPane.CallFrame.prototype = { | |
448 /** | |
449 * @param {!WebInspector.LiveLocation} liveLocation | |
450 */ | |
451 _update: function(liveLocation) | |
452 { | |
453 var uiLocation = liveLocation.uiLocation(); | |
454 if (!uiLocation) | |
455 return; | |
456 var text = uiLocation.linkText(); | |
457 this.setSubtitle(text.trimMiddle(30)); | |
458 this.subtitleElement.title = text; | |
459 }, | |
460 | |
461 __proto__: WebInspector.UIList.Item.prototype | |
462 }; | |
OLD | NEW |