Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Nested custom drag n drop: inconsist behavior

    I have several draggable container canvas elements, each contains a content element as a child. Both container and content child implement a drop handler (see example below). I'm not using dragReposition, as the application implements various custom logic during D'n'd.

    The expected behavior is that the drop events are received on both child and parent (bubbled from the child).

    However, the EventHandler.getDropTarget method produces following unwanted behavior:
    1) moving the container element to another position (without dropping it on another element) produces drop events on both container and content element. As we move as target, the canDropOnSelf variable inside getDropTarget is initialized correctly, but evaluates only the dragged container element, not its children.
    2) dragging t1 over t2 produces only drop events on t1 and c1. Dragging t2 over t1 produces correctly drop events on t1 and c1. The creation order of the elements (which is reflected in the list EH._dropRegistry) is causing this inconsistent behavior, as the order is significant to the algorithm who picks possible matching drop targets

    Code:
    isc.defineClass("DragContainer", "Canvas").addProperties({
        width:48, height:48,
        canDrag: true,
        canDrop: true,
        canAcceptDrop: true,
        dragAppearance: "target",
        drop: function() {
            console.log("drop " + this.getID());
        }
    });
    
    
    isc.defineClass("DragContent", "Label").addProperties({
        width:48, height:48,
        backgroundColor: "#eecccc",
        canAcceptDrop: true,
        drop: function() {
            console.log("drop " + this.contents);
        }
    });
    
    isc.DragContainer.create({
        ID: "c1",
        left: 100,
        children: [
            isc.DragContent.create({ contents: "t1" })
        ]
    });
    
    isc.DragContainer.create({
        ID: "c2",
        left: 200,
        children: [
            isc.DragContent.create({ contents: "t2" })
        ]
    });

    This behavior has been tested against SmartClient LGPL 8.3d and 8.2p from 2012-10-30.

    #2
    b) is a product of zIndex, which defaults to creation order but which you can explicitly set via moveAbove() / moveBelow() if you want to control which element becomes the drop target.

    a) we're having trouble following your description, and details matter. Can you either produce an extremely precision description (exactly where the cursor is and what bounding boxes overlap) or use a video capture tool such as Jing.

    Comment


      #3
      Ok, I'll try to explain better and I'm providing a possible solution.
      First, see following screencast: http://youtu.be/iVc-BrezKqo.

      Note: The only difference to the source code posted above is that I used different colors for both blocks.

      1a) 00:00 - 00:06: I'm moving the container element to another position. See console output with drop events from both content and container. I do not expect these drop events on the moved elements.

      1b) 00:06 - 00:21: when canAcceptDrop is false on the content element, no drop events are generated. This is the expected behavior.

      2) 00:22 - end: canAcceptDrop is again active on the content element. Now, when c2/t2 is moved over c1/t1, both c1 and t1 produce expected drop events. When c1/t1 is moved over c2/t2, I'm expecting that c2/t2 receive the drop events. However, only c1 and t1 produce unwanted drop events.

      Explanation:
      The method EventHandler.getDropTarget tries to find out which element is under the mouse pointer. In case it is the dragged element itself (for dragAppearance: target), the dragged element is ignored (no drop events are produced). This is expected and works fine - see 1b).
      However, when the content element also wants to capture drop events, it is not considered that the content element is a child of the dragged element. The content element is not ignored and produces unwanted drop events that propagate to the container element - see 1a).
      The same effect causes issue 2). The fact that the issue is only visible when dragging c1/t1 over c2/t2 depends on the creation order (not the zIndex) - but this is not the root of the issue.

      Solution:
      The unwanted behavior 1a) and 2) can be resolved when not only the dragged element, but also its descendants are ignored when determining the drop target. The patch seems simple and is working - however, I don't know whether it produces side effects or performance problems, as it affects a very central part of SmartClient...

      EventHandler.getDropTarget:
      Code:
              // check whether mouse coordinates are within candidate drop target
              // Note - we're using 'visibleAtPoint()' here rather than 'containsPoint()', as we don't
              // want to pick up a drop target that's occluded by another widget.
              // We may still pick up more than one match, as one canAcceptDrop:true widget may be
              // a child of another.
              // We ignore the dragMoveTarget in this check since it is likely to be under the mouse
              // (or near enough that a quick movement may put it under the mouse).
              for (;i<length;i++) {
                  var candidate = dropCandidates[i];
                  
                  if (candidate.canAcceptDrop && !candidate.isDisabled() &&
                      (
                       candidate.visibleAtPoint(event.x, event.y, false, 
                                                EH._getDragMoveComponents())
                       // candidate.containsPoint(event.x, event.y))
                      ) &&
                      // ORIGINAL LINE (canDropOnSelf || candidate != target)
                      // PATCHED LINE
                      (canDropOnSelf || !target.contains(candidate, true))
                      // END PATCH
                     ) 
                  {
                      matches.add(candidate);
                  }
              }

      Comment


        #4
        We were not reproducing issue #2 with your test code. We suspect it may be to do with the drag position of the mouse or similar -- see if you can reproduce it when starting your drag with the mousepointer in the center of the draggable rectangle (t2) rather than right at the edge.

        Regardless your patch looks correct and we plan to roll it into the product. Let us know if this is blocking you and we'll expedite this

        Thanks
        Isomorphic Software

        Comment


          #5
          Strange that you are not seeing #2. For us, it makes no difference where we are dragging the object.
          Anyway, the proposed fix resolves both issues for us. Currently, we have patched the method as described above, so we can proceed with our work for the moment. So no pressure in terms of days.
          However, it would be nice to see this integrated soon, as we're going to use this scenario in a number of projects, and we would like to avoid version/bugfix confusion. Maybe you could just drop a note when this patch will make it into the product.

          Comment


            #6
            The patch has been rolled into both the mainline (9.0d) and latest patch release (8.3p) branches.

            Regards
            Isomorphic Software

            Comment

            Working...
            X