Initial OpenECOMP Portal commit
[portal.git] / ecomp-portal-FE / client / bower_components / jqTree / src / node.coffee
diff --git a/ecomp-portal-FE/client/bower_components/jqTree/src/node.coffee b/ecomp-portal-FE/client/bower_components/jqTree/src/node.coffee
new file mode 100644 (file)
index 0000000..5af050a
--- /dev/null
@@ -0,0 +1,490 @@
+$ = jQuery
+
+
+Position =
+    getName: (position) ->
+        return Position.strings[position - 1]
+
+    nameToIndex: (name) ->
+        for i in [1..Position.strings.length]
+            if Position.strings[i - 1] == name
+                return i
+        return 0
+
+Position.BEFORE = 1
+Position.AFTER = 2
+Position.INSIDE = 3
+Position.NONE = 4
+
+Position.strings = ['before', 'after', 'inside', 'none']
+
+class Node
+    constructor: (o, is_root=false, node_class=Node) ->
+        @name = ''
+
+        @setData(o)
+
+        @children = []
+        @parent = null
+
+        if is_root
+            @id_mapping = {}
+            @tree = this
+            @node_class = node_class
+
+    setData: (o) ->
+        ###
+        Set the data of this node.
+
+        setData(string): set the name of the node
+        setdata(object): set attributes of the node
+
+        Examples:
+            setdata('node1')
+
+            setData({ name: 'node1', id: 1});
+
+            setData({ name: 'node2', id: 2, color: 'green'});
+
+        * This is an internal function; it is not in the docs
+        * Does not remove existing node values
+        ###
+        setName = (name) =>
+            if name != null
+                @name = name
+
+        if typeof o != 'object'
+            setName(o)
+        else
+            for key, value of o
+                if key == 'label'
+                    # You can use the 'label' key instead of 'name'; this is a legacy feature
+                    setName(value)
+                else if key != 'children'
+                    # You can't update the children using this function
+                    @[key] = value
+
+        return null
+
+    # Init Node from data without making it the root of the tree
+    initFromData: (data) ->
+        addNode = (node_data) =>
+            @setData(node_data)
+
+            if node_data.children
+                addChildren(node_data.children)
+
+        addChildren = (children_data) =>
+            for child in children_data
+                node = new @tree.node_class('')
+                node.initFromData(child)
+                @addChild(node)
+            return null
+
+        addNode(data)
+        return null
+
+    ###
+    Create tree from data.
+
+    Structure of data is:
+    [
+        {
+            label: 'node1',
+            children: [
+                { label: 'child1' },
+                { label: 'child2' }
+            ]
+        },
+        {
+            label: 'node2'
+        }
+    ]
+    ###
+    loadFromData: (data) ->
+        @removeChildren()
+
+        for o in data
+            node = new @tree.node_class(o)
+            @addChild(node)
+
+            if typeof o == 'object' and o.children
+                node.loadFromData(o.children)
+
+        return null
+
+    ###
+    Add child.
+
+    tree.addChild(
+        new Node('child1')
+    );
+    ###
+    addChild: (node) ->
+        @children.push(node)
+        node._setParent(this)
+
+    ###
+    Add child at position. Index starts at 0.
+
+    tree.addChildAtPosition(
+        new Node('abc'),
+        1
+    );
+    ###
+    addChildAtPosition: (node, index) ->
+        @children.splice(index, 0, node)
+        node._setParent(this)
+
+    _setParent: (parent) ->
+        @parent = parent
+        @tree = parent.tree
+        @tree.addNodeToIndex(this)
+
+    ###
+    Remove child. This also removes the children of the node.
+
+    tree.removeChild(tree.children[0]);
+    ###
+    removeChild: (node) ->
+        # remove children from the index
+        node.removeChildren()
+
+        @_removeChild(node)
+
+    _removeChild: (node) ->
+        @children.splice(
+            @getChildIndex(node),
+            1
+        )
+        @tree.removeNodeFromIndex(node)
+
+    ###
+    Get child index.
+
+    var index = getChildIndex(node);
+    ###
+    getChildIndex: (node) ->
+        return $.inArray(node, @children)
+
+    ###
+    Does the tree have children?
+
+    if (tree.hasChildren()) {
+        //
+    }
+    ###
+    hasChildren: ->
+        return @children.length != 0
+
+    isFolder: ->
+        return @hasChildren() or @load_on_demand
+
+    ###
+    Iterate over all the nodes in the tree.
+
+    Calls callback with (node, level).
+
+    The callback must return true to continue the iteration on current node.
+
+    tree.iterate(
+        function(node, level) {
+           console.log(node.name);
+
+           // stop iteration after level 2
+           return (level <= 2);
+        }
+    );
+
+    ###
+    iterate: (callback) ->
+        _iterate = (node, level) ->
+            if node.children
+                for child in node.children
+                    result = callback(child, level)
+
+                    if result and child.hasChildren()
+                        _iterate(child, level + 1)
+                return null
+
+        _iterate(this, 0)
+        return null
+
+    ###
+    Move node relative to another node.
+
+    Argument position: Position.BEFORE, Position.AFTER or Position.Inside
+
+    // move node1 after node2
+    tree.moveNode(node1, node2, Position.AFTER);
+    ###
+    moveNode: (moved_node, target_node, position) ->
+        if moved_node.isParentOf(target_node)
+            # Node is parent of target node. This is an illegal move
+            return
+
+        moved_node.parent._removeChild(moved_node)
+        if position == Position.AFTER
+            target_node.parent.addChildAtPosition(
+                moved_node,
+                target_node.parent.getChildIndex(target_node) + 1
+            )
+        else if position == Position.BEFORE
+            target_node.parent.addChildAtPosition(
+                moved_node,
+                target_node.parent.getChildIndex(target_node)
+            )
+        else if position == Position.INSIDE
+            # move inside as first child
+            target_node.addChildAtPosition(moved_node, 0)
+
+    ###
+    Get the tree as data.
+    ###
+    getData: (include_parent=false) ->
+        getDataFromNodes = (nodes) ->
+            data = []
+
+            for node in nodes
+                tmp_node = {}
+
+                for k, v of node
+                    if (
+                        k not in ['parent', 'children', 'element', 'tree'] and
+                        Object.prototype.hasOwnProperty.call(node, k)
+                    )
+                        tmp_node[k] = v
+
+                if node.hasChildren()
+                    tmp_node.children = getDataFromNodes(node.children)
+
+                data.push(tmp_node)
+
+            return data
+
+        if include_parent
+            return getDataFromNodes([this])
+        else
+            return getDataFromNodes(@children)
+
+    getNodeByName: (name) ->
+        return @getNodeByCallback(
+            (node) -> (node.name == name)
+        )
+
+    getNodeByCallback: (callback) ->
+        result = null
+
+        @iterate(
+            (node) ->
+                if callback(node)
+                    result = node
+                    return false
+                else
+                    return true
+        )
+
+        return result
+
+
+    addAfter: (node_info) ->
+        if not @parent
+            return null
+        else
+            node = new @tree.node_class(node_info)
+
+            child_index = @parent.getChildIndex(this)
+            @parent.addChildAtPosition(node, child_index + 1)
+
+            if typeof node_info == 'object' and node_info.children and node_info.children.length
+                node.loadFromData(node_info.children)
+
+            return node
+
+    addBefore: (node_info) ->
+        if not @parent
+            return null
+        else
+            node = new @tree.node_class(node_info)
+
+            child_index = @parent.getChildIndex(this)
+            @parent.addChildAtPosition(node, child_index)
+
+            if typeof node_info == 'object' and node_info.children and node_info.children.length
+                node.loadFromData(node_info.children)
+
+            return node
+
+    addParent: (node_info) ->
+        if not @parent
+            return null
+        else
+            new_parent = new @tree.node_class(node_info)
+            new_parent._setParent(@tree)
+            original_parent = @parent
+
+            for child in original_parent.children
+                new_parent.addChild(child)
+
+            original_parent.children = []
+            original_parent.addChild(new_parent)
+            return new_parent
+
+    remove: ->
+        if @parent
+            @parent.removeChild(this)
+            @parent = null
+
+    append: (node_info) ->
+        node = new @tree.node_class(node_info)
+        @addChild(node)
+
+        if typeof node_info == 'object' and node_info.children and node_info.children.length
+            node.loadFromData(node_info.children)
+
+        return node
+
+    prepend: (node_info) ->
+        node = new @tree.node_class(node_info)
+        @addChildAtPosition(node, 0)
+
+        if typeof node_info == 'object' and node_info.children and node_info.children.length
+            node.loadFromData(node_info.children)
+
+        return node
+
+    isParentOf: (node) ->
+        parent = node.parent
+
+        while parent
+            if parent == this
+                return true
+
+            parent = parent.parent
+
+        return false
+
+    getLevel: ->
+        level = 0
+        node = this
+
+        while node.parent
+            level += 1
+            node = node.parent
+
+        return level
+
+    getNodeById: (node_id) ->
+        return @id_mapping[node_id]
+
+    addNodeToIndex: (node) ->
+        if node.id?
+            @id_mapping[node.id] = node
+
+    removeNodeFromIndex: (node) ->
+        if node.id?
+            delete @id_mapping[node.id]
+
+    removeChildren: ->
+        @iterate(
+            (child) =>
+                @tree.removeNodeFromIndex(child)
+                return true
+        )
+
+        @children = []
+
+    getPreviousSibling: ->
+        if not @parent
+            return null
+        else
+            previous_index = @parent.getChildIndex(this) - 1
+            if previous_index >= 0
+                return @parent.children[previous_index]
+            else
+                return null
+
+    getNextSibling: ->
+        if not @parent
+            return null
+        else
+            next_index = @parent.getChildIndex(this) + 1
+            if next_index < @parent.children.length
+                return @parent.children[next_index]
+            else
+                return null
+
+    getNodesByProperty: (key, value) ->
+        return @filter(
+            (node) ->
+                return node[key] == value
+        )
+
+    filter: (f) ->
+        result = []
+
+        @iterate(
+            (node) ->
+                if f(node)
+                    result.push(node)
+
+                return true
+        )
+
+        return result
+
+    getNextNode: (include_children=true) ->
+        if include_children and @hasChildren() and @is_open
+            # First child
+            return @children[0]
+        else
+            if not @parent
+                return null
+            else
+                next_sibling = @getNextSibling()
+                if next_sibling
+                    # Next sibling
+                    return next_sibling
+                else
+                    # Next node of parent
+                    return @parent.getNextNode(false)
+
+    getPreviousNode: ->
+        if not @parent
+            return null
+        else
+            previous_sibling = @getPreviousSibling()
+            if previous_sibling
+                if not previous_sibling.hasChildren() or not previous_sibling.is_open
+                    # Previous sibling
+                    return previous_sibling
+                else
+                    # Last child of previous sibling
+                    return previous_sibling.getLastChild()
+            else
+                return @getParent()
+
+    getParent: ->
+        # Return parent except if it is the root node
+        if not @parent
+            return null
+        else if not @parent.parent
+            # Root node -> null
+            return null
+        else
+            return @parent
+
+    getLastChild: ->
+        if not @hasChildren()
+            return null
+        else
+            last_child = @children[@children.length - 1]
+            if not last_child.hasChildren() or not last_child.is_open
+                return last_child
+            else
+                return last_child.getLastChild()
+
+
+module.exports =
+    Node: Node
+    Position: Position