-
Notifications
You must be signed in to change notification settings - Fork 0
/
tree-browser.nonjsx.js
162 lines (155 loc) · 5.58 KB
/
tree-browser.nonjsx.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// TODO: REMOVE THIS GENERATED FILE FROM SOURCE AND USE REACT TOOLS FOR AUTO TRANSFORM
// IIFE to prevent global variable pollution.
var TreeBrowser = (function () {
"use strict";
/**
* Prefixes css class names to allow usage of component in web applications
* without worry about namespace collision.
* @param className
* @returns {string}
*/
function getCSSPrefix(className) {
return "react-tree-browser-" + className;
}
/**
* Method that returns false if input is non empty array.
* @param array
* @returns {boolean}
*/
function isEmpty(array) {
if (Array.isArray(array) && array.length > 0) {
return false;
}
return true;
}
/**
* TreeBrowser Component
* This component is responsible for defining the interface for
* the tree component and delegating rendering of nodes to the TreeNode
*/
var TreeBrowser = React.createClass({displayName: "TreeBrowser",
getInitialState: function () {
return this.props.data;
},
/**
* Method to update tree data after render.
* @param data
*/
setData: function(data) {
this.setState({ data: data });
},
/**
* A single click handler that handles all tree node clicks.
* This method ensures that click target is valid and traverse up the dom to
* figure out which data point in the component state to toggle collapse.
* @param event The click event
*/
_handleClick: function(event) {
var paths = this.refs.treeRoot.getPathForContainedNode($(event.target));
if (paths != null) {
var clickedNode = this._findNodeFromPathArray(paths);
clickedNode.collapse = !clickedNode.collapse;
this.forceUpdate();
}
},
/**
* Finds data for node given it's path, where a path represents a name of a node to traverse.
* @param paths Array of names
* @returns {node}
*/
_findNodeFromPathArray: function(paths) {
var nodePointer = { children: this.state.data };
paths.forEach(function(path) {
// Short circuit as soon as you find node with path as name
nodePointer.children.some(function(node) {
nodePointer = node;
return node.name === path;
});
});
return nodePointer;
},
render: function () {
return (
React.createElement("div", {className: getCSSPrefix("container")},
React.createElement("ul", {"data-root": "true", onClick: this._handleClick},
React.createElement(TreeNode, {ref: "treeRoot", data: this.state.data})
)
)
);
}
});
var TreeNode = React.createClass({displayName: "TreeNode",
/**
* Responsible applying right classes for styling based on node state (adding icons via css etc).
* @param node
* @returns {string}
*/
getNodeClass: function(node) {
var classes;
if (isEmpty(node.children)) {
classes = getCSSPrefix("leaf");
} else {
classes = getCSSPrefix("node");
}
return node.collapse ? classes + " " + getCSSPrefix("collapsed") : classes;
},
/**
* Given an element in subtree, returns it's path from the root.
* @param target
* @returns {*}
*/
getPathForContainedNode: function(target) {
var paths = [];
if (target.hasClass(getCSSPrefix("node"))) {
while (target && !target.data("root")) { // while not root node
if (isEmpty(paths)) {
paths.unshift(target.text());
} else {
paths.unshift(target.prev().text());
}
// Traverse additional parent because react is adding an extraneous container.
target = target.parent().parent();
}
return paths;
}
return null;
},
render: function () {
var treeNodes = this.props.data.map(function (node) {
var nodeFragment = [
React.createElement("li", {className: this.getNodeClass(node)},
node.name
)
];
if (!node.collapse && !isEmpty(node.children)) {
nodeFragment.push(
React.createElement("ul", null,
React.createElement(TreeNode, {data: node.children})
)
);
}
return nodeFragment;
}, this);
return (
React.createElement("div", {className: getCSSPrefix("node-level")},
treeNodes
)
);
}
});
return {
/**
* Creates a tree browser component.
* @param cssSelector Css selector to render item to.
* @param data Optional initial tree data to render
* @return {TreeBrowser}
*/
create: function(cssSelector, data) {
data = { data: data || [] };
return React.render(
React.createElement(TreeBrowser, {data: data}),
$(cssSelector)[0]
);
}
};
})();