The HTML Drag and Drop API defines two very similar events, dragleave and dragexit, which along with dragenter are intended to help track the current drop target.
A quick search didn't turn up any current and clear documentation of the two events, when one should be used over another, and the browser support, so I thought I'd ask here.
I'll share the resources I found so far:
The HTML specification has detailed description of when each event is supposed to be fired, but it requires some deciphering.
The MDN docs (HTML Drag and Drop API and individual dragexit/dragleave pages) are not much of a help, saying "The dragexit event is fired when an element is no longer the drag operation's immediate selection target." / "The dragleave event is fired when a dragged element or text selection leaves a valid drop target." and providing no information about browser support for dragexit (as of 2017-03)
Dottoro's dragexit docs (another of the top Google hits) seems out of date, claiming that "The dragexit event is obsolete in Firefox from version 3.5. Use the ondragleave event instead."
Mozilla's bug 619703 and W3C bug 11568 referenced there shed some light on the history of these two events:
Looks like Gecko/Firefox initially implemented dragexit while IE at least implemented dragleave, the major difference being the order of events: dragexit fires before corresponding dragenter, while dragleave, confusingly, fires after.
The HTML5 spec initially only defined dragleave with IE semantics, but later (~2013) added dragexit with Mozilla's semantics.
Gecko appears to have implemented dragleave in Firefox 3.5 (2009), originally synonymous with dragexit, but later (4.0, ~2011?) changing it to match the spec.
caniuse indicates that the HTML DnD API is more-or-less supported across modern browsers, but does not say anything about dragexit specifically
I have taken code sample from MDN and ran it on Chrome 57.0.2987.110 and Firefox 52.0.2.
Firefox event sequence is
dragexit
dragleave
drop
But Chrome never fired dragexit event.
Chrome event sequence is
dragleave
drop
Further analysis on dragexit event, I found out in Wikipedia that it's part of Mozilla XUL events which says:
In addition to the common/W3C events, Mozilla defined a set of events that work only with XUL elements
In case you need code snippets, here it is dragexit and dragleave event snippet from plunkr.
document.addEventListener("dragexit", function(event) {
console.log(event.type);
// reset the transparency
event.target.style.opacity = "";
}, false);
document.addEventListener("dragleave", function(event) {
console.log(event.type);
// reset background of potential drop target when the draggable element leaves it
if (event.target.className == "dropzone") {
event.target.style.background = "";
}
}, false);
There is an interesting tutorial that shows that DnD API can be fully implemented without using the dragexit event which is not fully supported by all browsers. Your safe bet is to use the dragleave event instead that is well supported by all major browsers.
The MDN web documents you cite are indeed correct. Dragexit is when a dragging and the cursor is "outside of the selected target", whereas Dragleave fires when dragging and the cursor "leaves."
If you drag your cursor slowly, then it goes is displacing pixel-by-pixel (i.e. a straight line): i.e., your cursor might be at position 500x500, 500x501, 500x502, etc.. If you drag your cursor fast, it might displace by multiple pixels: i.e., your cursor might be at position 500x500, then at 500x510, then at 500x520.
If your cursor moves outside of the element and doesn't touch the boundary of the element, then the DragLeave event will not fire, but the DragExit event will fire. For this reason, I usually just bind both events to the same handler, to get the absolute outcome.
Works for me on Chrome (v. 103.0.5060.134). To test, try dragging and dropping really fast, as that is the only way to produce the error of DragLeave not firing when you actually leave the element. But to be clear, drag and drop in HTML isn't something that I would consider stable across all browsers. (After all, what's your top 5 favorite sites that use drag and drop with their elements? Can you even think of 1?)
Related
According to various sources, including the Chrome developers, the following should make an element fullscreen with support for keyboard events:
myElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)
Unfortunately, it doesn't. The element is made fullscreen, but my keydown event listeners aren't triggered. A quick inspection shows that Element.ALLOW_KEYBOARD_INPUT is undefined. Ah...
Was this functionality removed? Looks like it, but I haven't been able to find any online article or release note mentioning this. Nor found anybody else having the same problem.
Or is this a red herring, was it always undefined, and is my bug somewhere else?
I'm on Chrome 108.0.5359.124, Linux.
Or it's just every browser happen to implement same behaviour? Only place I found in spec is in click event section which says
If the event target is focusable, the default action MUST be to give that element document focus.
But actually focus is the default action of mousedown event, which is widely used in today's frontend development, so I'd like to know why
Isn't the answer in the very quote you've posted?
If the event target is focusable, the default action MUST be to give that element document focus.
And then https://www.w3.org/TR/uievents/#event-type-focus
4.2.4.2. focus
...
A user agent MUST dispatch this event when an event target receives focus.
In other words: the spec indeed requires focus event to be fired when and if an element receives focus
By the way, the focus as event and focus as a property - is two different things.
But!.. The quote is actually from click event, not from mousedown
And if you test it in browsers you'll see that:
They behave differently (at least mine Chrome 81 and FF 75).
If you click inside <textarea>, but move out an only then release the button Chrome won't send click to the <textarea>, but FF will
But they give focus to <textarea> and fire focus event right after mousedown.
So that probably means, that:
No the spec doesn't require focus event to be fired after mousedown. (Instead it requires it to be fired after click)
Yes it's just so happens that every browser (well... at least those two I've tested) implement same non-standard behavior
So far the only thing I found in spec is
Many implementations use the mousedown event to begin a variety of contextually dependent default actions. These default actions can be prevented if this event is canceled. Some of these default actions could include: beginning a drag/drop interaction with an image or link, starting text selection, etc. Additionally, some implementations provide a mouse-driven panning feature that is activated when the middle mouse button is pressed at the time the mousedown event is dispatched.
Although it didn't explicitly says focus, I guess it's still enough evidence
I have a collection of draggable "content" elements, and a root-level "feedback" UI element which is displayed above them to provide feedback during drag and drop.
The problem is, during the drag operation, hovering over the "feedback" element causes the dragenter and dragover events to be fired on that element, rather than the underlying content element. It effectively "blocks" the dragenter event from firing on the correct element.
Is there a way for an element to cancel, or "opt out" of a dragenter/dragover event? I could display the feedback element underneath the content, but I'd rather not do that.
jsFiddle: http://jsfiddle.net/jact8/1/
I'm using the HTML drag/drop API, not jQuery or anything like that.
I've created a new fiddle. I think you want to use currentTarget instead of target in your handler on the columns to ensure that the event you receive is from the element you added the listener to (column) rather than the element it originated from (italicised text). See explanation here (it's for ActionScript but I believe it's valid for JavaScript also).
I'm assuming the listener on the insertionCaret element is for debug purposes only and have removed it (let me know if I'm mistaken here). You won't receive the event if you don't listen for it so won't need to opt out of it!
I'm working on a web app where I support dragging on the page, by simply watching for mousedown/mousemove/mouseup events. That part works great.
The problem is that I'm only handling dragging inside one particular element, by design, and if a user (accidentally or not) drags outside, it gets "stuck" in drag mode. That is, mouse-down, then mouse-leaves-window, then mouse-up, then mouse-returns to window looks like it's still dragging, to my app.
I haven't figured out any way to solve this -- even something simple like "when the mouse re-enters the window, is the mouse button down?" would work.
Does such functionality exist, and I'm just missing it? Or is there some clever workaround I can employ here?
Legacy support has no importance to me -- if it's an HTML5 solution that only works in FF3.5/Chr4/Sf4, I'm happy with that.
In IE7/IE8 you can detect if the mouse was released outside the window by using the following code:
document.onmousemove = function(event) {
event = event || window.event;
if (document.all && event.button != 1) {
canceldragging();
}
}
In Firefox and Webkit the mouseup event is fired on the document when the mouse is released even if mouse pointer outside the browser window. You can see this using http://www.quirksmode.org/dom/events/tests/click.html
For IE8 the document onmouseup event is fired when the mouse button is released outside the browser window only if you allow document selection to occur (as the link above does). That is, in IE8 you don't get the mouseup event if you use document.onselectstart and cancel the selection, or if you use unselectable="on" on the starting element, or if you called document.selection.clear() combined with document.selection.empty() while the mouse was down.
What if you had the onmouseout event of the element fire the mouseup event?
If you're just using inline handlers, something along the lines of:
<div id='dragElement' onmouseup='alert("stop dragging!")' onblur='this.onmouseup();'></div>
added to whatever event handling code you're already using. This would 'release' the drag whenever the element loses focus. Not the cleanest code, but you get the idea.
Is there any possibility to tell Firefox to use the mousewheel für scrolling through the select element. In firefox after selecting another value the select element looeses its focus, and in IE it doest loose its focus, so if i use my wheel the onchange event is fired.
Try here.
Is there any solution?
Thank you
There's a tutorial on how to act on mousewheel events at http://www.switchonthecode.com/tutorials/javascript-tutorial-the-scroll-wheel.
Mootools is a good way of engaging this as well: see the tutorial at http://demos.mootools.net/CustomEvents
But, I'd recommend against using Javascript to change how a browser behaves. Firefox users (whether they're aware of it or not) learn to expect certain behaviors, so changing that would make your site harder to use. Jakob Nielsens comment on 'the scroll wheel's revenge' comes immediately to mind.
There is this really cool jQuery Mouse Wheel Extension
Adds mouse wheel support for your application! Just call mousewheel to add the event and call unmousewheel to remove the event.
Example