diff options
Diffstat (limited to 'chromium/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js')
-rw-r--r-- | chromium/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js b/chromium/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js new file mode 100644 index 00000000000..ce6eb9cd5b6 --- /dev/null +++ b/chromium/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.SidebarPane} + */ +WebInspector.CallStackSidebarPane = function() +{ + WebInspector.SidebarPane.call(this, WebInspector.UIString("Call Stack")); + this.bodyElement.addEventListener("keydown", this._keyDown.bind(this), true); + this.bodyElement.tabIndex = 0; + + var asyncCheckbox = this.titleElement.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Async"), WebInspector.settings.enableAsyncStackTraces, true, undefined, WebInspector.UIString("Capture async stack traces"))); + asyncCheckbox.classList.add("scripts-callstack-async"); + asyncCheckbox.addEventListener("click", consumeEvent, false); + WebInspector.settings.enableAsyncStackTraces.addChangeListener(this._asyncStackTracesStateChanged, this); +} + +WebInspector.CallStackSidebarPane.Events = { + CallFrameRestarted: "CallFrameRestarted", + CallFrameSelected: "CallFrameSelected" +} + +WebInspector.CallStackSidebarPane.prototype = { + /** + * @param {?WebInspector.DebuggerPausedDetails} details + */ + update: function(details) + { + this.bodyElement.removeChildren(); + + if (!details) { + var infoElement = this.bodyElement.createChild("div", "info"); + infoElement.textContent = WebInspector.UIString("Not Paused"); + return; + } + + this._target = details.target(); + var callFrames = details.callFrames; + var asyncStackTrace = details.asyncStackTrace; + + delete this._statusMessageElement; + delete this._hiddenPlacardsMessageElement; + /** @type {!Array.<!WebInspector.CallStackSidebarPane.Placard>} */ + this.placards = []; + this._hiddenPlacards = 0; + + this._appendSidebarPlacards(callFrames); + var topStackHidden = (this._hiddenPlacards === this.placards.length); + + while (asyncStackTrace) { + var title = asyncStackTrace.description; + if (title) + title += " " + WebInspector.UIString("(async)"); + else + title = WebInspector.UIString("Async Call"); + var asyncPlacard = new WebInspector.Placard(title, ""); + asyncPlacard.element.addEventListener("click", this._selectNextVisiblePlacard.bind(this, this.placards.length, false), false); + asyncPlacard.element.addEventListener("contextmenu", this._asyncPlacardContextMenu.bind(this, this.placards.length), true); + asyncPlacard.element.classList.add("placard-label"); + this.bodyElement.appendChild(asyncPlacard.element); + this._appendSidebarPlacards(asyncStackTrace.callFrames, asyncPlacard); + asyncStackTrace = asyncStackTrace.asyncStackTrace; + } + + if (topStackHidden) + this._revealHiddenPlacards(); + if (this._hiddenPlacards) { + var element = document.createElementWithClass("div", "hidden-placards-message"); + if (this._hiddenPlacards === 1) + element.textContent = WebInspector.UIString("1 stack frame is hidden (black-boxed)."); + else + element.textContent = WebInspector.UIString("%d stack frames are hidden (black-boxed).", this._hiddenPlacards); + element.createTextChild(" "); + var showAllLink = element.createChild("span", "node-link"); + showAllLink.textContent = WebInspector.UIString("Show"); + showAllLink.addEventListener("click", this._revealHiddenPlacards.bind(this), false); + this.bodyElement.insertBefore(element, this.bodyElement.firstChild); + this._hiddenPlacardsMessageElement = element; + } + }, + + /** + * @param {!Array.<!WebInspector.DebuggerModel.CallFrame>} callFrames + * @param {!WebInspector.Placard=} asyncPlacard + */ + _appendSidebarPlacards: function(callFrames, asyncPlacard) + { + var allPlacardsHidden = true; + for (var i = 0, n = callFrames.length; i < n; ++i) { + var callFrame = callFrames[i]; + var placard = new WebInspector.CallStackSidebarPane.Placard(callFrame, asyncPlacard); + placard.element.addEventListener("click", this._placardSelected.bind(this, placard), false); + placard.element.addEventListener("contextmenu", this._placardContextMenu.bind(this, placard), true); + this.placards.push(placard); + this.bodyElement.appendChild(placard.element); + + if (callFrame.script.isFramework()) { + placard.setHidden(true); + placard.element.classList.add("dimmed"); + ++this._hiddenPlacards; + } else { + allPlacardsHidden = false; + } + } + if (allPlacardsHidden && asyncPlacard) + asyncPlacard.setHidden(true); + }, + + _revealHiddenPlacards: function() + { + if (!this._hiddenPlacards) + return; + this._hiddenPlacards = 0; + for (var i = 0; i < this.placards.length; ++i) { + var placard = this.placards[i]; + placard.setHidden(false); + if (placard._asyncPlacard) + placard._asyncPlacard.setHidden(false); + } + if (this._hiddenPlacardsMessageElement) { + this._hiddenPlacardsMessageElement.remove(); + delete this._hiddenPlacardsMessageElement; + } + }, + + /** + * @param {!WebInspector.CallStackSidebarPane.Placard} placard + * @param {?Event} event + */ + _placardContextMenu: function(placard, event) + { + var contextMenu = new WebInspector.ContextMenu(event); + + if (!placard._callFrame.isAsync()) + contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Restart frame" : "Restart Frame"), this._restartFrame.bind(this, placard)); + + contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy stack trace" : "Copy Stack Trace"), this._copyStackTrace.bind(this)); + contextMenu.show(); + }, + + /** + * @param {number} index + * @param {?Event} event + */ + _asyncPlacardContextMenu: function(index, event) + { + for (; index < this.placards.length; ++index) { + var placard = this.placards[index]; + if (!placard.isHidden()) { + this._placardContextMenu(placard, event); + break; + } + } + }, + + /** + * @param {!WebInspector.CallStackSidebarPane.Placard} placard + */ + _restartFrame: function(placard) + { + placard._callFrame.restart(); + this.dispatchEventToListeners(WebInspector.CallStackSidebarPane.Events.CallFrameRestarted, placard._callFrame); + }, + + _asyncStackTracesStateChanged: function() + { + var enabled = WebInspector.settings.enableAsyncStackTraces.get(); + if (!enabled && this.placards) + this._removeAsyncPlacards(); + }, + + _removeAsyncPlacards: function() + { + var shouldSelectTopFrame = false; + var lastSyncPlacardIndex = -1; + for (var i = 0; i < this.placards.length; ++i) { + var placard = this.placards[i]; + if (placard._asyncPlacard) { + if (placard.selected) + shouldSelectTopFrame = true; + placard._asyncPlacard.element.remove(); + placard.element.remove(); + } else { + lastSyncPlacardIndex = i; + } + } + this.placards.length = lastSyncPlacardIndex + 1; + if (shouldSelectTopFrame) + this._selectNextVisiblePlacard(0); + }, + + /** + * @param {!WebInspector.DebuggerModel.CallFrame} x + */ + setSelectedCallFrame: function(x) + { + for (var i = 0; i < this.placards.length; ++i) { + var placard = this.placards[i]; + placard.selected = (placard._callFrame === x); + if (placard.selected && placard.isHidden()) + this._revealHiddenPlacards(); + } + }, + + /** + * @return {boolean} + */ + _selectNextCallFrameOnStack: function() + { + var index = this._selectedCallFrameIndex(); + if (index === -1) + return false; + return this._selectNextVisiblePlacard(index + 1); + }, + + /** + * @return {boolean} + */ + _selectPreviousCallFrameOnStack: function() + { + var index = this._selectedCallFrameIndex(); + if (index === -1) + return false; + return this._selectNextVisiblePlacard(index - 1, true); + }, + + /** + * @param {number} index + * @param {boolean=} backward + * @return {boolean} + */ + _selectNextVisiblePlacard: function(index, backward) + { + while (0 <= index && index < this.placards.length) { + var placard = this.placards[index]; + if (!placard.isHidden()) { + this._placardSelected(placard); + return true; + } + index += backward ? -1 : 1; + } + return false; + }, + + /** + * @return {number} + */ + _selectedCallFrameIndex: function() + { + var selectedCallFrame = this._target.debuggerModel.selectedCallFrame(); + if (!selectedCallFrame) + return -1; + for (var i = 0; i < this.placards.length; ++i) { + var placard = this.placards[i]; + if (placard._callFrame === selectedCallFrame) + return i; + } + return -1; + }, + + /** + * @param {!WebInspector.CallStackSidebarPane.Placard} placard + */ + _placardSelected: function(placard) + { + placard.element.scrollIntoViewIfNeeded(); + this.dispatchEventToListeners(WebInspector.CallStackSidebarPane.Events.CallFrameSelected, placard._callFrame); + }, + + _copyStackTrace: function() + { + var text = ""; + var lastPlacard = null; + for (var i = 0; i < this.placards.length; ++i) { + var placard = this.placards[i]; + if (placard.isHidden()) + continue; + if (lastPlacard && placard._asyncPlacard !== lastPlacard._asyncPlacard) + text += placard._asyncPlacard.title + "\n"; + text += placard.title + " (" + placard.subtitle + ")\n"; + lastPlacard = placard; + } + InspectorFrontendHost.copyText(text); + }, + + /** + * @param {function(!Array.<!WebInspector.KeyboardShortcut.Descriptor>, function(?Event=):boolean)} registerShortcutDelegate + */ + registerShortcuts: function(registerShortcutDelegate) + { + registerShortcutDelegate(WebInspector.ShortcutsScreen.SourcesPanelShortcuts.NextCallFrame, this._selectNextCallFrameOnStack.bind(this)); + registerShortcutDelegate(WebInspector.ShortcutsScreen.SourcesPanelShortcuts.PrevCallFrame, this._selectPreviousCallFrameOnStack.bind(this)); + }, + + /** + * @param {!Element|string} status + */ + setStatus: function(status) + { + if (!this._statusMessageElement) + this._statusMessageElement = this.bodyElement.createChild("div", "info"); + if (typeof status === "string") { + this._statusMessageElement.textContent = status; + } else { + this._statusMessageElement.removeChildren(); + this._statusMessageElement.appendChild(status); + } + }, + + _keyDown: function(event) + { + if (event.altKey || event.shiftKey || event.metaKey || event.ctrlKey) + return; + if (event.keyIdentifier === "Up" && this._selectPreviousCallFrameOnStack() || event.keyIdentifier === "Down" && this._selectNextCallFrameOnStack()) + event.consume(true); + }, + + __proto__: WebInspector.SidebarPane.prototype +} + +/** + * @constructor + * @extends {WebInspector.Placard} + * @param {!WebInspector.DebuggerModel.CallFrame} callFrame + * @param {!WebInspector.Placard=} asyncPlacard + */ +WebInspector.CallStackSidebarPane.Placard = function(callFrame, asyncPlacard) +{ + WebInspector.Placard.call(this, callFrame.functionName || WebInspector.UIString("(anonymous function)"), ""); + callFrame.createLiveLocation(this._update.bind(this)); + this._callFrame = callFrame; + this._asyncPlacard = asyncPlacard; +} + +WebInspector.CallStackSidebarPane.Placard.prototype = { + /** + * @param {!WebInspector.UILocation} uiLocation + */ + _update: function(uiLocation) + { + this.subtitle = uiLocation.linkText().trimMiddle(100); + }, + + __proto__: WebInspector.Placard.prototype +} |