Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTML 5 Drag and Drop: Impossible to disallow a drop operation in GWT #9989

Open
jnehlmeier opened this issue Jul 29, 2024 · 6 comments
Open
Labels

Comments

@jnehlmeier
Copy link
Member

GWT version: HEAD
Browser (with version): any
Operating System: any


Description

To tell the browser that a future drop operation is allowed on an element/dropzone you have to call DragOverEvent.preventDefault(). If you DO NOT call it a drop operation on that element/dropzone results in a canceled drop operation. In that case the dragged element receives a dragend event with dropEffect = none

See: https://jsfiddle.net/gdtja9y7/2/

In GWT all HTML 5 Drag and Drop events are registered using addBitlessDomHandler. In DOMImplStandard.getBitlessEventDispatchers() GWT adds special handling for dragenter and dragover events. For both events GWT itself already calls event.preventDefault() before calling back to user code. So it is currently impossible in GWT to disallow a drop operation.

Known workarounds

Use a helper class to manage event handlers using elemental2

@jnehlmeier jnehlmeier added the bug label Jul 29, 2024
@niloc132
Copy link
Contributor

According to the comment, it looks like this was specifically (at the time, 11 years ago) to prevent a bug where while dragging something, text would be selected. I'm assuming that is no longer true, so it should be trivial to remove that line and comment (and test to confirm).

Without that line, this is just standard dispatchEvent(), so getBitlessEventDispatchers() can be simplified?

@jnehlmeier
Copy link
Member Author

I don't really understand that comment. The HTML5 DnD spec says that the browser should disable text selection if an element is marked with draggable so you actually drag the element and not text. This generally works except on iOS/iPadOs (not tested on Android). However this whole text selection thing is only relevant for the dragstart event. So you could check wether or not event.target is a text node and then disallow dragging. I could imagine that browsers in the past did allow text selection in a draggable element and that is what GWT tried to solve.

However, GWT does event.preventDefault in dragenter and dragover which are events you define on the drop zone. I don't think any browser in the past would select text after you have dragged something. Also GWT only prevents the default action once you add one or both event handlers to an element, but I would imagine a browser would have selected text on any element then and not just in elements having these listeners attached.

Anyways, yes the code should be deleted in GWT because event.preventDefault() is a crucial part of the HTML5 DnD API and standard dispatchEvent() should be used.

@niloc132
Copy link
Contributor

I can't speak confidently here without an 11 year old browser up and running, but did the spec say that 11+ years ago? Did all browsers consistently implement it that way? I'm guessing not.

If as you say (I have done no testing here) this is entirely unusable for modern browsers, there should be no harm in fixing it, even destructively. Anyone interrupted by this seem to have a simple workaround - put a preventDefault in their event handlers.

@jnehlmeier
Copy link
Member Author

This funny blog article of 2009 indicates that the spec was the same back in the days. You had to prevent the default action if you want to do a drop. If you don't no drop event is triggered and the drag operation is canceled.

@mP1
Copy link

mP1 commented Aug 3, 2024

What happens if you disable selection itself (not by preventing the selection event), that way the selection event never happen, and maybe only the drag event happens giving you a chance to prevent it.?

https://www.w3schools.com/howto/howto_css_disable_text_selection.asp

.prevent-select {
  -webkit-user-select: none; /* Safari */
  -ms-user-select: none; /* IE 10 and IE 11 */
  user-select: none; /* Standard syntax */
}

@jnehlmeier
Copy link
Member Author

@mP1 I think you mixed something. You can devide all DnD events into two groups

Source element: dragstart and dragend
Target element: dragenter, dragover, dragleave, drop

Without any DnD if you click and hold the mouse button and then move the mouse you select text on the page. That is why the spec says that draggable elements should automatically disallow text selection. Otherwise you select text instead of triggering dragstart. Or you might trigger dragstart but you are actually dragging text. This works for all browsers except mobile, so you would add your mentioned CSS for mobile to make the dragging experience better.

The issue here is that GWT calls preventDefault on the dragover event with a comment that says that it should avoid text selection. However dragover happens after dragstart and only reaches GWT code if you actually add an event listener for it on a target element. So I don't see the logic of it. Because it is native HTML5 DnD the page might not have any drop zone. If we treat the comment as correct, it would mean that you select text all over the page while dragging your data around. If the page has a drop zone but I never hover it then the code can't prevent text selection as well, assuming the comment is correct.

I think HTML5 DnD was badly implemented in browsers and complex to understand 10 years ago. So maybe that code and comment were added by accident. Even 10 years ago the spec states that in order to control wether or not dropping on an element is allowed you have to either prevent or not prevent the default action of dropover. So GWT should never ever call it behind the curtain. Even back then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants