diff options
Diffstat (limited to 'devtools/client/debugger/views/toolbar-view.js')
-rw-r--r-- | devtools/client/debugger/views/toolbar-view.js | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/devtools/client/debugger/views/toolbar-view.js b/devtools/client/debugger/views/toolbar-view.js new file mode 100644 index 000000000..d76275a71 --- /dev/null +++ b/devtools/client/debugger/views/toolbar-view.js @@ -0,0 +1,287 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* import-globals-from ../debugger-controller.js */ +/* import-globals-from ../debugger-view.js */ +/* import-globals-from ../utils.js */ +/* globals document */ +"use strict"; + +/** + * Functions handling the toolbar view: close button, expand/collapse button, + * pause/resume and stepping buttons etc. + */ +function ToolbarView(DebuggerController, DebuggerView) { + dumpn("ToolbarView was instantiated"); + + this.StackFrames = DebuggerController.StackFrames; + this.ThreadState = DebuggerController.ThreadState; + this.DebuggerController = DebuggerController; + this.DebuggerView = DebuggerView; + + this._onTogglePanesActivated = this._onTogglePanesActivated.bind(this); + this._onTogglePanesPressed = this._onTogglePanesPressed.bind(this); + this._onResumePressed = this._onResumePressed.bind(this); + this._onStepOverPressed = this._onStepOverPressed.bind(this); + this._onStepInPressed = this._onStepInPressed.bind(this); + this._onStepOutPressed = this._onStepOutPressed.bind(this); +} + +ToolbarView.prototype = { + get activeThread() { + return this.DebuggerController.activeThread; + }, + + get resumptionWarnFunc() { + return this.DebuggerController._ensureResumptionOrder; + }, + + /** + * Initialization function, called when the debugger is started. + */ + initialize: function () { + dumpn("Initializing the ToolbarView"); + + this._instrumentsPaneToggleButton = document.getElementById("instruments-pane-toggle"); + this._resumeButton = document.getElementById("resume"); + this._stepOverButton = document.getElementById("step-over"); + this._stepInButton = document.getElementById("step-in"); + this._stepOutButton = document.getElementById("step-out"); + this._resumeOrderTooltip = new Tooltip(document); + this._resumeOrderTooltip.defaultPosition = TOOLBAR_ORDER_POPUP_POSITION; + + let resumeKey = ShortcutUtils.prettifyShortcut(document.getElementById("resumeKey")); + let stepOverKey = ShortcutUtils.prettifyShortcut(document.getElementById("stepOverKey")); + let stepInKey = ShortcutUtils.prettifyShortcut(document.getElementById("stepInKey")); + let stepOutKey = ShortcutUtils.prettifyShortcut(document.getElementById("stepOutKey")); + this._resumeTooltip = L10N.getFormatStr("resumeButtonTooltip", resumeKey); + this._pauseTooltip = L10N.getFormatStr("pauseButtonTooltip", resumeKey); + this._pausePendingTooltip = L10N.getStr("pausePendingButtonTooltip"); + this._stepOverTooltip = L10N.getFormatStr("stepOverTooltip", stepOverKey); + this._stepInTooltip = L10N.getFormatStr("stepInTooltip", stepInKey); + this._stepOutTooltip = L10N.getFormatStr("stepOutTooltip", stepOutKey); + + this._instrumentsPaneToggleButton.addEventListener("mousedown", + this._onTogglePanesActivated, false); + this._instrumentsPaneToggleButton.addEventListener("keydown", + this._onTogglePanesPressed, false); + this._resumeButton.addEventListener("mousedown", this._onResumePressed, false); + this._stepOverButton.addEventListener("mousedown", this._onStepOverPressed, false); + this._stepInButton.addEventListener("mousedown", this._onStepInPressed, false); + this._stepOutButton.addEventListener("mousedown", this._onStepOutPressed, false); + + this._stepOverButton.setAttribute("tooltiptext", this._stepOverTooltip); + this._stepInButton.setAttribute("tooltiptext", this._stepInTooltip); + this._stepOutButton.setAttribute("tooltiptext", this._stepOutTooltip); + this._toggleButtonsState({ enabled: false }); + + this._addCommands(); + }, + + /** + * Destruction function, called when the debugger is closed. + */ + destroy: function () { + dumpn("Destroying the ToolbarView"); + + this._instrumentsPaneToggleButton.removeEventListener("mousedown", + this._onTogglePanesActivated, false); + this._instrumentsPaneToggleButton.removeEventListener("keydown", + this._onTogglePanesPressed, false); + this._resumeButton.removeEventListener("mousedown", this._onResumePressed, false); + this._stepOverButton.removeEventListener("mousedown", this._onStepOverPressed, false); + this._stepInButton.removeEventListener("mousedown", this._onStepInPressed, false); + this._stepOutButton.removeEventListener("mousedown", this._onStepOutPressed, false); + }, + + /** + * Add commands that XUL can fire. + */ + _addCommands: function () { + XULUtils.addCommands(document.getElementById("debuggerCommands"), { + resumeCommand: this.getCommandHandler("resumeCommand"), + stepOverCommand: this.getCommandHandler("stepOverCommand"), + stepInCommand: this.getCommandHandler("stepInCommand"), + stepOutCommand: this.getCommandHandler("stepOutCommand") + }); + }, + + /** + * Retrieve the callback associated with the provided debugger command. + * + * @param {String} command + * The debugger command id. + * @return {Function} the corresponding callback. + */ + getCommandHandler: function (command) { + switch (command) { + case "resumeCommand": + return () => this._onResumePressed(); + case "stepOverCommand": + return () => this._onStepOverPressed(); + case "stepInCommand": + return () => this._onStepInPressed(); + case "stepOutCommand": + return () => this._onStepOutPressed(); + default: + return () => {}; + } + }, + + /** + * Display a warning when trying to resume a debuggee while another is paused. + * Debuggees must be unpaused in a Last-In-First-Out order. + * + * @param string aPausedUrl + * The URL of the last paused debuggee. + */ + showResumeWarning: function (aPausedUrl) { + let label = L10N.getFormatStr("resumptionOrderPanelTitle", aPausedUrl); + let defaultStyle = "default-tooltip-simple-text-colors"; + this._resumeOrderTooltip.setTextContent({ messages: [label] }); + this._resumeOrderTooltip.show(this._resumeButton); + }, + + /** + * Sets the resume button state based on the debugger active thread. + * + * @param string aState + * Either "paused", "attached", or "breakOnNext". + * @param boolean hasLocation + * True if we are paused at a specific JS location + */ + toggleResumeButtonState: function (aState, hasLocation) { + // Intermidiate state after pressing the pause button and waiting + // for the next script execution to happen. + if (aState == "breakOnNext") { + this._resumeButton.setAttribute("break-on-next", "true"); + this._resumeButton.disabled = true; + this._resumeButton.setAttribute("tooltiptext", this._pausePendingTooltip); + return; + } + + this._resumeButton.removeAttribute("break-on-next"); + this._resumeButton.disabled = false; + + // If we're paused, check and show a resume label on the button. + if (aState == "paused") { + this._resumeButton.setAttribute("checked", "true"); + this._resumeButton.setAttribute("tooltiptext", this._resumeTooltip); + + // Only enable the stepping buttons if we are paused at a + // specific location. After bug 789430, we'll always be paused + // at a location, but currently you can pause the entire engine + // at any point without knowing the location. + if (hasLocation) { + this._toggleButtonsState({ enabled: true }); + } + } + // If we're attached, do the opposite. + else if (aState == "attached") { + this._resumeButton.removeAttribute("checked"); + this._resumeButton.setAttribute("tooltiptext", this._pauseTooltip); + this._toggleButtonsState({ enabled: false }); + } + }, + + _toggleButtonsState: function ({ enabled }) { + const buttons = [ + this._stepOutButton, + this._stepInButton, + this._stepOverButton + ]; + for (let button of buttons) { + button.disabled = !enabled; + } + }, + + /** + * Listener handling the toggle button space and return key event. + */ + _onTogglePanesPressed: function (event) { + if (ViewHelpers.isSpaceOrReturn(event)) { + this._onTogglePanesActivated(); + } + }, + + /** + * Listener handling the toggle button click event. + */ + _onTogglePanesActivated: function() { + DebuggerView.toggleInstrumentsPane({ + visible: DebuggerView.instrumentsPaneHidden, + animated: true, + delayed: true + }); + }, + + /** + * Listener handling the pause/resume button click event. + */ + _onResumePressed: function () { + if (this.StackFrames._currentFrameDescription != FRAME_TYPE.NORMAL || + this._resumeButton.disabled) { + return; + } + + if (this.activeThread.paused) { + this.StackFrames.currentFrameDepth = -1; + this.activeThread.resume(this.resumptionWarnFunc); + } else { + this.ThreadState.interruptedByResumeButton = true; + this.toggleResumeButtonState("breakOnNext"); + this.activeThread.breakOnNext(); + } + }, + + /** + * Listener handling the step over button click event. + */ + _onStepOverPressed: function () { + if (this.activeThread.paused && !this._stepOverButton.disabled) { + this.StackFrames.currentFrameDepth = -1; + this.activeThread.stepOver(this.resumptionWarnFunc); + } + }, + + /** + * Listener handling the step in button click event. + */ + _onStepInPressed: function () { + if (this.StackFrames._currentFrameDescription != FRAME_TYPE.NORMAL || + this._stepInButton.disabled) { + return; + } + + if (this.activeThread.paused) { + this.StackFrames.currentFrameDepth = -1; + this.activeThread.stepIn(this.resumptionWarnFunc); + } + }, + + /** + * Listener handling the step out button click event. + */ + _onStepOutPressed: function () { + if (this.activeThread.paused && !this._stepOutButton.disabled) { + this.StackFrames.currentFrameDepth = -1; + this.activeThread.stepOut(this.resumptionWarnFunc); + } + }, + + _instrumentsPaneToggleButton: null, + _resumeButton: null, + _stepOverButton: null, + _stepInButton: null, + _stepOutButton: null, + _resumeOrderTooltip: null, + _resumeTooltip: "", + _pauseTooltip: "", + _stepOverTooltip: "", + _stepInTooltip: "", + _stepOutTooltip: "" +}; + +DebuggerView.Toolbar = new ToolbarView(DebuggerController, DebuggerView); |