From 536fabf57cb2635dacf0d446db57b517cb0286d1 Mon Sep 17 00:00:00 2001 From: Benjamin Kniffler Date: Wed, 2 Dec 2015 14:11:23 +0100 Subject: [PATCH 1/8] Add childrenField and keyField --- src/components/header.js | 7 ++++--- src/components/node.js | 10 +++++++--- src/components/treebeard.js | 13 +++++++++---- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/components/header.js b/src/components/header.js index 2d6ffbb..ec87b40 100644 --- a/src/components/header.js +++ b/src/components/header.js @@ -10,8 +10,8 @@ class NodeHeader extends React.Component { super(props); } render(){ - const {style, animations, decorators} = this.props; - const terminal = !this.props.node.children; + const {style, animations, decorators, childrenField} = this.props; + const terminal = !this.props.node[childrenField]; const active = this.props.node.active; const linkStyle = [style.link, active ? style.activeLink : null]; return ( @@ -45,7 +45,8 @@ NodeHeader.propTypes = { decorators: React.PropTypes.object.isRequired, animations: React.PropTypes.object.isRequired, node: React.PropTypes.object.isRequired, - onClick: React.PropTypes.func + onClick: React.PropTypes.func, + childrenField: React.PropTypes.string }; export default NodeHeader; diff --git a/src/components/node.js b/src/components/node.js index 255b035..84568bb 100644 --- a/src/components/node.js +++ b/src/components/node.js @@ -54,6 +54,7 @@ class TreeNode extends React.Component { renderHeader(decorators, animations){ return ( - {rutils.children.map(this.props.node.children, (child, index) => + {rutils.children.map(this.props.node[childrenField], (child, index) => {data.map((node, index) => )} @@ -40,13 +42,16 @@ TreeBeard.propTypes = { ]).isRequired, animations: React.PropTypes.object, onToggle: React.PropTypes.func, - decorators: React.PropTypes.object + decorators: React.PropTypes.object, + keyField: React.PropTypes.string, + childrenField: React.PropTypes.string }; TreeBeard.defaultProps = { style: defaultTheme, animations: defaultAnimations, - decorators: defaultDecorators + decorators: defaultDecorators, + childrenField: 'children' }; export default TreeBeard; From 351af061c429e13eb9950a55ba706eba85baae02 Mon Sep 17 00:00:00 2001 From: Benjamin Kniffler Date: Wed, 2 Dec 2015 14:27:15 +0100 Subject: [PATCH 2/8] Allow for functions as key/children fields --- src/components/header.js | 6 +++--- src/components/node.js | 15 +++++++++------ src/components/treebeard.js | 29 ++++++++++++++++++++++------- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/components/header.js b/src/components/header.js index ec87b40..a6d4adb 100644 --- a/src/components/header.js +++ b/src/components/header.js @@ -10,8 +10,8 @@ class NodeHeader extends React.Component { super(props); } render(){ - const {style, animations, decorators, childrenField} = this.props; - const terminal = !this.props.node[childrenField]; + const {style, animations, decorators, childrenGetter} = this.props; + const terminal = !childrenGetter(this.props.node); const active = this.props.node.active; const linkStyle = [style.link, active ? style.activeLink : null]; return ( @@ -46,7 +46,7 @@ NodeHeader.propTypes = { animations: React.PropTypes.object.isRequired, node: React.PropTypes.object.isRequired, onClick: React.PropTypes.func, - childrenField: React.PropTypes.string + childrenGetter: React.PropTypes.func.isRequired }; export default NodeHeader; diff --git a/src/components/node.js b/src/components/node.js index 84568bb..21b5239 100644 --- a/src/components/node.js +++ b/src/components/node.js @@ -52,9 +52,10 @@ class TreeNode extends React.Component { ); } renderHeader(decorators, animations){ + const {childrenGetter} = this.props; return ( - {rutils.children.map(this.props.node[childrenField], (child, index) => + {rutils.children.map(childrenGetter(this.props.node), (child, index) => {data.map((node, index) => )} @@ -42,9 +59,7 @@ TreeBeard.propTypes = { ]).isRequired, animations: React.PropTypes.object, onToggle: React.PropTypes.func, - decorators: React.PropTypes.object, - keyField: React.PropTypes.string, - childrenField: React.PropTypes.string + decorators: React.PropTypes.object }; TreeBeard.defaultProps = { From 9abade14cf48271cd4213ec30e3c99b216375a1d Mon Sep 17 00:00:00 2001 From: Benjamin Kniffler Date: Wed, 2 Dec 2015 14:51:44 +0100 Subject: [PATCH 3/8] Update tests --- test/src/components/header-tests.js | 1 + test/src/components/node-tests.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/test/src/components/header-tests.js b/test/src/components/header-tests.js index 56ac51c..f2bc872 100644 --- a/test/src/components/header-tests.js +++ b/test/src/components/header-tests.js @@ -11,6 +11,7 @@ const factory = require('../utils/factory'); const defaults = { style: {}, node: { children: [] }, + childrenGetter: (node)=>node.children, animations: { toggle: {} }, decorators: factory.createDecorators() }; diff --git a/test/src/components/node-tests.js b/test/src/components/node-tests.js index f22ae40..7fd068c 100644 --- a/test/src/components/node-tests.js +++ b/test/src/components/node-tests.js @@ -11,6 +11,8 @@ const factory = require('../utils/factory'); const defaults = { style: {}, node: { chilren: [] }, + keyGetter: (node, index)=>index, + childrenGetter: (node)=>node.children, animations: factory.createAnimations(), decorators: factory.createDecorators() }; From 55b2a1638cc9080cde3a7b63b9e3c59cb35ab271 Mon Sep 17 00:00:00 2001 From: Benjamin Kniffler Date: Wed, 2 Dec 2015 15:09:16 +0100 Subject: [PATCH 4/8] Allow custom toggleField --- src/components/node.js | 5 +++-- src/components/treebeard.js | 11 ++++++++++- test/src/components/node-tests.js | 7 ++++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/components/node.js b/src/components/node.js index 21b5239..d7f679e 100644 --- a/src/components/node.js +++ b/src/components/node.js @@ -13,7 +13,7 @@ class TreeNode extends React.Component { this.onClick = this.onClick.bind(this); } componentWillReceiveProps(props){ - let toggled = props.node.toggled; + let toggled = props.toggledGetter(props.node); if(toggled !== undefined){ this.setState({ toggled }); } @@ -105,7 +105,8 @@ TreeNode.propTypes = { animations: React.PropTypes.object.isRequired, onToggle: React.PropTypes.func, childrenGetter: React.PropTypes.func.isRequired, - keyGetter: React.PropTypes.func.isRequired + keyGetter: React.PropTypes.func.isRequired, + toggledGetter: React.PropTypes.func.isRequired }; export default TreeNode; diff --git a/src/components/treebeard.js b/src/components/treebeard.js index 9621c99..d912583 100644 --- a/src/components/treebeard.js +++ b/src/components/treebeard.js @@ -28,6 +28,13 @@ class TreeBeard extends React.Component { } return node[childrenField]; } + toggledGetter(node){ + let {toggledField} = this.props; + if(typeof toggledField === 'function'){ + return toggledField(node); + } + return node[toggledField]; + } render(){ let {data} = this.props; // Support Multiple Root Nodes. Its not formally a tree, but its a use-case. @@ -44,6 +51,7 @@ class TreeBeard extends React.Component { style={this.props.style.tree.node} childrenGetter={this.childrenGetter.bind(this)} keyGetter={this.keyGetter.bind(this)} + toggledGetter={this.toggledGetter.bind(this)} /> )} @@ -66,7 +74,8 @@ TreeBeard.defaultProps = { style: defaultTheme, animations: defaultAnimations, decorators: defaultDecorators, - childrenField: 'children' + childrenField: 'children', + toggledField: 'toggled' }; export default TreeBeard; diff --git a/test/src/components/node-tests.js b/test/src/components/node-tests.js index 7fd068c..8266021 100644 --- a/test/src/components/node-tests.js +++ b/test/src/components/node-tests.js @@ -12,7 +12,8 @@ const defaults = { style: {}, node: { chilren: [] }, keyGetter: (node, index)=>index, - childrenGetter: (node)=>node.children, + childrenGetter: node=>node.children, + toggledGetter: node=>node.toggled, animations: factory.createAnimations(), decorators: factory.createDecorators() }; @@ -35,7 +36,7 @@ describe('node component', () => { node={node} /> ); - const changedProps = { node: { toggled: true } }; + const changedProps = { ...defaults, node: { toggled: true } }; treeNode.componentWillReceiveProps(changedProps); treeNode.state.toggled.should.equal(changedProps.node.toggled); }); @@ -47,7 +48,7 @@ describe('node component', () => { node={original} /> ); - const changedProps = { node: { toggled: undefined } }; + const changedProps = { ...defaults, node: { toggled: undefined } }; treeNode.componentWillReceiveProps(changedProps); treeNode.state.toggled.should.equal(original.toggled); }); From 62002eaee9008c7d69f615c30f2970ce8d26b057 Mon Sep 17 00:00:00 2001 From: Benjamin Kniffler Date: Wed, 2 Dec 2015 15:13:02 +0100 Subject: [PATCH 5/8] Fix --- src/components/node.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/node.js b/src/components/node.js index d7f679e..a6b1248 100644 --- a/src/components/node.js +++ b/src/components/node.js @@ -65,7 +65,7 @@ class TreeNode extends React.Component { ); } renderChildren(decorators){ - const {keyGetter, childrenGetter} = this.props; + const {keyGetter, childrenGetter, toggledGetter} = this.props; if(this.props.node.loading){ return this.renderLoading(decorators); } return (
    @@ -75,6 +75,7 @@ class TreeNode extends React.Component { key={keyGetter(child, index)} keyGetter={keyGetter} childrenGetter={childrenGetter} + toggledGetter={toggledGetter} node={child} decorators={this.props.decorators} animations={this.props.animations} From 069f3708b9b0f0bd49881ac92a75eba0de243bc8 Mon Sep 17 00:00:00 2001 From: Benjamin Kniffler Date: Wed, 2 Dec 2015 15:30:50 +0100 Subject: [PATCH 6/8] Cleanup --- src/components/treebeard.js | 49 ++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/src/components/treebeard.js b/src/components/treebeard.js index d912583..901c59d 100644 --- a/src/components/treebeard.js +++ b/src/components/treebeard.js @@ -11,47 +11,29 @@ class TreeBeard extends React.Component { constructor(props){ super(props); } - keyGetter(node, index){ - let {keyField} = this.props; - if(!keyField){ - return index; - } - else if(typeof keyField === 'function'){ - return keyField(node); - } - return node[keyField]; - } - childrenGetter(node){ - let {childrenField} = this.props; - if(typeof childrenField === 'function'){ - return childrenField(node); - } - return node[childrenField]; - } - toggledGetter(node){ - let {toggledField} = this.props; - if(typeof toggledField === 'function'){ - return toggledField(node); - } - return node[toggledField]; - } render(){ let {data} = this.props; // Support Multiple Root Nodes. Its not formally a tree, but its a use-case. if(!Array.isArray(data)){ data = [data]; } + + // Compose children, key and toggled getters + const getters = { + childrenGetter: node=>Getter(node, this.props.childrenField), + keyGetter: (node, index)=>Getter(node, this.props.keyField, index), + toggledGetter: node=>Getter(node, this.props.childrenField) + } + return (
      {data.map((node, index) => )}
    @@ -59,6 +41,17 @@ class TreeBeard extends React.Component { } } +// Helper: Get value by function or property name +function Getter(node, field, defaultValue){ + if(!field){ + return defaultValue; + } + else if(typeof field === 'function'){ + return field(node); + } + return node[field]; +} + TreeBeard.propTypes = { style: React.PropTypes.object, data: React.PropTypes.oneOfType([ From efb873fc1c07e78e59099d188cdcc212f3d8759d Mon Sep 17 00:00:00 2001 From: Benjamin Kniffler Date: Wed, 2 Dec 2015 15:35:58 +0100 Subject: [PATCH 7/8] Outsource getter helper --- src/components/helpers/getter.js | 14 ++++++++++++++ src/components/treebeard.js | 12 +----------- 2 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 src/components/helpers/getter.js diff --git a/src/components/helpers/getter.js b/src/components/helpers/getter.js new file mode 100644 index 0000000..dad7996 --- /dev/null +++ b/src/components/helpers/getter.js @@ -0,0 +1,14 @@ +'use strict'; + +// Helper: Get value by function or property name +function Getter(node, field, defaultValue){ + if(!field){ + return defaultValue; + } + else if(typeof field === 'function'){ + return field(node); + } + return node[field]; +} + +export default Getter; diff --git a/src/components/treebeard.js b/src/components/treebeard.js index 901c59d..17e4d4c 100644 --- a/src/components/treebeard.js +++ b/src/components/treebeard.js @@ -3,6 +3,7 @@ import React from 'react'; import TreeNode from './node'; +import Getter from './helpers/getter'; import defaultDecorators from './decorators'; import defaultTheme from '../themes/default'; import defaultAnimations from '../themes/animations'; @@ -41,17 +42,6 @@ class TreeBeard extends React.Component { } } -// Helper: Get value by function or property name -function Getter(node, field, defaultValue){ - if(!field){ - return defaultValue; - } - else if(typeof field === 'function'){ - return field(node); - } - return node[field]; -} - TreeBeard.propTypes = { style: React.PropTypes.object, data: React.PropTypes.oneOfType([ From 3e28f975888400bb68486d92435704a1b6138c2f Mon Sep 17 00:00:00 2001 From: Benjamin Kniffler Date: Wed, 2 Dec 2015 16:00:02 +0100 Subject: [PATCH 8/8] Bugfix --- src/components/treebeard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/treebeard.js b/src/components/treebeard.js index 17e4d4c..425a889 100644 --- a/src/components/treebeard.js +++ b/src/components/treebeard.js @@ -21,7 +21,7 @@ class TreeBeard extends React.Component { const getters = { childrenGetter: node=>Getter(node, this.props.childrenField), keyGetter: (node, index)=>Getter(node, this.props.keyField, index), - toggledGetter: node=>Getter(node, this.props.childrenField) + toggledGetter: node=>Getter(node, this.props.toggledField) } return (