anchor.diff:    
     /**
      * Hides the placeholder and shows the draggable.
  -   * If [revertToOriginal] is true, the draggable is shown at the 
  -   * [originalPosition]. If false, it is shown at the current [newPosition].
  -   */
  -  void hidePlaceholder({bool revertToOriginal: false}) {
  +   * If [dropped] is true, the draggable is shown at the 
  +   * [_currentPosition]. If false, it is shown at the [_originalPosition].
  +   */
  +  void hidePlaceholder({bool dropped: false}) {
  +    // Remove placeholder element from DOM.
       placeholderElement.remove();
  -    
  -    if (revertToOriginal) {
  -      originalPosition.insert(draggable);      
  -    } else {
  -      newPosition.insert(draggable);
  -      
  -      // Fire sort event
  -      if (newPosition != originalPosition) {
  +    placeholderElement = null;
  +    
  +    // Reset current placeholder so that no one else can call it.
  +    _currentPlaceholder = null;
  +    
  +    if (dropped) {
  +      _logger.finest('placeholder was dropped -> Show draggable at new position');
  +      _currentPosition.insert(_draggable);
  +      
  +      // Fire sort update event if the position has changed.
  +      if (_currentPosition != _originalPosition) {
           _logger.finest('firing onSortableComplete event');
           
  -        if (newGroup._onSortUpdate != null) {
  -          newGroup._onSortUpdate.add(new SortableEvent(draggable, 
  -              originalPosition, newPosition, originalGroup, newGroup));
  +        if (_currentGroup._onSortUpdate != null) {
  +          _currentGroup._onSortUpdate.add(new SortableEvent(_draggable, 
  +              _originalPosition, _currentPosition, _originalGroup, _currentGroup));
           }
         }
  +      
  +    } else {
  +      // Not dropped. This means the drag ended outside of a placeholder or
  +      // the drag was cancelled somehow (ESC-key, ...)
  +      // Revert to state before dragging.
  +      _logger.finest('placeholder not dropped -> Revert to state before dragging');
  +      _originalPosition.insert(_draggable);      
  +    }
  +    
  +    // Cancel all subscriptions.
  +    if (_dropzoneOverSub != null) {
  +      _dropzoneOverSub.cancel();
       }
     }
     
  
positive.code:  */
  class _Placeholder {
    /// The draggable that this placeholder is for.
    final Element draggable;
    
    /// Position of the draggable element before dragging.
    Position originalPosition;
    
    /// Current Position of the placeholder.
    Position newPosition;
    
    /// The group of the draggable element before dragging. 
    /// Might be a [DraggableGroup] or a [SortableGroup].
    DraggableGroup originalGroup;
    
    /// Current group of the placeholder.
    SortableGroup newGroup;
    
    /// The placeholder element.
    Element placeholderElement;
    
    /// A [DropzoneGroup] just for the placeholder to receive events from draggable.
    DropzoneGroup _placeholderDropzoneGroup;
    
    /// Flag to tell whether this dropzone was dropped.
    bool _dropped = false;
    
    StreamSubscription _dropzoneOverSub; 
    StreamSubscription _dropzoneDropSub; 
    StreamSubscription _placeholderDropSub;
    StreamSubscription _draggableEndSub;
    
    /**
     * Creates a new placeholder for the specified [draggable].
     */
    _Placeholder(this.draggable, this.originalGroup) {
      // Save original position of draggable for later.
      originalPosition = new Position(draggable.parent,
          html5.getElementIndexInParent(draggable));
      
      // Create a new DropzoneGroup just for the placeholder.
      _placeholderDropzoneGroup = new DropzoneGroup()
      ..accept.add(originalGroup);
    }
    
    
    /**
     * Shows the placeholder at the position of [dropzone].
  
negative.code:       // Last sortable of this group was uninstalled --> cancel subscriptions.
        _dragEnterSub.cancel();
        _dragEnterSub = null;
      }
    }
  }
  