diff options
Diffstat (limited to 'ecomp-portal-FE/client/bower_components/jqTree/src')
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: '▼' # 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 '◀' + else + # triangle to the right + return '►' + + _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, '&') + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(/\//g,'/') + + +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' |