Bug 1398734 - Implement devtools inspector extension page sidebar container component. draft
authorLuca Greco <lgreco@mozilla.com>
Sun, 10 Sep 2017 19:22:55 +0200
changeset 662509 7a59dba8b4e1be70673c7ae6585ecf3930884fb8
parent 662326 62fbe97f531d57a6e1f323f732e1d46a6b7d4e50
child 662510 bf65a41ceda74da939cde5da52c8ad6b6f053b91
push id79108
push userluca.greco@alcacoop.it
push dateMon, 11 Sep 2017 19:51:56 +0000
bugs1398734
milestone57.0a1
Bug 1398734 - Implement devtools inspector extension page sidebar container component. MozReview-Commit-ID: HbHoV32Xk3s
devtools/client/inspector/extensions/actions/index.js
devtools/client/inspector/extensions/actions/sidebar.js
devtools/client/inspector/extensions/components/ExtensionPage.js
devtools/client/inspector/extensions/components/ExtensionSidebar.js
devtools/client/inspector/extensions/components/moz.build
devtools/client/inspector/extensions/extension-sidebar.js
devtools/client/inspector/extensions/reducers/sidebar.js
--- a/devtools/client/inspector/extensions/actions/index.js
+++ b/devtools/client/inspector/extensions/actions/index.js
@@ -6,12 +6,15 @@
 
 const { createEnum } = require("devtools/client/shared/enum");
 
 createEnum([
 
   // Update the extension sidebar with an object TreeView.
   "EXTENSION_SIDEBAR_OBJECT_TREEVIEW_UPDATE",
 
+  // Switch the extension sidebar into an extension page container.
+  "EXTENSION_SIDEBAR_PAGE_UPDATE",
+
   // Remove an extension sidebar from the inspector store.
   "EXTENSION_SIDEBAR_REMOVE"
 
 ], module.exports);
--- a/devtools/client/inspector/extensions/actions/sidebar.js
+++ b/devtools/client/inspector/extensions/actions/sidebar.js
@@ -1,16 +1,17 @@
 /* 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 {
   EXTENSION_SIDEBAR_OBJECT_TREEVIEW_UPDATE,
+  EXTENSION_SIDEBAR_PAGE_UPDATE,
   EXTENSION_SIDEBAR_REMOVE,
 } = require("./index");
 
 module.exports = {
 
   /**
    * Update the sidebar with an object treeview.
    */
@@ -18,16 +19,26 @@ module.exports = {
     return {
       type: EXTENSION_SIDEBAR_OBJECT_TREEVIEW_UPDATE,
       sidebarId,
       object,
     };
   },
 
   /**
+   * Switch the sidebar into the extension page mode.
+   */
+  updateExtensionPage(sidebarId) {
+    return {
+      type: EXTENSION_SIDEBAR_PAGE_UPDATE,
+      sidebarId,
+    };
+  },
+
+  /**
    * Remove the extension sidebar from the inspector store.
    */
   removeExtensionSidebar(sidebarId) {
     return {
       type: EXTENSION_SIDEBAR_REMOVE,
       sidebarId,
     };
   }
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/extensions/components/ExtensionPage.js
@@ -0,0 +1,49 @@
+/* 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 {
+  createClass,
+  DOM: dom,
+  PropTypes,
+} = require("devtools/client/shared/vendor/react");
+
+/**
+ * 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.
+ */
+const ExtensionPage = createClass({
+  displayName: "ExtensionPage",
+
+  propTypes: {
+    onExtensionPageMount: PropTypes.func.isRequired,
+    onExtensionPageUnmount: PropTypes.func.isRequired,
+  },
+
+  componentDidMount() {
+    this.props.onExtensionPageMount(this.containerEl);
+  },
+
+  componentWillUnmount() {
+    this.props.onExtensionPageUnmount(this.containerEl);
+  },
+
+  render() {
+    return dom.div({
+      className: "inspector-extension-sidebar-page",
+      style: {
+        flex: "auto",
+        height: "100%",
+        margin: 0,
+        padding: 0,
+      },
+      ref: (divEl) => {
+        this.containerEl = divEl;
+      },
+    });
+  },
+});
+
+module.exports = ExtensionPage;
--- a/devtools/client/inspector/extensions/components/ExtensionSidebar.js
+++ b/devtools/client/inspector/extensions/components/ExtensionSidebar.js
@@ -9,55 +9,76 @@ const {
   createClass, createFactory,
   DOM: dom,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 
 const ObjectTreeView = createFactory(require("./ObjectTreeView"));
+const ExtensionPage = createFactory(require("./ExtensionPage"));
 
 /**
  * The ExtensionSidebar is a React component with 2 supported viewMode:
  * - an ObjectTreeView UI, used to show the JS objects (used by the sidebar.setObject
  *   and 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.
  */
 const ExtensionSidebar = createClass({
   displayName: "ExtensionSidebar",
 
   propTypes: {
     id: PropTypes.string.isRequired,
     extensionsSidebar: PropTypes.object.isRequired,
+    onExtensionPageMount: PropTypes.func.isRequired,
+    onExtensionPageUnmount: PropTypes.func.isRequired,
   },
 
   mixins: [ addons.PureRenderMixin ],
 
   render() {
-    const { id, extensionsSidebar } = this.props;
+    const {
+      id,
+      extensionsSidebar,
+      onExtensionPageMount,
+      onExtensionPageUnmount,
+    } = this.props;
 
     let {
       viewMode = "empty-sidebar",
-      object
+      object,
     } = extensionsSidebar[id] || {};
 
     let sidebarContentEl;
 
     switch (viewMode) {
       case "object-treeview":
         sidebarContentEl = ObjectTreeView({ object });
         break;
+      case "extension-page":
+        sidebarContentEl = ExtensionPage({
+          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);
+    return dom.div({
+      id,
+      className,
+      style: {
+        flex: "auto",
+        height: "100%",
+      },
+    }, sidebarContentEl);
   }
 });
 
 module.exports = connect(state => state)(ExtensionSidebar);
--- a/devtools/client/inspector/extensions/components/moz.build
+++ b/devtools/client/inspector/extensions/components/moz.build
@@ -1,10 +1,11 @@
 # -*- 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(
+    'ExtensionPage.js',
     'ExtensionSidebar.js',
     'ObjectTreeView.js',
 )
--- a/devtools/client/inspector/extensions/extension-sidebar.js
+++ b/devtools/client/inspector/extensions/extension-sidebar.js
@@ -2,23 +2,25 @@
  * 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 {
   createElement, createFactory,
 } = require("devtools/client/shared/vendor/react");
+const EventEmitter = require("devtools/shared/old-event-emitter");
 
 const { Provider } = require("devtools/client/shared/vendor/react-redux");
 
 const ExtensionSidebarComponent = createFactory(require("./components/ExtensionSidebar"));
 
 const {
   updateObjectTreeView,
+  updateExtensionPage,
   removeExtensionSidebar,
 } = require("./actions/sidebar");
 
 /**
  * ExtensionSidebar instances represents Inspector sidebars installed by add-ons
  * using the devtools.panels.elements.createSidebarPane WebExtensions API.
  *
  * The WebExtensions API registers the extensions' sidebars on the toolbox instance
@@ -31,16 +33,17 @@ const {
  * @param {Object} options
  * @param {String} options.id
  *        The unique id of the sidebar.
  * @param {String} options.title
  *        The title of the sidebar.
  */
 class ExtensionSidebar {
   constructor(inspector, {id, title}) {
+    EventEmitter.decorate(this);
     this.inspector = inspector;
     this.store = inspector.store;
     this.id = id;
     this.title = title;
 
     this.destroyed = false;
   }
 
@@ -50,16 +53,22 @@ class ExtensionSidebar {
   get provider() {
     if (!this._provider) {
       this._provider = createElement(Provider, {
         store: this.store,
         key: this.id,
         title: this.title,
       }, ExtensionSidebarComponent({
         id: this.id,
+        onExtensionPageMount: (containerEl) => {
+          this.emit("extension-page-mount", containerEl);
+        },
+        onExtensionPageUnmount: (containerEl) => {
+          this.emit("extension-page-unmount", containerEl);
+        },
       }));
     }
 
     return this._provider;
   }
 
   /**
    * Destroy the ExtensionSidebar instance, dispatch a removeExtensionSidebar Redux action
@@ -91,11 +100,19 @@ class ExtensionSidebar {
    */
   setObject(object) {
     if (this.removed) {
       throw new Error("Unable to set an object preview on a removed ExtensionSidebar");
     }
 
     this.store.dispatch(updateObjectTreeView(this.id, object));
   }
+
+  setExtensionPage() {
+    if (this.removed) {
+      throw new Error("Unable to set an object preview on a removed ExtensionSidebar");
+    }
+
+    this.store.dispatch(updateExtensionPage(this.id));
+  }
 }
 
 module.exports = ExtensionSidebar;
--- a/devtools/client/inspector/extensions/reducers/sidebar.js
+++ b/devtools/client/inspector/extensions/reducers/sidebar.js
@@ -1,16 +1,17 @@
 /* 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 {
   EXTENSION_SIDEBAR_OBJECT_TREEVIEW_UPDATE,
+  EXTENSION_SIDEBAR_PAGE_UPDATE,
   EXTENSION_SIDEBAR_REMOVE,
 } = require("../actions/index");
 
 const INITIAL_SIDEBAR = {};
 
 let reducers = {
 
   [EXTENSION_SIDEBAR_OBJECT_TREEVIEW_UPDATE](sidebar, {sidebarId, object}) {
@@ -19,16 +20,26 @@ let reducers = {
     return Object.assign({}, sidebar, {
       [sidebarId]: {
         viewMode: "object-treeview",
         object,
       }
     });
   },
 
+  [EXTENSION_SIDEBAR_PAGE_UPDATE](sidebar, {sidebarId}) {
+    // Update the sidebar to a "object-treeview" which shows
+    // the passed object.
+    return Object.assign({}, sidebar, {
+      [sidebarId]: {
+        viewMode: "extension-page",
+      }
+    });
+  },
+
   [EXTENSION_SIDEBAR_REMOVE](sidebar, {sidebarId}) {
     // Remove the sidebar from the Redux store.
     delete sidebar[sidebarId];
     return Object.assign({}, sidebar);
   },
 
 };