summaryrefslogtreecommitdiffstats
path: root/devtools/client/webconsole/components/Input/EagerEvaluation.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--devtools/client/webconsole/components/Input/EagerEvaluation.js147
1 files changed, 147 insertions, 0 deletions
diff --git a/devtools/client/webconsole/components/Input/EagerEvaluation.js b/devtools/client/webconsole/components/Input/EagerEvaluation.js
new file mode 100644
index 0000000000..fddc0c2aa4
--- /dev/null
+++ b/devtools/client/webconsole/components/Input/EagerEvaluation.js
@@ -0,0 +1,147 @@
+/* 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 {
+ Component,
+} = require("resource://devtools/client/shared/vendor/react.js");
+const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
+const {
+ connect,
+} = require("resource://devtools/client/shared/vendor/react-redux.js");
+
+const {
+ getTerminalEagerResult,
+} = require("resource://devtools/client/webconsole/selectors/history.js");
+
+const actions = require("resource://devtools/client/webconsole/actions/index.js");
+
+loader.lazyGetter(this, "REPS", function () {
+ return require("resource://devtools/client/shared/components/reps/index.js")
+ .REPS;
+});
+loader.lazyGetter(this, "MODE", function () {
+ return require("resource://devtools/client/shared/components/reps/index.js")
+ .MODE;
+});
+loader.lazyRequireGetter(
+ this,
+ "PropTypes",
+ "resource://devtools/client/shared/vendor/react-prop-types.js"
+);
+
+/**
+ * Show the results of evaluating the current terminal text, if possible.
+ */
+class EagerEvaluation extends Component {
+ static get propTypes() {
+ return {
+ terminalEagerResult: PropTypes.any,
+ serviceContainer: PropTypes.object.isRequired,
+ highlightDomElement: PropTypes.func.isRequired,
+ unHighlightDomElement: PropTypes.func.isRequired,
+ };
+ }
+
+ static getDerivedStateFromError(error) {
+ return { hasError: true };
+ }
+
+ componentDidUpdate(prevProps) {
+ const { highlightDomElement, unHighlightDomElement, terminalEagerResult } =
+ this.props;
+
+ if (canHighlightObject(prevProps.terminalEagerResult)) {
+ unHighlightDomElement(prevProps.terminalEagerResult.getGrip());
+ }
+
+ if (canHighlightObject(terminalEagerResult)) {
+ highlightDomElement(terminalEagerResult.getGrip());
+ }
+
+ if (this.state?.hasError) {
+ // If the render function threw at some point, clear the error after 1s so the
+ // component has a chance to render again.
+ // This way, we don't block instant evaluation for the whole session, in case the
+ // input changed in the meantime. If the input didn't change, we'll hit
+ // getDerivatedStateFromError again (and this won't render anything), so it's safe.
+ setTimeout(() => {
+ this.setState({ hasError: false });
+ }, 1000);
+ }
+ }
+
+ componentWillUnmount() {
+ const { unHighlightDomElement, terminalEagerResult } = this.props;
+
+ if (canHighlightObject(terminalEagerResult)) {
+ unHighlightDomElement(terminalEagerResult.getGrip());
+ }
+ }
+
+ renderRepsResult() {
+ const { terminalEagerResult } = this.props;
+
+ const result = terminalEagerResult.getGrip
+ ? terminalEagerResult.getGrip()
+ : terminalEagerResult;
+ const { isError } = result || {};
+
+ return REPS.Rep({
+ key: "rep",
+ object: result,
+ mode: isError ? MODE.SHORT : MODE.LONG,
+ });
+ }
+
+ render() {
+ const hasResult =
+ this.props.terminalEagerResult !== null &&
+ this.props.terminalEagerResult !== undefined &&
+ !this.state?.hasError;
+
+ return dom.div(
+ { className: "eager-evaluation-result", key: "eager-evaluation-result" },
+ hasResult
+ ? dom.span(
+ { className: "eager-evaluation-result__row" },
+ dom.span({
+ className: "eager-evaluation-result__icon",
+ key: "icon",
+ }),
+ dom.span(
+ { className: "eager-evaluation-result__text", key: "text" },
+ this.renderRepsResult()
+ )
+ )
+ : null
+ );
+ }
+}
+
+function canHighlightObject(obj) {
+ const grip = obj?.getGrip && obj.getGrip();
+ return (
+ grip &&
+ (REPS.ElementNode.supportsObject(grip) ||
+ REPS.TextNode.supportsObject(grip)) &&
+ grip.preview.isConnected
+ );
+}
+
+function mapStateToProps(state) {
+ return {
+ terminalEagerResult: getTerminalEagerResult(state),
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ highlightDomElement: grip => dispatch(actions.highlightDomElement(grip)),
+ unHighlightDomElement: grip =>
+ dispatch(actions.unHighlightDomElement(grip)),
+ };
+}
+module.exports = connect(mapStateToProps, mapDispatchToProps)(EagerEvaluation);