| 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 |