Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTML5 dragleave fired when hovering a child element

The problem I'm having is that the dragleave event of an element is fired when hovering a child element of that element. Also, dragenter is not fired when hovering back the parent element again.

I made a simplified fiddle: http://jsfiddle.net/pimvdb/HU6Mk/1/.

HTML:

<div id="drag" draggable="true">drag me</div>  <hr>  <div id="drop">     drop here     <p>child</p>     parent </div> 

with the following JavaScript:

$('#drop').bind({                  dragenter: function() {                      $(this).addClass('red');                  },                   dragleave: function() {                      $(this).removeClass('red');                  }                 });  $('#drag').bind({                  dragstart: function(e) {                      e.allowedEffect = "copy";                      e.setData("text/plain", "test");                  }                 }); 

What it is supposed to do is notifying the user by making the drop div red when dragging something there. This works, but if you drag into the p child, the dragleave is fired and the div isn't red anymore. Moving back to the drop div also doesn't make it red again. It's necessary to move completely out of the drop div and drag back into it again to make it red.

Is it possible to prevent dragleave from firing when dragging into a child element?

2017 Update: TL;DR, Look up CSS pointer-events: none; as described in @H.D.'s answer below that works in modern browsers and IE11.

like image 380
pimvdb Avatar asked Aug 18 '11 15:08

pimvdb


People also ask

How does dragenter work?

The dragenter event is fired when a dragged element or text selection enters a valid drop target. The target object is the immediate user selection (the element directly indicated by the user as the drop target), or the <body> element.


2 Answers

You just need to keep a reference counter, increment it when you get a dragenter, decrement when you get a dragleave. When the counter is at 0 - remove the class.

var counter = 0;  $('#drop').bind({     dragenter: function(ev) {         ev.preventDefault(); // needed for IE         counter++;         $(this).addClass('red');     },      dragleave: function() {         counter--;         if (counter === 0) {              $(this).removeClass('red');         }     } }); 

Note: In the drop event, reset counter to zero, and clear the added class.

You can run it here

like image 154
Woody Avatar answered Sep 26 '22 06:09

Woody


Is it possible to prevent dragleave from firing when dragging into a child element?

Yes.

#drop * {pointer-events: none;} 

That CSS seem to be enough for Chrome.

While using it with Firefox, the #drop shouldn't have text nodes directly (else there's a strange issue where a element "leave it to itself"), so I suggest to leave it with only one element (e.g., use a div inside #drop to put everything inside)

Here's a jsfiddle solving the original question (broken) example.

I've also made a simplified version forked from the @Theodore Brown example, but based only in this CSS.

Not all browsers have this CSS implemented, though: http://caniuse.com/pointer-events

Seeing the Facebook source code I could find this pointer-events: none; several times, however it's probably used together with graceful degradation fallbacks. At least it's so simple and solves the problem for a lot of environments.

like image 37
H.D. Avatar answered Sep 24 '22 06:09

H.D.