Add support for Map nodes

This commit is contained in:
Bill Noon 2015-08-13 12:16:51 -04:00
parent 644a202312
commit 79f1fee048
3 changed files with 130 additions and 0 deletions

View File

@ -0,0 +1,124 @@
import React from 'react';
import reactMixin from 'react-mixin';
import { ExpandedStateHandlerMixin } from './mixins';
import JSONArrow from './JSONArrow';
import grabNode from './grab-node';
const styles = {
base: {
position: 'relative',
paddingTop: 3,
paddingBottom: 3,
marginLeft: 14
},
label: {
margin: 0,
padding: 0,
display: 'inline-block'
},
span: {
cursor: 'default'
},
spanType: {
marginLeft: 5,
marginRight: 5
}
};
@reactMixin.decorate(ExpandedStateHandlerMixin)
export default class JSONMapNode extends React.Component {
defaultProps = {
data: [],
initialExpanded: false
};
// cache store for the number of items string we display
itemString = false;
// flag to see if we still need to render our child nodes
needsChildNodes = true;
// cache store for our child nodes
renderedChildren = [];
constructor(props) {
super(props);
this.state = {
expanded: this.props.initialExpanded,
createdChildNodes: false
};
}
// Returns the child nodes for each element in the object. If we have
// generated them previously, we return from cache, otherwise we create
// them.
getChildNodes() {
if (this.state.expanded && this.needsChildNodes) {
const map = this.props.data;
let childNodes = [];
map.forEach( (v, k) => {
let prevData;
if (typeof this.props.previousData !== 'undefined') {
if (this.props.previousData.has(k)) prevData = this.props.previousData.get(k);
}
const node = grabNode(k, v, prevData, this.props.theme);
if (node !== false) {
childNodes.push(node);
}
});
this.needsChildNodes = false;
this.renderedChildren = childNodes;
}
return this.renderedChildren;
}
// Returns the "n Items" string for this node, generating and
// caching it if it hasn't been created yet.
getItemString() {
if (!this.itemString) {
const len = this.props.data.size;
this.itemString = len + ' item' + (len !== 1 ? 's' : '');
}
return this.itemString;
}
render() {
let childListStyle = {
padding: 0,
margin: 0,
listStyle: 'none',
display: (this.state.expanded) ? 'block' : 'none'
};
let containerStyle;
let spanStyle = {
...styles.span,
color: this.props.theme.base0B
};
containerStyle = {
...styles.base
};
if (this.state.expanded) {
spanStyle = {
...spanStyle,
color: this.props.theme.base03
};
}
return (
<li style={containerStyle}>
<JSONArrow theme={this.props.theme} open={this.state.expanded} onClick={::this.handleClick}/>
<label style={{
...styles.label,
color: this.props.theme.base0D
}} onClick={::this.handleClick}>
{this.props.keyName}:
</label>
<span style={spanStyle} onClick={::this.handleClick}>
<span style={styles.spanType}>Map</span>
{this.getItemString()}
</span>
<ul style={childListStyle}>
{this.getChildNodes()}
</ul>
</li>
);
}
}

View File

@ -2,6 +2,7 @@ import React from 'react';
import objType from './obj-type'; import objType from './obj-type';
import JSONObjectNode from './JSONObjectNode'; import JSONObjectNode from './JSONObjectNode';
import JSONArrayNode from './JSONArrayNode'; import JSONArrayNode from './JSONArrayNode';
import JSONMapNode from './JSONMapNode';
import JSONStringNode from './JSONStringNode'; import JSONStringNode from './JSONStringNode';
import JSONNumberNode from './JSONNumberNode'; import JSONNumberNode from './JSONNumberNode';
import JSONBooleanNode from './JSONBooleanNode'; import JSONBooleanNode from './JSONBooleanNode';
@ -13,6 +14,8 @@ export default function(key, value, prevValue, theme) {
return <JSONObjectNode data={value} previousData={prevValue} theme={theme} keyName={key} key={key} />; return <JSONObjectNode data={value} previousData={prevValue} theme={theme} keyName={key} key={key} />;
} else if (nodeType === 'Array') { } else if (nodeType === 'Array') {
return <JSONArrayNode data={value} previousData={prevValue} theme={theme} keyName={key} key={key} />; return <JSONArrayNode data={value} previousData={prevValue} theme={theme} keyName={key} key={key} />;
} else if (nodeType === 'Map') {
return <JSONMapNode data={value} previousData={prevValue} theme={theme} keyName={key} key={key} />;
} else if (nodeType === 'String') { } else if (nodeType === 'String') {
return <JSONStringNode keyName={key} previousValue={prevValue} theme={theme} value={value} key={key} />; return <JSONStringNode keyName={key} previousValue={prevValue} theme={theme} value={value} key={key} />;
} else if (nodeType === 'Number') { } else if (nodeType === 'Number') {

View File

@ -7,6 +7,7 @@ import React from 'react';
import objectType from './obj-type'; import objectType from './obj-type';
import JSONObjectNode from './JSONObjectNode'; import JSONObjectNode from './JSONObjectNode';
import JSONArrayNode from './JSONArrayNode'; import JSONArrayNode from './JSONArrayNode';
import JSONMapNode from './JSONMapNode';
const styles = { const styles = {
tree: { tree: {
@ -43,6 +44,8 @@ export default class JSONTree extends React.Component {
rootNode = <JSONObjectNode theme={this.props.theme} data={this.props.data} previousData={this.props.previousData} keyName={keyName} initialExpanded={true} />; rootNode = <JSONObjectNode theme={this.props.theme} data={this.props.data} previousData={this.props.previousData} keyName={keyName} initialExpanded={true} />;
} else if (nodeType === 'Array') { } else if (nodeType === 'Array') {
rootNode = <JSONArrayNode theme={this.props.theme} data={this.props.data} previousData={this.props.previousData} initialExpanded={true} keyName={keyName} />; rootNode = <JSONArrayNode theme={this.props.theme} data={this.props.data} previousData={this.props.previousData} initialExpanded={true} keyName={keyName} />;
} else if (nodeType === 'Map') {
rootNode = <JSONMapNode theme={this.props.theme} data={this.props.data} previousData={this.props.previousData} initialExpanded={true} keyName={keyName} />;
} }
return ( return (
<ul style={{ <ul style={{