Open Bug 505521 Opened 15 years ago Updated 2 months ago

Set screen coordinates during HTML5 drag event

Categories

(Core :: DOM: Copy & Paste and Drag & Drop, defect, P2)

x86
All
defect

Tracking

()

Webcompat Priority P3

People

(Reporter: sebastian, Assigned: enndeakin, NeedInfo)

References

(Blocks 1 open bug)

Details

(5 keywords, Whiteboard: p=0 [DevRel:P2])

Attachments

(4 files, 5 obsolete files)

User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.33 Safari/530.5
Build Identifier: 

During the dragstart, drag and dragend events, the mouse position (pageX, clientX, screenX) is set to 0 (zero).



Reproducible: Always

Steps to Reproduce:
Create an element with draggable attribute set to true. Listen to the dragstart, drag and dragend events.
Actual Results:  
The pageX, clientX, screenX values are zero.

Expected Results:  
They should report the current mouse position, even if the mouse is currently outside of the document (just like mousedown + mousemove does).

Even if a DragEvent is initialized manually using initDragEvent, they values are set to zero.

As far as I know there are no known security issues with regards to mouse position and drag operations. Other browsers implement it fully. It's already possible to get the same mouse position during mousemove events even outside of the document if the mouse button is down.
We don't support coordinates on the drag and dragend events as they are not triggered by mouse events and don't occur at a specific point. As an special exception, the screen coordinates where the drop occurred are available during the dragend event.

I don't see a problem retrieving the coordinates during the dragstart event however, where they should be set. Can you please provide a testcase demonstrating this problem?
dragstart does retain the screen coordinates. I was a wrong there. drag and dragend doesn't.

The HTML5 drag & drop API is suppose to be UI/input device agnostic. However, DragEvent inherits MouseEvent because the typical case would be a mouse gesture.

For example, the drag event fills no significant purpose than to trigger an event when the mouse moves or something else moves in front of or behind it.

I know the spec defines that the events should trigger during certain time intervals but this doesn't make sense. All browsers triggers the sequence faster if the mouse is moved. In which case mouse position should be available.

I've brought it to the WHATWG list that this should be specified more clearly.

WebKit and IE currently treats the drag event as a mouse event similar to dragover or mousemove.
The current HTML5 spec describes that all DragEvent properties should be available during all the events - according to editor Ian Hickson.

http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2009-August/021917.html

All other implementations does this so I don't think the Mozilla implementation should be more limited in this regard.
Flags: wanted1.9.2?
Keywords: html5
Priority: -- → P2
(In reply to comment #3)
> The current HTML5 spec describes that all DragEvent properties should be
> available during all the events - according to editor Ian Hickson.

Note though that it doesn't specify what the properties should be set to, just that they should be set and we currently set them to 0.
Well I'm pretty sure it's implied that it's set to something useful. I guess it needs to be abundantly clear. But IMO that's just an excuse not to fix it. There's still an issue here.

Recently a comment has been added that they should be set to 0 if there is no relevant pointing device.

http://html5.org/tools/web-apps-tracker?from=3587&to=3588

But that just applies to keyboard actions, alternative input devices etc. In this case there IS a relevant pointing device - the mouse input. So implicitly it should be set to a relevant and useful property.
I'm not arguing it shouldn't be changed. But the spec doesn't specify what it should be set to. The 'drag' event isn't fired due to a mouse action. Since it is unspecified, any number of possible values could be used:
 - the coordinates should be set to 0
 - the coordinates are the location of the element the drag event is fired on
 - the coordinates are the x,y relative to the window the mouse is over, if any
 - the coordinates are the x,y relative to the window containing the element the drag event is over

What do other browsers do here?
Oh, I see what you mean.

Other browsers uses coordinates relative to the source node. I.e. the event target in this case. It works just like the mousemove event. If a mouse button is pressed "mousemove" is continually triggered even outside of the current document. (Values outside the bounds of the document is valid.) "drag" should work the same as "mousemove" in this regard.
What's up with this annoying issue?
 
I'd like to display a custom drag proxy when the user is dragging an element on the page (the "drag" event seems pretty appropriated to me), unfortunately as Sebastian said above the clientX and clientY are always set to zero.

I've tried to use setDragImage but it doesn't keep any reference to the DOM element being dragged, nor giving you the possibility to update this image anywhere else than the "dragstart" event. 

I've found a workaround to retrieve the mouse position by adding a "dragover" event listener at the document level, but that's a bit overkill and I don't understand why these properties aren't exposed on all events of the drag source.

My two cents.
Blocks: 455694
No longer blocks: 455694
Status: UNCONFIRMED → NEW
Ever confirmed: true
Summary: HTML5 Drag and Drop: DragEvent hides mouse position during source node events → Set screen coordinates during drag event
Flags: wanted1.9.2?
(In reply to Neil Deakin from comment #6)
> I'm not arguing it shouldn't be changed. But the spec doesn't specify what
> it should be set to. The 'drag' event isn't fired due to a mouse action.
> Since it is unspecified, any number of possible values could be used:
>  - the coordinates should be set to 0
>  - the coordinates are the location of the element the drag event is fired on
>  - the coordinates are the x,y relative to the window the mouse is over, if
> any
>  - the coordinates are the x,y relative to the window containing the element
> the drag event is over

My answer is that the coordinates should be given relative to the screen containing the element that is the target of the drag event. More precisely, screen is the screen whose top-left corner is used for calculating element.boxObject.screenX/Y, where element is the target of the drag event. In most or all cases, this will return the same values that checking screenX/Y would for a mouse event would.


> What do other browsers do here?

(In reply to Sebastian Markbåge from comment #7)
> Other browsers uses coordinates relative to the source node.

This is absolutely incorrect. In Chrome, screen coordinates are given relative to the screen's top-left corner as expected.
I was going to report this bug too, glad I found the existing report myself for once. :)
Here's my testcase, in case it helps anyone: http://jsfiddle.net/leaverou/89AtH/

The D&D API would be incredibly useful not only for dragging data outside or from outside the browser or for dragging an element onto another (as most demos show), but also for the typical dragging an element from one place in the document to another. This bug renders this completely impossible.
Blocks: 674925
(In reply to Frank Yan (:fryn) from comment #9)
> My answer is that the coordinates should be given relative to the screen
> containing the element that is the target of the drag event. More precisely,
> screen is the screen whose top-left corner is used for calculating
> element.boxObject.screenX/Y, where element is the target of the drag event.
> In most or all cases, this will return the same values that checking
> screenX/Y would for a mouse event would.

I absolutely concur. This is essential if you want to replace the default drag image with a custom one or do drop target detection on your own. At the moment I have to use the workaround from comment #8 which is really not that ideal.
Attached patch patch v1 (obsolete) — Splinter Review
I decided to take a stab and implemented it for GTK. This works quite well on my machine but there might be some edge cases I don't know of. Also I'm really not sure that's the right approach but I'm not too familiar with all the DnD and platform code :)
Attachment #571632 - Flags: feedback?(enndeakin)
(In reply to Tim Taubert [:ttaubert] from comment #11)
> I absolutely concur. This is essential if you want to replace the default
> drag image with a custom one or do drop target detection on your own.

Can you explain why you think you need this?
(In reply to Neil Deakin from comment #13)
> (In reply to Tim Taubert [:ttaubert] from comment #11)
> > I absolutely concur. This is essential if you want to replace the default
> > drag image with a custom one or do drop target detection on your own.
> 
> Can you explain why you think you need this?

In order to drag tabs with animated images designating what will happen if they drop, for example...
I think this should get a higher priority, since it is blocking more than a few bugs, most of which are encountered regularly. (see the dependency graph)
(In reply to Notlost from comment #14)
> > Can you explain why you think you need this?
> 
> In order to drag tabs with animated images designating what will happen if
> they drop, for example...

More details please?

You can't create animated images with the drag/drop api, (unless you use <panel> but you can already obtain its coordinates)
See bug 455694
That bug may be a reason to implement this, but it has nothing to do with animated or custom drag images.

Various people above are asserting that the screen coordinates are necessary for using custom drag images (animated or otherwise). I assert that it is not the case.

I want to know why specifically people disagree such that this can be implemented to address those usecases, or, explain why what they are doing doesn't need the coordinates.
Attached patch patch v2 (obsolete) — Splinter Review
FWIW, added Mac support.
Attachment #571632 - Attachment is obsolete: true
Attachment #571632 - Flags: feedback?(enndeakin)
(In reply to Neil Deakin from comment #13)
> Can you explain why you think you need this?

Sorry to step in so late, I obviously forgot to add me to the CC list :/

So, I'm implementing a feature that needs to implement a custom drag image. The default one is not what the UX wants to have (it's at 0.8 opacity or something and you can't change that). To achieve this I need to re-position the custom drag image on every 'drag' event. Currently, there's no way to do that but adding a 'dragover' listener to the documentElement. This does not feel like the right way at all when there's an event like 'drag' that could provide these coordinates to move the drag image accordingly.
I thought you were using a <panel> here? The transparency of the panel should be used. If not, why not, as it handles all of this for you?
(In reply to Neil Deakin from comment #21)
> I thought you were using a <panel> here? The transparency of the panel
> should be used. If not, why not, as it handles all of this for you?

I didn't know about the <panel> but (unfortunately) I'm implementing this feature as a HTML page so that's not available to me. I was talking about the HTML5 DnD API as were the other reporters (I think :).
Attached patch patch v3 (obsolete) — Splinter Review
Added Windows support.
Attachment #574562 - Attachment is obsolete: true
(In reply to Tim Taubert [:ttaubert] from comment #22)
> (In reply to Neil Deakin from comment #21)
> > I thought you were using a <panel> here? The transparency of the panel
> > should be used. If not, why not, as it handles all of this for you?
> 
> I didn't know about the <panel> but (unfortunately) I'm implementing this
> feature as a HTML page so that's not available to me.

You can mix XUL and HTML.
(In reply to Neil Deakin from comment #21)
> I thought you were using a <panel> here? The transparency of the panel
> should be used. If not, why not, as it handles all of this for you?

Ok, after Dão's hint I tried to use the XUL panel but had no luck in specifying a custom opacity. While that actually may be fixable I don't see any difference between passing a <panel> and passing an arbitrary HTML element to dataTransfer.setDragImage() - there's a copy of that element (with less opacity) used as the drag image.

The second thing about that is, that we implement a custom drop target detection (in the New Tab Page) based on the current drag image's position. So even when using a <panel> I can't get the drag image's position and use it to determine the current drop target. I'd still need to use pointer coordinates in the 'drag' event. Please tell me if I'm missing something here.
(In reply to Tim Taubert [:ttaubert] from comment #25)
> I don't see
> any difference between passing a <panel> and passing an arbitrary HTML
> element to dataTransfer.setDragImage() - there's a copy of that element
> (with less opacity) used as the drag image.

The difference is that you can change the styling of the contents of the panel on-the-fly, but that point isn't relevant to this bug.

The main problem here is that it is convoluted to have to attach a dragover handler to the drop target within a dragstart handler for an element when the handling is specific to the element. Just because it does not immediately add power to the API doesn't mean it shouldn't be done. We also implemented mouseenter and mouseleave to make things easier for developers.
Can someone clearly list what each of the other browsers use for coordinate values for drag events? Neil asked for that earlier in the comments, but there doesn't seem to be a definitive answer, only disputed assertions.
Yes, this is a bit confusing. My issue is about the use cases here, and there is confusing discussions from multiple people about drag images (comments 8, 10, 11, 14)  that makes it very unclear what people are doing 

Non-privileged code is prevented from using non-static drag images. If you are using privileged xul code, you should use <panel> to create non-static drag images. You cannot use non-static drag images at all in html as standalone <panels> do not render in html documents. (although you may be able to use menu trickery).

The patch itself is a good start, although I haven't tested it to see what coordinate system it is in. I think you may be able to combine mCurrentDragPoint and mEndDragPoint as well.
Attached patch patch v4 (obsolete) — Splinter Review
Combined mCurrentDragPoint and mEndDragPoint.

(In reply to Dietrich Ayala (:dietrich) from comment #27)
> Can someone clearly list what each of the other browsers use for coordinate
> values for drag events? Neil asked for that earlier in the comments, but
> there doesn't seem to be a definitive answer, only disputed assertions.

With the help of Lea's testcase http://jsfiddle.net/leaverou/89AtH/ I checked the current browser support:

* Chrome, IE and Safari support drag event coordinates.
* Opera does not support drag-and-drop at all.

Chrome, IE and Safari (and Firefox) fill the pageX/Y properties to have values relative to the document containing the drag event target.
Assignee: nobody → ttaubert
Attachment #575971 - Attachment is obsolete: true
Status: NEW → ASSIGNED
Attachment #579313 - Flags: review?(enndeakin)
Comment on attachment 579313 [details] [diff] [review]
patch v4

>   if (dragSession) {
>     if (aMessage == NS_DRAGDROP_OVER) {
>+      // set current drag position
>+      nsDragService* dragService = static_cast<nsDragService *>(mDragService);
>+      dragService->SetCurrentDragPoint(nsIntPoint(NSToIntRound(localPoint.x), NSToIntRound(localPoint.y)));

You're passing in values in a different coordinate system from dragend here. localPoint is relative to the 'self' whereas for dragend, screen coordinates are passed in.
Attachment #579313 - Flags: review?(enndeakin) → review-
Not going to block the New Tab Feature on this (anymore). We'll be using the workaround from comment #8 until this bug gets resolved. Alas, I don't have time at the moment to continue digging further into this.
Assignee: tim.taubert → nobody
No longer blocks: 455553
Status: ASSIGNED → NEW
Summary: Set screen coordinates during drag event → Set screen coordinates during HTML5 drag event
I would also greatly appreaciate this bug fixed. Here's a usecase for you, Neil, without all the convoluted arguments with ghost image adjustments:

I use the DnD API to resize elements (in my case some time intervals in a calendar). It's pretty straightforward using dragstart, drag, and dragend events. In other major browsers I can easily resize the element in question during the drag, because I get the current mouse position from the 'drag' event. In Firefox I'm screwed (or left to use the document dragover hotfix mentioned above). I understand that this is not exactly a fit for "drag & DROP" mechanism, but the "drag" part fits pretty well.
Since the drag/drop api shouldn't be used for resizing elements, that isn't a good usecase. The right way to do that is with ordinary mouse events, using setCapture if you need to go outside the window boundary.
Attached file Test case
I was about to report this issue, but saw this in the "Possible Duplicates" section after entering a title.

Attached is a test case.  It's not a use case, just a test case :)
My use case is selecting multiple items, then moving them all by dragging one. I need the coordinates in the `drag` event to move my custom ghost images of the other items.
(In reply to Forrest O. from comment #36)
> My use case is selecting multiple items, then moving them all by dragging
> one. I need the coordinates in the `drag` event to move my custom ghost
> images of the other items.

You should instead just be drawing them to an image/canvas and calling setDragImage. You won't be able to properly emulate the drag image behaviour otherwise.
We don’t need to talk about use cases. The question is: why does the drag event fire at all? It presents no useful data. Without position data the drag event is completely useless.
This thread started 2009 when Firefox 3.5 was the actual version. Now , 4 years later we have Firefox 23 and this sloppiness still exists!
Just drop the drag event in Firefox 24. It is useless this way.
We wanted use cases so we can identify the best way to implement the coordinates. Perhaps removing the event is one such solution.
Use case:

Problem
Imagine a puzzle you want to solve with a mouse. You want to drag the puzzle pieces to the right gaps in the puzzle. You could use drop targets, but drop targets react on the cursor position and not position of the moved element. So if you grab the puzzle piece at the lower right corner and drag the pointer to the upper left corner of the gap, the drop would work, but the puzzle piece would be far from being on the place where it belongs.

Solution
Don’t use the standard drop events, write your own drop method that measures the click position on dragstart, calculates the real position of the dragged element and only allows a drop if the element is over the gap. But that is only possible if the drag position is known while dragging.

Since an element is dragged with mouse or touch, why not simply output the same position of the mouse or finger as mousemove or touchmove does? It is the only purpose for a drag event.
Here’s a simple Fiddle for the use case:
http://jsfiddle.net/gimmel/tV8Hk/
In that last case, I'm not clear why you need to drag event at all. You can retrieve the current mouse coordinates within the dragover event.
That would allow you to detect and deal with the case where the mouse pointer was inside the gap but most of the dragged puzzle piece was outside the gap, but it would not let you detect the case where the mouse pointer was outside the gap but most of the dragged puzzle piece was inside the gap.
I was mistaken, retrieving the mouse coordinates manually should allow you to detect and deal with either of those cases.

Michael's right though, there is currently no useful information presented in the drag event, besides the fact that the mouse is moving.
Whiteboard: p=0
Another use case that I am up against is trying to get the screen to scroll during the dragging action. Given that it is the primary event controlling the behavior of the window at that point, it makes more sense to receive the data from the drag event than from an alternative event like mousedown. It just makes more semantic sense to me, at least. If the drag event is what's causing the screen to scroll, then it shouldn't be information from another pointer event that is defining the action.
No longer blocks: fxdesktopbacklog
Flags: firefox-backlog+
No longer blocks: 674925
A use case is demonstrated by the packery draggable functionality:  http://packery.metafizzy.co/draggable.html

There is a draggable demo there.  While dragging, I want to reposition other elements on the screen to give a preview of the effects of a drop to the user.  I need the coords during the drag event in order to do this. 

A quick test in chrome shows that the clientX, clientY, pageX, and pageY props are all set, and seem to be set to the same values: (pageX === clientX, and pageY === clientY).  They are set to the absolute window positions of the mouse cursor.  They only show movement within the window - the min value is 0,0.  If needed, you can record the original positions in the dragStart event to figure out relative movement.
The fact that IE and Chrome are both returning the mouse coordinates on drag event should be the main reason why this issue should be addressed ASAP.
I noticed that using the approach suggested at entry #8 will not work when I hover over the target area.Any idea how I can overcome this ?
This thread started 2009 when Firefox 3.5 was brand new. Now, FIVE years later (we have Firefox 32 now!) this topic is still discussed and Firefox still sets all position coordinates to 0 in the drag event.
The drag event in Firefox is still useless. I have lost any hope that this will change some day.
Whiteboard: p=0 → p=0 [parity-IE][parity-webkit]
It would be great if someone could fix this, please.
The lack of mouse coordinates makes it impossible to implement "resizable columns" in Firefox.
(In reply to Thibaut Courouble from comment #51)
> It would be great if someone could fix this, please.
> The lack of mouse coordinates makes it impossible to implement "resizable
> columns" in Firefox.

You shouldn't be using the drag and drop api for that. Instead you should use setCapture.
(In reply to Neil Deakin from comment #52)
> You shouldn't be using the drag and drop api for that. Instead you should
> use setCapture.

setCapture is non-standard and not supported in Blink/WebKit.
It's insane this is still a problem. How do you suggest we get the coordinates during a drag then? What's the point of drag and drop if I can't drag below the view and get scrolling. Is this ever going to be fixed?
Firefox 45 (or 44) broke the screenX property on the "dragend" event (its value is now always 0, same as pageX and clientX), making it impossible to implement any kind of UI drag feature (like resizing) in Firefox. Please fix.
Please file a new bug on that with a testcase and/or steps to reproduce and platform details.
(In reply to Neil Deakin from comment #57)
> Please file a new bug on that with a testcase and/or steps to reproduce and
> platform details.

Done: https://bugzilla.mozilla.org/show_bug.cgi?id=1244533
Whiteboard: p=0 [parity-IE][parity-webkit] → p=0 [parity-IE][parity-webkit][DevRel:P2]
Flags: platform-rel?
platform-rel: --- → ?
Another use case of the mouse coordinate during the drag event. I disabled the ghost image of the dragged element because I want to build a custom one with some data inside (how many item I have selected to drag, names etc..)

I respectably disabled the setDragImage, and make my other element to follow the cursor during the drag event.

Here is a quick example : http://jsfiddle.net/e1wqafyr/26/

As you can see the pageX and pageY aren't updated while we should have it.
I need this feature to :(

MDM claims, it is supported since Firefox 3.5
https://developer.mozilla.org/en-US/docs/Web/Events/drag
platform-rel: ? → ---
I'm trying to mimic the functionality of dragging files on drive.google.com.  
The only workaround I can think of is a document wide dragover handler which is pretty sloppy.
This works fine in Safari, Chrome, Opera and Edge. What would we need to do to land a fix?
9 years since this bug was reported and you still couldn't fix it? 
Please do something as this is overtly annoying.
Whiteboard: p=0 [parity-IE][parity-webkit][DevRel:P2] → p=0 [parity-IE][parity-webkit][parity-chrome][DevRel:P2]
Mass bug change to replace various 'parity' whiteboard flags with the new canonical keywords. (See bug 1443764 comment 13.)
Whiteboard: p=0 [parity-IE][parity-webkit][parity-chrome][DevRel:P2] → p=0 [DevRel:P2]
Webcompat Priority: --- → ?

Tom, can you write up a testcase to check which coordinates are missing vs. other browsers?
i.e., clientX/Y, pageX/Y, screenX/Y on different dnd events: dragstart, dragenter, dragleave, dragend, drag, dragover, dragexit, drop

thanks.

Flags: needinfo?(twisniewski)

Hi Mike, I have posted a while ago (3years ago) a test case to show what is missing, see my comment here : https://bugzilla.mozilla.org/show_bug.cgi?id=505521#c59

If you try to drag the red block around, you should have the blue block following the mouse position, open the console and look at the value of pageX and pageY, they are equal to the position of the red block and not changing at all while they should correspond to the mouse X and Y position.

I haven't looked at it since then for other coordinates, but pageX and pageY are not working as intended inside the drag event.

Attached file testcase.html (obsolete) —

Here's a test-case which just shows the screen coordinates during any drag event of any part of the window in the testcase. As expected, coords are always 0,0 in Firefox, but vary in Chrome.

Flags: needinfo?(twisniewski)
Attached file testcase.html

And here's a better testcase that shows the client/page/screen coordinates for the various event types in a table, so it's easier to see what differs between browsers.

It seems that drag events get 0,0 for all three coordinate types in Firefox, and dragend gets 0,0 for client and page events, but curiously it gets screen coordinates. The rest seem to work fine.

Chrome on the other hand returns 0,0 for the last drag and dragleave events as I let go of my mouse button to stop dragging, but otherwise the values seem reasonable as I drag around.

Attachment #9102653 - Attachment is obsolete: true

Olli, did you want to take a look too, given the above testcase?

Flags: needinfo?(bugs)

Thanks. Will try to take a look next week.

Blocks: 1589927
Webcompat Priority: ? → P3
Attached file drag_coord.html
Flags: needinfo?(bugs)

Hello.

May I ask you, if you will decide at some time to fix that, can you please notify me by e-mail when fix is released for windows users.
As for now i had to drop support for Firefox for one of my sites since i need drop functional and i can't get drop positions. I had to ask them to download Chrome which is like not respectful to them.

Also i wanted to thank for your nice work. I'm using Firefox for more than 11 years. It's like a never-ending story of success. Everything just works.

Cheers

This also affects Directus Headless CMS https://github.com/directus/app/issues/2090
Obviously not a P1 bug, but as it's so old, hope it will get tackled. I don't want to switch away from Firefox to get my work in Directus done.

I also stubmled over this bug (that's what i call it).
I can't believe that this comment
"Note though that it doesn't specify what the properties should be set to, just that they should be set and we currently set them to 0."
from 11years ago is still state of the art.

You know what i call firefox from now on? Internet Explorer.

Got damm, spent countless of hours just to waste it all cuz FF dose not do what other browsers are doing and haven't decided to fix it for 11 years. (i thought that a such old api would be pretty stable/normalized after a decade) Now i got to use the sloppy dragover event instead. that's going to be harder to workaround since I can't keep dragging while the mouse moves outside of the container. And finding the relative offset to that container just got harder - even worse is that my container can be rotated 90deg...

Take my vote and subscription so I can follow up on this issue.

But the spec doesn't specify what it should be set to
we currently set them to 0

0 is pretty darn useless. if it don't serve any purpose why have it anyway?
if it was uncertain, couldn't someone have asked what it should have been set to?
The solution is pretty easy

  1. Update/specify the spec.
  2. Get all browser to follow the spec.

The best/easiest solution would just be to do what Blink and Safari is doing.
Not sure how IE did things - don't have access to IE anymore.
The browser differences gives me head deck. Almost wish went for mousedown + mousemove + mouseup instead of using the drag api.

luckily the workaround was a bit easy i constructed a new mouseevent and dispatched a untrusted drag event on the element being dragged to get accurate position instead of getting bounding rect and figuring out things on my own.

    area.ondragover = evt => {
      draggingElm.dispatchEvent(new MouseEvent('drag', evt))
      evt.preventDefault()
    }

Just started learning React, decided to implement a very simple draggable div element. After a couple of hours I was pulling my hair out because I couldn't understand why the mouse position was always zero, and I was sure I must be missing some fundamental programming knowledge.

Turns out it's just Firefox, the same doesn't happen on Chromium. It surprises my because I assumed full compatibility with drag and drop events would basically be a requirement to meet the needs of modern websites, but I guess I was wrong!

So, until this bug is resolved, I've written a 99% drop-in patch:

if(/Firefox\/\d+[\d\.]*/.test(navigator.userAgent)
		&& typeof window.DragEvent === 'function'
		&& typeof window.addEventListener === 'function') (function(){
	// patch for Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=505521
	var cx, cy, px, py, ox, oy, sx, sy, lx, ly;
	function update(e) {
		cx = e.clientX; cy = e.clientY;
		px = e.pageX;   py = e.pageY;
		ox = e.offsetX; oy = e.offsetY;
		sx = e.screenX; sy = e.screenY;
		lx = e.layerX;  ly = e.layerY;
	}
	function assign(e) {
		e._ffix_cx = cx; e._ffix_cy = cy;
		e._ffix_px = px; e._ffix_py = py;
		e._ffix_ox = ox; e._ffix_oy = oy;
		e._ffix_sx = sx; e._ffix_sy = sy;
		e._ffix_lx = lx; e._ffix_ly = ly;
	}
	window.addEventListener('mousemove', update, true);
	window.addEventListener('dragover', update, true);
	// bug #505521 identifies these three listeners as problematic:
	// (although tests show 'dragstart' seems to work now, keep to be compatible)
	window.addEventListener('dragstart', assign, true);
	window.addEventListener('drag', assign, true);
	window.addEventListener('dragend', assign, true);

	var me = Object.getOwnPropertyDescriptors(window.MouseEvent.prototype),
		ue = Object.getOwnPropertyDescriptors(window.UIEvent.prototype);
	function getter(prop,repl) {
		return function() {return me[prop] && me[prop].get.call(this) || Number(this[repl]) || 0};
	}
	function layerGetter(prop,repl) {
		return function() {return this.type === 'dragover' && ue[prop] ? ue[prop].get.call(this) : (Number(this[repl]) || 0)};
	}
	Object.defineProperties(window.DragEvent.prototype,{
		clientX: {get: getter('clientX', '_ffix_cx')},
		clientY: {get: getter('clientY', '_ffix_cy')},
		pageX:   {get: getter('pageX', '_ffix_px')},
		pageY:   {get: getter('pageY', '_ffix_py')},
		offsetX: {get: getter('offsetX', '_ffix_ox')},
		offsetY: {get: getter('offsetY', '_ffix_oy')},
		screenX: {get: getter('screenX', '_ffix_sx')},
		screenY: {get: getter('screenY', '_ffix_sy')},
		x:       {get: getter('x', '_ffix_cx')},
		y:       {get: getter('y', '_ffix_cy')},
		layerX:  {get: layerGetter('layerX', '_ffix_lx')},
		layerY:  {get: layerGetter('layerY', '_ffix_ly')}
	});
})();

It borrows the coordinates from the last 'mousemove' or 'dragover' event and then implants them into the affected 'dragstart', 'drag', and 'dragend' events to replace the zero coordinates. It directly patches clientX/Y (and its alias, x/y), pageX/Y, offsetX/Y, screenX/Y, and also layerX/Y which appear to have a different issue: they're assigned to random exorbitantly large and generally constant numbers (garbage data?).

The main difference is that mouse coordinates will lag one event frame behind the true coordinates. Since the 'drag' event executes before the 'dragover' event, I don't believe there is any real way of getting the true coordinates (and 'mousemove' doesn't appear to execute at all during a drag-drop operation). Depending on the use case, this may not be a problem.

I did some testing on this and it looks like other browsers don't send the drag event at all when dragging over a different window/tab than you started the drag on. Firefox doesn't seem to either but that isn't intentional -- possibly some bug related to not dispatching the event to a child process, as the drag event does fire correctly on multiple parent process windows. The spec also doesn't have this restriction.

We could just decide that the drag event only fires when dragging over the source document and then make that the expected behaviour. That would make the coordinate handling fairly clear to implement, since the coordinates would be relative to the document being dragged over which is the same as the drag event target document.

Given this, this does mean that the workaround for this bug is to just use the dragover event instead since it does include the coordinates in the event, but just fires on a different target in the same document.

One other note is that Chromium has an oddity when dragging over a subframe from the same host: the coordinate of the drag event is relative to the subframe document being dragged over rather than the parent document.

This also more intentionally limits firing the drag event so that it only fires when dragging over the same document that the drag started in. This seems to be what other browsers do and we do unintentionally because we don't handle it in multiprocess. The only noticable behaviour change would be between parent process windows but the drag event is not used there except in tests.

Assignee: nobody → enndeakin
Status: NEW → ASSIGNED
Attachment #579313 - Attachment is obsolete: true

I checked today and this issue is still occurring (firefox version 99).

I can see no way to extract pointer input while a drag operation is occurring in firefox. There is no full workaround for this issue right now that I can see.

I am looking to create a general purpose drag and drop framework that sits on top of the browser drag and drop API. It is common to want to know where abouts a user pointer is so that you can do things like:

  • drawing
  • detect the closest edge of a drop target
  • resizing

Will this issue be actioned? It is already 13 years old, and I would love to see firefox become in sync with Chrome and Safari

Firefox is violating the drag and drop spec

"If there is no relevant pointing device, then initialize event's screenX, screenY, clientX, clientY, and button attributes to 0"

Firefox is setting all attributes to 0 even when there is a relevant pointing device

Flags: needinfo?(enndeakin)

Update for others:

I have found that firefox does publish position information (clientX, clientY and friends) for all drag and drop events other than drag

  • "dragstart"
  • "dragenter"
  • "dragleave"
  • "dragover"
  • "drop"
  • "dragend"
  • "drag"

In order to get drag like information:

  • add an event listener to a fairly high EventTarget (eg window)
  • listen for dragover events. (dragover fires whenever you are over a potential drop target, which is every Element)
  • 💰 profit: effectively get a drag event by repurposing dragover

The patch here had some issues with how the coordinates were handled in some cases, but I don't remember what they were and don't have time right now to investigate.

The workaround is to just use the dragover event as described above to get behaviour similar to Chrome/Webkit/etc.

Status: ASSIGNED → NEW
Flags: needinfo?(enndeakin)
Severity: normal → S3

The severity field for this bug is relatively low, S3. However, the bug has 4 duplicates, 29 votes and 67 CCs.
:enndeakin, could you consider increasing the bug severity?

For more information, please visit auto_nag documentation.

Flags: needinfo?(enndeakin)

The last needinfo from me was triggered in error by recent activity on the bug. I'm clearing the needinfo since this is a very old bug and I don't know if it's still relevant.

Flags: needinfo?(enndeakin)

(In reply to Alex Reardon from comment #95)

Update for others:

I have found that firefox does publish position information (clientX, clientY and friends) for all drag and drop events other than drag

  • "dragstart"
  • "dragenter"
  • "dragleave"
  • "dragover"
  • "drop"
  • "dragend"
  • "drag"

In order to get drag like information:

  • add an event listener to a fairly high EventTarget (eg window)
  • listen for dragover events. (dragover fires whenever you are over a potential drop target, which is every Element)
  • 💰 profit: effectively get a drag event by repurposing dragover

Bug still present.

Following this comment, here is what I did to implement it.
Hop this help:

let dragoverFixAdded = false,
    lastWindowDragEvent = false;

const fillEventClientPosition = (e) => {
    e.clientPosition = {
        x: e.clientX,
        y: e.clientY,
    };

    if (e.clientX || e.clientY) {
        // We're fine
        return;
    }

    if (!dragoverFixAdded) {
        window.addEventListener('dragover', (e) => {
            lastWindowDragEvent = e;
        });
    }

    if (lastWindowDragEvent && e.timeStamp - lastWindowDragEvent.timeStamp < 100) {
        // We can use the lastWindowDragEvent, it's not too old
        e.clientPosition = {
            x: lastWindowDragEvent.clientX,
            y: lastWindowDragEvent.clientY,
        };
    }
};

item.addEventListener('drag', (e) => {
    fillEventClientPosition(e);

    // Use e.clientPosition.x, e.clientPosition.y
});
Duplicate of this bug: 1822922
Duplicate of this bug: 1857203

Seems there is a similar issue with the click event on a select and select options in a modal

https://stackoverflow.com/questions/77402658/why-does-clicking-a-select-dropdown-inside-a-form-embedded-in-a-modal-dialog-clo

It's weird that I end up on this page for the 3rd time in the last few years, trying to debug why different drag/drop parts aren't working.

How come a bug like this even lives for 15 years? I would expect that even less severe bugs (although this is S2 which theoretically should be fixed within 1 release cycle) would get more attention as they get old.

Sorry, but is there an ETA for this issue?
Unfortunately the work around in comment #101 no longer works because the drag event on an element prevents the window dragover from firing.

Flags: needinfo?(enndeakin)
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: