-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Add CSSOM View extensions to MouseEvent #3484
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,8 +5,42 @@ const EventModifierMixinImpl = require("./EventModifierMixin-impl").implementati | |
const UIEventImpl = require("./UIEvent-impl").implementation; | ||
|
||
const MouseEventInit = require("../generated/MouseEventInit"); | ||
const { wrapperForImpl } = require("../generated/utils"); | ||
|
||
class MouseEventImpl extends UIEventImpl { | ||
get x() { | ||
return this.clientX; | ||
} | ||
get y() { | ||
return this.clientY; | ||
} | ||
get pageX() { | ||
if (this._dispatchFlag) { | ||
return 0; | ||
} | ||
const offset = wrapperForImpl(this.view)?.scrollX || 0; | ||
return offset + this.clientX; | ||
} | ||
get pageY() { | ||
if (this._dispatchFlag) { | ||
return 0; | ||
} | ||
const offset = wrapperForImpl(this.view)?.scrollY || 0; | ||
return offset + this.clientY; | ||
} | ||
get offsetX() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per spec these should be the same as pageX/pageY. A test, or enabling of an existing test, would be good. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
if (this._dispatchFlag) { | ||
return 0; | ||
} | ||
return this.pageX; | ||
} | ||
get offsetY() { | ||
if (this._dispatchFlag) { | ||
return 0; | ||
} | ||
return this.pageY; | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're missing getters for pageX and pageY. See how they are defined in steps 2-3 of https://drafts.csswg.org/cssom-view/#dom-mouseevent-pagex . There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, and added a test |
||
initMouseEvent( | ||
type, | ||
bubbles, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,6 @@ interface MouseEvent : UIEvent { | |
readonly attribute long screenY; | ||
readonly attribute long clientX; | ||
readonly attribute long clientY; | ||
|
||
readonly attribute boolean ctrlKey; | ||
readonly attribute boolean shiftKey; | ||
readonly attribute boolean altKey; | ||
|
@@ -52,3 +51,27 @@ partial interface MouseEvent { | |
optional short buttonArg = 0, | ||
optional EventTarget? relatedTargetArg = null); | ||
}; | ||
|
||
// https://drafts.csswg.org/cssom-view/#extensions-to-the-mouseevent-interface | ||
// Adds attributes and changes existing ones to doubles | ||
partial interface MouseEvent { | ||
readonly attribute double screenX; | ||
readonly attribute double screenY; | ||
readonly attribute double pageX; | ||
readonly attribute double pageY; | ||
readonly attribute double clientX; | ||
readonly attribute double clientY; | ||
readonly attribute double x; | ||
readonly attribute double y; | ||
readonly attribute double offsetX; | ||
readonly attribute double offsetY; | ||
}; | ||
|
||
// https://drafts.csswg.org/cssom-view/#extensions-to-the-mouseevent-interface | ||
// Changes existing coordinate entries to doubles | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure how well this works in webidl2js. I guess it didn't break the build, which is good, but does it properly "override" the existing ones? I think before merging, I need a test to ensure that these correctly come out as doubles instead of longs. So, construct a new MouseEvent with its screenX/screenY/clientX/clientY constructor options set to something fractional (e.g. Bonus points if you add a test that using initMouseEvent does not preserve the fractionalness, since the arguments are still defined to be longs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interestingly, it seems that although major browsers (chromium/firefox/webkit) have implemented these MouseEvent properties, they still convert doubles to longs (possibly for legacy compatibility reasons?) I don't know if that means jsdom shouldn't support doubles, but perhaps something to think about. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added tests around this |
||
partial dictionary MouseEventInit { | ||
double screenX = 0.0; | ||
double screenY = 0.0; | ||
double clientX = 0.0; | ||
double clientY = 0.0; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jenseng @domenic I'm wondering why
pageX
returns 0 here when_dispatchFlag
istrue
. This behavior leads to wrong results when accessing the event in a listener:Running this in a JSDOM environment logs
event 0 0
because thepageX
getter is called inside a dispatch.On the other hand, running the same code in Chrome logs the correct
event 10 10
.I see that the spec says things like "if the event’s dispatch flag is set, return A, otherwise return B", but that doesn't mean 0 is the right value. It should still be the coordinate of the event relative to some origin.
Looking at how Chrome handles this, I see that
pageX
isclientX
scrollX
offset if available.There is no mention of the dispatch flag, at least not explicitly. That leaves me with the conclusion that JSDOM shouldn't implement any special behavior when
_dispatchFlag
istrue
, always returningclientX + scrollX
is fine.This is quite a serious bug when JSDOM is used with Jest and React Testing Library, as it breaks unit tests that create
MouseEvent
s to simulate moving the mouse.I discovered this when trying out Jest upgraded to JSDOM 21 (jestjs/jest#13825) to run unit tests of WordPress Gutenberg project.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jsnajdr when implementing this, my goal was to:
A (minor) risk with returning the current
clientX + scrollX
is that it could be inconsistent with browsers, sincescrollX/Y
could change between the time of event initialization and whenpageX
/pageY
are read during dispatch (e.g. if explicitly set orscrollTo
is called during an earlier click handler).That said, it's probably still a better default than zero, and assuming
scrollX/Y
hasn't changed, it should be synonymous withthe position where the event occurred relative to the origin of the initial containing block
.@domenic wdyt? Seems like a reasonable change to me, though perhaps it's still a good idea to keep the dispatch branch even if the return value is the same. That way it's a good placeholder/indicator for when layout support is added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do have an existing PR that is closely related to this, and I think we can solve the minor risk outlined above by setting the new
_initialContainingBlockRelativeX/Y
toclientX/Y + scrollX/Y
.That way the values will be persisted at init time, and not risk changing if
scrollX/Y
changes later before/during dispatch.Maybe I'll just split it out into its own PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#3514 should resolve this