summaryrefslogtreecommitdiffstats
path: root/devtools/client/inspector/extensions/components
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/inspector/extensions/components')
-rw-r--r--devtools/client/inspector/extensions/components/ExpressionResultView.js110
-rw-r--r--devtools/client/inspector/extensions/components/ExtensionPage.js56
-rw-r--r--devtools/client/inspector/extensions/components/ExtensionSidebar.js106
-rw-r--r--devtools/client/inspector/extensions/components/ObjectTreeView.js67
-rw-r--r--devtools/client/inspector/extensions/components/moz.build12
5 files changed, 351 insertions, 0 deletions
diff --git a/devtools/client/inspector/extensions/components/ExpressionResultView.js b/devtools/client/inspector/extensions/components/ExpressionResultView.js
new file mode 100644
index 0000000000..887c5610c4
--- /dev/null
+++ b/devtools/client/inspector/extensions/components/ExpressionResultView.js
@@ -0,0 +1,110 @@
+/* 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 {
+ createFactory,
+ PureComponent,
+} = require("resource://devtools/client/shared/vendor/react.js");
+const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js");
+
+const Accordion = createFactory(
+ require("resource://devtools/client/shared/components/Accordion.js")
+);
+
+const Types = require("resource://devtools/client/inspector/extensions/types.js");
+
+const {
+ REPS: { Grip },
+ MODE,
+ objectInspector: { ObjectInspector: ObjectInspectorClass },
+} = require("resource://devtools/client/shared/components/reps/index.js");
+
+loader.lazyRequireGetter(
+ this,
+ "LongStringFront",
+ "resource://devtools/client/fronts/string.js",
+ true
+);
+
+loader.lazyRequireGetter(
+ this,
+ "ObjectFront",
+ "resource://devtools/client/fronts/object.js",
+ true
+);
+
+const ObjectInspector = createFactory(ObjectInspectorClass);
+
+class ObjectValueGripView extends PureComponent {
+ static get propTypes() {
+ return {
+ rootTitle: PropTypes.string,
+ expressionResult: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.number,
+ PropTypes.object,
+ ]).isRequired,
+ // Helpers injected as props by extension-sidebar.js.
+ serviceContainer: PropTypes.shape(Types.serviceContainer).isRequired,
+ };
+ }
+
+ render() {
+ const { expressionResult, serviceContainer, rootTitle } = this.props;
+
+ const isFront =
+ expressionResult instanceof ObjectFront ||
+ expressionResult instanceof LongStringFront;
+ const grip = isFront ? expressionResult.getGrip() : expressionResult;
+
+ const objectInspectorProps = {
+ autoExpandDepth: 1,
+ mode: MODE.SHORT,
+ // TODO: we disable focus since it's not currently working well in ObjectInspector.
+ // Let's remove the property below when problem are fixed in OI.
+ disabledFocus: true,
+ roots: [
+ {
+ path: expressionResult?.actorID || JSON.stringify(expressionResult),
+ contents: { value: grip, front: isFront ? expressionResult : null },
+ },
+ ],
+ // TODO: evaluate if there should also be a serviceContainer.openLink.
+ };
+
+ if (expressionResult?.actorID) {
+ Object.assign(objectInspectorProps, {
+ onDOMNodeMouseOver: serviceContainer.highlightDomElement,
+ onDOMNodeMouseOut: serviceContainer.unHighlightDomElement,
+ onInspectIconClick(object, e) {
+ // Stop the event propagation so we don't trigger ObjectInspector
+ // expand/collapse.
+ e.stopPropagation();
+ serviceContainer.openNodeInInspector(object);
+ },
+ defaultRep: Grip,
+ });
+ }
+
+ if (rootTitle) {
+ return Accordion({
+ items: [
+ {
+ component: ObjectInspector,
+ componentProps: objectInspectorProps,
+ header: rootTitle,
+ id: rootTitle.replace(/\s/g, "-"),
+ opened: true,
+ },
+ ],
+ });
+ }
+
+ return ObjectInspector(objectInspectorProps);
+ }
+}
+
+module.exports = ObjectValueGripView;
diff --git a/devtools/client/inspector/extensions/components/ExtensionPage.js b/devtools/client/inspector/extensions/components/ExtensionPage.js
new file mode 100644
index 0000000000..3f92b8f41f
--- /dev/null
+++ b/devtools/client/inspector/extensions/components/ExtensionPage.js
@@ -0,0 +1,56 @@
+/* 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 {
+ createRef,
+ PureComponent,
+} = require("resource://devtools/client/shared/vendor/react.js");
+const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
+const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js");
+
+/**
+ * The ExtensionPage React Component is used in the ExtensionSidebar component to provide
+ * a UI viewMode which shows an extension page rendered inside the sidebar panel.
+ */
+class ExtensionPage extends PureComponent {
+ static get propTypes() {
+ return {
+ iframeURL: PropTypes.string.isRequired,
+ onExtensionPageMount: PropTypes.func.isRequired,
+ onExtensionPageUnmount: PropTypes.func.isRequired,
+ };
+ }
+
+ constructor(props) {
+ super(props);
+
+ this.iframeRef = createRef();
+ }
+
+ componentDidMount() {
+ this.props.onExtensionPageMount(this.iframeRef.current);
+ }
+
+ componentWillUnmount() {
+ this.props.onExtensionPageUnmount(this.iframeRef.current);
+ }
+
+ render() {
+ return dom.iframe({
+ className: "inspector-extension-sidebar-page",
+ src: this.props.iframeURL,
+ style: {
+ width: "100%",
+ height: "100%",
+ margin: 0,
+ padding: 0,
+ },
+ ref: this.iframeRef,
+ });
+ }
+}
+
+module.exports = ExtensionPage;
diff --git a/devtools/client/inspector/extensions/components/ExtensionSidebar.js b/devtools/client/inspector/extensions/components/ExtensionSidebar.js
new file mode 100644
index 0000000000..a351b6add9
--- /dev/null
+++ b/devtools/client/inspector/extensions/components/ExtensionSidebar.js
@@ -0,0 +1,106 @@
+/* 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 {
+ createFactory,
+ PureComponent,
+} = require("resource://devtools/client/shared/vendor/react.js");
+const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
+const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js");
+const {
+ connect,
+} = require("resource://devtools/client/shared/vendor/react-redux.js");
+
+const ExtensionPage = createFactory(
+ require("resource://devtools/client/inspector/extensions/components/ExtensionPage.js")
+);
+const ObjectTreeView = createFactory(
+ require("resource://devtools/client/inspector/extensions/components/ObjectTreeView.js")
+);
+const ExpressionResultView = createFactory(
+ require("resource://devtools/client/inspector/extensions/components/ExpressionResultView.js")
+);
+const Types = require("resource://devtools/client/inspector/extensions/types.js");
+
+/**
+ * The ExtensionSidebar is a React component with 2 supported viewMode:
+ * - an ObjectTreeView UI, used to show the JS objects
+ * (used by the sidebar.setObject WebExtensions APIs)
+ * - an ExpressionResultView UI, used to show the result for an expression
+ * (used by sidebar.setExpression WebExtensions APIs)
+ * - an ExtensionPage UI used to show an extension page
+ * (used by the sidebar.setPage WebExtensions APIs).
+ *
+ * TODO: implement the ExtensionPage viewMode.
+ */
+class ExtensionSidebar extends PureComponent {
+ static get propTypes() {
+ return {
+ id: PropTypes.string.isRequired,
+ extensionsSidebar: PropTypes.object.isRequired,
+ onExtensionPageMount: PropTypes.func.isRequired,
+ onExtensionPageUnmount: PropTypes.func.isRequired,
+ // Helpers injected as props by extension-sidebar.js.
+ serviceContainer: PropTypes.shape(Types.serviceContainer).isRequired,
+ };
+ }
+
+ render() {
+ const {
+ id,
+ extensionsSidebar,
+ onExtensionPageMount,
+ onExtensionPageUnmount,
+ serviceContainer,
+ } = this.props;
+
+ const {
+ iframeURL,
+ object,
+ expressionResult,
+ rootTitle,
+ viewMode = "empty-sidebar",
+ } = extensionsSidebar[id] || {};
+
+ let sidebarContentEl;
+
+ switch (viewMode) {
+ case "object-treeview":
+ sidebarContentEl = ObjectTreeView({ object });
+ break;
+ case "object-value-grip-view":
+ sidebarContentEl = ExpressionResultView({
+ expressionResult,
+ rootTitle,
+ serviceContainer,
+ });
+ break;
+ case "extension-page":
+ sidebarContentEl = ExtensionPage({
+ iframeURL,
+ onExtensionPageMount,
+ onExtensionPageUnmount,
+ });
+ break;
+ case "empty-sidebar":
+ break;
+ default:
+ throw new Error(`Unknown ExtensionSidebar viewMode: "${viewMode}"`);
+ }
+
+ const className = "devtools-monospace extension-sidebar inspector-tabpanel";
+
+ return dom.div(
+ {
+ id,
+ className,
+ },
+ sidebarContentEl
+ );
+ }
+}
+
+module.exports = connect(state => state)(ExtensionSidebar);
diff --git a/devtools/client/inspector/extensions/components/ObjectTreeView.js b/devtools/client/inspector/extensions/components/ObjectTreeView.js
new file mode 100644
index 0000000000..1788f8d020
--- /dev/null
+++ b/devtools/client/inspector/extensions/components/ObjectTreeView.js
@@ -0,0 +1,67 @@
+/* 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 {
+ createFactory,
+ PureComponent,
+} = require("resource://devtools/client/shared/vendor/react.js");
+const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js");
+
+const {
+ REPS,
+ MODE,
+} = require("resource://devtools/client/shared/components/reps/index.js");
+const { Rep } = REPS;
+const TreeViewClass = require("resource://devtools/client/shared/components/tree/TreeView.js");
+const TreeView = createFactory(TreeViewClass);
+
+/**
+ * The ExpressionResultView React Component is used in the ExtensionSidebar component to
+ * provide a UI viewMode which shows a tree view of the passed JavaScript object.
+ */
+class ExpressionResultView extends PureComponent {
+ static get propTypes() {
+ return {
+ object: PropTypes.object.isRequired,
+ };
+ }
+
+ render() {
+ const { object } = this.props;
+
+ const columns = [
+ {
+ id: "value",
+ },
+ ];
+
+ // Render the node value (omitted on the root element if it has children).
+ const renderValue = props => {
+ if (props.member.level === 0 && props.member.hasChildren) {
+ return undefined;
+ }
+
+ return Rep(
+ Object.assign({}, props, {
+ cropLimit: 50,
+ })
+ );
+ };
+
+ return TreeView({
+ object,
+ mode: MODE.SHORT,
+ columns,
+ renderValue,
+ expandedNodes: TreeViewClass.getExpandedNodes(object, {
+ maxLevel: 1,
+ maxNodes: 1,
+ }),
+ });
+ }
+}
+
+module.exports = ExpressionResultView;
diff --git a/devtools/client/inspector/extensions/components/moz.build b/devtools/client/inspector/extensions/components/moz.build
new file mode 100644
index 0000000000..62f3d991c1
--- /dev/null
+++ b/devtools/client/inspector/extensions/components/moz.build
@@ -0,0 +1,12 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+DevToolsModules(
+ "ExpressionResultView.js",
+ "ExtensionPage.js",
+ "ExtensionSidebar.js",
+ "ObjectTreeView.js",
+)