summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/panel.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--devtools/client/debugger/panel.js286
1 files changed, 286 insertions, 0 deletions
diff --git a/devtools/client/debugger/panel.js b/devtools/client/debugger/panel.js
new file mode 100644
index 0000000000..e9c2634baa
--- /dev/null
+++ b/devtools/client/debugger/panel.js
@@ -0,0 +1,286 @@
+/* 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/>. */
+
+const { LocalizationHelper } = require("devtools/shared/l10n");
+
+loader.lazyRequireGetter(
+ this,
+ "openContentLink",
+ "devtools/client/shared/link",
+ true
+);
+loader.lazyRequireGetter(
+ this,
+ "features",
+ "devtools/client/debugger/src/utils/prefs",
+ true
+);
+loader.lazyRequireGetter(
+ this,
+ "registerStoreObserver",
+ "devtools/client/shared/redux/subscriber",
+ true
+);
+
+const DBG_STRINGS_URI = "devtools/client/locales/debugger.properties";
+const L10N = new LocalizationHelper(DBG_STRINGS_URI);
+
+async function getNodeFront(gripOrFront, toolbox) {
+ // Given a NodeFront
+ if ("actorID" in gripOrFront) {
+ return new Promise(resolve => resolve(gripOrFront));
+ }
+
+ const inspectorFront = await toolbox.target.getFront("inspector");
+ return inspectorFront.getNodeFrontFromNodeGrip(gripOrFront);
+}
+
+class DebuggerPanel {
+ constructor(iframeWindow, toolbox) {
+ this.panelWin = iframeWindow;
+ this.panelWin.L10N = L10N;
+ this.toolbox = toolbox;
+ }
+
+ async open() {
+ const {
+ actions,
+ store,
+ selectors,
+ client,
+ } = await this.panelWin.Debugger.bootstrap({
+ targetList: this.toolbox.targetList,
+ resourceWatcher: this.toolbox.resourceWatcher,
+ devToolsClient: this.toolbox.target.client,
+ workers: {
+ sourceMaps: this.toolbox.sourceMapService,
+ evaluationsParser: this.toolbox.parserService,
+ },
+ panel: this,
+ });
+
+ this._actions = actions;
+ this._store = store;
+ this._selectors = selectors;
+ this._client = client;
+ this.isReady = true;
+
+ this.panelWin.document.addEventListener(
+ "drag:start",
+ this.toolbox.toggleDragging
+ );
+ this.panelWin.document.addEventListener(
+ "drag:end",
+ this.toolbox.toggleDragging
+ );
+
+ registerStoreObserver(this._store, this._onDebuggerStateChange.bind(this));
+
+ const resourceWatcher = this.toolbox.resourceWatcher;
+ await resourceWatcher.watchResources(
+ [resourceWatcher.TYPES.ERROR_MESSAGE],
+ { onAvailable: actions.addExceptionFromResources }
+ );
+
+ return this;
+ }
+
+ _onDebuggerStateChange(state, oldState) {
+ const { getCurrentThread } = this._selectors;
+
+ const currentThreadActorID = getCurrentThread(state);
+ if (
+ currentThreadActorID &&
+ currentThreadActorID !== getCurrentThread(oldState)
+ ) {
+ const threadFront = this.toolbox.target.client.getFrontByID(
+ currentThreadActorID
+ );
+ this.toolbox.selectTarget(threadFront?.targetFront.actorID);
+ }
+ }
+
+ getVarsForTests() {
+ return {
+ store: this._store,
+ selectors: this._selectors,
+ actions: this._actions,
+ client: this._client,
+ };
+ }
+
+ _getState() {
+ return this._store.getState();
+ }
+
+ getToolboxStore() {
+ return this.toolbox.store;
+ }
+
+ openLink(url) {
+ openContentLink(url);
+ }
+
+ async openConsoleAndEvaluate(input) {
+ const { hud } = await this.toolbox.selectTool("webconsole");
+ hud.ui.wrapper.dispatchEvaluateExpression(input);
+ }
+
+ async openInspector() {
+ this.toolbox.selectTool("inspector");
+ }
+
+ async openElementInInspector(gripOrFront) {
+ const onSelectInspector = this.toolbox.selectTool("inspector");
+ const onGripNodeToFront = getNodeFront(gripOrFront, this.toolbox);
+
+ const [front, inspector] = await Promise.all([
+ onGripNodeToFront,
+ onSelectInspector,
+ ]);
+
+ const onInspectorUpdated = inspector.once("inspector-updated");
+ const onNodeFrontSet = this.toolbox.selection.setNodeFront(front, {
+ reason: "debugger",
+ });
+
+ return Promise.all([onNodeFrontSet, onInspectorUpdated]);
+ }
+
+ highlightDomElement(gripOrFront) {
+ if (!this._highlight) {
+ const { highlight, unhighlight } = this.toolbox.getHighlighter();
+ this._highlight = highlight;
+ this._unhighlight = unhighlight;
+ }
+
+ return this._highlight(gripOrFront);
+ }
+
+ unHighlightDomElement() {
+ if (!this._unhighlight) {
+ return;
+ }
+
+ return this._unhighlight();
+ }
+
+ getFrames() {
+ const thread = this._selectors.getCurrentThread(this._getState());
+ const frames = this._selectors.getFrames(this._getState(), thread);
+
+ // Frames is null when the debugger is not paused.
+ if (!frames) {
+ return {
+ frames: [],
+ selected: -1,
+ };
+ }
+
+ const selectedFrame = this._selectors.getSelectedFrame(
+ this._getState(),
+ thread
+ );
+ const selected = frames.findIndex(frame => frame.id == selectedFrame.id);
+
+ frames.forEach(frame => {
+ frame.actor = frame.id;
+ });
+ const target = this._client.lookupTarget(thread);
+
+ return { frames, selected, target };
+ }
+
+ getMappedExpression(expression) {
+ return this._actions.getMappedExpression(expression);
+ }
+
+ isPaused() {
+ const thread = this._selectors.getCurrentThread(this._getState());
+ return this._selectors.getIsPaused(this._getState(), thread);
+ }
+
+ selectSourceURL(url, line, column) {
+ const cx = this._selectors.getContext(this._getState());
+ return this._actions.selectSourceURL(cx, url, { line, column });
+ }
+
+ async selectWorker(workerDescriptorFront) {
+ const threadActorID = workerDescriptorFront.threadFront?.actorID;
+
+ const isThreadAvailable = this._selectors
+ .getThreads(this._getState())
+ .find(x => x.actor === threadActorID);
+
+ if (!features.windowlessServiceWorkers) {
+ console.error(
+ "Selecting a worker needs the pref debugger.features.windowless-service-workers set to true"
+ );
+ return;
+ }
+
+ if (!isThreadAvailable) {
+ console.error(`Worker ${threadActorID} is not available for debugging`);
+ return;
+ }
+
+ // select worker's thread
+ this.selectThread(threadActorID);
+
+ // select worker's source
+ const source = this.getSourceByURL(workerDescriptorFront._url);
+ await this.selectSource(source.id, 1, 1);
+ }
+
+ selectThread(threadActorID) {
+ const cx = this._selectors.getContext(this._getState());
+ this._actions.selectThread(cx, threadActorID);
+ }
+
+ previewPausedLocation(location) {
+ return this._actions.previewPausedLocation(location);
+ }
+
+ clearPreviewPausedLocation() {
+ return this._actions.clearPreviewPausedLocation();
+ }
+
+ async selectSource(sourceId, line, column) {
+ const cx = this._selectors.getContext(this._getState());
+ const location = { sourceId, line, column };
+
+ await this._actions.selectSource(cx, sourceId, location);
+ if (this._selectors.hasLogpoint(this._getState(), location)) {
+ this._actions.openConditionalPanel(location, true);
+ }
+ }
+
+ getSourceActorsForSource(sourceId) {
+ return this._selectors.getSourceActorsForSource(this._getState(), sourceId);
+ }
+
+ getSourceByActorId(sourceId) {
+ return this._selectors.getSourceByActorId(this._getState(), sourceId);
+ }
+
+ getSourceByURL(sourceURL) {
+ return this._selectors.getSourceByURL(this._getState(), sourceURL);
+ }
+
+ getSource(sourceId) {
+ return this._selectors.getSource(this._getState(), sourceId);
+ }
+
+ destroy() {
+ const resourceWatcher = this.toolbox.resourceWatcher;
+ resourceWatcher.unwatchResources([resourceWatcher.TYPES.ERROR_MESSAGE], {
+ onAvailable: this._actions.addExceptionFromResources,
+ });
+
+ this.panelWin.Debugger.destroy();
+ this.emit("destroyed");
+ }
+}
+
+exports.DebuggerPanel = DebuggerPanel;