diff options
Diffstat (limited to 'devtools/client/inspector/extensions/components')
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", +) |