summaryrefslogtreecommitdiffstats
path: root/ecomp-portal-FE/client/bower_components/jqTree/src/drag_and_drop_handler.coffee
diff options
context:
space:
mode:
Diffstat (limited to 'ecomp-portal-FE/client/bower_components/jqTree/src/drag_and_drop_handler.coffee')
-rw-r--r--ecomp-portal-FE/client/bower_components/jqTree/src/drag_and_drop_handler.coffee491
1 files changed, 491 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