Bug 1207997 - about:debugging use factories/dom helpers instead of createElement;r=janx draft
authorJulian Descottes <jdescottes@mozilla.com>
Sun, 21 Feb 2016 01:58:00 +0100
changeset 334935 8e3184bf82ad1b59d65bf0e94cc2f4662db856bd
parent 334587 5f9f5bacc390e2abd9bf9acbb76bd399171900e9
child 515034 3ad09c2320647fa86d824552d43e8bfb02175a20
push id11678
push userjdescottes@mozilla.com
push dateFri, 26 Feb 2016 15:28:20 +0000
reviewersjanx
bugs1207997
milestone47.0a1
Bug 1207997 - about:debugging use factories/dom helpers instead of createElement;r=janx Make about:debugging code less verbose: - use component factories to avoid having to remove calls to createElement - use React.DOM helpers - components only module.export their class (require('my-component.js').MyComponent -> require('my-component.js')) MozReview-Commit-ID: CBWLgcPUkMf
devtools/client/aboutdebugging/components/aboutdebugging.js
devtools/client/aboutdebugging/components/addons-controls.js
devtools/client/aboutdebugging/components/addons-tab.js
devtools/client/aboutdebugging/components/tab-header.js
devtools/client/aboutdebugging/components/tab-menu-entry.js
devtools/client/aboutdebugging/components/tab-menu.js
devtools/client/aboutdebugging/components/target-list.js
devtools/client/aboutdebugging/components/target.js
devtools/client/aboutdebugging/components/workers-tab.js
devtools/client/aboutdebugging/initializer.js
--- a/devtools/client/aboutdebugging/components/aboutdebugging.js
+++ b/devtools/client/aboutdebugging/components/aboutdebugging.js
@@ -3,36 +3,43 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* eslint-env browser */
 
 "use strict";
 
 const Services = require("Services");
 
-const React = require("devtools/client/shared/vendor/react");
-const { TabMenu } = require("./tab-menu");
+const { createFactory, createClass, DOM: dom } =
+  require("devtools/client/shared/vendor/react");
 
-loader.lazyRequireGetter(this, "AddonsTab", "./components/addons-tab", true);
-loader.lazyRequireGetter(this, "WorkersTab", "./components/workers-tab", true);
+const TabMenu = createFactory(require("./tab-menu"));
+loader.lazyGetter(this, "AddonsTab",
+  () => createFactory(require("./addons-tab")));
+loader.lazyGetter(this, "WorkersTab",
+  () => createFactory(require("./workers-tab")));
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
-const tabs = [
-  { id: "addons", name: Strings.GetStringFromName("addons"),
-    icon: "chrome://devtools/skin/images/debugging-addons.svg",
-    component: AddonsTab },
-  { id: "workers", name: Strings.GetStringFromName("workers"),
-    icon: "chrome://devtools/skin/images/debugging-workers.svg",
-    component: WorkersTab },
-];
+const tabs = [{
+  id: "addons",
+  name: Strings.GetStringFromName("addons"),
+  icon: "chrome://devtools/skin/images/debugging-addons.svg",
+  component: AddonsTab
+}, {
+  id: "workers",
+  name: Strings.GetStringFromName("workers"),
+  icon: "chrome://devtools/skin/images/debugging-workers.svg",
+  component: WorkersTab
+}];
+
 const defaultTabId = "addons";
 
-exports.AboutDebuggingApp = React.createClass({
+module.exports = createClass({
   displayName: "AboutDebuggingApp",
 
   getInitialState() {
     return {
       selectedTabId: defaultTabId
     };
   },
 
@@ -50,22 +57,21 @@ exports.AboutDebuggingApp = React.create
 
   render() {
     let { client } = this.props;
     let { selectedTabId } = this.state;
     let selectTab = this.selectTab;
 
     let selectedTab = tabs.find(t => t.id == selectedTabId);
 
-    return React.createElement(
-      "div", { className: "app"},
-        React.createElement(TabMenu, { tabs, selectedTabId, selectTab }),
-        React.createElement("div", { className: "main-content" },
-          React.createElement(selectedTab.component, { client }))
-        );
+    return dom.div({ className: "app" },
+      TabMenu({ tabs, selectedTabId, selectTab }),
+      dom.div({ className: "main-content" },
+        selectedTab.component({ client }))
+      );
   },
 
   onHashChange() {
     let tabId = window.location.hash.substr(1);
 
     let isValid = tabs.some(t => t.id == tabId);
     if (isValid) {
       this.setState({ selectedTabId: tabId });
--- a/devtools/client/aboutdebugging/components/addons-controls.js
+++ b/devtools/client/aboutdebugging/components/addons-controls.js
@@ -7,50 +7,49 @@
 "use strict";
 
 loader.lazyImporter(this, "AddonManager",
   "resource://gre/modules/AddonManager.jsm");
 
 const { Cc, Ci } = require("chrome");
 const Services = require("Services");
 
-const React = require("devtools/client/shared/vendor/react");
+const { createClass, DOM: dom } = require("devtools/client/shared/vendor/react");
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 const MORE_INFO_URL = "https://developer.mozilla.org/docs/Tools" +
                       "/about:debugging#Enabling_add-on_debugging";
 
-exports.AddonsControls = React.createClass({
+module.exports = createClass({
   displayName: "AddonsControls",
 
   render() {
     let { debugDisabled } = this.props;
 
-    return React.createElement(
-      "div", { className: "addons-controls" }, React.createElement(
-        "div", { className: "addons-options" },
-          React.createElement("input", {
+    return dom.div({ className: "addons-controls" },
+        dom.div({ className: "addons-options" },
+          dom.input({
             id: "enable-addon-debugging",
             type: "checkbox",
             checked: !debugDisabled,
             onChange: this.onEnableAddonDebuggingChange,
           }),
-          React.createElement("label", {
+          dom.label({
             className: "addons-debugging-label",
             htmlFor: "enable-addon-debugging",
             title: Strings.GetStringFromName("addonDebugging.tooltip")
           }, Strings.GetStringFromName("addonDebugging.label")),
           "(",
-          React.createElement("a", { href: MORE_INFO_URL, target: "_blank" },
+          dom.a({ href: MORE_INFO_URL, target: "_blank" },
             Strings.GetStringFromName("addonDebugging.moreInfo")),
           ")"
         ),
-        React.createElement("button", {
+        dom.button({
           id: "load-addon-from-file",
           onClick: this.loadAddonFromFile,
         }, Strings.GetStringFromName("loadTemporaryAddon"))
       );
   },
 
   onEnableAddonDebuggingChange(event) {
     let enabled = event.target.checked;
--- a/devtools/client/aboutdebugging/components/addons-tab.js
+++ b/devtools/client/aboutdebugging/components/addons-tab.js
@@ -1,32 +1,31 @@
 /* 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/. */
 
-/* global React */
-
 "use strict";
 
 const { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
 const Services = require("Services");
 
-const React = require("devtools/client/shared/vendor/react");
-const { AddonsControls } = require("./addons-controls");
-const { TabHeader } = require("./tab-header");
-const { TargetList } = require("./target-list");
+const { createFactory, createClass, DOM: dom } =
+  require("devtools/client/shared/vendor/react");
+const AddonsControls = createFactory(require("./addons-controls"));
+const TabHeader = createFactory(require("./tab-header"));
+const TargetList = createFactory(require("./target-list"));
 
 const ExtensionIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 const CHROME_ENABLED_PREF = "devtools.chrome.enabled";
 const REMOTE_ENABLED_PREF = "devtools.debugger.remote-enabled";
 
-exports.AddonsTab = React.createClass({
+module.exports = createClass({
   displayName: "AddonsTab",
 
   getInitialState() {
     return {
       extensions: [],
       debugDisabled: false,
     };
   },
@@ -51,29 +50,27 @@ exports.AddonsTab = React.createClass({
       this.updateDebugStatus);
   },
 
   render() {
     let { client } = this.props;
     let { debugDisabled, extensions: targets } = this.state;
     let name = Strings.GetStringFromName("extensions");
 
-    return React.createElement(
-      "div", { id: "tab-addons", className: "tab", role: "tabpanel",
-        "aria-labelledby": "tab-addons-header-name" },
-        React.createElement(TabHeader, {
-          id: "tab-addons-header-name",
-          name: Strings.GetStringFromName("addons")}),
-        React.createElement(AddonsControls, { debugDisabled }),
-        React.createElement(
-          "div", { id: "addons" },
-          React.createElement(TargetList,
-            { name, targets, client, debugDisabled })
-      )
-    );
+    return dom.div({
+      id: "tab-addons",
+      className: "tab",
+      role: "tabpanel",
+      "aria-labelledby": "tab-addons-header-name" },
+    TabHeader({
+      id: "tab-addons-header-name",
+      name: Strings.GetStringFromName("addons") }),
+    AddonsControls({ debugDisabled }),
+    dom.div({ id: "addons" },
+      TargetList({ name, targets, client, debugDisabled })));
   },
 
   updateDebugStatus() {
     let debugDisabled =
       !Services.prefs.getBoolPref(CHROME_ENABLED_PREF) ||
       !Services.prefs.getBoolPref(REMOTE_ENABLED_PREF);
 
     this.setState({ debugDisabled });
--- a/devtools/client/aboutdebugging/components/tab-header.js
+++ b/devtools/client/aboutdebugging/components/tab-header.js
@@ -1,19 +1,19 @@
 /* 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 React = require("devtools/client/shared/vendor/react");
+const { createClass, DOM: dom } =
+  require("devtools/client/shared/vendor/react");
 
-exports.TabHeader = React.createClass({
+module.exports = createClass({
   displayName: "TabHeader",
 
   render() {
     let { name, id } = this.props;
 
-    return React.createElement(
-      "div", { className: "header" }, React.createElement(
-        "h1", { id, className: "header-name" }, name));
+    return dom.div({ className: "header" },
+      dom.h1({ id, className: "header-name" }, name));
   },
 });
--- a/devtools/client/aboutdebugging/components/tab-menu-entry.js
+++ b/devtools/client/aboutdebugging/components/tab-menu-entry.js
@@ -1,30 +1,31 @@
 /* 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 React = require("devtools/client/shared/vendor/react");
+const { createClass, DOM: dom } =
+  require("devtools/client/shared/vendor/react");
 
-exports.TabMenuEntry = React.createClass({
+module.exports = createClass({
   displayName: "TabMenuEntry",
 
   render() {
     let { icon, name, selected } = this.props;
 
     // Here .category, .category-icon, .category-name classnames are used to
     // apply common styles defined.
     let className = "category" + (selected ? " selected" : "");
-    return React.createElement(
-      "div", { className, onClick: this.onClick,
-        "aria-selected": selected, role: "tab" },
-        React.createElement("img", { className: "category-icon", src: icon,
-          role: "presentation" }),
-        React.createElement("div", { className: "category-name" }, name)
-      );
+    return dom.div({
+      "aria-selected": selected,
+      className,
+      onClick: this.onClick,
+      role: "tab" },
+    dom.img({ className: "category-icon", src: icon, role: "presentation" }),
+    dom.div({ className: "category-name" }, name));
   },
 
   onClick() {
     this.props.selectTab(this.props.tabId);
   }
 });
--- a/devtools/client/aboutdebugging/components/tab-menu.js
+++ b/devtools/client/aboutdebugging/components/tab-menu.js
@@ -1,26 +1,24 @@
 /* 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/. */
 
-/* global React */
-
 "use strict";
 
-const React = require("devtools/client/shared/vendor/react");
-const { TabMenuEntry } = require("./tab-menu-entry");
+const { createClass, createFactory, DOM: dom } =
+  require("devtools/client/shared/vendor/react");
+const TabMenuEntry = createFactory(require("./tab-menu-entry"));
 
-exports.TabMenu = React.createClass({
+module.exports = createClass({
   displayName: "TabMenu",
 
   render() {
     let { tabs, selectedTabId, selectTab } = this.props;
     let tabLinks = tabs.map(({ id, name, icon }) => {
       let selected = id == selectedTabId;
-      return React.createElement(TabMenuEntry,
-        { tabId: id, name, icon, selected, selectTab });
+      return TabMenuEntry({ tabId: id, name, icon, selected, selectTab });
     });
 
     // "categories" id used for styling purposes
-    return React.createElement("div", { id: "categories" }, tabLinks);
+    return dom.div({ id: "categories" }, tabLinks);
   },
 });
--- a/devtools/client/aboutdebugging/components/target-list.js
+++ b/devtools/client/aboutdebugging/components/target-list.js
@@ -1,37 +1,38 @@
 /* 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/. */
 
-/* global React */
-
 "use strict";
 
 const Services = require("Services");
 
-const React = require("devtools/client/shared/vendor/react");
-const { Target } = require("./target");
+const { createClass, createFactory, DOM: dom } =
+  require("devtools/client/shared/vendor/react");
+const Target = createFactory(require("./target"));
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 const LocaleCompare = (a, b) => {
   return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
 };
 
-exports.TargetList = React.createClass({
+module.exports = createClass({
   displayName: "TargetList",
 
   render() {
     let { client, debugDisabled } = this.props;
     let targets = this.props.targets.sort(LocaleCompare).map(target => {
-      return React.createElement(Target, { client, target, debugDisabled });
+      return Target({ client, target, debugDisabled });
     });
+
     return (
-      React.createElement("div", { id: this.props.id, className: "targets" },
-        React.createElement("h4", null, this.props.name),
-        targets.length > 0 ? targets :
-          React.createElement("p", null, Strings.GetStringFromName("nothing"))
+      dom.div({ id: this.props.id, className: "targets" },
+        dom.h4(null, this.props.name),
+        targets.length > 0 ?
+          targets :
+          dom.p(null, Strings.GetStringFromName("nothing"))
       )
     );
   },
 });
--- a/devtools/client/aboutdebugging/components/target.js
+++ b/devtools/client/aboutdebugging/components/target.js
@@ -12,38 +12,39 @@ loader.lazyRequireGetter(this, "gDevTool
       "devtools/client/framework/devtools", true);
 loader.lazyRequireGetter(this, "Toolbox",
       "devtools/client/framework/toolbox", true);
 
 loader.lazyImporter(this, "BrowserToolboxProcess",
       "resource://devtools/client/framework/ToolboxProcess.jsm");
 
 const Services = require("Services");
-const React = require("devtools/client/shared/vendor/react");
+const { createClass, DOM: dom } =
+  require("devtools/client/shared/vendor/react");
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
-exports.Target = React.createClass({
+module.exports = createClass({
   displayName: "Target",
 
   render() {
     let { target, debugDisabled } = this.props;
     let isServiceWorker = (target.type === "serviceworker");
     let isRunning = (!isServiceWorker || target.workerActor);
-    return React.createElement("div", { className: "target" },
-      React.createElement("img", {
+    return dom.div({ className: "target" },
+      dom.img({
         className: "target-icon",
         role: "presentation",
         src: target.icon }),
-      React.createElement("div", { className: "target-details" },
-        React.createElement("div", { className: "target-name" }, target.name)
+      dom.div({ className: "target-details" },
+        dom.div({ className: "target-name" }, target.name)
       ),
       (isRunning ?
-        React.createElement("button", {
+        dom.button({
           className: "debug-button",
           onClick: this.debug,
           disabled: debugDisabled,
         }, Strings.GetStringFromName("debug")) :
         null
       )
     );
   },
--- a/devtools/client/aboutdebugging/components/workers-tab.js
+++ b/devtools/client/aboutdebugging/components/workers-tab.js
@@ -3,25 +3,26 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Ci } = require("chrome");
 const { Task } = require("resource://gre/modules/Task.jsm");
 const Services = require("Services");
 
-const React = require("devtools/client/shared/vendor/react");
-const { TargetList } = require("./target-list");
-const { TabHeader } = require("./tab-header");
+const { createClass, createFactory, DOM: dom } =
+  require("devtools/client/shared/vendor/react");
+const TabHeader = createFactory(require("./tab-header"));
+const TargetList = createFactory(require("./target-list"));
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 const WorkerIcon = "chrome://devtools/skin/images/debugging-workers.svg";
 
-exports.WorkersTab = React.createClass({
+module.exports = createClass({
   displayName: "WorkersTab",
 
   getInitialState() {
     return {
       workers: {
         service: [],
         shared: [],
         other: []
@@ -43,37 +44,40 @@ exports.WorkersTab = React.createClass({
     client.removeListener("serviceWorkerRegistrationListChanged", this.update);
     client.removeListener("workerListChanged", this.update);
   },
 
   render() {
     let { client } = this.props;
     let { workers } = this.state;
 
-    return React.createElement(
-      "div", { id: "tab-workers", className: "tab", role: "tabpanel",
-        "aria-labelledby": "tab-workers-header-name" },
-        React.createElement(TabHeader, {
-          id: "tab-workers-header-name",
-          name: Strings.GetStringFromName("workers")}),
-        React.createElement(
-          "div", { id: "workers", className: "inverted-icons" },
-          React.createElement(TargetList, {
-            id: "service-workers",
-            name: Strings.GetStringFromName("serviceWorkers"),
-            targets: workers.service, client }),
-          React.createElement(TargetList, {
-            id: "shared-workers",
-            name: Strings.GetStringFromName("sharedWorkers"),
-            targets: workers.shared, client }),
-          React.createElement(TargetList, {
-            id: "other-workers",
-            name: Strings.GetStringFromName("otherWorkers"),
-            targets: workers.other, client }))
-      );
+    return dom.div({
+      id: "tab-workers",
+      className: "tab",
+      role: "tabpanel",
+      "aria-labelledby": "tab-workers-header-name" },
+    TabHeader({
+      id: "tab-workers-header-name",
+      name: Strings.GetStringFromName("workers") }),
+    dom.div({ id: "workers", className: "inverted-icons" },
+      TargetList({
+        id: "service-workers",
+        name: Strings.GetStringFromName("serviceWorkers"),
+        targets: workers.service,
+        client }),
+      TargetList({
+        id: "shared-workers",
+        name: Strings.GetStringFromName("sharedWorkers"),
+        targets: workers.shared,
+        client }),
+      TargetList({
+        id: "other-workers",
+        name: Strings.GetStringFromName("otherWorkers"),
+        targets: workers.other,
+        client })));
   },
 
   update() {
     let workers = this.getInitialState().workers;
 
     this.getWorkerForms().then(forms => {
       forms.registrations.forEach(form => {
         workers.service.push({
--- a/devtools/client/aboutdebugging/initializer.js
+++ b/devtools/client/aboutdebugging/initializer.js
@@ -1,14 +1,13 @@
 /* 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/. */
 
 /* eslint-env browser */
-/* global DebuggerClient, DebuggerServer */
 
 "use strict";
 
 const { loader } = Components.utils.import(
   "resource://devtools/shared/Loader.jsm", {});
 
 loader.lazyRequireGetter(this, "DebuggerClient",
   "devtools/shared/client/main", true);
@@ -17,39 +16,42 @@ loader.lazyRequireGetter(this, "Debugger
 loader.lazyRequireGetter(this, "Telemetry",
   "devtools/client/shared/telemetry");
 
 const { BrowserLoader } = Components.utils.import(
   "resource://devtools/client/shared/browser-loader.js", {});
 const { require } =
   BrowserLoader("resource://devtools/client/aboutdebugging/", window);
 
-const React = require("devtools/client/shared/vendor/react");
-const { AboutDebuggingApp } = require("./components/aboutdebugging");
+const {
+  createFactory,
+  render,
+  unmountComponentAtNode } = require("devtools/client/shared/vendor/react");
+const AboutDebuggingApp = createFactory(require("./components/aboutdebugging"));
 
 var AboutDebugging = {
   init() {
     if (!DebuggerServer.initialized) {
       DebuggerServer.init();
       DebuggerServer.addBrowserActors();
     }
     DebuggerServer.allowChromeProcess = true;
     this.client = new DebuggerClient(DebuggerServer.connectPipe());
 
     this.client.connect().then(() => {
       let client = this.client;
       let telemetry = new Telemetry();
 
-      let app = React.createElement(AboutDebuggingApp, { client, telemetry });
-      React.render(app, document.querySelector("#body"));
+      render(AboutDebuggingApp({ client, telemetry }),
+        document.querySelector("#body"));
     });
   },
 
   destroy() {
-    React.unmountComponentAtNode(document.querySelector("#body"));
+    unmountComponentAtNode(document.querySelector("#body"));
 
     this.client.close();
     this.client = null;
   },
 };
 
 window.addEventListener("DOMContentLoaded", function load() {
   window.removeEventListener("DOMContentLoaded", load);