From f51f763fde48e4a97d4b3ccd0d9b758f8c229226 Mon Sep 17 00:00:00 2001 From: Brian Grinstead Date: Tue, 2 May 2017 14:52:34 -0700 Subject: [PATCH] Bug 1361537 - Add a simple jsterm implementation to console launchpad;r=Honza MozReview-Commit-ID: DbkR4MqUKBN --HG-- extra : rebase_source : cfa99ef9597e641b7759e29dc3de42273b1a8dcc --- devtools/client/themes/new-webconsole.css | 4 + devtools/client/webconsole/local-dev/index.js | 2 + .../webconsole/local-dev/jsterm-stub.js | 163 +++++++++++++++++- devtools/client/webconsole/new-webconsole.js | 16 +- 4 files changed, 181 insertions(+), 4 deletions(-) diff --git a/devtools/client/themes/new-webconsole.css b/devtools/client/themes/new-webconsole.css index a2d1a20e2e1a..548c956fbc95 100644 --- a/devtools/client/themes/new-webconsole.css +++ b/devtools/client/themes/new-webconsole.css @@ -473,6 +473,10 @@ body { color: var(--theme-comment); } +.jsterm-input-node-html { + width: 100%; +} + .jsterm-input-node { /* Always allow scrolling on input - it auto expands in js by setting height, but don't want it to get bigger than the window. 24px = toolbar height. */ diff --git a/devtools/client/webconsole/local-dev/index.js b/devtools/client/webconsole/local-dev/index.js index 1a28fb5158b9..ee17449e6607 100644 --- a/devtools/client/webconsole/local-dev/index.js +++ b/devtools/client/webconsole/local-dev/index.js @@ -75,6 +75,8 @@ function onConnect(connection) { iframeWindow: window, chromeWindow: window, hudId: "hud_0", + getDebuggerFrames: () => { }, + getInspectorSelection: () => { }, target: connection.tabConnection.tabTarget, _browserConsole: false, NewConsoleOutputWrapper, diff --git a/devtools/client/webconsole/local-dev/jsterm-stub.js b/devtools/client/webconsole/local-dev/jsterm-stub.js index e03e29b1e632..2fb0f912a66a 100644 --- a/devtools/client/webconsole/local-dev/jsterm-stub.js +++ b/devtools/client/webconsole/local-dev/jsterm-stub.js @@ -4,14 +4,173 @@ "use strict"; +const { ConsoleCommand } = require("devtools/client/webconsole/new-console-output/types"); + function JSTerm(webConsoleFrame) { this.hud = webConsoleFrame; this.hudId = this.hud.hudId; this.historyLoaded = new Promise(r => { r(); }); - this.openVariablesView = () => { }; - this.init = () => { }; } +JSTerm.prototype = { + SELECTED_FRAME: -1, + + get webConsoleClient() { + return this.hud.webConsoleClient; + }, + + openVariablesView() { }, + clearOutput() { }, + + init() { + this.doc = this.hud.window.document; + this.root = this.doc.createElement("div"); + this.root.className = "jsterm-input-container"; + this.inputNode = this.doc.createElement("input"); + this.inputNode.className = "jsterm-input-node jsterm-input-node-html"; + this.root.appendChild(this.inputNode); + this.doc.querySelector("#app-wrapper").appendChild(this.root); + + this.inputNode.onkeypress = (e) => { + if (e.key === "Enter") { + this.execute(); + } + }; + }, + + /** + * Sets the value of the input field (command line), and resizes the field to + * fit its contents. This method is preferred over setting "inputNode.value" + * directly, because it correctly resizes the field. + * + * @param string newValue + * The new value to set. + * @returns void + */ + setInputValue(newValue) { + this.inputNode.value = newValue; + // this.resizeInput(); + }, + + /** + * Gets the value from the input field + * @returns string + */ + getInputValue() { + return this.inputNode.value || ""; + }, + + execute(executeString) { + return new Promise(resolve => { + // attempt to execute the content of the inputNode + executeString = executeString || this.getInputValue(); + if (!executeString) { + return; + } + + let message = new ConsoleCommand({ + messageText: executeString, + }); + this.hud.proxy.dispatchMessageAdd(message); + + let selectedNodeActor = null; + let inspectorSelection = this.hud.owner.getInspectorSelection(); + if (inspectorSelection && inspectorSelection.nodeFront) { + selectedNodeActor = inspectorSelection.nodeFront.actorID; + } + + let onResult = (response) => { + if (response.error) { + console.error("Evaluation error " + response.error + ": " + + response.message); + return; + } + this.hud.newConsoleOutput.dispatchMessageAdd(response, true).then(resolve); + }; + + let options = { + frame: this.SELECTED_FRAME, + selectedNodeActor: selectedNodeActor, + }; + + this.requestEvaluation(executeString, options).then(onResult, onResult); + this.setInputValue(""); + }); + }, + + /** + * Request a JavaScript string evaluation from the server. + * + * @param string str + * String to execute. + * @param object [options] + * Options for evaluation: + * - bindObjectActor: tells the ObjectActor ID for which you want to do + * the evaluation. The Debugger.Object of the OA will be bound to + * |_self| during evaluation, such that it's usable in the string you + * execute. + * - frame: tells the stackframe depth to evaluate the string in. If + * the jsdebugger is paused, you can pick the stackframe to be used for + * evaluation. Use |this.SELECTED_FRAME| to always pick the + * user-selected stackframe. + * If you do not provide a |frame| the string will be evaluated in the + * global content window. + * - selectedNodeActor: tells the NodeActor ID of the current selection + * in the Inspector, if such a selection exists. This is used by + * helper functions that can evaluate on the current selection. + * @return object + * A promise object that is resolved when the server response is + * received. + */ + requestEvaluation(str, options = {}) { + return new Promise((resolve, reject) => { + let frameActor = null; + if ("frame" in options) { + frameActor = this.getFrameActor(options.frame); + } + let evalOptions = { + bindObjectActor: options.bindObjectActor, + frameActor: frameActor, + selectedNodeActor: options.selectedNodeActor, + selectedObjectActor: options.selectedObjectActor, + }; + let onResponse = response => { + if (!response.error) { + resolve(response); + } else { + reject(response); + } + }; + + this.webConsoleClient.evaluateJSAsync(str, onResponse, evalOptions); + }); + }, + + /** + * Retrieve the FrameActor ID given a frame depth. + * + * @param number frame + * Frame depth. + * @return string|null + * The FrameActor ID for the given frame depth. + */ + getFrameActor(frame) { + let state = this.hud.owner.getDebuggerFrames(); + if (!state) { + return null; + } + + let grip; + if (frame == this.SELECTED_FRAME) { + grip = state.frames[state.selected]; + } else { + grip = state.frames[frame]; + } + + return grip ? grip.actor : null; + }, +}; + module.exports.JSTerm = JSTerm; diff --git a/devtools/client/webconsole/new-webconsole.js b/devtools/client/webconsole/new-webconsole.js index 82710bf799fb..0a71384abb40 100644 --- a/devtools/client/webconsole/new-webconsole.js +++ b/devtools/client/webconsole/new-webconsole.js @@ -114,13 +114,17 @@ NewWebConsoleFrame.prototype = { }, + handleNetworkEventUpdate() { + + }, + /** * Setter for saving of network request and response bodies. * * @param boolean value * The new value you want to set. */ - setSaveRequestAndResponseBodies: function (value) { + setSaveRequestAndResponseBodies(value) { if (!this.webConsoleClient) { // Don't continue if the webconsole disconnected. return promise.resolve(null); @@ -252,7 +256,7 @@ NewWebConsoleFrame.prototype = { packet._type = true; this.newConsoleOutput.dispatchMessageAdd(packet); } else { - this.jsterm.clearOutput(); + this.clearOutput(false); } } @@ -264,6 +268,14 @@ NewWebConsoleFrame.prototype = { this.logWarningAboutReplacedAPI(); } }, + + clearOutput(clearStorage) { + this.newConsoleOutput.dispatchMessagesClear(); + this.webConsoleClient.clearNetworkRequests(); + if (clearStorage) { + this.webConsoleClient.clearMessagesCache(); + } + }, }; exports.NewWebConsoleFrame = NewWebConsoleFrame;