зеркало из https://github.com/mozilla/gecko-dev.git
288 строки
10 KiB
JavaScript
288 строки
10 KiB
JavaScript
/* -*- 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);
|
|
this._instrumentsPaneToggleButton.addEventListener("keydown",
|
|
this._onTogglePanesPressed);
|
|
this._resumeButton.addEventListener("mousedown", this._onResumePressed);
|
|
this._stepOverButton.addEventListener("mousedown", this._onStepOverPressed);
|
|
this._stepInButton.addEventListener("mousedown", this._onStepInPressed);
|
|
this._stepOutButton.addEventListener("mousedown", this._onStepOutPressed);
|
|
|
|
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);
|
|
this._instrumentsPaneToggleButton.removeEventListener("keydown",
|
|
this._onTogglePanesPressed);
|
|
this._resumeButton.removeEventListener("mousedown", this._onResumePressed);
|
|
this._stepOverButton.removeEventListener("mousedown", this._onStepOverPressed);
|
|
this._stepInButton.removeEventListener("mousedown", this._onStepInPressed);
|
|
this._stepOutButton.removeEventListener("mousedown", this._onStepOutPressed);
|
|
},
|
|
|
|
/**
|
|
* 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);
|