зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1567174 - Move expression evaluation to a proper Redux action. r=jdescottes.
The goal is to not directly use the panel.hud.ui.proxy reference directly from the JsTerm, so we're in better shape when Fission comes. It's also a nice refactor to make the JSTerm component more React-like. As a nice benefit, we can handle telemetry and history persistence from their middleware. As the `requestEvaluation` method is removed from the JSTerm, some callsites needed to be updated to still work. Differential Revision: https://phabricator.services.mozilla.com/D39022 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
65526f541b
Коммит
734f57b508
|
@ -359,26 +359,27 @@ class MarkupContextMenu {
|
||||||
* temp variable on the content window. Also opens the split console and
|
* temp variable on the content window. Also opens the split console and
|
||||||
* autofills it with the temp variable.
|
* autofills it with the temp variable.
|
||||||
*/
|
*/
|
||||||
_useInConsole() {
|
async _useInConsole() {
|
||||||
this.toolbox.openSplitConsole().then(() => {
|
await this.toolbox.openSplitConsole();
|
||||||
const { hud } = this.toolbox.getPanel("webconsole");
|
const { hud } = this.toolbox.getPanel("webconsole");
|
||||||
|
|
||||||
const evalString = `{ let i = 0;
|
const evalString = `{ let i = 0;
|
||||||
while (window.hasOwnProperty("temp" + i) && i < 1000) {
|
while (window.hasOwnProperty("temp" + i) && i < 1000) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
window["temp" + i] = $0;
|
window["temp" + i] = $0;
|
||||||
"temp" + i;
|
"temp" + i;
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
selectedNodeActor: this.selection.nodeFront.actorID,
|
selectedNodeActor: this.selection.nodeFront.actorID,
|
||||||
};
|
};
|
||||||
hud.jsterm.requestEvaluation(evalString, options).then(res => {
|
const res = await hud.ui.webConsoleClient.evaluateJSAsync(
|
||||||
hud.setInputValue(res.result);
|
evalString,
|
||||||
this.inspector.emit("console-var-ready");
|
options
|
||||||
});
|
);
|
||||||
});
|
hud.setInputValue(res.result);
|
||||||
|
this.inspector.emit("console-var-ready");
|
||||||
}
|
}
|
||||||
|
|
||||||
_buildA11YMenuItem(menu) {
|
_buildA11YMenuItem(menu) {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
const actionModules = [
|
const actionModules = [
|
||||||
require("./autocomplete"),
|
require("./autocomplete"),
|
||||||
require("./filters"),
|
require("./filters"),
|
||||||
|
require("./input"),
|
||||||
require("./messages"),
|
require("./messages"),
|
||||||
require("./ui"),
|
require("./ui"),
|
||||||
require("./notifications"),
|
require("./notifications"),
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
/* -*- 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/. */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { Utils: WebConsoleUtils } = require("devtools/client/webconsole/utils");
|
||||||
|
const { EVALUATE_EXPRESSION } = require("devtools/client/webconsole/constants");
|
||||||
|
|
||||||
|
loader.lazyServiceGetter(
|
||||||
|
this,
|
||||||
|
"clipboardHelper",
|
||||||
|
"@mozilla.org/widget/clipboardhelper;1",
|
||||||
|
"nsIClipboardHelper"
|
||||||
|
);
|
||||||
|
loader.lazyRequireGetter(
|
||||||
|
this,
|
||||||
|
"saveScreenshot",
|
||||||
|
"devtools/shared/screenshot/save"
|
||||||
|
);
|
||||||
|
loader.lazyRequireGetter(
|
||||||
|
this,
|
||||||
|
"messagesActions",
|
||||||
|
"devtools/client/webconsole/actions/messages"
|
||||||
|
);
|
||||||
|
loader.lazyRequireGetter(
|
||||||
|
this,
|
||||||
|
"historyActions",
|
||||||
|
"devtools/client/webconsole/actions/history"
|
||||||
|
);
|
||||||
|
loader.lazyRequireGetter(
|
||||||
|
this,
|
||||||
|
"ConsoleCommand",
|
||||||
|
"devtools/client/webconsole/types",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
const HELP_URL = "https://developer.mozilla.org/docs/Tools/Web_Console/Helpers";
|
||||||
|
|
||||||
|
function evaluateExpression(expression) {
|
||||||
|
return async ({ dispatch, services }) => {
|
||||||
|
if (!expression) {
|
||||||
|
expression = services.getInputValue();
|
||||||
|
}
|
||||||
|
if (!expression) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We use the messages action as it's doing additional transformation on the message.
|
||||||
|
dispatch(
|
||||||
|
messagesActions.messagesAdd([
|
||||||
|
new ConsoleCommand({
|
||||||
|
messageText: expression,
|
||||||
|
timeStamp: Date.now(),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
dispatch({
|
||||||
|
type: EVALUATE_EXPRESSION,
|
||||||
|
expression,
|
||||||
|
});
|
||||||
|
|
||||||
|
WebConsoleUtils.usageCount++;
|
||||||
|
|
||||||
|
let mappedExpressionRes;
|
||||||
|
try {
|
||||||
|
mappedExpressionRes = await services.getMappedExpression(expression);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Error when calling getMappedExpression", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
expression = mappedExpressionRes
|
||||||
|
? mappedExpressionRes.expression
|
||||||
|
: expression;
|
||||||
|
|
||||||
|
const { frameActor, client } = services.getFrameActor();
|
||||||
|
|
||||||
|
// Even if requestEvaluation rejects (because of webConsoleClient.evaluateJSAsync),
|
||||||
|
// we still need to pass the error response to onExpressionEvaluated.
|
||||||
|
const onSettled = res => res;
|
||||||
|
|
||||||
|
const response = await client
|
||||||
|
.evaluateJSAsync(expression, {
|
||||||
|
frameActor,
|
||||||
|
selectedNodeActor: services.getSelectedNodeActor(),
|
||||||
|
mapped: mappedExpressionRes ? mappedExpressionRes.mapped : null,
|
||||||
|
})
|
||||||
|
.then(onSettled, onSettled);
|
||||||
|
|
||||||
|
return onExpressionEvaluated(response, {
|
||||||
|
dispatch,
|
||||||
|
services,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JavaScript evaluation response handler.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} response
|
||||||
|
* The message received from the server.
|
||||||
|
*/
|
||||||
|
async function onExpressionEvaluated(response, { dispatch, services } = {}) {
|
||||||
|
if (response.error) {
|
||||||
|
console.error(`Evaluation error`, response.error, ": ", response.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the evaluation was a top-level await expression that was rejected, there will
|
||||||
|
// be an uncaught exception reported, so we don't need to do anything.
|
||||||
|
if (response.topLevelAwaitRejected === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.helperResult) {
|
||||||
|
dispatch(messagesActions.messagesAdd([response]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await handleHelperResult(response, { dispatch, services });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleHelperResult(response, { dispatch, services }) {
|
||||||
|
const result = response.result;
|
||||||
|
const helperResult = response.helperResult;
|
||||||
|
const helperHasRawOutput = !!(helperResult || {}).rawOutput;
|
||||||
|
|
||||||
|
if (helperResult && helperResult.type) {
|
||||||
|
switch (helperResult.type) {
|
||||||
|
case "clearOutput":
|
||||||
|
dispatch(messagesActions.messagesClear());
|
||||||
|
break;
|
||||||
|
case "clearHistory":
|
||||||
|
dispatch(historyActions.clearHistory());
|
||||||
|
break;
|
||||||
|
case "inspectObject":
|
||||||
|
services.inspectObjectActor(helperResult.object);
|
||||||
|
break;
|
||||||
|
case "help":
|
||||||
|
services.openLink(HELP_URL);
|
||||||
|
break;
|
||||||
|
case "copyValueToClipboard":
|
||||||
|
clipboardHelper.copyString(helperResult.value);
|
||||||
|
break;
|
||||||
|
case "screenshotOutput":
|
||||||
|
const { args, value } = helperResult;
|
||||||
|
const screenshotMessages = await saveScreenshot(
|
||||||
|
services.getPanelWindow(),
|
||||||
|
args,
|
||||||
|
value
|
||||||
|
);
|
||||||
|
dispatch(
|
||||||
|
messagesActions.messagesAdd(
|
||||||
|
screenshotMessages.map(message => ({
|
||||||
|
message,
|
||||||
|
type: "logMessage",
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// early return as we already dispatched necessary messages.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasErrorMessage =
|
||||||
|
response.exceptionMessage ||
|
||||||
|
(helperResult && helperResult.type === "error");
|
||||||
|
|
||||||
|
// Hide undefined results coming from helper functions.
|
||||||
|
const hasUndefinedResult =
|
||||||
|
result && typeof result == "object" && result.type == "undefined";
|
||||||
|
|
||||||
|
if (hasErrorMessage || helperHasRawOutput || !hasUndefinedResult) {
|
||||||
|
dispatch(messagesActions.messagesAdd([response]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
evaluateExpression,
|
||||||
|
};
|
|
@ -8,6 +8,7 @@ DevToolsModules(
|
||||||
'filters.js',
|
'filters.js',
|
||||||
'history.js',
|
'history.js',
|
||||||
'index.js',
|
'index.js',
|
||||||
|
'input.js',
|
||||||
'messages.js',
|
'messages.js',
|
||||||
'notifications.js',
|
'notifications.js',
|
||||||
'ui.js',
|
'ui.js',
|
||||||
|
|
|
@ -300,7 +300,6 @@ class App extends Component {
|
||||||
key: "reverse-search-input",
|
key: "reverse-search-input",
|
||||||
setInputValue: serviceContainer.setInputValue,
|
setInputValue: serviceContainer.setInputValue,
|
||||||
focusInput: serviceContainer.focusInput,
|
focusInput: serviceContainer.focusInput,
|
||||||
evaluateInput: serviceContainer.evaluateInput,
|
|
||||||
initialValue: reverseSearchInitialValue,
|
initialValue: reverseSearchInitialValue,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,14 +23,14 @@ const {
|
||||||
class EditorToolbar extends Component {
|
class EditorToolbar extends Component {
|
||||||
static get propTypes() {
|
static get propTypes() {
|
||||||
return {
|
return {
|
||||||
webConsoleUI: PropTypes.object.isRequired,
|
|
||||||
editorMode: PropTypes.bool,
|
editorMode: PropTypes.bool,
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
|
webConsoleUI: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { editorMode, webConsoleUI, dispatch } = this.props;
|
const { editorMode, dispatch, webConsoleUI } = this.props;
|
||||||
|
|
||||||
if (!editorMode) {
|
if (!editorMode) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -48,7 +48,7 @@ class EditorToolbar extends Component {
|
||||||
"webconsole.editor.toolbar.executeButton.tooltip",
|
"webconsole.editor.toolbar.executeButton.tooltip",
|
||||||
[isMacOS ? "Cmd + Enter" : "Ctrl + Enter"]
|
[isMacOS ? "Cmd + Enter" : "Ctrl + Enter"]
|
||||||
),
|
),
|
||||||
onClick: () => webConsoleUI.jsterm.execute(),
|
onClick: () => dispatch(actions.evaluateExpression()),
|
||||||
},
|
},
|
||||||
l10n.getStr("webconsole.editor.toolbar.executeButton.label")
|
l10n.getStr("webconsole.editor.toolbar.executeButton.label")
|
||||||
),
|
),
|
||||||
|
|
|
@ -8,12 +8,6 @@ const { Utils: WebConsoleUtils } = require("devtools/client/webconsole/utils");
|
||||||
const Services = require("Services");
|
const Services = require("Services");
|
||||||
const { debounce } = require("devtools/shared/debounce");
|
const { debounce } = require("devtools/shared/debounce");
|
||||||
|
|
||||||
loader.lazyServiceGetter(
|
|
||||||
this,
|
|
||||||
"clipboardHelper",
|
|
||||||
"@mozilla.org/widget/clipboardhelper;1",
|
|
||||||
"nsIClipboardHelper"
|
|
||||||
);
|
|
||||||
loader.lazyRequireGetter(this, "Debugger", "Debugger");
|
loader.lazyRequireGetter(this, "Debugger", "Debugger");
|
||||||
loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
|
loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
|
||||||
loader.lazyRequireGetter(
|
loader.lazyRequireGetter(
|
||||||
|
@ -37,12 +31,6 @@ loader.lazyRequireGetter(
|
||||||
"Editor",
|
"Editor",
|
||||||
"devtools/client/shared/sourceeditor/editor"
|
"devtools/client/shared/sourceeditor/editor"
|
||||||
);
|
);
|
||||||
loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
|
|
||||||
loader.lazyRequireGetter(
|
|
||||||
this,
|
|
||||||
"saveScreenshot",
|
|
||||||
"devtools/shared/screenshot/save"
|
|
||||||
);
|
|
||||||
loader.lazyRequireGetter(
|
loader.lazyRequireGetter(
|
||||||
this,
|
this,
|
||||||
"focusableSelector",
|
"focusableSelector",
|
||||||
|
@ -50,10 +38,6 @@ loader.lazyRequireGetter(
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
const l10n = require("devtools/client/webconsole/utils/l10n");
|
|
||||||
|
|
||||||
const HELP_URL = "https://developer.mozilla.org/docs/Tools/Web_Console/Helpers";
|
|
||||||
|
|
||||||
// React & Redux
|
// React & Redux
|
||||||
const { Component } = require("devtools/client/shared/vendor/react");
|
const { Component } = require("devtools/client/shared/vendor/react");
|
||||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||||
|
@ -67,8 +51,7 @@ const {
|
||||||
const {
|
const {
|
||||||
getAutocompleteState,
|
getAutocompleteState,
|
||||||
} = require("devtools/client/webconsole/selectors/autocomplete");
|
} = require("devtools/client/webconsole/selectors/autocomplete");
|
||||||
const historyActions = require("devtools/client/webconsole/actions/history");
|
const actions = require("devtools/client/webconsole/actions/index");
|
||||||
const autocompleteActions = require("devtools/client/webconsole/actions/autocomplete");
|
|
||||||
|
|
||||||
// Constants used for defining the direction of JSTerm input history navigation.
|
// Constants used for defining the direction of JSTerm input history navigation.
|
||||||
const {
|
const {
|
||||||
|
@ -100,6 +83,8 @@ class JSTerm extends Component {
|
||||||
// Handler for clipboard 'paste' event (also used for 'drop' event, callback).
|
// Handler for clipboard 'paste' event (also used for 'drop' event, callback).
|
||||||
onPaste: PropTypes.func,
|
onPaste: PropTypes.func,
|
||||||
codeMirrorEnabled: PropTypes.bool,
|
codeMirrorEnabled: PropTypes.bool,
|
||||||
|
// Evaluate provided expression.
|
||||||
|
evaluateExpression: PropTypes.func.isRequired,
|
||||||
// Update position in the history after executing an expression (action).
|
// Update position in the history after executing an expression (action).
|
||||||
updateHistoryPosition: PropTypes.func.isRequired,
|
updateHistoryPosition: PropTypes.func.isRequired,
|
||||||
// Update autocomplete popup state.
|
// Update autocomplete popup state.
|
||||||
|
@ -142,8 +127,6 @@ class JSTerm extends Component {
|
||||||
this.inputNode = null;
|
this.inputNode = null;
|
||||||
this.completeNode = null;
|
this.completeNode = null;
|
||||||
|
|
||||||
this._telemetry = new Telemetry();
|
|
||||||
|
|
||||||
EventEmitter.decorate(this);
|
EventEmitter.decorate(this);
|
||||||
webConsoleUI.jsterm = this;
|
webConsoleUI.jsterm = this;
|
||||||
}
|
}
|
||||||
|
@ -596,204 +579,26 @@ class JSTerm extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The JavaScript evaluation response handler.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Object} response
|
|
||||||
* The message received from the server.
|
|
||||||
*/
|
|
||||||
/* eslint-disable complexity */
|
|
||||||
async _executeResultCallback(response) {
|
|
||||||
if (!this.webConsoleUI) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.error) {
|
|
||||||
console.error(
|
|
||||||
"Evaluation error " + response.error + ": " + response.message
|
|
||||||
);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the evaluation was a top-level await expression that was rejected, there will
|
|
||||||
// be an uncaught exception reported, so we don't want need to print anything here.
|
|
||||||
if (response.topLevelAwaitRejected === true) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let errorMessage = response.exceptionMessage;
|
|
||||||
|
|
||||||
// Wrap thrown strings in Error objects, so `throw "foo"` outputs "Error: foo"
|
|
||||||
if (typeof response.exception === "string") {
|
|
||||||
errorMessage = new Error(errorMessage).toString();
|
|
||||||
}
|
|
||||||
const result = response.result;
|
|
||||||
const helperResult = response.helperResult;
|
|
||||||
const helperHasRawOutput = !!(helperResult || {}).rawOutput;
|
|
||||||
|
|
||||||
if (helperResult && helperResult.type) {
|
|
||||||
switch (helperResult.type) {
|
|
||||||
case "clearOutput":
|
|
||||||
this.webConsoleUI.clearOutput();
|
|
||||||
break;
|
|
||||||
case "clearHistory":
|
|
||||||
this.props.clearHistory();
|
|
||||||
break;
|
|
||||||
case "inspectObject":
|
|
||||||
this.webConsoleUI.inspectObjectActor(helperResult.object);
|
|
||||||
break;
|
|
||||||
case "error":
|
|
||||||
try {
|
|
||||||
errorMessage = l10n.getStr(helperResult.message);
|
|
||||||
} catch (ex) {
|
|
||||||
errorMessage = helperResult.message;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "help":
|
|
||||||
this.webConsoleUI.hud.openLink(HELP_URL);
|
|
||||||
break;
|
|
||||||
case "copyValueToClipboard":
|
|
||||||
clipboardHelper.copyString(helperResult.value);
|
|
||||||
break;
|
|
||||||
case "screenshotOutput":
|
|
||||||
const { args, value } = helperResult;
|
|
||||||
const results = await saveScreenshot(
|
|
||||||
this.webConsoleUI.window,
|
|
||||||
args,
|
|
||||||
value
|
|
||||||
);
|
|
||||||
this.screenshotNotify(results);
|
|
||||||
// early return as screenshot notify has dispatched all necessary messages
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hide undefined results coming from JSTerm helper functions.
|
|
||||||
if (
|
|
||||||
!errorMessage &&
|
|
||||||
result &&
|
|
||||||
typeof result == "object" &&
|
|
||||||
result.type == "undefined" &&
|
|
||||||
helperResult &&
|
|
||||||
!helperHasRawOutput
|
|
||||||
) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.webConsoleUI.wrapper) {
|
|
||||||
return this.webConsoleUI.wrapper.dispatchMessageAdd(response, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
/* eslint-enable complexity */
|
|
||||||
|
|
||||||
screenshotNotify(results) {
|
|
||||||
const wrappedResults = results.map(message => ({
|
|
||||||
message,
|
|
||||||
type: "logMessage",
|
|
||||||
}));
|
|
||||||
this.webConsoleUI.wrapper.dispatchMessagesAdd(wrappedResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a string. Execution happens asynchronously in the content process.
|
* Execute a string. Execution happens asynchronously in the content process.
|
||||||
*
|
*
|
||||||
* @param {String} executeString
|
* @param {String} executeString
|
||||||
* The string you want to execute. If this is not provided, the current
|
* The string you want to execute. If this is not provided, the current
|
||||||
* user input is used - taken from |this._getValue()|.
|
* user input is used - taken from |this._getValue()|.
|
||||||
* @returns {Promise}
|
|
||||||
* Resolves with the message once the result is displayed.
|
|
||||||
*/
|
*/
|
||||||
async execute(executeString) {
|
execute(executeString) {
|
||||||
// attempt to execute the content of the inputNode
|
// attempt to execute the content of the inputNode
|
||||||
executeString = executeString || this._getValue();
|
executeString = executeString || this._getValue();
|
||||||
if (!executeString) {
|
if (!executeString) {
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append executed expression into the history list.
|
|
||||||
this.props.appendToHistory(executeString);
|
|
||||||
|
|
||||||
WebConsoleUtils.usageCount++;
|
|
||||||
|
|
||||||
if (!this.props.editorMode) {
|
if (!this.props.editorMode) {
|
||||||
this._setValue("");
|
this._setValue("");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.clearCompletion();
|
this.clearCompletion();
|
||||||
|
|
||||||
let selectedNodeActor = null;
|
this.props.evaluateExpression(executeString);
|
||||||
const inspectorSelection = this.webConsoleUI.hud.getInspectorSelection();
|
|
||||||
if (inspectorSelection && inspectorSelection.nodeFront) {
|
|
||||||
selectedNodeActor = inspectorSelection.nodeFront.actorID;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { ConsoleCommand } = require("devtools/client/webconsole/types");
|
|
||||||
const cmdMessage = new ConsoleCommand({
|
|
||||||
messageText: executeString,
|
|
||||||
timeStamp: Date.now(),
|
|
||||||
});
|
|
||||||
this.webConsoleUI.proxy.dispatchMessageAdd(cmdMessage);
|
|
||||||
|
|
||||||
let mappedExpressionRes = null;
|
|
||||||
try {
|
|
||||||
mappedExpressionRes = await this.webConsoleUI.hud.getMappedExpression(
|
|
||||||
executeString
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
console.warn("Error when calling getMappedExpression", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
executeString = mappedExpressionRes
|
|
||||||
? mappedExpressionRes.expression
|
|
||||||
: executeString;
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
selectedNodeActor,
|
|
||||||
mapped: mappedExpressionRes ? mappedExpressionRes.mapped : null,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Even if requestEvaluation rejects (because of webConsoleClient.evaluateJSAsync),
|
|
||||||
// we still need to pass the error response to executeResultCallback.
|
|
||||||
const onEvaluated = this.requestEvaluation(executeString, options).then(
|
|
||||||
res => res,
|
|
||||||
res => res
|
|
||||||
);
|
|
||||||
const response = await onEvaluated;
|
|
||||||
return this._executeResultCallback(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request a JavaScript string evaluation from the server.
|
|
||||||
*
|
|
||||||
* @param string str
|
|
||||||
* String to execute.
|
|
||||||
* @param object [options]
|
|
||||||
* Options for evaluation:
|
|
||||||
* - 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.
|
|
||||||
* - mapped: basically getMappedExpression().mapped. An object that indicates
|
|
||||||
* which modifications were done to the input entered by the user.
|
|
||||||
* @return object
|
|
||||||
* A promise object that is resolved when the server response is
|
|
||||||
* received.
|
|
||||||
*/
|
|
||||||
requestEvaluation(str, options = {}) {
|
|
||||||
// Send telemetry event. If we are in the browser toolbox we send -1 as the
|
|
||||||
// toolbox session id.
|
|
||||||
this.props.serviceContainer.recordTelemetryEvent("execute_js", {
|
|
||||||
lines: str.split(/\n/).length,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { frameActor, client } = this.props.serviceContainer.getFrameActor();
|
|
||||||
|
|
||||||
return client.evaluateJSAsync(str, {
|
|
||||||
frameActor,
|
|
||||||
...options,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1800,13 +1605,15 @@ function mapStateToProps(state) {
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
function mapDispatchToProps(dispatch) {
|
||||||
return {
|
return {
|
||||||
appendToHistory: expr => dispatch(historyActions.appendToHistory(expr)),
|
appendToHistory: expr => dispatch(actions.appendToHistory(expr)),
|
||||||
clearHistory: () => dispatch(historyActions.clearHistory()),
|
clearHistory: () => dispatch(actions.clearHistory()),
|
||||||
updateHistoryPosition: (direction, expression) =>
|
updateHistoryPosition: (direction, expression) =>
|
||||||
dispatch(historyActions.updateHistoryPosition(direction, expression)),
|
dispatch(actions.updateHistoryPosition(direction, expression)),
|
||||||
autocompleteUpdate: (force, getterPath) =>
|
autocompleteUpdate: (force, getterPath) =>
|
||||||
dispatch(autocompleteActions.autocompleteUpdate(force, getterPath)),
|
dispatch(actions.autocompleteUpdate(force, getterPath)),
|
||||||
autocompleteClear: () => dispatch(autocompleteActions.autocompleteClear()),
|
autocompleteClear: () => dispatch(actions.autocompleteClear()),
|
||||||
|
evaluateExpression: expression =>
|
||||||
|
dispatch(actions.evaluateExpression(expression)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,6 @@ class ReverseSearchInput extends Component {
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
setInputValue: PropTypes.func.isRequired,
|
setInputValue: PropTypes.func.isRequired,
|
||||||
focusInput: PropTypes.func.isRequired,
|
focusInput: PropTypes.func.isRequired,
|
||||||
evaluateInput: PropTypes.func.isRequired,
|
|
||||||
reverseSearchResult: PropTypes.string,
|
reverseSearchResult: PropTypes.string,
|
||||||
reverseSearchTotalResults: PropTypes.number,
|
reverseSearchTotalResults: PropTypes.number,
|
||||||
reverseSearchResultPosition: PropTypes.number,
|
reverseSearchResultPosition: PropTypes.number,
|
||||||
|
@ -92,10 +91,10 @@ class ReverseSearchInput extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnterKeyboardShortcut(event) {
|
onEnterKeyboardShortcut(event) {
|
||||||
const { dispatch, evaluateInput } = this.props;
|
const { dispatch } = this.props;
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
dispatch(actions.reverseSearchInputToggle());
|
dispatch(actions.reverseSearchInputToggle());
|
||||||
evaluateInput();
|
dispatch(actions.evaluateExpression());
|
||||||
}
|
}
|
||||||
|
|
||||||
onEscapeKeyboardShortcut(event) {
|
onEscapeKeyboardShortcut(event) {
|
||||||
|
|
|
@ -15,6 +15,7 @@ const actionTypes = {
|
||||||
BATCH_ACTIONS: "BATCH_ACTIONS",
|
BATCH_ACTIONS: "BATCH_ACTIONS",
|
||||||
CLEAR_HISTORY: "CLEAR_HISTORY",
|
CLEAR_HISTORY: "CLEAR_HISTORY",
|
||||||
EDITOR_TOGGLE: "EDITOR_TOGGLE",
|
EDITOR_TOGGLE: "EDITOR_TOGGLE",
|
||||||
|
EVALUATE_EXPRESSION: "EVALUATE_EXPRESSION",
|
||||||
FILTER_TEXT_SET: "FILTER_TEXT_SET",
|
FILTER_TEXT_SET: "FILTER_TEXT_SET",
|
||||||
FILTER_TOGGLE: "FILTER_TOGGLE",
|
FILTER_TOGGLE: "FILTER_TOGGLE",
|
||||||
FILTERS_CLEAR: "FILTERS_CLEAR",
|
FILTERS_CLEAR: "FILTERS_CLEAR",
|
||||||
|
|
|
@ -8,6 +8,7 @@ const {
|
||||||
FILTER_TEXT_SET,
|
FILTER_TEXT_SET,
|
||||||
FILTER_TOGGLE,
|
FILTER_TOGGLE,
|
||||||
DEFAULT_FILTERS_RESET,
|
DEFAULT_FILTERS_RESET,
|
||||||
|
EVALUATE_EXPRESSION,
|
||||||
MESSAGES_ADD,
|
MESSAGES_ADD,
|
||||||
PERSIST_TOGGLE,
|
PERSIST_TOGGLE,
|
||||||
} = require("devtools/client/webconsole/constants");
|
} = require("devtools/client/webconsole/constants");
|
||||||
|
@ -50,6 +51,13 @@ function eventTelemetryMiddleware(telemetry, sessionId, store) {
|
||||||
session_id: sessionId,
|
session_id: sessionId,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
} else if (action.type === EVALUATE_EXPRESSION) {
|
||||||
|
// Send telemetry event. If we are in the browser toolbox we send -1 as the
|
||||||
|
// toolbox session id.
|
||||||
|
telemetry.recordEvent("execute_js", "webconsole", null, {
|
||||||
|
lines: action.expression.split(/\n/).length,
|
||||||
|
session_id: sessionId,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
const {
|
const {
|
||||||
APPEND_TO_HISTORY,
|
APPEND_TO_HISTORY,
|
||||||
CLEAR_HISTORY,
|
CLEAR_HISTORY,
|
||||||
|
EVALUATE_EXPRESSION,
|
||||||
} = require("devtools/client/webconsole/constants");
|
} = require("devtools/client/webconsole/constants");
|
||||||
|
|
||||||
const historyActions = require("devtools/client/webconsole/actions/history");
|
const historyActions = require("devtools/client/webconsole/actions/history");
|
||||||
|
@ -35,7 +36,11 @@ function historyPersistenceMiddleware(store) {
|
||||||
return next => action => {
|
return next => action => {
|
||||||
const res = next(action);
|
const res = next(action);
|
||||||
|
|
||||||
const triggerStoreActions = [APPEND_TO_HISTORY, CLEAR_HISTORY];
|
const triggerStoreActions = [
|
||||||
|
APPEND_TO_HISTORY,
|
||||||
|
CLEAR_HISTORY,
|
||||||
|
EVALUATE_EXPRESSION,
|
||||||
|
];
|
||||||
|
|
||||||
// Save the current history entries when modified, but wait till
|
// Save the current history entries when modified, but wait till
|
||||||
// entries from the previous session are loaded.
|
// entries from the previous session are loaded.
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
const {
|
const {
|
||||||
APPEND_TO_HISTORY,
|
APPEND_TO_HISTORY,
|
||||||
CLEAR_HISTORY,
|
CLEAR_HISTORY,
|
||||||
|
EVALUATE_EXPRESSION,
|
||||||
HISTORY_LOADED,
|
HISTORY_LOADED,
|
||||||
UPDATE_HISTORY_POSITION,
|
UPDATE_HISTORY_POSITION,
|
||||||
HISTORY_BACK,
|
HISTORY_BACK,
|
||||||
|
@ -46,6 +47,7 @@ function getInitialState() {
|
||||||
function history(state = getInitialState(), action, prefsState) {
|
function history(state = getInitialState(), action, prefsState) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case APPEND_TO_HISTORY:
|
case APPEND_TO_HISTORY:
|
||||||
|
case EVALUATE_EXPRESSION:
|
||||||
return appendToHistory(state, prefsState, action.expression);
|
return appendToHistory(state, prefsState, action.expression);
|
||||||
case CLEAR_HISTORY:
|
case CLEAR_HISTORY:
|
||||||
return clearHistory(state);
|
return clearHistory(state);
|
||||||
|
|
|
@ -20,7 +20,7 @@ const WebConsoleWrapper = require("devtools/client/webconsole/webconsole-wrapper
|
||||||
const { messagesAdd } = require("devtools/client/webconsole/actions/messages");
|
const { messagesAdd } = require("devtools/client/webconsole/actions/messages");
|
||||||
|
|
||||||
async function getWebConsoleWrapper() {
|
async function getWebConsoleWrapper() {
|
||||||
const hud = { target: { client: {} } };
|
const hud = { target: { client: {} }, getMappedExpression: () => {} };
|
||||||
const webConsoleUi = {
|
const webConsoleUi = {
|
||||||
emit: () => {},
|
emit: () => {},
|
||||||
hud,
|
hud,
|
||||||
|
@ -30,6 +30,7 @@ async function getWebConsoleWrapper() {
|
||||||
ensureCSSErrorReportingEnabled: () => {},
|
ensureCSSErrorReportingEnabled: () => {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
inspectObjectActor: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const wcow = new WebConsoleWrapper(null, webConsoleUi, null, null);
|
const wcow = new WebConsoleWrapper(null, webConsoleUi, null, null);
|
||||||
|
|
|
@ -109,8 +109,11 @@ async function storeAsVariable(hud, msg, type, varIdx, equalTo) {
|
||||||
|
|
||||||
is(getInputValue(hud), "temp" + varIdx, "Input was set");
|
is(getInputValue(hud), "temp" + varIdx, "Input was set");
|
||||||
|
|
||||||
const equal = await hud.jsterm.requestEvaluation(
|
await executeAndWaitForMessage(
|
||||||
"temp" + varIdx + " === " + equalTo
|
hud,
|
||||||
|
`temp${varIdx} === ${equalTo}`,
|
||||||
|
true,
|
||||||
|
".result"
|
||||||
);
|
);
|
||||||
is(equal.result, true, "Correct variable assigned into console.");
|
ok(true, "Correct variable assigned into console.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,10 +164,12 @@ function createContextMenu(
|
||||||
selectedObjectActor: actor,
|
selectedObjectActor: actor,
|
||||||
};
|
};
|
||||||
|
|
||||||
webConsoleUI.jsterm.requestEvaluation(evalString, options).then(res => {
|
webConsoleUI.webConsoleClient
|
||||||
webConsoleUI.jsterm.focus();
|
.evaluateJSAsync(evalString, options)
|
||||||
webConsoleUI.hud.setInputValue(res.result);
|
.then(res => {
|
||||||
});
|
webConsoleUI.jsterm.focus();
|
||||||
|
webConsoleUI.hud.setInputValue(res.result);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
|
@ -204,10 +204,6 @@ class WebConsoleWrapper {
|
||||||
return webConsoleUI.jsterm && webConsoleUI.jsterm.focus();
|
return webConsoleUI.jsterm && webConsoleUI.jsterm.focus();
|
||||||
},
|
},
|
||||||
|
|
||||||
evaluateInput: expression => {
|
|
||||||
return webConsoleUI.jsterm && webConsoleUI.jsterm.execute(expression);
|
|
||||||
},
|
|
||||||
|
|
||||||
requestEvaluation: (string, options) => {
|
requestEvaluation: (string, options) => {
|
||||||
return webConsoleUI.webConsoleClient.evaluateJSAsync(string, options);
|
return webConsoleUI.webConsoleClient.evaluateJSAsync(string, options);
|
||||||
},
|
},
|
||||||
|
@ -230,6 +226,9 @@ class WebConsoleWrapper {
|
||||||
}
|
}
|
||||||
return webConsoleUI.jsterm.completeNode;
|
return webConsoleUI.jsterm.completeNode;
|
||||||
},
|
},
|
||||||
|
getMappedExpression: this.hud.getMappedExpression.bind(this.hud),
|
||||||
|
getPanelWindow: () => webConsoleUI.window,
|
||||||
|
inspectObjectActor: webConsoleUI.inspectObjectActor.bind(webConsoleUI),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set `openContextMenu` this way so, `serviceContainer` variable
|
// Set `openContextMenu` this way so, `serviceContainer` variable
|
||||||
|
|
Загрузка…
Ссылка в новой задаче