).
*/
- 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",
+
+ /**
+ * Optimize cell rendering. If value is the same do not render.
+ */
+ shouldComponentUpdate: function(nextProps) {
+ return (this.props.value != nextProps.value);
+ },
+
+ getCellClass: function(object, id) {
+ let decorator = this.props.decorator;
+ if (!decorator || !decorator.getCellClass) {
+ return [];
+ }
+
+ // Decorator can return a simple string or array of strings.
+ let classNames = decorator.getCellClass(object, id);
+ if (!classNames) {
+ return [];
+ }
+
+ if (typeof classNames == "string") {
+ classNames = [classNames];
+ }
+
+ return classNames;
+ },
+
+ 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;
+
+ // Compute class name list for the element.
+ let classNames = this.getCellClass(member.object, id) || [];
+ classNames.push("treeValueCell");
+ classNames.push(type + "Cell");
+
+ // 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;
+ }
+
+ let props = Object.assign({}, this.props, {
+ object: value,
+ });
+
+ // Render me!
+ return (
+ td({ className: classNames.join(" ") },
+ span({}, renderValue(props))
+ )
+ );
}
+ });
- // Decorator can return a simple string or array of strings.
- let classNames = decorator.getCellClass(object, id);
- if (!classNames) {
- return [];
- }
-
- if (typeof classNames == "string") {
- classNames = [classNames];
- }
-
- return classNames;
- },
-
- 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;
-
- // Compute class name list for the | element.
- let classNames = this.getCellClass(member.object, id) || [];
- classNames.push("treeValueCell");
- classNames.push(type + "Cell");
-
- // 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;
- }
-
- let props = Object.assign({}, this.props, {
- object: value,
- });
-
- // Render me!
+ // Default value rendering.
+ let defaultRenderValue = props => {
return (
- td({ className: classNames.join(" ") },
- span({}, renderValue(props))
- )
+ props.object + ""
);
- }
+ };
+
+ // Exports from this module
+ module.exports = TreeCell;
});
-
-// Default value rendering.
-var defaultRenderValue = props => {
- return (
- props.object + ""
- );
-};
-
-// Exports from this module
-module.exports = TreeCell;
diff --git a/devtools/client/shared/components/tree/tree-header.js b/devtools/client/shared/components/tree/tree-header.js
index f41797a001a3..9f760b9ff12d 100644
--- a/devtools/client/shared/components/tree/tree-header.js
+++ b/devtools/client/shared/components/tree/tree-header.js
@@ -5,93 +5,96 @@
* 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 { thead, tr, td, div } = React.DOM;
-const PropTypes = React.PropTypes;
+ // Shortcuts
+ const { thead, tr, td, div } = React.DOM;
+ const PropTypes = React.PropTypes;
-/**
- * This component is responsible for rendering tree header.
- * It's based on 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
- },
+ /**
+ * This component is responsible for rendering tree header.
+ * It's based on 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
+ },
- displayName: "TreeHeader",
+ displayName: "TreeHeader",
- getDefaultProps: function() {
- return {
- columns: [{
- id: "default"
- }]
- };
- },
-
- getHeaderClass: function(colId) {
- let decorator = this.props.decorator;
- if (!decorator || !decorator.getHeaderClass) {
- return [];
- }
-
- // Decorator can return a simple string or array of strings.
- let classNames = decorator.getHeaderClass(colId);
- if (!classNames) {
- return [];
- }
-
- 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 : "",
+ getDefaultProps: function() {
+ return {
+ columns: [{
+ id: "default"
+ }]
};
+ },
- let classNames = [];
-
- if (visible) {
- classNames = this.getHeaderClass(col.id);
- classNames.push("treeHeaderCell");
+ getHeaderClass: function(colId) {
+ let decorator = this.props.decorator;
+ if (!decorator || !decorator.getHeaderClass) {
+ return [];
}
- cells.push(
- td({
- className: classNames.join(" "),
- style: cellStyle,
- key: col.id},
- div({ className: visible ? "treeHeaderCellBox" : "" },
- visible ? col.title : ""
+ // Decorator can return a simple string or array of strings.
+ let classNames = decorator.getHeaderClass(colId);
+ if (!classNames) {
+ return [];
+ }
+
+ 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;
diff --git a/devtools/client/shared/components/tree/tree-row.js b/devtools/client/shared/components/tree/tree-row.js
index 1e5c7deae64d..7eb71bae7665 100644
--- a/devtools/client/shared/components/tree/tree-row.js
+++ b/devtools/client/shared/components/tree/tree-row.js
@@ -5,177 +5,180 @@
* 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");
+// 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");
-// Tree
-const TreeCell = React.createFactory(require("./tree-cell"));
-const LabelCell = React.createFactory(require("./label-cell"));
+ // Tree
+ const TreeCell = React.createFactory(require("./tree-cell"));
+ const LabelCell = React.createFactory(require("./label-cell"));
-// Shortcuts
-const { tr } = React.DOM;
-const PropTypes = React.PropTypes;
-
-/**
- * This template represents a node in TreeView component. It's rendered
- * using element (the entire tree is one big ).
- */
-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
- },
-
- 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 element (the entire tree is one big ).
*/
- 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
+ },
+
+ displayName: "TreeRow",
+
+ /**
+ * 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;
- },
+ return false;
+ },
- 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");
- }
- },
+ 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");
+ }
+ },
- getRowClass: function(object) {
- let decorator = this.props.decorator;
- if (!decorator || !decorator.getRowClass) {
- return [];
- }
+ getRowClass: function(object) {
+ let decorator = this.props.decorator;
+ if (!decorator || !decorator.getRowClass) {
+ return [];
+ }
- // Decorator can return a simple string or array of strings.
- let classNames = decorator.getRowClass(object);
- if (!classNames) {
- return [];
- }
+ // Decorator can return a simple string or array of strings.
+ let classNames = decorator.getRowClass(object);
+ if (!classNames) {
+ return [];
+ }
- if (typeof classNames == "string") {
- classNames = [classNames];
- }
+ if (typeof classNames == "string") {
+ classNames = [classNames];
+ }
- return classNames;
- },
+ return classNames;
+ },
- render: function() {
- let member = this.props.member;
- let decorator = this.props.decorator;
+ render: function() {
+ let member = this.props.member;
+ let decorator = this.props.decorator;
- // Compute class name list for the element.
- let classNames = this.getRowClass(member.object) || [];
- classNames.push("treeRow");
- classNames.push(member.type + "Row");
+ // Compute class name list for the element.
+ let classNames = this.getRowClass(member.object) || [];
+ classNames.push("treeRow");
+ classNames.push(member.type + "Row");
- if (member.hasChildren) {
- classNames.push("hasChildren");
- }
+ if (member.hasChildren) {
+ classNames.push("hasChildren");
+ }
- if (member.open) {
- classNames.push("opened");
- }
+ if (member.open) {
+ classNames.push("opened");
+ }
- if (member.loading) {
- classNames.push("loading");
- }
+ 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);
- }
+ // Render tree row
+ return (
+ tr({
+ className: classNames.join(" "),
+ onClick: this.props.onClick},
+ cells
+ )
+ );
+ }
+ });
- let render = (col.id == "default") ? renderLabelCell : renderCell;
+ // Helpers
- // 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));
- }
- });
+ let RenderCell = props => {
+ return TreeCell(props);
+ };
- // Render tree row
- return (
- tr({
- className: classNames.join(" "),
- onClick: this.props.onClick},
- cells
- )
- );
- }
+ let RenderLabelCell = props => {
+ return LabelCell(props);
+ };
+
+ // Exports from this module
+ module.exports = TreeRow;
});
-
-// Helpers
-
-var RenderCell = props => {
- return TreeCell(props);
-};
-
-var RenderLabelCell = props => {
- return LabelCell(props);
-};
-
-// Exports from this module
-module.exports = TreeRow;
diff --git a/devtools/client/shared/components/tree/tree-view.js b/devtools/client/shared/components/tree/tree-view.js
index cb6e4c8c7c55..04d74a05a88d 100644
--- a/devtools/client/shared/components/tree/tree-view.js
+++ b/devtools/client/shared/components/tree/tree-view.js
@@ -5,344 +5,348 @@
* 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");
-// Reps
-const { ObjectProvider } = require("./object-provider");
-const TreeRow = React.createFactory(require("./tree-row"));
-const TreeHeader = React.createFactory(require("./tree-header"));
+ // 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;
+ // Shortcuts
+ const DOM = React.DOM;
+ const PropTypes = React.PropTypes;
-/**
- * This component represents a tree view with expandable/collapsible nodes.
- * The tree is rendered using element where every node is represented
- * by 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,
+ /**
+ * This component represents a tree view with expandable/collapsible nodes.
+ * The tree is rendered using element where every node is represented
+ * by 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);
+ * }
+ */
+ 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,
- renderCelL: 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,
- }),
- // 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
- }))
- },
+ // 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
+ }))
+ },
- displayName: "TreeView",
+ displayName: "TreeView",
- getDefaultProps: function() {
- return {
- object: null,
- renderRow: null,
- provider: ObjectProvider,
- expandedNodes: new Set(),
- columns: []
- };
- },
+ 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)
- };
- },
+ getInitialState: function() {
+ return {
+ expandedNodes: this.props.expandedNodes,
+ columns: ensureDefaultColumn(this.props.columns)
+ };
+ },
- // Node expand/collapse
+ // 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
-
- /**
- * 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;
+ 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
+ }));
+ },
- /**
- * Render tree rows/nodes.
- */
- renderRows: function(parent, level = 0, path = "") {
- let rows = [];
- let decorator = this.props.decorator;
- let renderRow = this.props.renderRow || TreeRow;
+ isExpanded: function(nodePath) {
+ return this.state.expandedNodes.has(nodePath);
+ },
- // 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;
- }
+ // Event Handlers
- members.forEach(member => {
- if (decorator && decorator.renderRow) {
- renderRow = decorator.renderRow(member.object) || renderRow;
+ 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;
+ }
+
+ // 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;
+ }
+
+ 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);
+
+ // 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 .
+ 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);
-
- // 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 .
- 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, {
- columns: this.state.columns
- });
-
- return (
- DOM.table({
- className: classNames.join(" "),
- cellPadding: 0,
- cellSpacing: 0},
- TreeHeader(props),
- DOM.tbody({},
- rows
+ 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 = [];
+ }
+
+ let defaultColumn = columns.filter(col => col.id == "default");
+ if (defaultColumn.length) {
+ return columns;
+ }
+
+ // 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;
});
-
-// 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 = [];
- }
-
- let defaultColumn = columns.filter(col => col.id == "default");
- if (defaultColumn.length) {
- return columns;
- }
-
- // 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;
|