nexus site path corrected
[portal.git] / ecomp-portal-FE / client / bower_components / jqTree / src / node.coffee
1 $ = jQuery
2
3
4 Position =
5     getName: (position) ->
6         return Position.strings[position - 1]
7
8     nameToIndex: (name) ->
9         for i in [1..Position.strings.length]
10             if Position.strings[i - 1] == name
11                 return i
12         return 0
13
14 Position.BEFORE = 1
15 Position.AFTER = 2
16 Position.INSIDE = 3
17 Position.NONE = 4
18
19 Position.strings = ['before', 'after', 'inside', 'none']
20
21 class Node
22     constructor: (o, is_root=false, node_class=Node) ->
23         @name = ''
24
25         @setData(o)
26
27         @children = []
28         @parent = null
29
30         if is_root
31             @id_mapping = {}
32             @tree = this
33             @node_class = node_class
34
35     setData: (o) ->
36         ###
37         Set the data of this node.
38
39         setData(string): set the name of the node
40         setdata(object): set attributes of the node
41
42         Examples:
43             setdata('node1')
44
45             setData({ name: 'node1', id: 1});
46
47             setData({ name: 'node2', id: 2, color: 'green'});
48
49         * This is an internal function; it is not in the docs
50         * Does not remove existing node values
51         ###
52         setName = (name) =>
53             if name != null
54                 @name = name
55
56         if typeof o != 'object'
57             setName(o)
58         else
59             for key, value of o
60                 if key == 'label'
61                     # You can use the 'label' key instead of 'name'; this is a legacy feature
62                     setName(value)
63                 else if key != 'children'
64                     # You can't update the children using this function
65                     @[key] = value
66
67         return null
68
69     # Init Node from data without making it the root of the tree
70     initFromData: (data) ->
71         addNode = (node_data) =>
72             @setData(node_data)
73
74             if node_data.children
75                 addChildren(node_data.children)
76
77         addChildren = (children_data) =>
78             for child in children_data
79                 node = new @tree.node_class('')
80                 node.initFromData(child)
81                 @addChild(node)
82             return null
83
84         addNode(data)
85         return null
86
87     ###
88     Create tree from data.
89
90     Structure of data is:
91     [
92         {
93             label: 'node1',
94             children: [
95                 { label: 'child1' },
96                 { label: 'child2' }
97             ]
98         },
99         {
100             label: 'node2'
101         }
102     ]
103     ###
104     loadFromData: (data) ->
105         @removeChildren()
106
107         for o in data
108             node = new @tree.node_class(o)
109             @addChild(node)
110
111             if typeof o == 'object' and o.children
112                 node.loadFromData(o.children)
113
114         return null
115
116     ###
117     Add child.
118
119     tree.addChild(
120         new Node('child1')
121     );
122     ###
123     addChild: (node) ->
124         @children.push(node)
125         node._setParent(this)
126
127     ###
128     Add child at position. Index starts at 0.
129
130     tree.addChildAtPosition(
131         new Node('abc'),
132         1
133     );
134     ###
135     addChildAtPosition: (node, index) ->
136         @children.splice(index, 0, node)
137         node._setParent(this)
138
139     _setParent: (parent) ->
140         @parent = parent
141         @tree = parent.tree
142         @tree.addNodeToIndex(this)
143
144     ###
145     Remove child. This also removes the children of the node.
146
147     tree.removeChild(tree.children[0]);
148     ###
149     removeChild: (node) ->
150         # remove children from the index
151         node.removeChildren()
152
153         @_removeChild(node)
154
155     _removeChild: (node) ->
156         @children.splice(
157             @getChildIndex(node),
158             1
159         )
160         @tree.removeNodeFromIndex(node)
161
162     ###
163     Get child index.
164
165     var index = getChildIndex(node);
166     ###
167     getChildIndex: (node) ->
168         return $.inArray(node, @children)
169
170     ###
171     Does the tree have children?
172
173     if (tree.hasChildren()) {
174         //
175     }
176     ###
177     hasChildren: ->
178         return @children.length != 0
179
180     isFolder: ->
181         return @hasChildren() or @load_on_demand
182
183     ###
184     Iterate over all the nodes in the tree.
185
186     Calls callback with (node, level).
187
188     The callback must return true to continue the iteration on current node.
189
190     tree.iterate(
191         function(node, level) {
192            console.log(node.name);
193
194            // stop iteration after level 2
195            return (level <= 2);
196         }
197     );
198
199     ###
200     iterate: (callback) ->
201         _iterate = (node, level) ->
202             if node.children
203                 for child in node.children
204                     result = callback(child, level)
205
206                     if result and child.hasChildren()
207                         _iterate(child, level + 1)
208                 return null
209
210         _iterate(this, 0)
211         return null
212
213     ###
214     Move node relative to another node.
215
216     Argument position: Position.BEFORE, Position.AFTER or Position.Inside
217
218     // move node1 after node2
219     tree.moveNode(node1, node2, Position.AFTER);
220     ###
221     moveNode: (moved_node, target_node, position) ->
222         if moved_node.isParentOf(target_node)
223             # Node is parent of target node. This is an illegal move
224             return
225
226         moved_node.parent._removeChild(moved_node)
227         if position == Position.AFTER
228             target_node.parent.addChildAtPosition(
229                 moved_node,
230                 target_node.parent.getChildIndex(target_node) + 1
231             )
232         else if position == Position.BEFORE
233             target_node.parent.addChildAtPosition(
234                 moved_node,
235                 target_node.parent.getChildIndex(target_node)
236             )
237         else if position == Position.INSIDE
238             # move inside as first child
239             target_node.addChildAtPosition(moved_node, 0)
240
241     ###
242     Get the tree as data.
243     ###
244     getData: (include_parent=false) ->
245         getDataFromNodes = (nodes) ->
246             data = []
247
248             for node in nodes
249                 tmp_node = {}
250
251                 for k, v of node
252                     if (
253                         k not in ['parent', 'children', 'element', 'tree'] and
254                         Object.prototype.hasOwnProperty.call(node, k)
255                     )
256                         tmp_node[k] = v
257
258                 if node.hasChildren()
259                     tmp_node.children = getDataFromNodes(node.children)
260
261                 data.push(tmp_node)
262
263             return data
264
265         if include_parent
266             return getDataFromNodes([this])
267         else
268             return getDataFromNodes(@children)
269
270     getNodeByName: (name) ->
271         return @getNodeByCallback(
272             (node) -> (node.name == name)
273         )
274
275     getNodeByCallback: (callback) ->
276         result = null
277
278         @iterate(
279             (node) ->
280                 if callback(node)
281                     result = node
282                     return false
283                 else
284                     return true
285         )
286
287         return result
288
289
290     addAfter: (node_info) ->
291         if not @parent
292             return null
293         else
294             node = new @tree.node_class(node_info)
295
296             child_index = @parent.getChildIndex(this)
297             @parent.addChildAtPosition(node, child_index + 1)
298
299             if typeof node_info == 'object' and node_info.children and node_info.children.length
300                 node.loadFromData(node_info.children)
301
302             return node
303
304     addBefore: (node_info) ->
305         if not @parent
306             return null
307         else
308             node = new @tree.node_class(node_info)
309
310             child_index = @parent.getChildIndex(this)
311             @parent.addChildAtPosition(node, child_index)
312
313             if typeof node_info == 'object' and node_info.children and node_info.children.length
314                 node.loadFromData(node_info.children)
315
316             return node
317
318     addParent: (node_info) ->
319         if not @parent
320             return null
321         else
322             new_parent = new @tree.node_class(node_info)
323             new_parent._setParent(@tree)
324             original_parent = @parent
325
326             for child in original_parent.children
327                 new_parent.addChild(child)
328
329             original_parent.children = []
330             original_parent.addChild(new_parent)
331             return new_parent
332
333     remove: ->
334         if @parent
335             @parent.removeChild(this)
336             @parent = null
337
338     append: (node_info) ->
339         node = new @tree.node_class(node_info)
340         @addChild(node)
341
342         if typeof node_info == 'object' and node_info.children and node_info.children.length
343             node.loadFromData(node_info.children)
344
345         return node
346
347     prepend: (node_info) ->
348         node = new @tree.node_class(node_info)
349         @addChildAtPosition(node, 0)
350
351         if typeof node_info == 'object' and node_info.children and node_info.children.length
352             node.loadFromData(node_info.children)
353
354         return node
355
356     isParentOf: (node) ->
357         parent = node.parent
358
359         while parent
360             if parent == this
361                 return true
362
363             parent = parent.parent
364
365         return false
366
367     getLevel: ->
368         level = 0
369         node = this
370
371         while node.parent
372             level += 1
373             node = node.parent
374
375         return level
376
377     getNodeById: (node_id) ->
378         return @id_mapping[node_id]
379
380     addNodeToIndex: (node) ->
381         if node.id?
382             @id_mapping[node.id] = node
383
384     removeNodeFromIndex: (node) ->
385         if node.id?
386             delete @id_mapping[node.id]
387
388     removeChildren: ->
389         @iterate(
390             (child) =>
391                 @tree.removeNodeFromIndex(child)
392                 return true
393         )
394
395         @children = []
396
397     getPreviousSibling: ->
398         if not @parent
399             return null
400         else
401             previous_index = @parent.getChildIndex(this) - 1
402             if previous_index >= 0
403                 return @parent.children[previous_index]
404             else
405                 return null
406
407     getNextSibling: ->
408         if not @parent
409             return null
410         else
411             next_index = @parent.getChildIndex(this) + 1
412             if next_index < @parent.children.length
413                 return @parent.children[next_index]
414             else
415                 return null
416
417     getNodesByProperty: (key, value) ->
418         return @filter(
419             (node) ->
420                 return node[key] == value
421         )
422
423     filter: (f) ->
424         result = []
425
426         @iterate(
427             (node) ->
428                 if f(node)
429                     result.push(node)
430
431                 return true
432         )
433
434         return result
435
436     getNextNode: (include_children=true) ->
437         if include_children and @hasChildren() and @is_open
438             # First child
439             return @children[0]
440         else
441             if not @parent
442                 return null
443             else
444                 next_sibling = @getNextSibling()
445                 if next_sibling
446                     # Next sibling
447                     return next_sibling
448                 else
449                     # Next node of parent
450                     return @parent.getNextNode(false)
451
452     getPreviousNode: ->
453         if not @parent
454             return null
455         else
456             previous_sibling = @getPreviousSibling()
457             if previous_sibling
458                 if not previous_sibling.hasChildren() or not previous_sibling.is_open
459                     # Previous sibling
460                     return previous_sibling
461                 else
462                     # Last child of previous sibling
463                     return previous_sibling.getLastChild()
464             else
465                 return @getParent()
466
467     getParent: ->
468         # Return parent except if it is the root node
469         if not @parent
470             return null
471         else if not @parent.parent
472             # Root node -> null
473             return null
474         else
475             return @parent
476
477     getLastChild: ->
478         if not @hasChildren()
479             return null
480         else
481             last_child = @children[@children.length - 1]
482             if not last_child.hasChildren() or not last_child.is_open
483                 return last_child
484             else
485                 return last_child.getLastChild()
486
487
488 module.exports =
489     Node: Node
490     Position: Position