4

I am doing drag and drop the HTML5-way (i.e. no jQuery draggable/droppable). I have a drop target (a div) that is partially obscured by another, absolutely positioned div, like so:

<div id="drop-target" style="width:100%; height:500px; background-color:blue;" />

<div id="obscuring-div" style="width:40%; height:150px; position:absolute; top:10px; left: 10px; background-color:red;" />

When I drop items on the absolutely positioned obscuring-div, is there any way to make the drop event trigger on drop-target instead of obscuring-div?

MW.
  • 12,550
  • 9
  • 36
  • 65
  • could you not make the child div droppable with a drop event that moves it to the parent? – Pete Jun 12 '14 at 12:25
  • @Pete It's not a child div, it's placed at the same level as the drop target. In the real code, they are stored in completely different parts of the DOM tree, and there are multiple drop targets as well as multiple obscuring divs. So I don't know which drop-target should be triggered, unless I can find the correct one based on mouse position somehow? – MW. Jun 12 '14 at 12:35
  • You could disable the [pointer events](https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events) of the top div. This is however [not compatible](http://caniuse.com/pointer-events) with all browsers, but there are [workarounds](http://stackoverflow.com/questions/5855135/css-pointer-events-property-alternative-for-ie) - probably more js libraries now too since that question was asked 3 years ago – Pete Jun 12 '14 at 13:01
  • @Pete: Your links led to this: http://www.vinylfox.com/forwarding-mouse-events-through-layers/ which was exactly what I needed! Post it as an answer and I'll accept it for you. – MW. Jun 12 '14 at 13:40
  • You should post your code above as an answer to your own question - I just gave some helpful (hopefully!) pointers – Pete Jun 12 '14 at 14:25
  • 1
    @Pete They sure were :) Thanks! – MW. Jun 12 '14 at 14:39

2 Answers2

3

The comments from Pete led me to a javascript solution for forwarding click events through layers, and I could do something similar for drop events. For future reference, here's the code:

var element = $('#drop-target');
// This element should be droppable
element.on('dragover', function (event) {
    event.preventDefault();
});
// This element should be droppable
element.on('dragenter', function (event) {
    event.preventDefault();
});

element.on('drop', function (event) {
    // Find position of drop event
    var xPos = event.originalEvent.clientX,
        yPos = event.originalEvent.clientY;

    // Temporarily hide this element
    element.hide();

    // Find the element that is the real drop target
    var dropTargetBelow = $(document.elementFromPoint(xPos, yPos));

    // Trigger the drop event on real drop target
    dropTargetBelow.trigger(event);

    // Show this element again
    $(this).show();
});

This also works when the elements are stacked, for example if there are three obscuring divs in front of the drop target.

MW.
  • 12,550
  • 9
  • 36
  • 65
1

Just for the record: a similar approach using the elementsFromPoint method and the native dispatchEvent:

someHandler(event): {
  let elements = document.elementsFromPoint(event.clientX, event.clientY);
  let target = elements.find(e => e.matches('#obscuring-div'));
  target.dispatchEvent(new DragEvent('drop', {
    // anything you need to pass; works without that in the simplest case
  }));
}
Andrey Stukalin
  • 5,328
  • 2
  • 31
  • 50