I'm attempting to track a dragenter/leave for the entire screen, which is so far working fine in Chrome/Safari, courtesy of the draghover plugin from as in:
$.fn.draghover = function(options) {
return this.each(function() {
var collection = $(),
self = $(this);
self.on('dragenter', function(e) {
if (collection.size() === 0) {
self.trigger('draghoverstart');
}
collection = collection.add(e.target);
});
self.on('dragleave drop', function(e) {
// timeout is needed because Firefox 3.6 fires the dragleave event on
// the previous element before firing dragenter on the next one
setTimeout( function() {
collection = collection.not(e.target);
if (collection.size() === 0) {
self.trigger('draghoverend');
}
}, 1);
});
});
};
function setText(text) {
$('p.target').text(text);
}
$(document).ready(function() {
$(window).draghover().on({
'draghoverstart': function() {
setText('enter');
},
'draghoverend': function() {
setText('leave');
}
});
});
However Firefox is still giving me problems when I drag over text items, here's a fiddle to demonstrate: /
Is this a Firefox bug or can this be tamed with JS? Or is there a more robust method for performing all of this?
Thanks!
UPDATE: Updated fiddle to / to reduce clutter a bit. To explain the expected behavior of the fiddle:
- Drag a file into the window and p.target should be "ENTER" colored yellow.
- Drag a file out of the window and p.target should be "LEAVE" colored red.
- Drop a file in the window and p.target should be "LEAVE" colored red.
In firefox, the LEAVE event is triggered when you drag the file over text.
I'm attempting to track a dragenter/leave for the entire screen, which is so far working fine in Chrome/Safari, courtesy of the draghover plugin from https://stackoverflow.com/a/10310815/698289 as in:
$.fn.draghover = function(options) {
return this.each(function() {
var collection = $(),
self = $(this);
self.on('dragenter', function(e) {
if (collection.size() === 0) {
self.trigger('draghoverstart');
}
collection = collection.add(e.target);
});
self.on('dragleave drop', function(e) {
// timeout is needed because Firefox 3.6 fires the dragleave event on
// the previous element before firing dragenter on the next one
setTimeout( function() {
collection = collection.not(e.target);
if (collection.size() === 0) {
self.trigger('draghoverend');
}
}, 1);
});
});
};
function setText(text) {
$('p.target').text(text);
}
$(document).ready(function() {
$(window).draghover().on({
'draghoverstart': function() {
setText('enter');
},
'draghoverend': function() {
setText('leave');
}
});
});
However Firefox is still giving me problems when I drag over text items, here's a fiddle to demonstrate: http://jsfiddle.net/tusRy/6/
Is this a Firefox bug or can this be tamed with JS? Or is there a more robust method for performing all of this?
Thanks!
UPDATE: Updated fiddle to http://jsfiddle.net/tusRy/6/ to reduce clutter a bit. To explain the expected behavior of the fiddle:
- Drag a file into the window and p.target should be "ENTER" colored yellow.
- Drag a file out of the window and p.target should be "LEAVE" colored red.
- Drop a file in the window and p.target should be "LEAVE" colored red.
In firefox, the LEAVE event is triggered when you drag the file over text.
Share Improve this question edited May 23, 2017 at 12:33 CommunityBot 11 silver badge asked Jan 7, 2013 at 10:46 DanHDanH 5,8186 gold badges50 silver badges76 bronze badges 1- I have worked around this for now by using an overlay div, as per jsfiddle.net/tusRy/7 however I'm not really happy about this being THE solution so I'll leave this question open until a better idea comes along. – DanH Commented Jan 7, 2013 at 13:58
4 Answers
Reset to default 10As of version 22.0 Firefox is still doing this. When you drag over a text node it fires two kinds of dragenter
and dragleave
events: one where the event target and relatedTarget are BOTH the parent element of the text node, and another where the target is the parent element and the relatedTarget is the actual text node (not even a proper DOM element).
The workaround is just to check for those two kinds of events in your dragenter
and dragleave
handlers and ignore them:
try {
if(event.relatedTarget.nodeType == 3) return;
} catch(err) {}
if(event.target === event.relatedTarget) return;
I use a try/catch block to check the nodeType because occasionally events fire (inexplicably) from outside the document (eg. in other iframes) and trying to access their nodeType throws a permissions error.
Here's the implementation: http://jsfiddle.net/9A7te/
I came up with kind of a solution, yet to test on other browsers other than Chrome and FF but working so far. This is how the setTimeout
looks now:
setTimeout( function() {
var isChild = false;
// in order to get permission errors, use the try-catch
// to check if the relatedTarget is a child of the body
try {
isChild = $('body').find(e.relatedTarget).length ? true : isChild;
}
catch(err){} // do nothing
collection = collection.not(e.target);
if (collection.size() === 0 && !isChild) {
self.trigger('draghoverend');
}
}, 1);
The entire code here - http://jsfiddle.net/tusRy/13/.
The idea is to check if the related tag is a child of the body, in which case we are still in the Browsers and the draghoverend
event should be not triggered. As this can throw errors when moving out of the windows, I used a try method to avoid it.
Well, perhaps somebody with more skills on JS could improve this :)
1) Your dropzone should have only one child element, which might have everything else you need. Something like
<div id="#dropzone">
<div><!--Your contents here--></div>
</div>
2) Use this CSS:
#dropzone * { pointer-events: none; }
You might need to include the :before
and :after
since the *
don't apply to them.
This should be enough to let the drop work in Firefox and Chrome. In your example, it should be enough to add:
body * { pointer-events: none; }
At the end of the CSS. I've done it here:
- http://jsfiddle.net/djsbellini/eKttq/
Other examples:
- http://jsfiddle.net/djsbellini/6yZV6/1/
- http://jsfiddle.net/djsbellini/yR8t8/
I found the answer in a non-selected answer to this SO question asking about dragleave firing on child elements. I have a <div>
that has many children elements. An semi-opaque overlay <span>
becomes visible over the <div>
whenever there's a dragenter
on the page. As you found, 'dragover' isn't like mouseover
. It triggers dragleave
whenever you hover over a child element.
The solution? Dragout It makes dragover
work more like mouseover
. Very short.