     # Redraw the main canvas
     @redrawMain()
 
+Editor::getClosestDroppableBlock = (position) ->
+  best = null; min = Infinity
+
+  if not (@dropPointQuadTree)
+    return null
+
+  testPoints = @dropPointQuadTree.retrieve {
+    x: position.x - MAX_DROP_DISTANCE
+    y: position.y - MAX_DROP_DISTANCE
+    w: MAX_DROP_DISTANCE * 2
+    h: MAX_DROP_DISTANCE * 2
+  }, (point) =>
+    unless (point.acceptLevel is helper.DISCOURAGE) and not event.shiftKey
+      # Find a modified "distance" to the point
+      # that weights horizontal distance more
+      distance = position.from(point)
+      distance.y *= 2; distance = distance.magnitude()
+
+      # Select the node that is closest by said "distance"
+      if distance < min and position.from(point).magnitude() < MAX_DROP_DISTANCE and
+         @view.getViewNodeFor(point._droplet_node).highlightArea?
+        best = point._droplet_node
+        min = distance
+  best
+
+Editor::isDragPointOverSocket = (position) ->
+  if not @currentlyUsingBlocks
+    return true
+
+  mainPoint = @trackerPointToMain(position)
+  dropBlock = @getClosestDroppableBlock(mainPoint)
+  return (dropBlock) and dropBlock.type is 'socket'
+
 Editor::getAcceptLevel = (drag, drop) ->
   if drop.type is 'socket'
     if drag.type is 'list'

      # If the user is touching the original location,
      # assume they want to replace the block where they found it.
      if @hitTest mainPoint, @draggingBlock
        best = null
        @dragReplacing = true

      # Otherwise, find the closest droppable block
      else
        @dragReplacing = false
        testPoints = @dropPointQuadTree.retrieve {
          x: mainPoint.x - MAX_DROP_DISTANCE
          y: mainPoint.y - MAX_DROP_DISTANCE
          w: MAX_DROP_DISTANCE * 2
          h: MAX_DROP_DISTANCE * 2
        }, (point) =>
          unless (point.acceptLevel is helper.DISCOURAGE) and not event.shiftKey
            # Find a modified "distance" to the point
            # that weights horizontal distance more
            distance = mainPoint.from(point)
            distance.y *= 2; distance = distance.magnitude()

            # Select the node that is closest by said "distance"
            if distance < min and mainPoint.from(point).magnitude() < MAX_DROP_DISTANCE and
               @view.getViewNodeFor(point._droplet_node).highlightArea?
              best = point._droplet_node
              min = distance

      # Update highlight if necessary.
      if best isnt @lastHighlight
        # TODO if this becomes a performance issue,
        # pull the drop highlights out into a new canvas.
        @redrawHighlights()

        if best?
          @view.getViewNodeFor(best).highlightArea.draw @highlightCtx
          @maskFloatingPaths(best.getDocument())

        @lastHighlight = best

    palettePoint = @trackerPointToPalette position


    # TODO figure out what to do with lists here

    # Draw the new dragging block on the drag canvas.
    @drawDraggingBlock()

    # Translate it immediately into position
    position = new @draw.Point(
