Bug 1256757 - Support AMD in tree modules. r=jryans
authorJan Odvarko <odvarko@gmail.com>
Mon, 21 Mar 2016 13:29:17 +0100
changeset 313369 3be9cf3907ad5bbcb0b5cde7dfca5597b4b8096e
parent 313368 216d9ae88a315bed4961b121fb96f930411cf4b2
child 313370 3ddb1c19d1003e3eccc9f82f4664349e8d6b1213
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjryans
bugs1256757
milestone48.0a1
Bug 1256757 - Support AMD in tree modules. r=jryans
devtools/client/shared/components/tree/label-cell.js
devtools/client/shared/components/tree/object-provider.js
devtools/client/shared/components/tree/tree-cell.js
devtools/client/shared/components/tree/tree-header.js
devtools/client/shared/components/tree/tree-row.js
devtools/client/shared/components/tree/tree-view.js
--- a/devtools/client/shared/components/tree/label-cell.js
+++ b/devtools/client/shared/components/tree/label-cell.js
@@ -1,52 +1,55 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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";
 
-// ReactJS
-const React = require("devtools/client/shared/vendor/react");
+// Make this available to both AMD and CJS environments
+define(function(require, exports, module) {
+  // ReactJS
+  const React = require("devtools/client/shared/vendor/react");
 
-// Shortcuts
-const { td, span } = React.DOM;
-const PropTypes = React.PropTypes;
+  // Shortcuts
+  const { td, span } = React.DOM;
+  const PropTypes = React.PropTypes;
 
-/**
- * Render the default cell used for toggle buttons
- */
-var LabelCell = React.createClass({
-  // See the TreeView component for details related
-  // to the 'member' object.
-  propTypes: {
-    member: PropTypes.object.isRequired
-  },
+  /**
+   * Render the default cell used for toggle buttons
+   */
+  let LabelCell = React.createClass({
+    // See the TreeView component for details related
+    // to the 'member' object.
+    propTypes: {
+      member: PropTypes.object.isRequired
+    },
 
-  displayName: "LabelCell",
-
-  render: function() {
-    let member = this.props.member;
-    let level = member.level || 0;
+    displayName: "LabelCell",
 
-    // Compute indentation dynamically. The deeper the item is
-    // inside the hierarchy, the bigger is the left padding.
-    let rowStyle = {
-      "paddingLeft": (level * 16) + "px",
-    };
+    render: function() {
+      let member = this.props.member;
+      let level = member.level || 0;
+
+      // Compute indentation dynamically. The deeper the item is
+      // inside the hierarchy, the bigger is the left padding.
+      let rowStyle = {
+        "paddingLeft": (level * 16) + "px",
+      };
 
-    return (
-      td({
-        className: "treeLabelCell",
-        key: "default",
-        style: rowStyle},
-        span({ className: "treeIcon" }),
-        span({ className: "treeLabel " + member.type + "Label" },
-          member.name
+      return (
+        td({
+          className: "treeLabelCell",
+          key: "default",
+          style: rowStyle},
+          span({ className: "treeIcon" }),
+          span({ className: "treeLabel " + member.type + "Label" },
+            member.name
+          )
         )
-      )
-    );
-  }
+      );
+    }
+  });
+
+  // Exports from this module
+  module.exports = LabelCell;
 });
-
-// Exports from this module
-module.exports = LabelCell;
--- a/devtools/client/shared/components/tree/object-provider.js
+++ b/devtools/client/shared/components/tree/object-provider.js
@@ -1,87 +1,90 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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";
 
-/**
- * Implementation of the default data provider. A provider is state less
- * object responsible for transformation data (usually a state) to
- * a structure that can be directly consumed by the tree-view component.
- */
-var ObjectProvider = {
-  getChildren: function(object) {
-    let children = [];
+// Make this available to both AMD and CJS environments
+define(function(require, exports, module) {
+  /**
+   * Implementation of the default data provider. A provider is state less
+   * object responsible for transformation data (usually a state) to
+   * a structure that can be directly consumed by the tree-view component.
+   */
+  let ObjectProvider = {
+    getChildren: function(object) {
+      let children = [];
 
-    if (object instanceof ObjectProperty) {
-      object = object.value;
-    }
+      if (object instanceof ObjectProperty) {
+        object = object.value;
+      }
 
-    if (!object) {
-      return [];
-    }
+      if (!object) {
+        return [];
+      }
 
-    if (typeof (object) == "string") {
-      return [];
-    }
+      if (typeof (object) == "string") {
+        return [];
+      }
 
-    for (let prop in object) {
-      try {
-        children.push(new ObjectProperty(prop, object[prop]));
-      } catch (e) {
-        console.error(e);
+      for (let prop in object) {
+        try {
+          children.push(new ObjectProperty(prop, object[prop]));
+        } catch (e) {
+          console.error(e);
+        }
       }
-    }
-    return children;
-  },
+      return children;
+    },
 
-  hasChildren: function(object) {
-    if (object instanceof ObjectProperty) {
-      object = object.value;
-    }
+    hasChildren: function(object) {
+      if (object instanceof ObjectProperty) {
+        object = object.value;
+      }
 
-    if (!object) {
-      return false;
-    }
+      if (!object) {
+        return false;
+      }
 
-    if (typeof object == "string") {
-      return false;
-    }
+      if (typeof object == "string") {
+        return false;
+      }
 
-    if (typeof object !== "object") {
-      return false;
-    }
+      if (typeof object !== "object") {
+        return false;
+      }
 
-    return Object.keys(object).length > 1;
-  },
+      return Object.keys(object).length > 1;
+    },
 
-  getLabel: function(object) {
-    return (object instanceof ObjectProperty) ?
-      object.name : null;
-  },
+    getLabel: function(object) {
+      return (object instanceof ObjectProperty) ?
+        object.name : null;
+    },
+
+    getValue: function(object) {
+      return (object instanceof ObjectProperty) ?
+        object.value : null;
+    },
 
-  getValue: function(object) {
-    return (object instanceof ObjectProperty) ?
-      object.value : null;
-  },
-
-  getKey: function(object) {
-    return (object instanceof ObjectProperty) ?
-      object.name : null;
-  },
+    getKey: function(object) {
+      return (object instanceof ObjectProperty) ?
+        object.name : null;
+    },
 
-  getType: function(object) {
-    return (object instanceof ObjectProperty) ?
-      typeof object.value : typeof object;
-  }
-};
+    getType: function(object) {
+      return (object instanceof ObjectProperty) ?
+        typeof object.value : typeof object;
+    }
+  };
 
-function ObjectProperty(name, value) {
-  this.name = name;
-  this.value = value;
-}
+  function ObjectProperty(name, value) {
+    this.name = name;
+    this.value = value;
+  }
 
-// Exports from this module
-exports.ObjectProperty = ObjectProperty;
-exports.ObjectProvider = ObjectProvider;
+  // Exports from this module
+  exports.ObjectProperty = ObjectProperty;
+  exports.ObjectProvider = ObjectProvider;
+});
--- a/devtools/client/shared/components/tree/tree-cell.js
+++ b/devtools/client/shared/components/tree/tree-cell.js
@@ -1,96 +1,99 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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");
-
-// Shortcuts
-const { td, span } = React.DOM;
-const PropTypes = React.PropTypes;
+// Make this available to both AMD and CJS environments
+define(function(require, exports, module) {
+  const React = require("devtools/client/shared/vendor/react");
 
-/**
- * This template represents a cell in TreeView row. It's rendered
- * using <td> element (the row is <tr> and the entire tree is <table>).
- */
-var TreeCell = React.createClass({
-  // See TreeView component for detailed property explanation.
-  propTypes: {
-    value: PropTypes.any,
-    decorator: PropTypes.object,
-    id: PropTypes.string.isRequired,
-    member: PropTypes.object.isRequired,
-    renderValue: PropTypes.func.isRequired
-  },
-
-  displayName: "TreeCell",
+  // Shortcuts
+  const { td, span } = React.DOM;
+  const PropTypes = React.PropTypes;
 
   /**
-   * Optimize cell rendering. If value is the same do not render.
+   * This template represents a cell in TreeView row. It's rendered
+   * using <td> element (the row is <tr> and the entire tree is <table>).
    */
-  shouldComponentUpdate: function(nextProps) {
-    return (this.props.value != nextProps.value);
-  },
+  let TreeCell = React.createClass({
+    // See TreeView component for detailed property explanation.
+    propTypes: {
+      value: PropTypes.any,
+      decorator: PropTypes.object,
+      id: PropTypes.string.isRequired,
+      member: PropTypes.object.isRequired,
+      renderValue: PropTypes.func.isRequired
+    },
 
-  getCellClass: function(object, id) {
-    let decorator = this.props.decorator;
-    if (!decorator || !decorator.getCellClass) {
-      return [];
-    }
+    displayName: "TreeCell",
 
-    // Decorator can return a simple string or array of strings.
-    let classNames = decorator.getCellClass(object, id);
-    if (!classNames) {
-      return [];
-    }
+    /**
+     * Optimize cell rendering. If value is the same do not render.
+     */
+    shouldComponentUpdate: function(nextProps) {
+      return (this.props.value != nextProps.value);
+    },
 
-    if (typeof classNames == "string") {
-      classNames = [classNames];
-    }
+    getCellClass: function(object, id) {
+      let decorator = this.props.decorator;
+      if (!decorator || !decorator.getCellClass) {
+        return [];
+      }
 
-    return classNames;
-  },
+      // Decorator can return a simple string or array of strings.
+      let classNames = decorator.getCellClass(object, id);
+      if (!classNames) {
+        return [];
+      }
 
-  render: function() {
-    let member = this.props.member;
-    let type = member.type || "";
-    let id = this.props.id;
-    let value = this.props.value;
-    let decorator = this.props.decorator;
+      if (typeof classNames == "string") {
+        classNames = [classNames];
+      }
+
+      return classNames;
+    },
 
-    // Compute class name list for the <td> element.
-    let classNames = this.getCellClass(member.object, id) || [];
-    classNames.push("treeValueCell");
-    classNames.push(type + "Cell");
+    render: function() {
+      let member = this.props.member;
+      let type = member.type || "";
+      let id = this.props.id;
+      let value = this.props.value;
+      let decorator = this.props.decorator;
 
-    // Render value using a default render function or custom
-    // provided function from props or a decorator.
-    let renderValue = this.props.renderValue || defaultRenderValue;
-    if (decorator && decorator.renderValue) {
-      renderValue = decorator.renderValue(member.object, id) || renderValue;
-    }
+      // Compute class name list for the <td> element.
+      let classNames = this.getCellClass(member.object, id) || [];
+      classNames.push("treeValueCell");
+      classNames.push(type + "Cell");
 
-    let props = Object.assign({}, this.props, {
-      object: value,
-    });
+      // Render value using a default render function or custom
+      // provided function from props or a decorator.
+      let renderValue = this.props.renderValue || defaultRenderValue;
+      if (decorator && decorator.renderValue) {
+        renderValue = decorator.renderValue(member.object, id) || renderValue;
+      }
 
-    // Render me!
-    return (
-      td({ className: classNames.join(" ") },
-        span({}, renderValue(props))
-      )
-    );
-  }
-});
+      let props = Object.assign({}, this.props, {
+        object: value,
+      });
 
-// Default value rendering.
-var defaultRenderValue = props => {
-  return (
-    props.object + ""
-  );
-};
+      // Render me!
+      return (
+        td({ className: classNames.join(" ") },
+          span({}, renderValue(props))
+        )
+      );
+    }
+  });
 
-// Exports from this module
-module.exports = TreeCell;
+  // Default value rendering.
+  let defaultRenderValue = props => {
+    return (
+      props.object + ""
+    );
+  };
+
+  // Exports from this module
+  module.exports = TreeCell;
+});
--- a/devtools/client/shared/components/tree/tree-header.js
+++ b/devtools/client/shared/components/tree/tree-header.js
@@ -1,97 +1,100 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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";
 
-// ReactJS
-const React = require("devtools/client/shared/vendor/react");
-
-// Shortcuts
-const { thead, tr, td, div } = React.DOM;
-const PropTypes = React.PropTypes;
+// Make this available to both AMD and CJS environments
+define(function(require, exports, module) {
+  // ReactJS
+  const React = require("devtools/client/shared/vendor/react");
 
-/**
- * This component is responsible for rendering tree header.
- * It's based on <thead> element.
- */
-var TreeHeader = React.createClass({
-  // See also TreeView component for detailed info about properties.
-  propTypes: {
-    // Custom tree decorator
-    decorator: PropTypes.object,
-    // True if the header should be visible
-    header: PropTypes.bool,
-    // Array with column definition
-    columns: PropTypes.array
-  },
-
-  displayName: "TreeHeader",
-
-  getDefaultProps: function() {
-    return {
-      columns: [{
-        id: "default"
-      }]
-    };
-  },
+  // Shortcuts
+  const { thead, tr, td, div } = React.DOM;
+  const PropTypes = React.PropTypes;
 
-  getHeaderClass: function(colId) {
-    let decorator = this.props.decorator;
-    if (!decorator || !decorator.getHeaderClass) {
-      return [];
-    }
+  /**
+   * This component is responsible for rendering tree header.
+   * It's based on <thead> element.
+   */
+  let TreeHeader = React.createClass({
+    // See also TreeView component for detailed info about properties.
+    propTypes: {
+      // Custom tree decorator
+      decorator: PropTypes.object,
+      // True if the header should be visible
+      header: PropTypes.bool,
+      // Array with column definition
+      columns: PropTypes.array
+    },
 
-    // Decorator can return a simple string or array of strings.
-    let classNames = decorator.getHeaderClass(colId);
-    if (!classNames) {
-      return [];
-    }
-
-    if (typeof classNames == "string") {
-      classNames = [classNames];
-    }
+    displayName: "TreeHeader",
 
-    return classNames;
-  },
-
-  render: function() {
-    let cells = [];
-    let visible = this.props.header;
+    getDefaultProps: function() {
+      return {
+        columns: [{
+          id: "default"
+        }]
+      };
+    },
 
-    // Render the rest of the columns (if any)
-    this.props.columns.forEach(col => {
-      let cellStyle = {
-        "width": col.width ? col.width : "",
-      };
+    getHeaderClass: function(colId) {
+      let decorator = this.props.decorator;
+      if (!decorator || !decorator.getHeaderClass) {
+        return [];
+      }
 
-      let classNames = [];
-
-      if (visible) {
-        classNames = this.getHeaderClass(col.id);
-        classNames.push("treeHeaderCell");
+      // Decorator can return a simple string or array of strings.
+      let classNames = decorator.getHeaderClass(colId);
+      if (!classNames) {
+        return [];
       }
 
-      cells.push(
-        td({
-          className: classNames.join(" "),
-          style: cellStyle,
-          key: col.id},
-          div({ className: visible ? "treeHeaderCellBox" : "" },
-            visible ? col.title : ""
+      if (typeof classNames == "string") {
+        classNames = [classNames];
+      }
+
+      return classNames;
+    },
+
+    render: function() {
+      let cells = [];
+      let visible = this.props.header;
+
+      // Render the rest of the columns (if any)
+      this.props.columns.forEach(col => {
+        let cellStyle = {
+          "width": col.width ? col.width : "",
+        };
+
+        let classNames = [];
+
+        if (visible) {
+          classNames = this.getHeaderClass(col.id);
+          classNames.push("treeHeaderCell");
+        }
+
+        cells.push(
+          td({
+            className: classNames.join(" "),
+            style: cellStyle,
+            key: col.id},
+            div({ className: visible ? "treeHeaderCellBox" : "" },
+              visible ? col.title : ""
+            )
           )
-        )
+        );
+      });
+
+      return (
+        thead({}, tr({ className: visible ? "treeHeaderRow" : "" },
+          cells
+        ))
       );
-    });
+    }
+  });
 
-    return (
-      thead({}, tr({ className: visible ? "treeHeaderRow" : "" },
-        cells
-      ))
-    );
-  }
+  // Exports from this module
+  module.exports = TreeHeader;
 });
-
-// Exports from this module
-module.exports = TreeHeader;
--- a/devtools/client/shared/components/tree/tree-row.js
+++ b/devtools/client/shared/components/tree/tree-row.js
@@ -1,181 +1,184 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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";
 
-// ReactJS
-const React = require("devtools/client/shared/vendor/react");
-const ReactDOM = require("devtools/client/shared/vendor/react-dom");
-
-// Tree
-const TreeCell = React.createFactory(require("./tree-cell"));
-const LabelCell = React.createFactory(require("./label-cell"));
-
-// Shortcuts
-const { tr } = React.DOM;
-const PropTypes = React.PropTypes;
+// Make this available to both AMD and CJS environments
+define(function(require, exports, module) {
+  // ReactJS
+  const React = require("devtools/client/shared/vendor/react");
+  const ReactDOM = require("devtools/client/shared/vendor/react-dom");
 
-/**
- * This template represents a node in TreeView component. It's rendered
- * using <tr> element (the entire tree is one big <table>).
- */
-var TreeRow = React.createClass({
-  // See TreeView component for more details about the props and
-  // the 'member' object.
-  propTypes: {
-    member: PropTypes.shape({
-      object: PropTypes.obSject,
-      name: PropTypes.sring,
-      type: PropTypes.string.isRequired,
-      rowClass: PropTypes.string.isRequired,
-      level: PropTypes.number.isRequired,
-      hasChildren: PropTypes.bool,
-      value: PropTypes.any,
-      open: PropTypes.bool.isRequired,
-      path: PropTypes.string.isRequired,
-      hidden: PropTypes.bool,
-    }),
-    decorator: PropTypes.object,
-    renderCell: PropTypes.object,
-    renderLabelCell: PropTypes.object,
-    columns: PropTypes.array.isRequired,
-    provider: PropTypes.object.isRequired,
-    onClick: PropTypes.func.isRequired
-  },
+  // Tree
+  const TreeCell = React.createFactory(require("./tree-cell"));
+  const LabelCell = React.createFactory(require("./label-cell"));
 
-  displayName: "TreeRow",
+  // Shortcuts
+  const { tr } = React.DOM;
+  const PropTypes = React.PropTypes;
 
   /**
-   * Optimize row rendering. If props are the same do not render.
-   * This makes the rendering a lot faster!
+   * This template represents a node in TreeView component. It's rendered
+   * using <tr> element (the entire tree is one big <table>).
    */
-  shouldComponentUpdate: function(nextProps) {
-    let props = ["name", "open", "value", "loading"];
-    for (let p in props) {
-      if (nextProps.member[props[p]] != this.props.member[props[p]]) {
-        return true;
-      }
-    }
+  let TreeRow = React.createClass({
+    // See TreeView component for more details about the props and
+    // the 'member' object.
+    propTypes: {
+      member: PropTypes.shape({
+        object: PropTypes.obSject,
+        name: PropTypes.sring,
+        type: PropTypes.string.isRequired,
+        rowClass: PropTypes.string.isRequired,
+        level: PropTypes.number.isRequired,
+        hasChildren: PropTypes.bool,
+        value: PropTypes.any,
+        open: PropTypes.bool.isRequired,
+        path: PropTypes.string.isRequired,
+        hidden: PropTypes.bool,
+      }),
+      decorator: PropTypes.object,
+      renderCell: PropTypes.object,
+      renderLabelCell: PropTypes.object,
+      columns: PropTypes.array.isRequired,
+      provider: PropTypes.object.isRequired,
+      onClick: PropTypes.func.isRequired
+    },
 
-    return false;
-  },
+    displayName: "TreeRow",
 
-  componentWillReceiveProps(nextProps) {
-    // I don't like accessing the underlying DOM elements directly,
-    // but this optimization makes the filtering so damn fast!
-    // The row doesn't have to be re-rendered, all we really need
-    // to do is toggling a class name.
-    // The important part is that DOM elements don't need to be
-    // re-created when they should appear again.
-    if (nextProps.member.hidden != this.props.member.hidden) {
-      let row = ReactDOM.findDOMNode(this);
-      row.classList.toggle("hidden");
-    }
-  },
+    /**
+     * Optimize row rendering. If props are the same do not render.
+     * This makes the rendering a lot faster!
+     */
+    shouldComponentUpdate: function(nextProps) {
+      let props = ["name", "open", "value", "loading"];
+      for (let p in props) {
+        if (nextProps.member[props[p]] != this.props.member[props[p]]) {
+          return true;
+        }
+      }
+
+      return false;
+    },
 
-  getRowClass: function(object) {
-    let decorator = this.props.decorator;
-    if (!decorator || !decorator.getRowClass) {
-      return [];
-    }
+    componentWillReceiveProps(nextProps) {
+      // I don't like accessing the underlying DOM elements directly,
+      // but this optimization makes the filtering so damn fast!
+      // The row doesn't have to be re-rendered, all we really need
+      // to do is toggling a class name.
+      // The important part is that DOM elements don't need to be
+      // re-created when they should appear again.
+      if (nextProps.member.hidden != this.props.member.hidden) {
+        let row = ReactDOM.findDOMNode(this);
+        row.classList.toggle("hidden");
+      }
+    },
 
-    // Decorator can return a simple string or array of strings.
-    let classNames = decorator.getRowClass(object);
-    if (!classNames) {
-      return [];
-    }
-
-    if (typeof classNames == "string") {
-      classNames = [classNames];
-    }
-
-    return classNames;
-  },
+    getRowClass: function(object) {
+      let decorator = this.props.decorator;
+      if (!decorator || !decorator.getRowClass) {
+        return [];
+      }
 
-  render: function() {
-    let member = this.props.member;
-    let decorator = this.props.decorator;
+      // Decorator can return a simple string or array of strings.
+      let classNames = decorator.getRowClass(object);
+      if (!classNames) {
+        return [];
+      }
 
-    // Compute class name list for the <tr> element.
-    let classNames = this.getRowClass(member.object) || [];
-    classNames.push("treeRow");
-    classNames.push(member.type + "Row");
+      if (typeof classNames == "string") {
+        classNames = [classNames];
+      }
+
+      return classNames;
+    },
+
+    render: function() {
+      let member = this.props.member;
+      let decorator = this.props.decorator;
 
-    if (member.hasChildren) {
-      classNames.push("hasChildren");
-    }
+      // Compute class name list for the <tr> element.
+      let classNames = this.getRowClass(member.object) || [];
+      classNames.push("treeRow");
+      classNames.push(member.type + "Row");
 
-    if (member.open) {
-      classNames.push("opened");
-    }
+      if (member.hasChildren) {
+        classNames.push("hasChildren");
+      }
 
-    if (member.loading) {
-      classNames.push("loading");
-    }
+      if (member.open) {
+        classNames.push("opened");
+      }
+
+      if (member.loading) {
+        classNames.push("loading");
+      }
 
-    if (member.hidden) {
-      classNames.push("hidden");
-    }
+      if (member.hidden) {
+        classNames.push("hidden");
+      }
 
-    // The label column (with toggle buttons) is usually
-    // the first one, but there might be cases (like in
-    // the Memory panel) where the toggling is done
-    // in the last column.
-    let cells = [];
+      // The label column (with toggle buttons) is usually
+      // the first one, but there might be cases (like in
+      // the Memory panel) where the toggling is done
+      // in the last column.
+      let cells = [];
+
+      // Get components for rendering cells.
+      let renderCell = this.props.renderCell || RenderCell;
+      let renderLabelCell = this.props.renderLabelCell || RenderLabelCell;
+      if (decorator && decorator.renderLabelCell) {
+        renderLabelCell = decorator.renderLabelCell(member.object) ||
+          renderLabelCell;
+      }
 
-    // Get components for rendering cells.
-    let renderCell = this.props.renderCell || RenderCell;
-    let renderLabelCell = this.props.renderLabelCell || RenderLabelCell;
-    if (decorator && decorator.renderLabelCell) {
-      renderLabelCell = decorator.renderLabelCell(member.object) ||
-        renderLabelCell;
-    }
+      // Render a cell for every column.
+      this.props.columns.forEach(col => {
+        let props = Object.assign({}, this.props, {
+          key: col.id,
+          id: col.id,
+          value: this.props.provider.getValue(member.object, col.id)
+        });
 
-    // Render a cell for every column.
-    this.props.columns.forEach(col => {
-      let props = Object.assign({}, this.props, {
-        key: col.id,
-        id: col.id,
-        value: this.props.provider.getValue(member.object, col.id)
+        if (decorator && decorator.renderCell) {
+          renderCell = decorator.renderCell(member.object, col.id);
+        }
+
+        let render = (col.id == "default") ? renderLabelCell : renderCell;
+
+        // Some cells don't have to be rendered. This happens when some
+        // other cells span more columns. Note that the label cells contains
+        // toggle buttons and should be usually there unless we are rendering
+        // a simple non-expandable table.
+        if (render) {
+          cells.push(render(props));
+        }
       });
 
-      if (decorator && decorator.renderCell) {
-        renderCell = decorator.renderCell(member.object, col.id);
-      }
-
-      let render = (col.id == "default") ? renderLabelCell : renderCell;
-
-      // Some cells don't have to be rendered. This happens when some
-      // other cells span more columns. Note that the label cells contains
-      // toggle buttons and should be usually there unless we are rendering
-      // a simple non-expandable table.
-      if (render) {
-        cells.push(render(props));
-      }
-    });
+      // Render tree row
+      return (
+        tr({
+          className: classNames.join(" "),
+          onClick: this.props.onClick},
+          cells
+        )
+      );
+    }
+  });
 
-    // Render tree row
-    return (
-      tr({
-        className: classNames.join(" "),
-        onClick: this.props.onClick},
-        cells
-      )
-    );
-  }
-});
+  // Helpers
+
+  let RenderCell = props => {
+    return TreeCell(props);
+  };
 
-// Helpers
-
-var RenderCell = props => {
-  return TreeCell(props);
-};
+  let RenderLabelCell = props => {
+    return LabelCell(props);
+  };
 
-var RenderLabelCell = props => {
-  return LabelCell(props);
-};
-
-// Exports from this module
-module.exports = TreeRow;
+  // Exports from this module
+  module.exports = TreeRow;
+});
--- a/devtools/client/shared/components/tree/tree-view.js
+++ b/devtools/client/shared/components/tree/tree-view.js
@@ -1,348 +1,352 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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";
 
-// ReactJS
-const React = require("devtools/client/shared/vendor/react");
-
-// Reps
-const { ObjectProvider } = require("./object-provider");
-const TreeRow = React.createFactory(require("./tree-row"));
-const TreeHeader = React.createFactory(require("./tree-header"));
-
-// Shortcuts
-const DOM = React.DOM;
-const PropTypes = React.PropTypes;
+// Make this available to both AMD and CJS environments
+define(function(require, exports, module) {
+  // ReactJS
+  const React = require("devtools/client/shared/vendor/react");
 
-/**
- * This component represents a tree view with expandable/collapsible nodes.
- * The tree is rendered using <table> element where every node is represented
- * by <tr> element. The tree is one big table where nodes (rows) are properly
- * indented from the left to mimic hierarchical structure of the data.
- *
- * The tree can have arbitrary number of columns and so, might be use
- * as an expandable tree-table UI widget as well. By default, there is
- * one column for node label and one for node value.
- *
- * The tree is maintaining its (presentation) state, which consists
- * from list of expanded nodes and list of columns.
- *
- * Complete data provider interface:
- * var TreeProvider = {
- *   getChildren: function(object);
- *   hasChildren: function(object);
- *   getLabel: function(object, colId);
- *   getValue: function(object, colId);
- *   getKey: function(object);
- *   getType: function(object);
- * }
- *
- * Complete tree decorator interface:
- * var TreeDecorator = {
- *   getRowClass: function(object);
- *   getCellClass: function(object, colId);
- *   getHeaderClass: function(colId);
- *   renderValue: function(object, colId);
- *   renderRow: function(object);
- *   renderCelL: function(object, colId);
- *   renderLabelCell: function(object);
- * }
- */
-var TreeView = React.createClass({
-  // The only required property (not set by default) is the input data
-  // object that is used to puputate the tree.
-  propTypes: {
-    // The input data object.
-    object: PropTypes.any,
-    className: PropTypes.string,
-    // Data provider (see also the interface above)
-    provider: PropTypes.shape({
-      getChildren: PropTypes.func,
-      hasChildren: PropTypes.func,
-      getLabel: PropTypes.func,
-      getValue: PropTypes.func,
-      getKey: PropTypes.func,
-      getType: PropTypes.func,
-    }).isRequired,
-    // Tree decorator (see also the interface above)
-    decorator: PropTypes.shape({
-      getRowClass: PropTypes.func,
-      getCellClass: PropTypes.func,
-      getHeaderClass: PropTypes.func,
-      renderValue: PropTypes.func,
-      renderRow: PropTypes.func,
-      renderCelL: PropTypes.func,
-      renderLabelCell: PropTypes.func,
-    }),
-    // Custom tree row (node) renderer
-    renderRow: PropTypes.func,
-    // Custom cell renderer
-    renderCell: PropTypes.func,
-    // Custom value renderef
-    renderValue: PropTypes.func,
-    // Custom tree label (including a toggle button) renderer
-    renderLabelCell: PropTypes.func,
-    // Set of expanded nodes
-    expandedNodes: PropTypes.object,
-    // Custom filtering callback
-    onFilter: PropTypes.func,
-    // Custom sorting callback
-    onSort: PropTypes.func,
-    // A header is displayed if set to true
-    header: PropTypes.bool,
-    // Array of columns
-    columns: PropTypes.arrayOf(PropTypes.shape({
-      id: PropTypes.string.isRequired,
-      title: PropTypes.string,
-      width: PropTypes.string
-    }))
-  },
+  // Reps
+  const { ObjectProvider } = require("./object-provider");
+  const TreeRow = React.createFactory(require("./tree-row"));
+  const TreeHeader = React.createFactory(require("./tree-header"));
 
-  displayName: "TreeView",
-
-  getDefaultProps: function() {
-    return {
-      object: null,
-      renderRow: null,
-      provider: ObjectProvider,
-      expandedNodes: new Set(),
-      columns: []
-    };
-  },
-
-  getInitialState: function() {
-    return {
-      expandedNodes: this.props.expandedNodes,
-      columns: ensureDefaultColumn(this.props.columns)
-    };
-  },
-
-  // Node expand/collapse
-
-  toggle: function(nodePath) {
-    let nodes = this.state.expandedNodes;
-    if (this.isExpanded(nodePath)) {
-      nodes.delete(nodePath);
-    } else {
-      nodes.add(nodePath);
-    }
-
-    // Compute new state and update the tree.
-    this.setState(Object.assign({}, this.state, {
-      expandedNodes: nodes
-    }));
-  },
-
-  isExpanded: function(nodePath) {
-    return this.state.expandedNodes.has(nodePath);
-  },
-
-  // Event Handlers
-
-  onClickRow: function(nodePath, event) {
-    event.stopPropagation();
-    this.toggle(nodePath);
-  },
-
-  // Filtering & Sorting
+  // Shortcuts
+  const DOM = React.DOM;
+  const PropTypes = React.PropTypes;
 
   /**
-   * Filter out nodes that don't correspond to the current filter.
-   * @return {Boolean} true if the node should be visible otherwise false.
-   */
-  onFilter: function(object) {
-    let onFilter = this.props.onFilter;
-    return onFilter ? onFilter(object) : true;
-  },
-
-  onSort: function(parent, children) {
-    let onSort = this.props.onSort;
-    return onSort ? onSort(parent, children) : children;
-  },
-
-  // Members
-
-  /**
-   * Return children node objects (so called 'members') for given
-   * parent object.
+   * This component represents a tree view with expandable/collapsible nodes.
+   * The tree is rendered using <table> element where every node is represented
+   * by <tr> element. The tree is one big table where nodes (rows) are properly
+   * indented from the left to mimic hierarchical structure of the data.
+   *
+   * The tree can have arbitrary number of columns and so, might be use
+   * as an expandable tree-table UI widget as well. By default, there is
+   * one column for node label and one for node value.
+   *
+   * The tree is maintaining its (presentation) state, which consists
+   * from list of expanded nodes and list of columns.
+   *
+   * Complete data provider interface:
+   * var TreeProvider = {
+   *   getChildren: function(object);
+   *   hasChildren: function(object);
+   *   getLabel: function(object, colId);
+   *   getValue: function(object, colId);
+   *   getKey: function(object);
+   *   getType: function(object);
+   * }
+   *
+   * Complete tree decorator interface:
+   * var TreeDecorator = {
+   *   getRowClass: function(object);
+   *   getCellClass: function(object, colId);
+   *   getHeaderClass: function(colId);
+   *   renderValue: function(object, colId);
+   *   renderRow: function(object);
+   *   renderCelL: function(object, colId);
+   *   renderLabelCell: function(object);
+   * }
    */
-  getMembers: function(parent, level, path) {
-    // Strings don't have children. Note that 'long' strings are using
-    // the expander icon (+/-) to display the entire original value,
-    // but there are no child items.
-    if (typeof parent == "string") {
-      return [];
-    }
-
-    let provider = this.props.provider;
-    let children = provider.getChildren(parent) || [];
+  let TreeView = React.createClass({
+    // The only required property (not set by default) is the input data
+    // object that is used to puputate the tree.
+    propTypes: {
+      // The input data object.
+      object: PropTypes.any,
+      className: PropTypes.string,
+      // Data provider (see also the interface above)
+      provider: PropTypes.shape({
+        getChildren: PropTypes.func,
+        hasChildren: PropTypes.func,
+        getLabel: PropTypes.func,
+        getValue: PropTypes.func,
+        getKey: PropTypes.func,
+        getType: PropTypes.func,
+      }).isRequired,
+      // Tree decorator (see also the interface above)
+      decorator: PropTypes.shape({
+        getRowClass: PropTypes.func,
+        getCellClass: PropTypes.func,
+        getHeaderClass: PropTypes.func,
+        renderValue: PropTypes.func,
+        renderRow: PropTypes.func,
+        renderCelL: PropTypes.func,
+        renderLabelCell: PropTypes.func,
+      }),
+      // Custom tree row (node) renderer
+      renderRow: PropTypes.func,
+      // Custom cell renderer
+      renderCell: PropTypes.func,
+      // Custom value renderef
+      renderValue: PropTypes.func,
+      // Custom tree label (including a toggle button) renderer
+      renderLabelCell: PropTypes.func,
+      // Set of expanded nodes
+      expandedNodes: PropTypes.object,
+      // Custom filtering callback
+      onFilter: PropTypes.func,
+      // Custom sorting callback
+      onSort: PropTypes.func,
+      // A header is displayed if set to true
+      header: PropTypes.bool,
+      // Array of columns
+      columns: PropTypes.arrayOf(PropTypes.shape({
+        id: PropTypes.string.isRequired,
+        title: PropTypes.string,
+        width: PropTypes.string
+      }))
+    },
 
-    // If the return value is non-array, the children
-    // are being loaded asynchronously.
-    if (!Array.isArray(children)) {
-      return children;
-    }
+    displayName: "TreeView",
 
-    children = this.onSort(parent, children) || children;
+    getDefaultProps: function() {
+      return {
+        object: null,
+        renderRow: null,
+        provider: ObjectProvider,
+        expandedNodes: new Set(),
+        columns: []
+      };
+    },
 
-    return children.map(child => {
-      let key = provider.getKey(child);
-      let nodePath = path + "/" + key;
-      let type = provider.getType(child);
-      let hasChildren = provider.hasChildren(child);
+    getInitialState: function() {
+      return {
+        expandedNodes: this.props.expandedNodes,
+        columns: ensureDefaultColumn(this.props.columns)
+      };
+    },
 
-      // Value with no column specified is used for optimization.
-      // The row is re-rendered only if this value changes.
-      // Value for actual column is get when a cell is rendered.
-      let value = provider.getValue(child);
+    // Node expand/collapse
 
-      if (isLongString(value)) {
-        hasChildren = true;
+    toggle: function(nodePath) {
+      let nodes = this.state.expandedNodes;
+      if (this.isExpanded(nodePath)) {
+        nodes.delete(nodePath);
+      } else {
+        nodes.add(nodePath);
       }
 
-      // Return value is a 'member' object containing meta-data about
-      // tree node. It describes node label, value, type, etc.
-      return {
-        // An object associated with this node.
-        object: child,
-        // A label for the child node
-        name: provider.getLabel(child),
-        // Data type of the child node (used for CSS customization)
-        type: type,
-        // Class attribute computed from the type.
-        rowClass: "treeRow-" + type,
-        // Level of the child within the hierarchy (top == 0)
-        level: level,
-        // True if this node has children.
-        hasChildren: hasChildren,
-        // Value associated with this node (as provided by the data provider)
-        value: value,
-        // True if the node is expanded.
-        open: this.isExpanded(nodePath),
-        // Node path
-        path: nodePath,
-        // True if the node is hidden (used for filtering)
-        hidden: !this.onFilter(child)
-      };
-    });
-  },
+      // Compute new state and update the tree.
+      this.setState(Object.assign({}, this.state, {
+        expandedNodes: nodes
+      }));
+    },
+
+    isExpanded: function(nodePath) {
+      return this.state.expandedNodes.has(nodePath);
+    },
+
+    // Event Handlers
+
+    onClickRow: function(nodePath, event) {
+      event.stopPropagation();
+      this.toggle(nodePath);
+    },
+
+    // Filtering & Sorting
+
+    /**
+     * Filter out nodes that don't correspond to the current filter.
+     * @return {Boolean} true if the node should be visible otherwise false.
+     */
+    onFilter: function(object) {
+      let onFilter = this.props.onFilter;
+      return onFilter ? onFilter(object) : true;
+    },
+
+    onSort: function(parent, children) {
+      let onSort = this.props.onSort;
+      return onSort ? onSort(parent, children) : children;
+    },
+
+    // Members
+
+    /**
+     * Return children node objects (so called 'members') for given
+     * parent object.
+     */
+    getMembers: function(parent, level, path) {
+      // Strings don't have children. Note that 'long' strings are using
+      // the expander icon (+/-) to display the entire original value,
+      // but there are no child items.
+      if (typeof parent == "string") {
+        return [];
+      }
+
+      let provider = this.props.provider;
+      let children = provider.getChildren(parent) || [];
+
+      // If the return value is non-array, the children
+      // are being loaded asynchronously.
+      if (!Array.isArray(children)) {
+        return children;
+      }
+
+      children = this.onSort(parent, children) || children;
+
+      return children.map(child => {
+        let key = provider.getKey(child);
+        let nodePath = path + "/" + key;
+        let type = provider.getType(child);
+        let hasChildren = provider.hasChildren(child);
+
+        // Value with no column specified is used for optimization.
+        // The row is re-rendered only if this value changes.
+        // Value for actual column is get when a cell is rendered.
+        let value = provider.getValue(child);
+
+        if (isLongString(value)) {
+          hasChildren = true;
+        }
 
-  /**
-   * Render tree rows/nodes.
-   */
-  renderRows: function(parent, level = 0, path = "") {
-    let rows = [];
-    let decorator = this.props.decorator;
-    let renderRow = this.props.renderRow || TreeRow;
+        // Return value is a 'member' object containing meta-data about
+        // tree node. It describes node label, value, type, etc.
+        return {
+          // An object associated with this node.
+          object: child,
+          // A label for the child node
+          name: provider.getLabel(child),
+          // Data type of the child node (used for CSS customization)
+          type: type,
+          // Class attribute computed from the type.
+          rowClass: "treeRow-" + type,
+          // Level of the child within the hierarchy (top == 0)
+          level: level,
+          // True if this node has children.
+          hasChildren: hasChildren,
+          // Value associated with this node (as provided by the data provider)
+          value: value,
+          // True if the node is expanded.
+          open: this.isExpanded(nodePath),
+          // Node path
+          path: nodePath,
+          // True if the node is hidden (used for filtering)
+          hidden: !this.onFilter(child)
+        };
+      });
+    },
+
+    /**
+     * Render tree rows/nodes.
+     */
+    renderRows: function(parent, level = 0, path = "") {
+      let rows = [];
+      let decorator = this.props.decorator;
+      let renderRow = this.props.renderRow || TreeRow;
+
+      // Get children for given parent node, iterate over them and render
+      // a row for every one. Use row template (a component) from properties.
+      // If the return value is non-array, the children are being loaded
+      // asynchronously.
+      let members = this.getMembers(parent, level, path);
+      if (!Array.isArray(members)) {
+        return members;
+      }
+
+      members.forEach(member => {
+        if (decorator && decorator.renderRow) {
+          renderRow = decorator.renderRow(member.object) || renderRow;
+        }
 
-    // Get children for given parent node, iterate over them and render
-    // a row for every one. Use row template (a component) from properties.
-    // If the return value is non-array, the children are being loaded
-    // asynchronously.
-    let members = this.getMembers(parent, level, path);
-    if (!Array.isArray(members)) {
-      return members;
-    }
+        let props = Object.assign({}, this.props, {
+          key: member.path,
+          member: member,
+          columns: this.state.columns,
+          onClick: this.onClickRow.bind(this, member.path)
+        });
+
+        // Render single row.
+        rows.push(renderRow(props));
+
+        // If a child node is expanded render its rows too.
+        if (member.hasChildren && member.open) {
+          let childRows = this.renderRows(member.object, level + 1,
+            member.path);
 
-    members.forEach(member => {
-      if (decorator && decorator.renderRow) {
-        renderRow = decorator.renderRow(member.object) || renderRow;
+          // If children needs to be asynchronously fetched first,
+          // set 'loading' property to the parent row. Otherwise
+          // just append children rows to the array of all rows.
+          if (!Array.isArray(childRows)) {
+            let lastIndex = rows.length - 1;
+            props.member.loading = true;
+            rows[lastIndex] = React.cloneElement(rows[lastIndex], props);
+          } else {
+            rows = rows.concat(childRows);
+          }
+        }
+      });
+
+      return rows;
+    },
+
+    render: function() {
+      let root = this.props.object;
+      let classNames = ["treeTable"];
+
+      // Use custom class name from props.
+      let className = this.props.className;
+      if (className) {
+        classNames.push(...className.split(" "));
+      }
+
+      // Alright, let's render all tree rows. The tree is one big <table>.
+      let rows = this.renderRows(root, 0, "");
+
+      // This happens when the view needs to do initial asynchronous
+      // fetch for the root object. The tree might provide a hook API
+      // for rendering animated spinner (just like for tree nodes).
+      if (!Array.isArray(rows)) {
+        rows = [];
       }
 
       let props = Object.assign({}, this.props, {
-        key: member.path,
-        member: member,
-        columns: this.state.columns,
-        onClick: this.onClickRow.bind(this, member.path)
+        columns: this.state.columns
       });
 
-      // Render single row.
-      rows.push(renderRow(props));
-
-      // If a child node is expanded render its rows too.
-      if (member.hasChildren && member.open) {
-        let childRows = this.renderRows(member.object, level + 1, member.path);
+      return (
+        DOM.table({
+          className: classNames.join(" "),
+          cellPadding: 0,
+          cellSpacing: 0},
+          TreeHeader(props),
+          DOM.tbody({},
+            rows
+          )
+        )
+      );
+    }
+  });
 
-        // If children needs to be asynchronously fetched first,
-        // set 'loading' property to the parent row. Otherwise
-        // just append children rows to the array of all rows.
-        if (!Array.isArray(childRows)) {
-          let lastIndex = rows.length - 1;
-          props.member.loading = true;
-          rows[lastIndex] = React.cloneElement(rows[lastIndex], props);
-        } else {
-          rows = rows.concat(childRows);
-        }
-      }
-    });
+  // Helpers
 
-    return rows;
-  },
-
-  render: function() {
-    let root = this.props.object;
-    let classNames = ["treeTable"];
-
-    // Use custom class name from props.
-    let className = this.props.className;
-    if (className) {
-      classNames.push(...className.split(" "));
+  /**
+   * There should always be at least one column (the one with toggle buttons)
+   * and this function ensures that it's true.
+   */
+  function ensureDefaultColumn(columns) {
+    if (!columns) {
+      columns = [];
     }
 
-    // Alright, let's render all tree rows. The tree is one big <table>.
-    let rows = this.renderRows(root, 0, "");
-
-    // This happens when the view needs to do initial asynchronous
-    // fetch for the root object. The tree might provide a hook API
-    // for rendering animated spinner (just like for tree nodes).
-    if (!Array.isArray(rows)) {
-      rows = [];
+    let defaultColumn = columns.filter(col => col.id == "default");
+    if (defaultColumn.length) {
+      return columns;
     }
 
-    let props = Object.assign({}, this.props, {
-      columns: this.state.columns
-    });
-
-    return (
-      DOM.table({
-        className: classNames.join(" "),
-        cellPadding: 0,
-        cellSpacing: 0},
-        TreeHeader(props),
-        DOM.tbody({},
-          rows
-        )
-      )
-    );
-  }
-});
-
-// Helpers
-
-/**
- * There should always be at least one column (the one with toggle buttons)
- * and this function ensures that it's true.
- */
-function ensureDefaultColumn(columns) {
-  if (!columns) {
-    columns = [];
+    // The default column is usually the first one.
+    return [{id: "default"}, ...columns];
   }
 
-  let defaultColumn = columns.filter(col => col.id == "default");
-  if (defaultColumn.length) {
-    return columns;
+  function isLongString(value) {
+    return typeof value == "string" && value.length > 50;
   }
 
-  // The default column is usually the first one.
-  return [{id: "default"}, ...columns];
-}
-
-function isLongString(value) {
-  return typeof value == "string" && value.length > 50;
-}
-
-// Exports from this module
-module.exports = TreeView;
+  // Exports from this module
+  module.exports = TreeView;
+});