6 getName: function(position) {
7 return Position.strings[position - 1];
9 nameToIndex: function(name) {
11 for (i = j = 1, ref = Position.strings.length; 1 <= ref ? j <= ref : j >= ref; i = 1 <= ref ? ++j : --j) {
12 if (Position.strings[i - 1] === name) {
28 Position.strings = ['before', 'after', 'inside', 'none'];
31 function Node(o, is_root, node_class) {
32 if (is_root == null) {
35 if (node_class == null) {
45 this.node_class = node_class;
49 Node.prototype.setData = function(o) {
52 Set the data of this node.
54 setData(string): set the name of the node
55 setdata(object): set attributes of the node
60 setData({ name: 'node1', id: 1});
62 setData({ name: 'node2', id: 2, color: 'green'});
64 * This is an internal function; it is not in the docs
65 * Does not remove existing node values
67 var key, setName, value;
68 setName = (function(_this) {
69 return function(name) {
71 return _this.name = name;
75 if (typeof o !== 'object') {
80 if (key === 'label') {
82 } else if (key !== 'children') {
90 Node.prototype.initFromData = function(data) {
91 var addChildren, addNode;
92 addNode = (function(_this) {
93 return function(node_data) {
94 _this.setData(node_data);
95 if (node_data.children) {
96 return addChildren(node_data.children);
100 addChildren = (function(_this) {
101 return function(children_data) {
102 var child, j, len, node;
103 for (j = 0, len = children_data.length; j < len; j++) {
104 child = children_data[j];
105 node = new _this.tree.node_class('');
106 node.initFromData(child);
107 _this.addChild(node);
118 Create tree from data.
120 Structure of data is:
135 Node.prototype.loadFromData = function(data) {
137 this.removeChildren();
138 for (j = 0, len = data.length; j < len; j++) {
140 node = new this.tree.node_class(o);
142 if (typeof o === 'object' && o.children) {
143 node.loadFromData(o.children);
158 Node.prototype.addChild = function(node) {
159 this.children.push(node);
160 return node._setParent(this);
165 Add child at position. Index starts at 0.
167 tree.addChildAtPosition(
173 Node.prototype.addChildAtPosition = function(node, index) {
174 this.children.splice(index, 0, node);
175 return node._setParent(this);
178 Node.prototype._setParent = function(parent) {
179 this.parent = parent;
180 this.tree = parent.tree;
181 return this.tree.addNodeToIndex(this);
186 Remove child. This also removes the children of the node.
188 tree.removeChild(tree.children[0]);
191 Node.prototype.removeChild = function(node) {
192 node.removeChildren();
193 return this._removeChild(node);
196 Node.prototype._removeChild = function(node) {
197 this.children.splice(this.getChildIndex(node), 1);
198 return this.tree.removeNodeFromIndex(node);
205 var index = getChildIndex(node);
208 Node.prototype.getChildIndex = function(node) {
209 return $.inArray(node, this.children);
214 Does the tree have children?
216 if (tree.hasChildren()) {
221 Node.prototype.hasChildren = function() {
222 return this.children.length !== 0;
225 Node.prototype.isFolder = function() {
226 return this.hasChildren() || this.load_on_demand;
231 Iterate over all the nodes in the tree.
233 Calls callback with (node, level).
235 The callback must return true to continue the iteration on current node.
238 function(node, level) {
239 console.log(node.name);
241 // stop iteration after level 2
247 Node.prototype.iterate = function(callback) {
249 _iterate = function(node, level) {
250 var child, j, len, ref, result;
253 for (j = 0, len = ref.length; j < len; j++) {
255 result = callback(child, level);
256 if (result && child.hasChildren()) {
257 _iterate(child, level + 1);
269 Move node relative to another node.
271 Argument position: Position.BEFORE, Position.AFTER or Position.Inside
273 // move node1 after node2
274 tree.moveNode(node1, node2, Position.AFTER);
277 Node.prototype.moveNode = function(moved_node, target_node, position) {
278 if (moved_node.isParentOf(target_node)) {
281 moved_node.parent._removeChild(moved_node);
282 if (position === Position.AFTER) {
283 return target_node.parent.addChildAtPosition(moved_node, target_node.parent.getChildIndex(target_node) + 1);
284 } else if (position === Position.BEFORE) {
285 return target_node.parent.addChildAtPosition(moved_node, target_node.parent.getChildIndex(target_node));
286 } else if (position === Position.INSIDE) {
287 return target_node.addChildAtPosition(moved_node, 0);
293 Get the tree as data.
296 Node.prototype.getData = function(include_parent) {
297 var getDataFromNodes;
298 if (include_parent == null) {
299 include_parent = false;
301 getDataFromNodes = function(nodes) {
302 var data, j, k, len, node, tmp_node, v;
304 for (j = 0, len = nodes.length; j < len; j++) {
309 if ((k !== 'parent' && k !== 'children' && k !== 'element' && k !== 'tree') && Object.prototype.hasOwnProperty.call(node, k)) {
313 if (node.hasChildren()) {
314 tmp_node.children = getDataFromNodes(node.children);
320 if (include_parent) {
321 return getDataFromNodes([this]);
323 return getDataFromNodes(this.children);
327 Node.prototype.getNodeByName = function(name) {
328 return this.getNodeByCallback(function(node) {
329 return node.name === name;
333 Node.prototype.getNodeByCallback = function(callback) {
336 this.iterate(function(node) {
337 if (callback(node)) {
347 Node.prototype.addAfter = function(node_info) {
348 var child_index, node;
352 node = new this.tree.node_class(node_info);
353 child_index = this.parent.getChildIndex(this);
354 this.parent.addChildAtPosition(node, child_index + 1);
355 if (typeof node_info === 'object' && node_info.children && node_info.children.length) {
356 node.loadFromData(node_info.children);
362 Node.prototype.addBefore = function(node_info) {
363 var child_index, node;
367 node = new this.tree.node_class(node_info);
368 child_index = this.parent.getChildIndex(this);
369 this.parent.addChildAtPosition(node, child_index);
370 if (typeof node_info === 'object' && node_info.children && node_info.children.length) {
371 node.loadFromData(node_info.children);
377 Node.prototype.addParent = function(node_info) {
378 var child, j, len, new_parent, original_parent, ref;
382 new_parent = new this.tree.node_class(node_info);
383 new_parent._setParent(this.tree);
384 original_parent = this.parent;
385 ref = original_parent.children;
386 for (j = 0, len = ref.length; j < len; j++) {
388 new_parent.addChild(child);
390 original_parent.children = [];
391 original_parent.addChild(new_parent);
396 Node.prototype.remove = function() {
398 this.parent.removeChild(this);
399 return this.parent = null;
403 Node.prototype.append = function(node_info) {
405 node = new this.tree.node_class(node_info);
407 if (typeof node_info === 'object' && node_info.children && node_info.children.length) {
408 node.loadFromData(node_info.children);
413 Node.prototype.prepend = function(node_info) {
415 node = new this.tree.node_class(node_info);
416 this.addChildAtPosition(node, 0);
417 if (typeof node_info === 'object' && node_info.children && node_info.children.length) {
418 node.loadFromData(node_info.children);
423 Node.prototype.isParentOf = function(node) {
425 parent = node.parent;
427 if (parent === this) {
430 parent = parent.parent;
435 Node.prototype.getLevel = function() {
439 while (node.parent) {
446 Node.prototype.getNodeById = function(node_id) {
447 return this.id_mapping[node_id];
450 Node.prototype.addNodeToIndex = function(node) {
451 if (node.id != null) {
452 return this.id_mapping[node.id] = node;
456 Node.prototype.removeNodeFromIndex = function(node) {
457 if (node.id != null) {
458 return delete this.id_mapping[node.id];
462 Node.prototype.removeChildren = function() {
463 this.iterate((function(_this) {
464 return function(child) {
465 _this.tree.removeNodeFromIndex(child);
469 return this.children = [];
472 Node.prototype.getPreviousSibling = function() {
477 previous_index = this.parent.getChildIndex(this) - 1;
478 if (previous_index >= 0) {
479 return this.parent.children[previous_index];
486 Node.prototype.getNextSibling = function() {
491 next_index = this.parent.getChildIndex(this) + 1;
492 if (next_index < this.parent.children.length) {
493 return this.parent.children[next_index];
500 Node.prototype.getNodesByProperty = function(key, value) {
501 return this.filter(function(node) {
502 return node[key] === value;
506 Node.prototype.filter = function(f) {
509 this.iterate(function(node) {
518 Node.prototype.getNextNode = function(include_children) {
520 if (include_children == null) {
521 include_children = true;
523 if (include_children && this.hasChildren() && this.is_open) {
524 return this.children[0];
529 next_sibling = this.getNextSibling();
533 return this.parent.getNextNode(false);
539 Node.prototype.getPreviousNode = function() {
540 var previous_sibling;
544 previous_sibling = this.getPreviousSibling();
545 if (previous_sibling) {
546 if (!previous_sibling.hasChildren() || !previous_sibling.is_open) {
547 return previous_sibling;
549 return previous_sibling.getLastChild();
552 return this.getParent();
557 Node.prototype.getParent = function() {
560 } else if (!this.parent.parent) {
567 Node.prototype.getLastChild = function() {
569 if (!this.hasChildren()) {
572 last_child = this.children[this.children.length - 1];
573 if (!last_child.hasChildren() || !last_child.is_open) {
576 return last_child.getLastChild();