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

Allow an EventTarget to provide the default value of the AddEventListenerOptions #365

Closed
dtapuska opened this issue Nov 4, 2016 · 35 comments · Fixed by #1087
Closed

Allow an EventTarget to provide the default value of the AddEventListenerOptions #365

dtapuska opened this issue Nov 4, 2016 · 35 comments · Fixed by #1087

Comments

@dtapuska
Copy link

dtapuska commented Nov 4, 2016

In order to support interventions such as Default passive true for touch blocking listeners on root level targets we need a hook in the DOM specification to be able to override the default value of the passive field.

dtapuska added a commit to dtapuska/dom that referenced this issue Nov 4, 2016
the default passive value of AddEventListenerOptions.

Fixes issue whatwg#365
@dtapuska
Copy link
Author

dtapuska commented Nov 4, 2016

@foolip @RByers @smaug---- @annevk

WDYT? And then I'll have to put a hook in the touch event spec that defines a default passive algorithm on window, document and html element.

@annevk
Copy link
Member

annevk commented Nov 7, 2016

In your patch you say an argument is passed, but you don't actually pass a parameter. Assuming that is fixed, would we only change the default for certain event types?

@dtapuska
Copy link
Author

dtapuska commented Nov 7, 2016

Yes only touchstart and touchmove are covered under our intervention. Our long term goal is to have these both default to passive: true. However in the meantime we'd like to default them to passive: true if the ContextObject is either window, document, or document.body (as defined in HTML spec). I was planning on putting this wording into the Touch Event Spec; ie to define the default passive algorithm on Window, Document and HTMLElement.

@annevk
Copy link
Member

annevk commented Nov 7, 2016

I think it's a little weird for Touch Events to define that as HTML/DOM define these objects. Guess I'll wait to see what everyone else who was pinged thinks.

@foolip
Copy link
Member

foolip commented Nov 7, 2016

Given the goal of making some addEventListener('touchfoo', callback) calls result in passive behavior without code changes, I don't see any way other than treating a missing passive member as a third state that resolves to either true or false. So I have no suggested changes for the behavior itself.

Making EventTarget the extension point works for me, but I can see two other ways that'd be indistinguishable but result in different layering:

  • Instead of making the event target the extension point and passing the event type, make the event type the extension point and pass the event target.
  • Resolve undefined to true or false later when determining which elements have event handlers that can preventDefault() and block scrolling.

In both cases Touch Events would use the extension point. If either of those or another mechanism seems preferable to anyone they ought to work, but implementation-wise I think there's little reason to layer things like that.

@dtapuska
Copy link
Author

dtapuska commented Nov 9, 2016

I've created a pull request on the touch event spec; see w3c/touch-events#75

@foolip
Copy link
Member

foolip commented Nov 9, 2016

@smaug----, do you have time to go over the options here?

@RByers
Copy link
Contributor

RByers commented Nov 9, 2016

This seems reasonable to me.

Instead of making the event target the extension point and passing the event type, make the event type the extension point and pass the event target.

I can see how this might be simpler.

Resolve undefined to true or false later when determining which elements have event handlers that can preventDefault() and block scrolling.

This would have slightly different semantics from the current definition, eg. in the case that a 2nd HTMLBodyElement is added after the addEventListener call. We could probably work around that, but in general deferring the decision point to after addEventListener seems more complex and harder to reason about to me. I don't have a strong opinion though.

@smaug----
Copy link
Collaborator

(in my todo list, but can't do the context switch just right now.)

@annevk
Copy link
Member

annevk commented Nov 10, 2016

Talking with @foolip "offline" I noticed that since event handler attributes are not explicitly linked to addEventListener() at this point in time. So ontouchfoo would not be affected while it probably should be.

w3c/ServiceWorker#1004 is basically that issue.

@foolip
Copy link
Member

foolip commented Nov 10, 2016

The current situation is that in the blink-dev intent thread, we're trying to get some sense of whether anyone else will be interested in shipping this.

My take is that tweaking addEventListener isn't super satisfying layering-wise, but I see no good alternative, and the end user benefits are substantial. Therefore, lacking objections, I think we should go ahead and try shipping this in Blink, and to be prepared to make changes based on feedback (and data) and get the spec changes merged once it's clear that the change was in fact web compatible. Before then, the PRs should hopefully be enough to unambiguously document what will ship.

@annevk
Copy link
Member

annevk commented Nov 10, 2016

Well, it isn't really. E.g., does it affect event handler attributes or not?

@RByers
Copy link
Contributor

RByers commented Nov 10, 2016

Talking with @foolip "offline" I noticed that since event handler attributes are not explicitly linked to addEventListener() at this point in time. So ontouchfoo would not be affected while it probably should be.

That's a really good point, thanks! Yes ontouchfoo should be affected too. @dtapuska can you look into updating the PRs to make that clear somehow?

@foolip
Copy link
Member

foolip commented Nov 10, 2016

I've checked Blink, and it uses a shared code path so that it'll behave as if addEventListener('touchfoo', callback, false) were called.

@annevk
Copy link
Member

annevk commented Nov 10, 2016

The way we need to make that work is by updating DOM and HTML. DOM needs to have an abstract algorithm that addEventListener() invokes (and I guess the same for removeEventListener()). And HTML needs to start using that algorithm for event handler attributes rather than directly manipulating event listeners.

@foolip
Copy link
Member

foolip commented Nov 10, 2016

Makes sense. Since this PR won't be merged for a few months still I think there's plenty of time to work through that.

hubot pushed a commit to WebKit/WebKit-http that referenced this issue Aug 23, 2017
https://bugs.webkit.org/show_bug.cgi?id=175346
<rdar://problem/33164597>

Reviewed by Sam Weinig.

Source/WebCore:

Make any touchstart or touchmove event listeners passive by default
if they are on the document, window, body or document element targets.
This follows the "intervention" first implemented by Chrome/Blink:

WICG/interventions#35
https://docs.google.com/document/d/1II7oSIpd8pK91V5kEM3tDLKcIj398jOJn8Niqy6_loI/edit
whatwg/dom#365

If the event listener explicitly defines "passive" to false in their
options dictionary, then they'll still get a non-passive listener.

NOTE: Any fallout from this bug should be collected in:
https://bugs.webkit.org/show_bug.cgi?id=175869
Please do not revert this change just because a site is broken. We'll
gather the issues and see if we can evangelise or detect via code.

Tests: fast/events/touch/ios/passive-by-default-on-document-and-window.html
       fast/events/touch/ios/passive-by-default-overridden-on-document-and-window.html

* dom/EventNames.h:
(WebCore::EventNames::isTouchScrollBlockingEventType const): Added this helper
to identify the types of touches we want to check for.
* dom/EventTarget.cpp:
(WebCore::EventTarget::addEventListener): Check for the event being one of the touch-types
that we care about, and the target being one of the Node/Window types we care about. If
so, tell the event listener to be passive.
* dom/EventTarget.h: Use an optional for the passive member.
(WebCore::EventTarget::AddEventListenerOptions::AddEventListenerOptions):
* dom/EventTarget.idl: Change "passive" to not have a default value, so we
can detect if it was explicitly set to false.

LayoutTests:

* fast/events/touch/ios/passive-by-default-on-document-and-window-expected.txt: Added.
* fast/events/touch/ios/passive-by-default-on-document-and-window.html: Added.
* fast/events/touch/ios/passive-by-default-overridden-on-document-and-window-expected.txt: Added.
* fast/events/touch/ios/passive-by-default-overridden-on-document-and-window.html: Added.
* fast/events/touch/ios/tap-with-active-listener-on-window.html: Explicitly set passive to false.
* fast/events/touch/ios/touch-event-regions/document.html: Ditto.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@221092 268f45cc-cd09-0410-ab3c-d52691b4dbfc
@domfarolino
Copy link
Member

@annevk You're saying the abstract DOM algorithm would also be invoked somewhere in this list correct?

@RByers @dtapuska Seems like this has been shipped in Chrome for a little while, is there any more data that has been collected that suggests this should make it in the specs? Just curious :)

@annevk
Copy link
Member

annevk commented Oct 21, 2017

@domfarolino the bit that says "the user agent must append an event listener" will need to be modified in HTML.

@annevk
Copy link
Member

annevk commented Mar 13, 2018

Created #596 for #365 (comment).

Would be good to get an answer to @domfarolino's question too.

annevk added a commit to whatwg/html that referenced this issue Mar 13, 2018
annevk added a commit that referenced this issue Mar 14, 2018
This hook ensures that any special casing in addEventListener() is shared with event handlers. This commit also makes numerous editorial improvements that were long overdue around dictionary members.

The corresponding change to the HTML Standard, which defines event handlers, is tracked by whatwg/html#3561.

This helps with #365 and w3c/ServiceWorker#1004. (Tests will be added as part of #365 eventually.)
@annevk
Copy link
Member

annevk commented Mar 14, 2018

I did not mean to close this. Apologies.

@domfarolino
Copy link
Member

I noticed that w3c/touch-events#75 was closed (to me, unexpectedly), so I'm not really sure what the status of #366 or if we're still planning on following through with the aforementioned intervention in the spec, but more info would be greatly appreciated!

alice pushed a commit to alice/html that referenced this issue Jan 8, 2019
This hook was provided whatwg/dom#596 and event handlers need to use it to fix whatwg/dom#365 and w3c/ServiceWorker#1004 properly. Tests will be added as part of resolving those issues.
@foolip
Copy link
Member

foolip commented May 19, 2021

I've sent web-platform-tests/wpt#29039 to rename those two tests.

@domenic
Copy link
Member

domenic commented Apr 13, 2022

Quick status update: it appears what remains to be specced (and is implemented in at least 2 browsers, maybe 3?) is:

  • wheel, mousewheel, touchstart, and touchmove events...
  • are passive: true by default, when used on window, document, or document.body

We have .tentative test coverage for wheel and touchmove on document. So the work to do is:

@zcorpan
Copy link
Member

zcorpan commented Jun 15, 2022

This test https://github.com/web-platform-tests/wpt/blob/master/dom/events/document-level-wheel-event-listener-passive-by-default.tentative.html says it's a manual test (but doesn't use -manual filename suffix), but still includes testdriver.js et al. Loading the page from wpt serve it fails immediately with promise_test: Unhandled rejection with value: object "Error: unimplemented"

Running it with wpt run it passes in Chrome, so, it seems it's not actually a manual test. It does this

    await new test_driver.Actions()
       .scroll(pos_x, pos_y, delta_x, delta_y).send();

I'll assume that the manual test statement is wrong. Please let me know if I'm missing something though :)

@zcorpan
Copy link
Member

zcorpan commented Jun 16, 2022

I've opened a PR with the tests @domenic outlined above in web-platform-tests/wpt#34464

Since the tests fail in Firefox and Safari due to test infrastructure issues, I also wrote demos to be able to assess interop. See web-platform-tests/wpt#34464 (comment)

The behavior of both Chrome and Safari for the third demo can't be explained by the existing intervention design docs, as far as I can tell. The behavior seems to be something like: first fire a cancelable event, and if that event is not preventDefault()ed, subsequent events for the same gesture are not cancelable.

@zcorpan
Copy link
Member

zcorpan commented Jun 16, 2022

I suppose it's possible that certain events are not cancelable, independently from default passive event listeners. Is that the case?

@smfr
Copy link

smfr commented Jun 16, 2022

The behavior of both Chrome and Safari for the third demo can't be explained by the existing intervention design docs, as far as I can tell. The behavior seems to be something like: first fire a cancelable event, and if that event is not preventDefault()ed, subsequent events for the same gesture are not cancelable.

That is an accurate description of Chrome and Safari's behavior, yes.

@zcorpan
Copy link
Member

zcorpan commented Jun 16, 2022

@smfr thanks! But it's unrelated to default passive event listener, which happens during addEventListener, right?

The chromium code for that is here:
https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/dom/events/event_target.cc;l=288;bpv=0;bpt=1

which I think still matches WICG/interventions#35 (comment) (+ wheel and mousewheel)

@smfr
Copy link

smfr commented Jun 16, 2022

@smfr thanks! But it's unrelated to default passive event listener, which happens during addEventListener, right?

Right. It's a separate kind of intervention intended to maintain good scrolling performance.

@zcorpan
Copy link
Member

zcorpan commented Jun 16, 2022

Great! Makes sense. I'll file a separate issue about that intervention.

@zcorpan
Copy link
Member

zcorpan commented Jun 16, 2022

Oh, I see now that it's already in the UI Events spec: https://w3c.github.io/uievents/#cancelability-of-wheel-events

And for touch* here https://w3c.github.io/touch-events/#cancelability

@zcorpan
Copy link
Member

zcorpan commented Jun 16, 2022

So, Chromium and WebKit also implement this hack for smoothscroll.js:
https://bugs.chromium.org/p/chromium/issues/detail?id=501568
https://github.com/WebKit/WebKit/blob/dd956d5e74249681ddf904e0bbe401f308b65e0f/Source/WebCore/page/Quirks.cpp#L929-L946

As far as I can tell, Gecko does not. https://searchfox.org/mozilla-central/source/dom/events/EventListenerManager.cpp#1593 (and no search results for "ssc_wheel")

Should we put this in the spec?

The use counter is currently at ~0.01% of page views. But scrolling the page doesn't work at all without the hack.
https://chromestatus.com/metrics/feature/timeline/popularity/2020

@domenic
Copy link
Member

domenic commented Jun 16, 2022

IMO we should put that hack in the spec, although it could perhaps be done separably since it's such a ... unique ... hack.

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

Successfully merging a pull request may close this issue.

10 participants