summaryrefslogtreecommitdiffstats
path: root/ecomp-portal-FE/client/bower_components/jqTree/src
diff options
context:
space:
mode:
Diffstat (limited to 'ecomp-portal-FE/client/bower_components/jqTree/src')
-rw-r--r--ecomp-portal-FE/client/bower_components/jqTree/src/drag_and_drop_handler.coffee491
-rw-r--r--ecomp-portal-FE/client/bower_components/jqTree/src/elements_renderer.coffee237
-rw-r--r--ecomp-portal-FE/client/bower_components/jqTree/src/header.txt17
-rw-r--r--ecomp-portal-FE/client/bower_components/jqTree/src/key_handler.coffee107
-rw-r--r--ecomp-portal-FE/client/bower_components/jqTree/src/mouse.widget.coffee184
-rw-r--r--ecomp-portal-FE/client/bower_components/jqTree/src/node.coffee490
-rw-r--r--ecomp-portal-FE/client/bower_components/jqTree/src/node_element.coffee170
-rw-r--r--ecomp-portal-FE/client/bower_components/jqTree/src/save_state_handler.coffee208
-rw-r--r--ecomp-portal-FE/client/bower_components/jqTree/src/scroll_handler.coffee114
-rw-r--r--ecomp-portal-FE/client/bower_components/jqTree/src/select_node_handler.coffee84
-rw-r--r--ecomp-portal-FE/client/bower_components/jqTree/src/simple.widget.coffee107
-rw-r--r--ecomp-portal-FE/client/bower_components/jqTree/src/tree.jquery.coffee918
-rw-r--r--ecomp-portal-FE/client/bower_components/jqTree/src/util.coffee48
-rw-r--r--ecomp-portal-FE/client/bower_components/jqTree/src/version.coffee1
14 files changed, 3176 insertions, 0 deletions
diff --git a/ecomp-portal-FE/client/bower_components/jqTree/src/drag_and_drop_handler.coffee b/ecomp-portal-FE/client/bower_components/jqTree/src/drag_and_drop_handler.coffee
new file mode 100644
index 00000000..38b1d521
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/jqTree/src/drag_and_drop_handler.coffee
@@ -0,0 +1,491 @@
+node_module = require './node'
+util = require './util'
+
+Position = node_module.Position
+
+$ = jQuery
+
+
+class DragAndDropHandler
+ constructor: (tree_widget) ->
+ @tree_widget = tree_widget
+
+ @hovered_area = null
+ @$ghost = null
+ @hit_areas = []
+ @is_dragging = false
+ @current_item = null
+
+ mouseCapture: (position_info) ->
+ $element = $(position_info.target)
+
+ if not @mustCaptureElement($element)
+ return null
+
+ if @tree_widget.options.onIsMoveHandle and not @tree_widget.options.onIsMoveHandle($element)
+ return null
+
+ node_element = @tree_widget._getNodeElement($element)
+
+ if node_element and @tree_widget.options.onCanMove
+ if not @tree_widget.options.onCanMove(node_element.node)
+ node_element = null
+
+ @current_item = node_element
+ return (@current_item != null)
+
+ mouseStart: (position_info) ->
+ @refresh()
+
+ offset = $(position_info.target).offset()
+
+ node = @current_item.node
+
+ if @tree_widget.options.autoEscape
+ node_name = util.html_escape(node.name)
+ else
+ node_name = node.name
+
+ @drag_element = new DragElement(
+ node_name,
+ position_info.page_x - offset.left,
+ position_info.page_y - offset.top,
+ @tree_widget.element
+ )
+
+ @is_dragging = true
+ @current_item.$element.addClass('jqtree-moving')
+ return true
+
+ mouseDrag: (position_info) ->
+ @drag_element.move(position_info.page_x, position_info.page_y)
+
+ area = @findHoveredArea(position_info.page_x, position_info.page_y)
+ can_move_to = @canMoveToArea(area)
+
+ if can_move_to and area
+ if !area.node.isFolder()
+ @stopOpenFolderTimer()
+
+ if @hovered_area != area
+ @hovered_area = area
+
+ # If this is a closed folder, start timer to open it
+ if @mustOpenFolderTimer(area)
+ @startOpenFolderTimer(area.node)
+ else
+ @stopOpenFolderTimer()
+
+ @updateDropHint()
+ else
+ @removeHover()
+ @removeDropHint()
+ @stopOpenFolderTimer()
+
+ if not area
+ if @tree_widget.options.onDragMove?
+ @tree_widget.options.onDragMove(@current_item.node, position_info.original_event)
+
+ return true
+
+ mustCaptureElement: ($element) ->
+ return not $element.is('input,select,textarea')
+
+ canMoveToArea: (area) ->
+ if not area
+ return false
+ else if @tree_widget.options.onCanMoveTo
+ position_name = Position.getName(area.position)
+
+ return @tree_widget.options.onCanMoveTo(@current_item.node, area.node, position_name)
+ else
+ return true
+
+ mouseStop: (position_info) ->
+ @moveItem(position_info)
+ @clear()
+ @removeHover()
+ @removeDropHint()
+ @removeHitAreas()
+
+ current_item = @current_item
+
+ if @current_item
+ @current_item.$element.removeClass('jqtree-moving')
+ @current_item = null
+
+ @is_dragging = false
+
+ if not @hovered_area and current_item
+ if @tree_widget.options.onDragStop?
+ @tree_widget.options.onDragStop(current_item.node, position_info.original_event)
+
+ return false
+
+ refresh: ->
+ @removeHitAreas()
+
+ if @current_item
+ @generateHitAreas()
+
+ @current_item = @tree_widget._getNodeElementForNode(@current_item.node)
+
+ if @is_dragging
+ @current_item.$element.addClass('jqtree-moving')
+
+ removeHitAreas: ->
+ @hit_areas = []
+
+ clear: ->
+ @drag_element.remove()
+ @drag_element = null
+
+ removeDropHint: ->
+ if @previous_ghost
+ @previous_ghost.remove()
+
+ removeHover: ->
+ @hovered_area = null
+
+ generateHitAreas: ->
+ hit_areas_generator = new HitAreasGenerator(
+ @tree_widget.tree,
+ @current_item.node,
+ @getTreeDimensions().bottom
+ )
+ @hit_areas = hit_areas_generator.generate()
+
+ findHoveredArea: (x, y) ->
+ dimensions = @getTreeDimensions()
+
+ if (
+ x < dimensions.left or
+ y < dimensions.top or
+ x > dimensions.right or
+ y > dimensions.bottom
+ )
+ return null
+
+ low = 0
+ high = @hit_areas.length
+ while (low < high)
+ mid = (low + high) >> 1
+ area = @hit_areas[mid]
+
+ if y < area.top
+ high = mid
+ else if y > area.bottom
+ low = mid + 1
+ else
+ return area
+
+ return null
+
+ mustOpenFolderTimer: (area) ->
+ node = area.node
+
+ return (
+ node.isFolder() and
+ not node.is_open and
+ area.position == Position.INSIDE
+ )
+
+ updateDropHint: ->
+ if not @hovered_area
+ return
+
+ # remove previous drop hint
+ @removeDropHint()
+
+ # add new drop hint
+ node_element = @tree_widget._getNodeElementForNode(@hovered_area.node)
+ @previous_ghost = node_element.addDropHint(@hovered_area.position)
+
+ startOpenFolderTimer: (folder) ->
+ openFolder = =>
+ @tree_widget._openNode(
+ folder,
+ @tree_widget.options.slide,
+ =>
+ @refresh()
+ @updateDropHint()
+ )
+
+ @stopOpenFolderTimer()
+
+ @open_folder_timer = setTimeout(openFolder, @tree_widget.options.openFolderDelay)
+
+ stopOpenFolderTimer: ->
+ if @open_folder_timer
+ clearTimeout(@open_folder_timer)
+ @open_folder_timer = null
+
+ moveItem: (position_info) ->
+ if (
+ @hovered_area and
+ @hovered_area.position != Position.NONE and
+ @canMoveToArea(@hovered_area)
+ )
+ moved_node = @current_item.node
+ target_node = @hovered_area.node
+ position = @hovered_area.position
+ previous_parent = moved_node.parent
+
+ if position == Position.INSIDE
+ @hovered_area.node.is_open = true
+
+ doMove = =>
+ @tree_widget.tree.moveNode(moved_node, target_node, position)
+ @tree_widget.element.empty()
+ @tree_widget._refreshElements()
+
+ event = @tree_widget._triggerEvent(
+ 'tree.move',
+ move_info:
+ moved_node: moved_node
+ target_node: target_node
+ position: Position.getName(position)
+ previous_parent: previous_parent
+ do_move: doMove
+ original_event: position_info.original_event
+ )
+
+ doMove() unless event.isDefaultPrevented()
+
+ getTreeDimensions: ->
+ # Return the dimensions of the tree. Add a margin to the bottom to allow
+ # for some to drag-and-drop the last element.
+ offset = @tree_widget.element.offset()
+
+ return {
+ left: offset.left,
+ top: offset.top,
+ right: offset.left + @tree_widget.element.width(),
+ bottom: offset.top + @tree_widget.element.height() + 16
+ }
+
+
+class VisibleNodeIterator
+ constructor: (tree) ->
+ @tree = tree
+
+ iterate: ->
+ is_first_node = true
+
+ _iterateNode = (node, next_node) =>
+ must_iterate_inside = (
+ (node.is_open or not node.element) and node.hasChildren()
+ )
+
+ if node.element
+ $element = $(node.element)
+
+ if not $element.is(':visible')
+ return
+
+ if is_first_node
+ @handleFirstNode(node, $element)
+ is_first_node = false
+
+ if not node.hasChildren()
+ @handleNode(node, next_node, $element)
+ else if node.is_open
+ if not @handleOpenFolder(node, $element)
+ must_iterate_inside = false
+ else
+ @handleClosedFolder(node, next_node, $element)
+
+ if must_iterate_inside
+ children_length = node.children.length
+ for child, i in node.children
+ if i == (children_length - 1)
+ _iterateNode(node.children[i], null)
+ else
+ _iterateNode(node.children[i], node.children[i+1])
+
+ if node.is_open
+ @handleAfterOpenFolder(node, next_node, $element)
+
+ _iterateNode(@tree, null)
+
+ handleNode: (node, next_node, $element) ->
+ # override
+
+ handleOpenFolder: (node, $element) ->
+ # override
+ # return
+ # - true: continue iterating
+ # - false: stop iterating
+
+ handleClosedFolder: (node, next_node, $element) ->
+ # override
+
+ handleAfterOpenFolder: (node, next_node, $element) ->
+ # override
+
+ handleFirstNode: (node, $element) ->
+ # override
+
+
+class HitAreasGenerator extends VisibleNodeIterator
+ constructor: (tree, current_node, tree_bottom) ->
+ super(tree)
+
+ @current_node = current_node
+ @tree_bottom = tree_bottom
+
+ generate: ->
+ @positions = []
+ @last_top = 0
+
+ @iterate()
+
+ return @generateHitAreas(@positions)
+
+ getTop: ($element) ->
+ return $element.offset().top
+
+ addPosition: (node, position, top) ->
+ area = {
+ top: top
+ node: node
+ position: position
+ }
+
+ @positions.push(area)
+ @last_top = top
+
+ handleNode: (node, next_node, $element) ->
+ top = @getTop($element)
+
+ if node == @current_node
+ # Cannot move inside current item
+ @addPosition(node, Position.NONE, top)
+ else
+ @addPosition(node, Position.INSIDE, top)
+
+ if (
+ next_node == @current_node or
+ node == @current_node
+ )
+ # Cannot move before or after current item
+ @addPosition(node, Position.NONE, top)
+ else
+ @addPosition(node, Position.AFTER, top)
+
+ handleOpenFolder: (node, $element) ->
+ if node == @current_node
+ # Cannot move inside current item
+ # Stop iterating
+ return false
+
+ # Cannot move before current item
+ if node.children[0] != @current_node
+ @addPosition(node, Position.INSIDE, @getTop($element))
+
+ # Continue iterating
+ return true
+
+ handleClosedFolder: (node, next_node, $element) ->
+ top = @getTop($element)
+
+ if node == @current_node
+ # Cannot move after current item
+ @addPosition(node, Position.NONE, top)
+ else
+ @addPosition(node, Position.INSIDE, top)
+
+ # Cannot move before current item
+ if next_node != @current_node
+ @addPosition(node, Position.AFTER, top)
+
+ handleFirstNode: (node, $element) ->
+ if node != @current_node
+ @addPosition(node, Position.BEFORE, @getTop($(node.element)))
+
+ handleAfterOpenFolder: (node, next_node, $element) ->
+ if (
+ node == @current_node.node or
+ next_node == @current_node.node
+ )
+ # Cannot move before or after current item
+ @addPosition(node, Position.NONE, @last_top)
+ else
+ @addPosition(node, Position.AFTER, @last_top)
+
+ generateHitAreas: (positions) ->
+ previous_top = -1
+ group = []
+ hit_areas = []
+
+ for position in positions
+ if position.top != previous_top and group.length
+ if group.length
+ @generateHitAreasForGroup(
+ hit_areas,
+ group,
+ previous_top,
+ position.top
+ )
+
+ previous_top = position.top
+ group = []
+
+ group.push(position)
+
+ @generateHitAreasForGroup(
+ hit_areas,
+ group,
+ previous_top,
+ @tree_bottom
+ )
+
+ return hit_areas
+
+ generateHitAreasForGroup: (hit_areas, positions_in_group, top, bottom) ->
+ # limit positions in group
+ position_count = Math.min(positions_in_group.length, 4)
+
+ area_height = Math.round((bottom - top) / position_count)
+ area_top = top
+
+ i = 0
+ while (i < position_count)
+ position = positions_in_group[i]
+
+ hit_areas.push(
+ top: area_top,
+ bottom: area_top + area_height,
+ node: position.node,
+ position: position.position
+ )
+
+ area_top += area_height
+ i += 1
+
+ return null
+
+
+class DragElement
+ constructor: (node_name, offset_x, offset_y, $tree) ->
+ @offset_x = offset_x
+ @offset_y = offset_y
+
+ @$element = $("<span class=\"jqtree-title jqtree-dragging\">#{ node_name }</span>")
+ @$element.css("position", "absolute")
+ $tree.append(@$element)
+
+ move: (page_x, page_y) ->
+ @$element.offset(
+ left: page_x - @offset_x,
+ top: page_y - @offset_y
+ )
+
+ remove: ->
+ @$element.remove()
+
+
+module.exports =
+ DragAndDropHandler: DragAndDropHandler
+ DragElement: DragElement
+ HitAreasGenerator: HitAreasGenerator
diff --git a/ecomp-portal-FE/client/bower_components/jqTree/src/elements_renderer.coffee b/ecomp-portal-FE/client/bower_components/jqTree/src/elements_renderer.coffee
new file mode 100644
index 00000000..b68cf917
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/jqTree/src/elements_renderer.coffee
@@ -0,0 +1,237 @@
+node_element = require './node_element'
+NodeElement = node_element.NodeElement
+
+util = require './util'
+html_escape = util.html_escape
+
+
+$ = jQuery
+
+
+class ElementsRenderer
+ constructor: (tree_widget) ->
+ @tree_widget = tree_widget
+
+ @opened_icon_element = @createButtonElement(tree_widget.options.openedIcon)
+ @closed_icon_element = @createButtonElement(tree_widget.options.closedIcon)
+
+ render: (from_node) ->
+ if from_node and from_node.parent
+ @renderFromNode(from_node)
+ else
+ @renderFromRoot()
+
+ renderFromRoot: ->
+ $element = @tree_widget.element
+ $element.empty()
+
+ @createDomElements($element[0], @tree_widget.tree.children, true, true, 1)
+
+ renderFromNode: (node) ->
+ # remember current li
+ $previous_li = $(node.element)
+
+ # create element
+ li = @createLi(node, node.getLevel())
+ @attachNodeData(node, li)
+
+ # add element to dom
+ $previous_li.after(li)
+
+ # remove previous li
+ $previous_li.remove()
+
+ # create children
+ if node.children
+ @createDomElements(li, node.children, false, false, node.getLevel() + 1)
+
+ createDomElements: (element, children, is_root_node, is_open, level) ->
+ ul = @createUl(is_root_node)
+ element.appendChild(ul)
+
+ for child in children
+ li = @createLi(child, level)
+ ul.appendChild(li)
+
+ @attachNodeData(child, li)
+
+ if child.hasChildren()
+ @createDomElements(li, child.children, false, child.is_open, level + 1)
+
+ return null
+
+ attachNodeData: (node, li) ->
+ node.element = li
+ $(li).data('node', node)
+
+ createUl: (is_root_node) ->
+ if !is_root_node
+ class_string = ''
+ role = 'group'
+ else
+ class_string = 'jqtree-tree'
+ role = 'tree'
+
+ if @tree_widget.options.rtl
+ class_string += ' jqtree-rtl'
+
+ ul = document.createElement('ul')
+ ul.className = "jqtree_common #{ class_string }"
+
+ ul.setAttribute('role', role)
+
+ return ul
+
+ createLi: (node, level) ->
+ is_selected = @tree_widget.select_node_handler and @tree_widget.select_node_handler.isNodeSelected(node)
+
+ if node.isFolder()
+ li = @createFolderLi(node, level, is_selected)
+ else
+ li = @createNodeLi(node, level, is_selected)
+
+ if @tree_widget.options.onCreateLi
+ @tree_widget.options.onCreateLi(node, $(li))
+
+ return li
+
+ createFolderLi: (node, level, is_selected) ->
+ button_classes = @getButtonClasses(node)
+ folder_classes = @getFolderClasses(node, is_selected)
+
+ if node.is_open
+ icon_element = @opened_icon_element
+ else
+ icon_element = @closed_icon_element
+
+ # li
+ li = document.createElement('li')
+ li.className = "jqtree_common #{ folder_classes }"
+ li.setAttribute('role', 'presentation')
+
+ # div
+ div = document.createElement('div')
+ div.className = "jqtree-element jqtree_common"
+ div.setAttribute('role', 'presentation')
+
+ li.appendChild(div)
+
+ # button link
+ button_link = document.createElement('a')
+ button_link.className = button_classes
+
+ button_link.appendChild(
+ icon_element.cloneNode(false)
+ )
+
+ button_link.setAttribute('role', 'presentation')
+ button_link.setAttribute('aria-hidden', 'true')
+
+ if @tree_widget.options.buttonLeft
+ div.appendChild(button_link)
+
+ # title span
+ div.appendChild(
+ @createTitleSpan(node.name, level, is_selected, node.is_open, is_folder=true)
+ )
+
+ if not @tree_widget.options.buttonLeft
+ div.appendChild(button_link)
+
+ return li
+
+ createNodeLi: (node, level, is_selected) ->
+ li_classes = ['jqtree_common']
+
+ if is_selected
+ li_classes.push('jqtree-selected')
+
+ class_string = li_classes.join(' ')
+
+ # li
+ li = document.createElement('li')
+ li.className = class_string
+ li.setAttribute('role', 'presentation')
+
+ # div
+ div = document.createElement('div')
+ div.className = "jqtree-element jqtree_common"
+ div.setAttribute('role', 'presentation')
+
+ li.appendChild(div)
+
+ # title span
+ div.appendChild(
+ @createTitleSpan(node.name, level, is_selected, node.is_open, is_folder=false)
+ )
+
+ return li
+
+ createTitleSpan: (node_name, level, is_selected, is_open, is_folder) ->
+ title_span = document.createElement('span')
+
+ classes = "jqtree-title jqtree_common"
+
+ if is_folder
+ classes += " jqtree-title-folder"
+
+ title_span.className = classes
+
+ title_span.setAttribute('role', 'treeitem')
+ title_span.setAttribute('aria-level', level)
+
+ title_span.setAttribute('aria-selected', util.getBoolString(is_selected))
+ title_span.setAttribute('aria-expanded', util.getBoolString(is_open))
+
+ if is_selected
+ title_span.setAttribute('tabindex', 0)
+
+ title_span.innerHTML = @escapeIfNecessary(node_name)
+
+ return title_span
+
+ getButtonClasses: (node) ->
+ classes = ['jqtree-toggler', 'jqtree_common']
+
+ if not node.is_open
+ classes.push('jqtree-closed')
+
+ if @tree_widget.options.buttonLeft
+ classes.push('jqtree-toggler-left')
+ else
+ classes.push('jqtree-toggler-right')
+
+ return classes.join(' ')
+
+ getFolderClasses: (node, is_selected) ->
+ classes = ['jqtree-folder']
+
+ if not node.is_open
+ classes.push('jqtree-closed')
+
+ if is_selected
+ classes.push('jqtree-selected')
+
+ if node.is_loading
+ classes.push('jqtree-loading')
+
+ return classes.join(' ')
+
+ escapeIfNecessary: (value) ->
+ if @tree_widget.options.autoEscape
+ return html_escape(value)
+ else
+ return value
+
+ createButtonElement: (value) ->
+ if typeof value == 'string'
+ # convert value to html
+ div = document.createElement('div')
+ div.innerHTML = value
+
+ return document.createTextNode(div.innerHTML)
+ else
+ return $(value)[0]
+
+
+module.exports = ElementsRenderer
diff --git a/ecomp-portal-FE/client/bower_components/jqTree/src/header.txt b/ecomp-portal-FE/client/bower_components/jqTree/src/header.txt
new file mode 100644
index 00000000..bb10525a
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/jqTree/src/header.txt
@@ -0,0 +1,17 @@
+/*
+JqTree <%= pkg.version %>
+
+Copyright 2015 Marco Braak
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
diff --git a/ecomp-portal-FE/client/bower_components/jqTree/src/key_handler.coffee b/ecomp-portal-FE/client/bower_components/jqTree/src/key_handler.coffee
new file mode 100644
index 00000000..c8c17e7c
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/jqTree/src/key_handler.coffee
@@ -0,0 +1,107 @@
+$ = jQuery
+
+
+class KeyHandler
+ LEFT = 37
+ UP = 38
+ RIGHT = 39
+ DOWN = 40
+
+ constructor: (tree_widget) ->
+ @tree_widget = tree_widget
+
+ if tree_widget.options.keyboardSupport
+ $(document).bind('keydown.jqtree', $.proxy(@handleKeyDown, this))
+
+ deinit: ->
+ $(document).unbind('keydown.jqtree')
+
+ moveDown: ->
+ node = @tree_widget.getSelectedNode()
+
+ if node
+ return @selectNode(node.getNextNode())
+ else
+ return false
+
+ moveUp: ->
+ node = @tree_widget.getSelectedNode()
+
+ if node
+ return @selectNode(node.getPreviousNode())
+ else
+ return false
+
+ moveRight: ->
+ node = @tree_widget.getSelectedNode()
+
+ if not node
+ return true
+ else if not node.isFolder()
+ return true
+ else
+ # folder node
+ if node.is_open
+ # Right moves to the first child of an open node
+ return @selectNode(node.getNextNode())
+ else
+ # Right expands a closed node
+ @tree_widget.openNode(node)
+ return false
+
+ moveLeft: ->
+ node = @tree_widget.getSelectedNode()
+
+ if not node
+ return true
+ else if node.isFolder() and node.is_open
+ # Left on an open node closes the node
+ @tree_widget.closeNode(node)
+ return false
+ else
+ # Left on a closed or end node moves focus to the node's parent
+ return @selectNode(node.getParent())
+
+ handleKeyDown: (e) ->
+ if not @tree_widget.options.keyboardSupport
+ return true
+
+ if $(document.activeElement).is('textarea,input,select')
+ return true
+
+ if not @tree_widget.getSelectedNode()
+ return true
+
+ key = e.which
+
+ switch key
+ when DOWN
+ return @moveDown()
+
+ when UP
+ return @moveUp()
+
+ when RIGHT
+ return @moveRight()
+
+ when LEFT
+ return @moveLeft()
+
+ return true
+
+ selectNode: (node) =>
+ if not node
+ return true
+ else
+ @tree_widget.selectNode(node)
+
+ if (
+ @tree_widget.scroll_handler and
+ (not @tree_widget.scroll_handler.isScrolledIntoView($(node.element).find('.jqtree-element')))
+ )
+ @tree_widget.scrollToNode(node)
+
+ return false
+
+
+module.exports = KeyHandler
diff --git a/ecomp-portal-FE/client/bower_components/jqTree/src/mouse.widget.coffee b/ecomp-portal-FE/client/bower_components/jqTree/src/mouse.widget.coffee
new file mode 100644
index 00000000..f76ff7e6
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/jqTree/src/mouse.widget.coffee
@@ -0,0 +1,184 @@
+###
+This widget does the same a the mouse widget in jqueryui.
+###
+
+SimpleWidget = require './simple.widget'
+
+
+$ = jQuery
+
+
+class MouseWidget extends SimpleWidget
+ @is_mouse_handled = false
+
+ _init: ->
+ @$el.bind('mousedown.mousewidget', $.proxy(@_mouseDown, this))
+ @$el.bind('touchstart.mousewidget', $.proxy(@_touchStart, this))
+
+ @is_mouse_started = false
+ @mouse_delay = 0
+ @_mouse_delay_timer = null
+ @_is_mouse_delay_met = true
+ @mouse_down_info = null
+
+ _deinit: ->
+ @$el.unbind('mousedown.mousewidget')
+ @$el.unbind('touchstart.mousewidget')
+
+ $document = $(document)
+ $document.unbind('mousemove.mousewidget')
+ $document.unbind('mouseup.mousewidget')
+
+ _mouseDown: (e) ->
+ # Is left mouse button?
+ if e.which != 1
+ return
+
+ result = @_handleMouseDown(
+ e,
+ @_getPositionInfo(e)
+ )
+
+ if result
+ e.preventDefault()
+
+ return result
+
+ _handleMouseDown: (e, position_info) ->
+ # Don't let more than one widget handle mouseStart
+ if MouseWidget.is_mouse_handled
+ return
+
+ # We may have missed mouseup (out of window)
+ if @is_mouse_started
+ @_handleMouseUp(position_info)
+
+ @mouse_down_info = position_info
+
+ if not @_mouseCapture(position_info)
+ return
+
+ @_handleStartMouse()
+
+ @is_mouse_handled = true
+ return true
+
+ _handleStartMouse: ->
+ $document = $(document)
+ $document.bind('mousemove.mousewidget', $.proxy(@_mouseMove, this))
+ $document.bind('touchmove.mousewidget', $.proxy(@_touchMove, this))
+ $document.bind('mouseup.mousewidget', $.proxy(@_mouseUp, this))
+ $document.bind('touchend.mousewidget', $.proxy(@_touchEnd, this))
+
+ if @mouse_delay
+ @_startMouseDelayTimer()
+
+ _startMouseDelayTimer: ->
+ if @_mouse_delay_timer
+ clearTimeout(@_mouse_delay_timer)
+
+ @_mouse_delay_timer = setTimeout(
+ =>
+ @_is_mouse_delay_met = true
+ , @mouse_delay
+ )
+
+ @_is_mouse_delay_met = false
+
+ _mouseMove: (e) ->
+ return @_handleMouseMove(
+ e,
+ @_getPositionInfo(e)
+ )
+
+ _handleMouseMove: (e, position_info) ->
+ if @is_mouse_started
+ @_mouseDrag(position_info)
+ return e.preventDefault()
+
+ if @mouse_delay and not @_is_mouse_delay_met
+ return true
+
+ @is_mouse_started = @_mouseStart(@mouse_down_info) != false
+
+ if @is_mouse_started
+ @_mouseDrag(position_info)
+ else
+ @_handleMouseUp(position_info)
+
+ return not @is_mouse_started
+
+ _getPositionInfo: (e) ->
+ return {
+ page_x: e.pageX,
+ page_y: e.pageY,
+ target: e.target,
+ original_event: e
+ }
+
+ _mouseUp: (e) ->
+ return @_handleMouseUp(
+ @_getPositionInfo(e)
+ )
+
+ _handleMouseUp: (position_info) ->
+ $document = $(document)
+ $document.unbind('mousemove.mousewidget')
+ $document.unbind('touchmove.mousewidget')
+ $document.unbind('mouseup.mousewidget')
+ $document.unbind('touchend.mousewidget')
+
+ if @is_mouse_started
+ @is_mouse_started = false
+ @_mouseStop(position_info)
+
+ return
+
+ _mouseCapture: (position_info) ->
+ return true
+
+ _mouseStart: (position_info) ->
+ null
+
+ _mouseDrag: (position_info) ->
+ null
+
+ _mouseStop: (position_info) ->
+ null
+
+ setMouseDelay: (mouse_delay) ->
+ @mouse_delay = mouse_delay
+
+ _touchStart: (e) ->
+ if e.originalEvent.touches.length > 1
+ return
+
+ touch = e.originalEvent.changedTouches[0]
+
+ return @_handleMouseDown(
+ e,
+ @_getPositionInfo(touch)
+ )
+
+ _touchMove: (e) ->
+ if e.originalEvent.touches.length > 1
+ return
+
+ touch = e.originalEvent.changedTouches[0]
+
+ return @_handleMouseMove(
+ e,
+ @_getPositionInfo(touch)
+ )
+
+ _touchEnd: (e) ->
+ if e.originalEvent.touches.length > 1
+ return
+
+ touch = e.originalEvent.changedTouches[0]
+
+ return @_handleMouseUp(
+ @_getPositionInfo(touch)
+ )
+
+module.exports = MouseWidget
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
index 00000000..5af050ac
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/jqTree/src/node.coffee
@@ -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
diff --git a/ecomp-portal-FE/client/bower_components/jqTree/src/node_element.coffee b/ecomp-portal-FE/client/bower_components/jqTree/src/node_element.coffee
new file mode 100644
index 00000000..57c06a30
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/jqTree/src/node_element.coffee
@@ -0,0 +1,170 @@
+node = require './node'
+Position = node.Position
+
+
+$ = jQuery
+
+
+class NodeElement
+ constructor: (node, tree_widget) ->
+ @init(node, tree_widget)
+
+ init: (node, tree_widget) ->
+ @node = node
+ @tree_widget = tree_widget
+
+ if not node.element
+ node.element = @tree_widget.element
+
+ @$element = $(node.element)
+
+ getUl: ->
+ return @$element.children('ul:first')
+
+ getSpan: ->
+ return @$element.children('.jqtree-element').find('span.jqtree-title')
+
+ getLi: ->
+ return @$element
+
+ addDropHint: (position) ->
+ if position == Position.INSIDE
+ return new BorderDropHint(@$element)
+ else
+ return new GhostDropHint(@node, @$element, position)
+
+ select: ->
+ $li = @getLi()
+
+ $li.addClass('jqtree-selected')
+ $li.attr('aria-selected', 'true')
+
+ $span = @getSpan()
+ $span.attr('tabindex', 0)
+
+ deselect: ->
+ $li = @getLi()
+
+ $li.removeClass('jqtree-selected')
+ $li.attr('aria-selected', 'false')
+
+ $span = @getSpan()
+ $span.attr('tabindex', -1)
+
+
+class FolderElement extends NodeElement
+ open: (on_finished, slide=true) ->
+ if not @node.is_open
+ @node.is_open = true
+ $button = @getButton()
+ $button.removeClass('jqtree-closed')
+ $button.html('')
+ $button.append(@tree_widget.renderer.opened_icon_element.cloneNode(false))
+
+ doOpen = =>
+ $li = @getLi()
+ $li.removeClass('jqtree-closed')
+
+ $span = @getSpan()
+ $span.attr('aria-expanded', 'true')
+
+ if on_finished
+ on_finished(@node)
+
+ @tree_widget._triggerEvent('tree.open', node: @node)
+
+ if slide
+ @getUl().slideDown('fast', doOpen)
+ else
+ @getUl().show()
+ doOpen()
+
+ close: (slide=true) ->
+ if @node.is_open
+ @node.is_open = false
+ $button = @getButton()
+ $button.addClass('jqtree-closed')
+ $button.html('')
+ $button.append(@tree_widget.renderer.closed_icon_element.cloneNode(false))
+
+ doClose = =>
+ $li = @getLi()
+ $li.addClass('jqtree-closed')
+
+ $span = @getSpan()
+ $span.attr('aria-expanded', 'false')
+
+ @tree_widget._triggerEvent('tree.close', node: @node)
+
+ if slide
+ @getUl().slideUp('fast', doClose)
+ else
+ @getUl().hide()
+ doClose()
+
+ getButton: ->
+ return @$element.children('.jqtree-element').find('a.jqtree-toggler')
+
+ addDropHint: (position) ->
+ if not @node.is_open and position == Position.INSIDE
+ return new BorderDropHint(@$element)
+ else
+ return new GhostDropHint(@node, @$element, position)
+
+
+class BorderDropHint
+ constructor: ($element) ->
+ $div = $element.children('.jqtree-element')
+ width = $element.width() - 4
+
+ @$hint = $('<span class="jqtree-border"></span>')
+ $div.append(@$hint)
+
+ @$hint.css(
+ width: width
+ height: $div.outerHeight() - 4
+ )
+
+ remove: ->
+ @$hint.remove()
+
+
+class GhostDropHint
+ constructor: (node, $element, position) ->
+ @$element = $element
+
+ @node = node
+ @$ghost = $('<li class="jqtree_common jqtree-ghost"><span class="jqtree_common jqtree-circle"></span><span class="jqtree_common jqtree-line"></span></li>')
+
+ if position == Position.AFTER
+ @moveAfter()
+ else if position == Position.BEFORE
+ @moveBefore()
+ else if position == Position.INSIDE
+ if node.isFolder() and node.is_open
+ @moveInsideOpenFolder()
+ else
+ @moveInside()
+
+ remove: ->
+ @$ghost.remove()
+
+ moveAfter: ->
+ @$element.after(@$ghost)
+
+ moveBefore: ->
+ @$element.before(@$ghost)
+
+ moveInsideOpenFolder: ->
+ $(@node.children[0].element).before(@$ghost)
+
+ moveInside: ->
+ @$element.after(@$ghost)
+ @$ghost.addClass('jqtree-inside')
+
+
+module.exports =
+ BorderDropHint: BorderDropHint
+ FolderElement: FolderElement
+ GhostDropHint: GhostDropHint
+ NodeElement: NodeElement
diff --git a/ecomp-portal-FE/client/bower_components/jqTree/src/save_state_handler.coffee b/ecomp-portal-FE/client/bower_components/jqTree/src/save_state_handler.coffee
new file mode 100644
index 00000000..65810357
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/jqTree/src/save_state_handler.coffee
@@ -0,0 +1,208 @@
+util = require './util'
+
+indexOf = util.indexOf
+isInt = util.isInt
+
+
+$ = jQuery
+
+
+class SaveStateHandler
+ constructor: (tree_widget) ->
+ @tree_widget = tree_widget
+
+ saveState: ->
+ state = JSON.stringify(@getState())
+
+ if @tree_widget.options.onSetStateFromStorage
+ @tree_widget.options.onSetStateFromStorage(state)
+ else if @supportsLocalStorage()
+ localStorage.setItem(
+ @getCookieName(),
+ state
+ )
+ else if $.cookie
+ $.cookie.raw = true
+ $.cookie(
+ @getCookieName(),
+ state,
+ {path: '/'}
+ )
+
+ getStateFromStorage: ->
+ json_data = @_loadFromStorage()
+
+ if json_data
+ return @_parseState(json_data)
+ else
+ return null
+
+ _parseState: (json_data) ->
+ state = $.parseJSON(json_data)
+
+ # Check if selected_node is an int (instead of an array)
+ if state and state.selected_node and isInt(state.selected_node)
+ # Convert to array
+ state.selected_node = [state.selected_node]
+
+ return state
+
+ _loadFromStorage: ->
+ if @tree_widget.options.onGetStateFromStorage
+ return @tree_widget.options.onGetStateFromStorage()
+ else if @supportsLocalStorage()
+ return localStorage.getItem(
+ @getCookieName()
+ )
+ else if $.cookie
+ $.cookie.raw = true
+ return $.cookie(@getCookieName())
+ else
+ return null
+
+ getState: ->
+ getOpenNodeIds = =>
+ open_nodes = []
+
+ @tree_widget.tree.iterate((node) ->
+ if (
+ node.is_open and
+ node.id and
+ node.hasChildren()
+ )
+ open_nodes.push(node.id)
+ return true
+ )
+
+ return open_nodes
+
+ getSelectedNodeIds = =>
+ return (n.id for n in @tree_widget.getSelectedNodes())
+
+ return {
+ open_nodes: getOpenNodeIds(),
+ selected_node: getSelectedNodeIds()
+ }
+
+ # Set initial state
+ # Don't handle nodes that are loaded on demand
+ #
+ # result: must load on demand
+ setInitialState: (state) ->
+ if not state
+ return false
+ else
+ must_load_on_demand = @_openInitialNodes(state.open_nodes)
+
+ @_selectInitialNodes(state.selected_node)
+
+ return must_load_on_demand
+
+ _openInitialNodes: (node_ids) ->
+ must_load_on_demand = false
+
+ for node_id in node_ids
+ node = @tree_widget.getNodeById(node_id)
+
+ if node
+ if not node.load_on_demand
+ node.is_open = true
+ else
+ must_load_on_demand = true
+
+ return must_load_on_demand
+
+ _selectInitialNodes: (node_ids) ->
+ select_count = 0
+
+ for node_id in node_ids
+ node = @tree_widget.getNodeById(node_id)
+
+ if node
+ select_count += 1
+
+ @tree_widget.select_node_handler.addToSelection(node)
+
+ return select_count != 0
+
+ setInitialStateOnDemand: (state, cb_finished) ->
+ if state
+ @_setInitialStateOnDemand(state.open_nodes, state.selected_node, cb_finished)
+ else
+ cb_finished()
+
+ _setInitialStateOnDemand: (node_ids, selected_nodes, cb_finished) ->
+ loading_count = 0
+
+ openNodes = =>
+ new_nodes_ids = []
+
+ for node_id in node_ids
+ node = @tree_widget.getNodeById(node_id)
+
+ if not node
+ new_nodes_ids.push(node_id)
+ else
+ if not node.is_loading
+ if node.load_on_demand
+ loadAndOpenNode(node)
+ else
+ @tree_widget._openNode(node, false)
+
+ node_ids = new_nodes_ids
+
+ if @_selectInitialNodes(selected_nodes)
+ @tree_widget._refreshElements()
+
+ if loading_count == 0
+ cb_finished()
+
+ loadAndOpenNode = (node) =>
+ loading_count += 1
+ @tree_widget._openNode(
+ node,
+ false,
+ ->
+ loading_count -= 1
+ openNodes()
+ )
+
+ openNodes()
+
+ getCookieName: ->
+ if typeof @tree_widget.options.saveState is 'string'
+ return @tree_widget.options.saveState
+ else
+ return 'tree'
+
+ supportsLocalStorage: ->
+ testSupport = ->
+ # Is local storage supported?
+ if not localStorage?
+ return false
+ else
+ # Check if it's possible to store an item. Safari does not allow this in private browsing mode.
+ try
+ key = '_storage_test'
+ sessionStorage.setItem(key, true)
+ sessionStorage.removeItem(key)
+ catch error
+ return false
+
+ return true
+
+ if not @_supportsLocalStorage?
+ @_supportsLocalStorage = testSupport()
+
+ return @_supportsLocalStorage
+
+ getNodeIdToBeSelected: ->
+ state = @getStateFromStorage()
+
+ if state and state.selected_node
+ return state.selected_node[0]
+ else
+ return null
+
+
+module.exports = SaveStateHandler
diff --git a/ecomp-portal-FE/client/bower_components/jqTree/src/scroll_handler.coffee b/ecomp-portal-FE/client/bower_components/jqTree/src/scroll_handler.coffee
new file mode 100644
index 00000000..3456dec5
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/jqTree/src/scroll_handler.coffee
@@ -0,0 +1,114 @@
+$ = jQuery
+
+
+class ScrollHandler
+ constructor: (tree_widget) ->
+ @tree_widget = tree_widget
+ @previous_top = -1
+ @is_initialized = false
+
+ _initScrollParent: ->
+ getParentWithOverflow = =>
+ css_values = ['overflow', 'overflow-y']
+
+ hasOverFlow = (el) ->
+ for css_value in css_values
+ if $.css(el, css_value) in ['auto', 'scroll']
+ return true
+
+ return false
+
+ if hasOverFlow(@tree_widget.$el[0])
+ return @tree_widget.$el
+
+ for el in @tree_widget.$el.parents()
+ if hasOverFlow(el)
+ return $(el)
+
+ return null
+
+ setDocumentAsScrollParent = =>
+ @scroll_parent_top = 0
+ @$scroll_parent = null
+
+ if @tree_widget.$el.css('position') == 'fixed'
+ setDocumentAsScrollParent()
+
+ $scroll_parent = getParentWithOverflow()
+
+ if $scroll_parent and $scroll_parent.length and $scroll_parent[0].tagName != 'HTML'
+ @$scroll_parent = $scroll_parent
+ @scroll_parent_top = @$scroll_parent.offset().top
+ else
+ setDocumentAsScrollParent()
+
+ @is_initialized = true
+
+ _ensureInit: ->
+ if not @is_initialized
+ @_initScrollParent()
+
+ checkScrolling: ->
+ @_ensureInit()
+
+ hovered_area = @tree_widget.dnd_handler.hovered_area
+
+ if hovered_area and hovered_area.top != @previous_top
+ @previous_top = hovered_area.top
+
+ if @$scroll_parent
+ @_handleScrollingWithScrollParent(hovered_area)
+ else
+ @_handleScrollingWithDocument(hovered_area)
+
+ _handleScrollingWithScrollParent: (area) ->
+ distance_bottom = @scroll_parent_top + @$scroll_parent[0].offsetHeight - area.bottom
+
+ if distance_bottom < 20
+ @$scroll_parent[0].scrollTop += 20
+ @tree_widget.refreshHitAreas()
+ @previous_top = -1
+ else if (area.top - @scroll_parent_top) < 20
+ @$scroll_parent[0].scrollTop -= 20
+ @tree_widget.refreshHitAreas()
+ @previous_top = -1
+
+ _handleScrollingWithDocument: (area) ->
+ distance_top = area.top - $(document).scrollTop()
+
+ if distance_top < 20
+ $(document).scrollTop($(document).scrollTop() - 20)
+ else if $(window).height() - (area.bottom - $(document).scrollTop()) < 20
+ $(document).scrollTop($(document).scrollTop() + 20)
+
+ scrollTo: (top) ->
+ @_ensureInit()
+
+ if @$scroll_parent
+ @$scroll_parent[0].scrollTop = top
+ else
+ tree_top = @tree_widget.$el.offset().top
+ $(document).scrollTop(top + tree_top)
+
+ isScrolledIntoView: (element) ->
+ @_ensureInit()
+
+ $element = $(element)
+
+ if @$scroll_parent
+ view_top = 0
+ view_bottom = @$scroll_parent.height()
+
+ element_top = $element.offset().top - @scroll_parent_top
+ element_bottom = element_top + $element.height()
+ else
+ view_top = $(window).scrollTop()
+ view_bottom = view_top + $(window).height()
+
+ element_top = $element.offset().top
+ element_bottom = element_top + $element.height()
+
+ return (element_bottom <= view_bottom) and (element_top >= view_top)
+
+
+module.exports = ScrollHandler
diff --git a/ecomp-portal-FE/client/bower_components/jqTree/src/select_node_handler.coffee b/ecomp-portal-FE/client/bower_components/jqTree/src/select_node_handler.coffee
new file mode 100644
index 00000000..1c1fe582
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/jqTree/src/select_node_handler.coffee
@@ -0,0 +1,84 @@
+$ = jQuery
+
+
+class SelectNodeHandler
+ constructor: (tree_widget) ->
+ @tree_widget = tree_widget
+ @clear()
+
+ getSelectedNode: ->
+ selected_nodes = @getSelectedNodes()
+
+ if selected_nodes.length
+ return selected_nodes[0]
+ else
+ return false
+
+ getSelectedNodes: ->
+ if @selected_single_node
+ return [@selected_single_node]
+ else
+ selected_nodes = []
+
+ for id of @selected_nodes
+ node = @tree_widget.getNodeById(id)
+ if node
+ selected_nodes.push(node)
+
+ return selected_nodes
+
+ getSelectedNodesUnder: (parent) ->
+ if @selected_single_node
+ if parent.isParentOf(@selected_single_node)
+ return [@selected_single_node]
+ else
+ return []
+ else
+ selected_nodes = []
+
+ for id of @selected_nodes
+ node = @tree_widget.getNodeById(id)
+ if node and parent.isParentOf(node)
+ selected_nodes.push(node)
+
+ return selected_nodes
+
+ isNodeSelected: (node) ->
+ if not node
+ return false
+ else if node.id
+ if @selected_nodes[node.id]
+ return true
+ else
+ return false
+ else if @selected_single_node
+ return @selected_single_node.element == node.element
+ else
+ return false
+
+ clear: ->
+ @selected_nodes = {}
+ @selected_single_node = null
+
+ removeFromSelection: (node, include_children=false) ->
+ if not node.id
+ if @selected_single_node && node.element == @selected_single_node.element
+ @selected_single_node = null
+ else
+ delete @selected_nodes[node.id]
+
+ if include_children
+ node.iterate(
+ (n) =>
+ delete @selected_nodes[node.id]
+ return true
+ )
+
+ addToSelection: (node) ->
+ if node.id
+ @selected_nodes[node.id] = true
+ else
+ @selected_single_node = node
+
+
+module.exports = SelectNodeHandler
diff --git a/ecomp-portal-FE/client/bower_components/jqTree/src/simple.widget.coffee b/ecomp-portal-FE/client/bower_components/jqTree/src/simple.widget.coffee
new file mode 100644
index 00000000..a3ca6e3e
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/jqTree/src/simple.widget.coffee
@@ -0,0 +1,107 @@
+###
+Copyright 2013 Marco Braak
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+###
+
+$ = jQuery
+
+
+class SimpleWidget
+ defaults: {}
+
+ constructor: (el, options) ->
+ @$el = $(el)
+ @options = $.extend({}, @defaults, options)
+
+ destroy: ->
+ @_deinit()
+
+ _init: ->
+ null
+
+ _deinit: ->
+ null
+
+ @register = (widget_class, widget_name) ->
+ getDataKey = ->
+ return "simple_widget_#{widget_name}"
+
+ getWidgetData = (el, data_key) ->
+ widget = $.data(el, data_key)
+
+ if widget and (widget instanceof SimpleWidget)
+ return widget
+ else
+ return null
+
+ createWidget = ($el, options) ->
+ data_key = getDataKey()
+
+ for el in $el
+ existing_widget = getWidgetData(el, data_key)
+
+ if not existing_widget
+ widget = new widget_class(el, options)
+
+ if not $.data(el, data_key)
+ $.data(el, data_key, widget)
+
+ # Call init after setting data, so we can call methods
+ widget._init()
+
+ return $el
+
+ destroyWidget = ($el) ->
+ data_key = getDataKey()
+
+ for el in $el
+ widget = getWidgetData(el, data_key)
+
+ if widget
+ widget.destroy()
+
+ $.removeData(el, data_key)
+
+ callFunction = ($el, function_name, args) ->
+ result = null
+
+ for el in $el
+ widget = $.data(el, getDataKey())
+
+ if widget and (widget instanceof SimpleWidget)
+ widget_function = widget[function_name]
+
+ if widget_function and (typeof widget_function == 'function')
+ result = widget_function.apply(widget, args)
+
+ return result
+
+ $.fn[widget_name] = (argument1, args...) ->
+ $el = this
+
+ if argument1 is undefined or typeof argument1 == 'object'
+ options = argument1
+ return createWidget($el, options)
+ else if typeof argument1 == 'string' and argument1[0] != '_'
+ function_name = argument1
+
+ if function_name == 'destroy'
+ return destroyWidget($el)
+ else if function_name == 'get_widget_class'
+ return widget_class
+ else
+ return callFunction($el, function_name, args)
+
+
+module.exports = SimpleWidget
diff --git a/ecomp-portal-FE/client/bower_components/jqTree/src/tree.jquery.coffee b/ecomp-portal-FE/client/bower_components/jqTree/src/tree.jquery.coffee
new file mode 100644
index 00000000..15e13e1b
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/jqTree/src/tree.jquery.coffee
@@ -0,0 +1,918 @@
+__version__ = require './version'
+drag_and_drop_handler = require './drag_and_drop_handler'
+ElementsRenderer = require './elements_renderer'
+KeyHandler = require './key_handler'
+MouseWidget = require './mouse.widget'
+SaveStateHandler = require './save_state_handler'
+ScrollHandler = require './scroll_handler'
+SelectNodeHandler = require './select_node_handler'
+SimpleWidget = require './simple.widget'
+
+node_module = require './node'
+Node = node_module.Node
+Position = node_module.Position
+
+util_module = require './util'
+
+{isFunction} = util_module
+
+{BorderDropHint,FolderElement,GhostDropHint,NodeElement} = require './node_element'
+
+{DragAndDropHandler, DragElement, HitAreasGenerator} = drag_and_drop_handler
+
+
+$ = jQuery
+
+
+class JqTreeWidget extends MouseWidget
+ BorderDropHint: BorderDropHint
+ DragElement: DragElement
+ DragAndDropHandler: DragAndDropHandler
+ ElementsRenderer: ElementsRenderer
+ GhostDropHint: GhostDropHint
+ HitAreasGenerator: HitAreasGenerator
+ Node: Node
+ SaveStateHandler: SaveStateHandler
+ ScrollHandler: ScrollHandler
+ SelectNodeHandler: SelectNodeHandler
+
+ defaults:
+ autoOpen: false # true / false / int (open n levels starting at 0)
+ saveState: false # true / false / string (cookie name)
+ dragAndDrop: false
+ selectable: true
+ useContextMenu: true
+ onCanSelectNode: null
+ onSetStateFromStorage: null
+ onGetStateFromStorage: null
+ onCreateLi: null
+ onIsMoveHandle: null
+ onCanMove: null # Can this node be moved? function(node)
+ onCanMoveTo: null # Can this node be moved to this position? function(moved_node, target_node, position)
+ onLoadFailed: null
+ autoEscape: true
+ dataUrl: null
+ closedIcon: null # The symbol to use for a closed node - ► BLACK RIGHT-POINTING POINTER http://www.fileformat.info/info/unicode/char/25ba/index.htm
+ openedIcon: '&#x25bc;' # The symbol to use for an open node - ▼ BLACK DOWN-POINTING TRIANGLE http://www.fileformat.info/info/unicode/char/25bc/index.htm
+ slide: true # must display slide animation?
+ nodeClass: Node
+ dataFilter: null
+ keyboardSupport: true
+ openFolderDelay: 500 # The delay for opening a folder during drag and drop; the value is in milliseconds
+ rtl: null # right-to-left support; true / false (default)
+ onDragMove: null
+ onDragStop: null
+ buttonLeft: true
+ onLoading: null
+
+ toggle: (node, slide=null) ->
+ if slide == null
+ slide = @options.slide
+
+ if node.is_open
+ @closeNode(node, slide)
+ else
+ @openNode(node, slide)
+
+ return @element
+
+ getTree: ->
+ return @tree
+
+ selectNode: (node) ->
+ @_selectNode(node, false)
+ return @element
+
+ _selectNode: (node, must_toggle=false) ->
+ if not @select_node_handler
+ return
+
+ canSelect = =>
+ if @options.onCanSelectNode
+ return @options.selectable and @options.onCanSelectNode(node)
+ else
+ return @options.selectable
+
+ openParents = =>
+ parent = node.parent
+
+ if parent and parent.parent and not parent.is_open
+ @openNode(parent, false)
+
+ saveState = =>
+ if @options.saveState
+ @save_state_handler.saveState()
+
+ if not node
+ # Called with empty node -> deselect current node
+ @_deselectCurrentNode()
+ saveState()
+ return
+
+ if not canSelect()
+ return
+
+ if @select_node_handler.isNodeSelected(node)
+ if must_toggle
+ @_deselectCurrentNode()
+ @_triggerEvent(
+ 'tree.select',
+ node: null,
+ previous_node: node
+ )
+ else
+ deselected_node = @getSelectedNode()
+ @_deselectCurrentNode()
+ @addToSelection(node)
+ @_triggerEvent('tree.select', node: node, deselected_node: deselected_node)
+ openParents()
+
+ saveState()
+
+ getSelectedNode: ->
+ if @select_node_handler
+ return @select_node_handler.getSelectedNode()
+ else
+ return null
+
+ toJson: ->
+ return JSON.stringify(
+ @tree.getData()
+ )
+
+ loadData: (data, parent_node) ->
+ @_loadData(data, parent_node)
+ return @element
+
+ ###
+ signatures:
+ - loadDataFromUrl(url, parent_node=null, on_finished=null)
+ loadDataFromUrl('/my_data');
+ loadDataFromUrl('/my_data', node1);
+ loadDataFromUrl('/my_data', node1, function() { console.log('finished'); });
+ loadDataFromUrl('/my_data', null, function() { console.log('finished'); });
+
+ - loadDataFromUrl(parent_node=null, on_finished=null)
+ loadDataFromUrl();
+ loadDataFromUrl(node1);
+ loadDataFromUrl(null, function() { console.log('finished'); });
+ loadDataFromUrl(node1, function() { console.log('finished'); });
+ ###
+ loadDataFromUrl: (param1, param2, param3) ->
+ if $.type(param1) == 'string'
+ # first parameter is url
+ @_loadDataFromUrl(param1, param2, param3)
+ else
+ # first parameter is not url
+ @_loadDataFromUrl(null, param1, param2)
+
+ return @element
+
+ reload: (on_finished) ->
+ @_loadDataFromUrl(null, null, on_finished)
+ return @element
+
+ _loadDataFromUrl: (url_info, parent_node, on_finished) ->
+ $el = null
+
+ addLoadingClass = =>
+ if parent_node
+ $el = $(parent_node.element)
+ else
+ $el = @element
+
+ $el.addClass('jqtree-loading')
+ @_notifyLoading(true, parent_node, $el)
+
+ removeLoadingClass = =>
+ if $el
+ $el.removeClass('jqtree-loading')
+
+ @_notifyLoading(false, parent_node, $el)
+
+ parseUrlInfo = ->
+ if $.type(url_info) == 'string'
+ return url: url_info
+
+ if not url_info.method
+ url_info.method = 'get'
+
+ return url_info
+
+ handeLoadData = (data) =>
+ removeLoadingClass()
+ @_loadData(data, parent_node)
+
+ if on_finished and $.isFunction(on_finished)
+ on_finished()
+
+ handleSuccess = (response) =>
+ if $.isArray(response) or typeof response == 'object'
+ data = response
+ else if data?
+ data = $.parseJSON(response)
+ else
+ data = []
+
+ if @options.dataFilter
+ data = @options.dataFilter(data)
+
+ handeLoadData(data)
+
+ handleError = (response) =>
+ removeLoadingClass()
+
+ if @options.onLoadFailed
+ @options.onLoadFailed(response)
+
+ loadDataFromUrlInfo = ->
+ url_info = parseUrlInfo()
+
+ $.ajax(
+ $.extend(
+ {},
+ url_info,
+ {
+ method: if url_info.method? then url_info.method.toUpperCase() else 'GET',
+ cache: false,
+ dataType: 'json',
+ success: handleSuccess,
+ error: handleError
+ }
+ )
+ )
+
+ if not url_info
+ # Generate url for node
+ url_info = @_getDataUrlInfo(parent_node)
+
+ addLoadingClass()
+
+ if not url_info
+ removeLoadingClass()
+ return
+ else if $.isArray(url_info)
+ handeLoadData(url_info)
+ return
+ else
+ loadDataFromUrlInfo()
+ return
+
+ _loadData: (data, parent_node=null) ->
+ deselectNodes = =>
+ if @select_node_handler
+ selected_nodes_under_parent = @select_node_handler.getSelectedNodesUnder(parent_node)
+ for n in selected_nodes_under_parent
+ @select_node_handler.removeFromSelection(n)
+
+ return null
+
+ loadSubtree = =>
+ parent_node.loadFromData(data)
+
+ parent_node.load_on_demand = false
+ parent_node.is_loading = false
+
+ @_refreshElements(parent_node)
+
+ if not data
+ return
+
+ @_triggerEvent('tree.load_data', tree_data: data)
+
+ if not parent_node
+ @_initTree(data)
+ else
+ deselectNodes()
+ loadSubtree()
+
+ if @isDragging()
+ @dnd_handler.refresh()
+
+ getNodeById: (node_id) ->
+ return @tree.getNodeById(node_id)
+
+ getNodeByName: (name) ->
+ return @tree.getNodeByName(name)
+
+ getNodesByProperty: (key, value) ->
+ return @tree.getNodesByProperty(key, value)
+
+ getNodeByHtmlElement: (element) ->
+ return @_getNode($(element))
+
+ getNodeByCallback: (callback) ->
+ return @tree.getNodeByCallback(callback)
+
+ openNode: (node, slide_param=null, on_finished_param=null) ->
+ parseParams = =>
+ if isFunction(slide_param)
+ on_finished = slide_param
+ slide = null
+ else
+ slide = slide_param
+ on_finished = on_finished_param
+
+ if slide == null
+ slide = @options.slide
+
+ return [slide, on_finished]
+
+ [slide, on_finished] = parseParams()
+
+ if node
+ @_openNode(node, slide, on_finished)
+
+ return @element
+
+ _openNode: (node, slide=true, on_finished) ->
+ doOpenNode = (_node, _slide, _on_finished) =>
+ folder_element = new FolderElement(_node, this)
+ folder_element.open(_on_finished, _slide)
+
+ if node.isFolder()
+ if node.load_on_demand
+ @_loadFolderOnDemand(node, slide, on_finished)
+ else
+ parent = node.parent
+
+ while parent
+ # nb: do not open root element
+ if parent.parent
+ doOpenNode(parent, false, null)
+ parent = parent.parent
+
+ doOpenNode(node, slide, on_finished)
+ @_saveState()
+
+ _loadFolderOnDemand: (node, slide=true, on_finished) ->
+ node.is_loading = true
+
+ @_loadDataFromUrl(
+ null,
+ node,
+ =>
+ @_openNode(node, slide, on_finished)
+ )
+
+ closeNode: (node, slide=null) ->
+ if slide == null
+ slide = @options.slide
+
+ if node.isFolder()
+ new FolderElement(node, this).close(slide)
+
+ @_saveState()
+
+ return @element
+
+ isDragging: ->
+ if @dnd_handler
+ return @dnd_handler.is_dragging
+ else
+ return false
+
+ refreshHitAreas: ->
+ @dnd_handler.refresh()
+ return @element
+
+ addNodeAfter: (new_node_info, existing_node) ->
+ new_node = existing_node.addAfter(new_node_info)
+ @_refreshElements(existing_node.parent)
+ return new_node
+
+ addNodeBefore: (new_node_info, existing_node) ->
+ new_node = existing_node.addBefore(new_node_info)
+ @_refreshElements(existing_node.parent)
+ return new_node
+
+ addParentNode: (new_node_info, existing_node) ->
+ new_node = existing_node.addParent(new_node_info)
+ @_refreshElements(new_node.parent)
+ return new_node
+
+ removeNode: (node) ->
+ parent = node.parent
+ if parent
+ @select_node_handler.removeFromSelection(node, true) # including children
+
+ node.remove()
+ @_refreshElements(parent)
+
+ return @element
+
+ appendNode: (new_node_info, parent_node) ->
+ parent_node = parent_node or @tree
+
+ node = parent_node.append(new_node_info)
+
+ @_refreshElements(parent_node)
+
+ return node
+
+ prependNode: (new_node_info, parent_node) ->
+ if not parent_node
+ parent_node = @tree
+
+ node = parent_node.prepend(new_node_info)
+
+ @_refreshElements(parent_node)
+
+ return node
+
+ updateNode: (node, data) ->
+ id_is_changed = data.id and data.id != node.id
+
+ if id_is_changed
+ @tree.removeNodeFromIndex(node)
+
+ node.setData(data)
+
+ if id_is_changed
+ @tree.addNodeToIndex(node)
+
+ if typeof data == 'object' and data.children
+ node.removeChildren()
+
+ if data.children.length
+ node.loadFromData(data.children)
+
+ @renderer.renderFromNode(node)
+ @_selectCurrentNode()
+
+ return @element
+
+ moveNode: (node, target_node, position) ->
+ position_index = Position.nameToIndex(position)
+
+ @tree.moveNode(node, target_node, position_index)
+ @_refreshElements()
+ return @element
+
+ getStateFromStorage: ->
+ return @save_state_handler.getStateFromStorage()
+
+ addToSelection: (node) ->
+ if node
+ @select_node_handler.addToSelection(node)
+
+ @_getNodeElementForNode(node).select()
+ @_saveState()
+
+ return @element
+
+ getSelectedNodes: ->
+ return @select_node_handler.getSelectedNodes()
+
+ isNodeSelected: (node) ->
+ return @select_node_handler.isNodeSelected(node)
+
+ removeFromSelection: (node) ->
+ @select_node_handler.removeFromSelection(node)
+
+ @_getNodeElementForNode(node).deselect()
+ @_saveState()
+ return @element
+
+ scrollToNode: (node) ->
+ $element = $(node.element)
+ top = $element.offset().top - @$el.offset().top
+
+ @scroll_handler.scrollTo(top)
+ return @element
+
+ getState: ->
+ return @save_state_handler.getState()
+
+ setState: (state) ->
+ @save_state_handler.setInitialState(state)
+ @_refreshElements()
+ return @element
+
+ setOption: (option, value) ->
+ @options[option] = value
+ return @element
+
+ moveDown: ->
+ if @key_handler
+ @key_handler.moveDown()
+
+ return @element
+
+ moveUp: ->
+ if @key_handler
+ @key_handler.moveUp()
+
+ return @element
+
+ getVersion: ->
+ return __version__
+
+ _init: ->
+ super()
+
+ @element = @$el
+ @mouse_delay = 300
+ @is_initialized = false
+
+ @options.rtl = @_getRtlOption()
+
+ if !@options.closedIcon
+ @options.closedIcon = @_getDefaultClosedIcon()
+
+ @renderer = new ElementsRenderer(this)
+
+ if SaveStateHandler?
+ @save_state_handler = new SaveStateHandler(this)
+ else
+ @options.saveState = false
+
+ if SelectNodeHandler?
+ @select_node_handler = new SelectNodeHandler(this)
+
+ if DragAndDropHandler?
+ @dnd_handler = new DragAndDropHandler(this)
+ else
+ @options.dragAndDrop = false
+
+ if ScrollHandler?
+ @scroll_handler = new ScrollHandler(this)
+
+ if KeyHandler? and SelectNodeHandler?
+ @key_handler = new KeyHandler(this)
+
+ @_initData()
+
+ @element.click($.proxy(@_click, this))
+ @element.dblclick($.proxy(@_dblclick, this))
+
+ if @options.useContextMenu
+ @element.bind('contextmenu', $.proxy(@_contextmenu, this))
+
+ _deinit: ->
+ @element.empty()
+ @element.unbind()
+
+ if @key_handler
+ @key_handler.deinit()
+
+ @tree = null
+
+ super()
+
+ _initData: ->
+ if @options.data
+ @_loadData(@options.data)
+ else
+ data_url = @_getDataUrlInfo()
+
+ if data_url
+ @_loadDataFromUrl()
+ else
+ @_loadData([])
+
+ _getDataUrlInfo: (node) ->
+ data_url = @options.dataUrl or @element.data('url')
+
+ getUrlFromString = =>
+ url_info = url: data_url
+
+ if node and node.id
+ # Load on demand of a subtree; add node parameter
+ data = node: node.id
+ url_info['data'] = data
+ else
+ # Add selected_node parameter
+ selected_node_id = @_getNodeIdToBeSelected()
+ if selected_node_id
+ data = selected_node: selected_node_id
+ url_info['data'] = data
+
+ return url_info
+
+ if $.isFunction(data_url)
+ return data_url(node)
+ else if $.type(data_url) == 'string'
+ return getUrlFromString()
+ else
+ return data_url
+
+ _getNodeIdToBeSelected: ->
+ if @options.saveState
+ return @save_state_handler.getNodeIdToBeSelected()
+ else
+ return null
+
+ _initTree: (data) ->
+ doInit = =>
+ if not @is_initialized
+ @is_initialized = true
+ @_triggerEvent('tree.init')
+
+ @tree = new @options.nodeClass(null, true, @options.nodeClass)
+
+ if @select_node_handler
+ @select_node_handler.clear()
+
+ @tree.loadFromData(data)
+
+ must_load_on_demand = @_setInitialState()
+
+ @_refreshElements()
+
+ if not must_load_on_demand
+ doInit()
+ else
+ # Load data on demand and then init the tree
+ @_setInitialStateOnDemand(doInit)
+
+ # Set initial state, either by restoring the state or auto-opening nodes
+ # result: must load nodes on demand?
+ _setInitialState: ->
+ restoreState = =>
+ # result: is state restored, must load on demand?
+ if not (@options.saveState and @save_state_handler)
+ return [false, false]
+ else
+ state = @save_state_handler.getStateFromStorage()
+
+ if not state
+ return [false, false]
+ else
+ must_load_on_demand = @save_state_handler.setInitialState(state)
+
+ # return true: the state is restored
+ return [true, must_load_on_demand]
+
+ autoOpenNodes = =>
+ # result: must load on demand?
+ if @options.autoOpen is false
+ return false
+
+ max_level = @_getAutoOpenMaxLevel()
+ must_load_on_demand = false
+
+ @tree.iterate (node, level) ->
+ if node.load_on_demand
+ must_load_on_demand = true
+ return false
+ else if not node.hasChildren()
+ return false
+ else
+ node.is_open = true
+ return (level != max_level)
+
+ return must_load_on_demand
+
+ [is_restored, must_load_on_demand] = restoreState()
+
+ if not is_restored
+ must_load_on_demand = autoOpenNodes()
+
+ return must_load_on_demand
+
+ # Set the initial state for nodes that are loaded on demand
+ # Call cb_finished when done
+ _setInitialStateOnDemand: (cb_finished) ->
+ restoreState = =>
+ if not (@options.saveState and @save_state_handler)
+ return false
+ else
+ state = @save_state_handler.getStateFromStorage()
+
+ if not state
+ return false
+ else
+ @save_state_handler.setInitialStateOnDemand(state, cb_finished)
+
+ return true
+
+ autoOpenNodes = =>
+ max_level = @_getAutoOpenMaxLevel()
+ loading_count = 0
+
+ loadAndOpenNode = (node) =>
+ loading_count += 1
+ @_openNode(
+ node,
+ false,
+ ->
+ loading_count -= 1
+ openNodes()
+ )
+
+ openNodes = =>
+ @tree.iterate (node, level) =>
+ if node.load_on_demand
+ if not node.is_loading
+ loadAndOpenNode(node)
+
+ return false
+ else
+ @_openNode(node, false)
+
+ return (level != max_level)
+
+ if loading_count == 0
+ cb_finished()
+
+ openNodes()
+
+ if not restoreState()
+ autoOpenNodes()
+
+ _getAutoOpenMaxLevel: ->
+ if @options.autoOpen is true
+ return -1
+ else
+ return parseInt(@options.autoOpen)
+
+ ###
+ Redraw the tree or part of the tree.
+ # from_node: redraw this subtree
+ ###
+ _refreshElements: (from_node=null) ->
+ @renderer.render(from_node)
+
+ @_triggerEvent('tree.refresh')
+
+ _click: (e) ->
+ click_target = @_getClickTarget(e.target)
+
+ if click_target
+ if click_target.type == 'button'
+ @toggle(click_target.node, @options.slide)
+
+ e.preventDefault()
+ e.stopPropagation()
+ else if click_target.type == 'label'
+ node = click_target.node
+ event = @_triggerEvent(
+ 'tree.click',
+ node: node
+ click_event: e
+ )
+
+ if not event.isDefaultPrevented()
+ @_selectNode(node, true)
+
+ _dblclick: (e) ->
+ click_target = @_getClickTarget(e.target)
+
+ if click_target and click_target.type == 'label'
+ @_triggerEvent(
+ 'tree.dblclick',
+ node: click_target.node
+ click_event: e
+ )
+
+ _getClickTarget: (element) ->
+ $target = $(element)
+
+ $button = $target.closest('.jqtree-toggler')
+
+ if $button.length
+ node = @_getNode($button)
+
+ if node
+ return {
+ type: 'button',
+ node: node
+ }
+ else
+ $el = $target.closest('.jqtree-element')
+ if $el.length
+ node = @_getNode($el)
+ if node
+ return {
+ type: 'label',
+ node: node
+ }
+
+ return null
+
+ _getNode: ($element) ->
+ $li = $element.closest('li.jqtree_common')
+ if $li.length == 0
+ return null
+ else
+ return $li.data('node')
+
+ _getNodeElementForNode: (node) ->
+ if node.isFolder()
+ return new FolderElement(node, this)
+ else
+ return new NodeElement(node, this)
+
+ _getNodeElement: ($element) ->
+ node = @_getNode($element)
+ if node
+ return @_getNodeElementForNode(node)
+ else
+ return null
+
+ _contextmenu: (e) ->
+ $div = $(e.target).closest('ul.jqtree-tree .jqtree-element')
+ if $div.length
+ node = @_getNode($div)
+ if node
+ e.preventDefault()
+ e.stopPropagation()
+
+ @_triggerEvent(
+ 'tree.contextmenu',
+ node: node
+ click_event: e
+ )
+ return false
+
+ _saveState: ->
+ if @options.saveState
+ @save_state_handler.saveState()
+
+ _mouseCapture: (position_info) ->
+ if @options.dragAndDrop
+ return @dnd_handler.mouseCapture(position_info)
+ else
+ return false
+
+ _mouseStart: (position_info) ->
+ if @options.dragAndDrop
+ return @dnd_handler.mouseStart(position_info)
+ else
+ return false
+
+ _mouseDrag: (position_info) ->
+ if @options.dragAndDrop
+ result = @dnd_handler.mouseDrag(position_info)
+
+ if @scroll_handler
+ @scroll_handler.checkScrolling()
+ return result
+ else
+ return false
+
+ _mouseStop: (position_info) ->
+ if @options.dragAndDrop
+ return @dnd_handler.mouseStop(position_info)
+ else
+ return false
+
+ _triggerEvent: (event_name, values) ->
+ event = $.Event(event_name)
+ $.extend(event, values)
+
+ @element.trigger(event)
+ return event
+
+ testGenerateHitAreas: (moving_node) ->
+ @dnd_handler.current_item = @_getNodeElementForNode(moving_node)
+ @dnd_handler.generateHitAreas()
+ return @dnd_handler.hit_areas
+
+ _selectCurrentNode: ->
+ node = @getSelectedNode()
+ if node
+ node_element = @_getNodeElementForNode(node)
+ if node_element
+ node_element.select()
+
+ _deselectCurrentNode: ->
+ node = @getSelectedNode()
+ if node
+ @removeFromSelection(node)
+
+ _getDefaultClosedIcon: ->
+ if @options.rtl
+ # triangle to the left
+ return '&#x25c0;'
+ else
+ # triangle to the right
+ return '&#x25ba;'
+
+ _getRtlOption: ->
+ if @options.rtl != null
+ return @options.rtl
+ else
+ data_rtl = @element.data('rtl')
+
+ if data_rtl? and data_rtl != false
+ return true
+ else
+ return false
+
+ _notifyLoading: (is_loading, node, $el) ->
+ if @options.onLoading
+ @options.onLoading(is_loading, node, $el)
+
+
+JqTreeWidget.getModule = (name) ->
+ modules =
+ 'node': node_module
+ 'util': util_module
+ 'drag_and_drop_handler': drag_and_drop_handler
+
+ return modules[name]
+
+
+SimpleWidget.register(JqTreeWidget, 'tree')
diff --git a/ecomp-portal-FE/client/bower_components/jqTree/src/util.coffee b/ecomp-portal-FE/client/bower_components/jqTree/src/util.coffee
new file mode 100644
index 00000000..2375b14e
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/jqTree/src/util.coffee
@@ -0,0 +1,48 @@
+# Standard javascript indexOf. Implemented here because not all browsers support it.
+_indexOf = (array, item) ->
+ for value, i in array
+ if value == item
+ return i
+ return -1
+
+indexOf = (array, item) ->
+ if array.indexOf
+ # The browser supports indexOf
+ return array.indexOf(item)
+ else
+ # Do our own indexOf
+ return _indexOf(array, item)
+
+isInt = (n) ->
+ return typeof n is 'number' and n % 1 == 0
+
+
+isFunction = (v) ->
+ return typeof v == 'function'
+
+
+# Escape a string for HTML interpolation; copied from underscore js
+html_escape = (string) ->
+ return (''+string)
+ .replace(/&/g, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/"/g, '&quot;')
+ .replace(/'/g, '&#x27;')
+ .replace(/\//g,'&#x2F;')
+
+
+getBoolString = (value) ->
+ if value
+ return 'true'
+ else
+ return 'false'
+
+
+module.exports =
+ _indexOf: _indexOf
+ getBoolString: getBoolString
+ html_escape: html_escape
+ indexOf: indexOf
+ isInt: isInt
+ isFunction: isFunction
diff --git a/ecomp-portal-FE/client/bower_components/jqTree/src/version.coffee b/ecomp-portal-FE/client/bower_components/jqTree/src/version.coffee
new file mode 100644
index 00000000..ccaef948
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/jqTree/src/version.coffee
@@ -0,0 +1 @@
+module.exports = '1.3.7'