-
Notifications
You must be signed in to change notification settings - Fork 139
Should the passive option be part of the event listener key #27
Comments
Perhaps I am misunderstanding.... It seems to make sense for capture to me... I think because we don't know what will be in the EventListenerOptions and what each UA supports defining individual items as not part of the matching algorithm seems odd to me. It would seem cleaner to me call it with the same args the behavior is this. For example: Suppose Chrome doesn't support the sendUntrustedEvents option of the dictionary but FireFox does. And they define it in a fashion you are describing here. How does that work in UAs that don't support the field? |
[Edit - I was smoking something when I wrote my response, sorry] |
I don't know why capture behaves the way it does. Maybe @smaug---- does? |
because it is the sane thing to do? event phase is a core piece of whole event dispatch and you may want to use the same listener for many things. Like add capturing and bubble listener to window object. capturing listener could set some state and the bubble listener would be sort of catch call, close to default handling. And depending on the state you may or may not want get called during capturing phase. Gecko's allowUntrusted is inconsistent here. Has been since the beginning. addEventListener does care about the untrusted flag (you can add same listener twice even for same phase), but removeEventListener explicitly just removes the listener which has matching (type, listener, capture). But this is tricky. One could easily reuse same listener (or {handleEvent: function() {}}) for many things, both passive and non-passive, and capturing and non-capturing, and add it and remove it using different options. That is not weird code at all, and it should just work. If we go with the approach where capture is special cased, removeEventListener wouldn't need to take EventListenerOptions, but just boolean. Or in practice it would perhaps just use the capture flag of the dictionary. But then, what should happen if one does This is tricky. Need to think this a bit. |
So I think as we add more features we want some kind of identifier approach. Either something similar to |
|
This is interesting, thanks guys. I'm kinda shocked we didn't think through the implications of this over the past year of debate on this API ;-) I support saying that We're actively getting sites to use |
And that has the risk to break sites on browsers which don't support EventListenerOptions :/ |
btw, except in some trivial cases, based on my experience it takes at least two separate implementations before some API becomes good enough. Hmm, perhaps we should try to not ship APIs unless there is at least some other implementation (which could be still on nightly/dev builds only). |
As does using every new API. Let's not rehash the issue #12 centi-thread here, shall we? Here's my first PR, note the feature detection. |
Actually, if we're going to add var options = shouldCapture;
if (supportsCaptureOption)
options = {capture:shouldCapture};
target.addEventListener(type, handler, options);
...
target.removeEventListener(type, handler, options); I think that's probably better than saying |
Yes, but it's something that over time will become very useful. Just like @RByers I guess that's fair. Sounds like a reasonable solution. |
So I did some testing to see if jQuery could give us some guidance, especially with regard to the proposed It turns out they don't seem to have the notion of key at all; every call to their |
I'm a big fan of having addEventListener return an ID the way setTimeout does. I don't know if that's backwards compatible. Hopefully not much content depends on the return value of addEventListener being undefined. I also agree that just adding the listener multiple times is the simplest thing to reason about from a developer and platform perspective. There aren't great use cases here, so doing the simplest thing makes the most sense to me. FWIW, there is a use case for removeEventListener with once, e.g. you register a click handler but decide to remove it before the click has happened. |
@ojanvafai in whatwg/dom#208 I argued why having a "group" feature is better than returning an identifier. Having said that, it seems like there is agreement for |
I think the group feature is fine as well. I see the appeal of being able to remove a group of listeners at once, but I'm a bit skeptical that authors will actually use it that way. In either case, I don't feel strongly between the two options. To be clear, I wasn't making an argument that passive be part of the key or not part of the key. It's weird to me that passive wouldn't be part of the key, but frankly, I'm not invested enough in this problem to have an informed opinion, so I defer to @RByers and @dtapuska here. |
Thanks Anne. Filed a bug to update the blink implementation But we still need to iron out the exact semantics (ideally prior to reviewing the PR over in WHATWG). I see two main options:
Personally I think I prefer option 1, but I haven't thought through the implications for the other potential options we're talking about. I guess we could go with 1 for passive and leave the door open to doing 2 for new options where it might make more sense (eg. a 'maxRate' option). @jacobrossi any input? |
Yeah, my thinking was 1. That keeps the logic very straightforward: If input.key not in eventListeners, then append input to eventListeners. |
if we don't do (1), then passive would be somehow part of the key. |
What about libraries that do event delegation? If you force only the first registration to win, then I can see libraries just ignoring whether their listeners want passive or not -- they just register their delegate as non-passive always. But for an option like (2), you would give the library a way to support exposing passive to their listeners and then the browser handles whether the event can be fired passively (using the OR union logic). I suppose, event with (1), a library could remove its delegate listener and re-add it if it needs to change its passive status. But that might not be intuitive. |
Event delegation works by registering a single listener that handles the events for many of its descendant targets. I don't quite understand the scenario you're sketching. Also, event delegation is something we should support natively, see whatwg/dom#215 for that. |
One, perhaps a bit ugly option, is to throw if one tries to add existing listener with same key but different EventListenerOptions. |
In the event delegation scenario, any such library should really be delegating separately for the passive and non-passive clients (and so installing two real listeners with different handler functions). Eg. we wouldn't want one tiny non-passive touch listener on the page to cause an existing passive touch listener on the window to be treated as non-passive (that would be really bad for perf). I agree it's possible that event delegation code might screw this up, but I think there's a lot of ways they could screw up in any of the options, not clear to me that either approach is substantially less error-prone. Or maybe I don't understand completely?
I'd be fine with that, it also gives us the flexibility to potentially relax in the future if we deem it valuable. |
The problem with throwing is that we don't do that for capture, so we'd have to allow same-listener/different-options in the case where the options vary in their capture value. (Unless the proposal is to add another bit to the key, "boolean or object", then throw only for cases where "boolean or object" is "object" and any of the options differ.) |
well, .capture is part of the key. So we'd first look for (type, listener, capturingOrNot) listener, and then compare the options. |
I think it's worth pondering how something like PEP would handle this. Requiring separate delegators just for this feature might more overhead than the library authors deem worth it. jquery-archive/PEP#278 (comment) |
Let me try again, could you explain in more detail how this affects delegation? |
@RByers when is the next version of Chrome coming out? I'd like to see this resolved and implemented as resolved by then. |
I think the PEP case is conceptually easy actually (although the implementation may be complicated). They ALWAYS install just passive touch listeners for the purpose of generating pointer events (since pointer events never block scrolling). The trickier part is in emulating
Chrome 51 (the release with Regardless it sounds like there's rough consensus here that we should follow option 1) above. Unless anyone has a concrete reason why that would be worse than some other choice, I'll prepare a PR to the DOM spec for this next week (on vacation for most of the rest of this week). |
Thinking on this further, I don't think the delegation scenario presents much of an issue. Carry on. :-) |
Sounds good. @RByers I don't disagree regarding the risk, I just didn't want to delay it more than one release after |
Yep, agreed @annevk. PR up for review - it was trivial thanks to your |
If you can think of one let me know. |
* Add more legacy event types for createEvent() Approximately as requested at https://bugzilla.mozilla.org/show_bug.cgi?id=1251198#c7. This is the list of events supported in createEvent() by at least two of Firefox, Chrome, and IE 11. The one exception is I omitted MutationEvent, which all three support, because apparently spec-land has decided to deny its existence in the hope that it will go away. Bikeshed does not know about all of the added interface names, hopefully that will sort itself out over time. * Meta: improve pull request instructions for DOM See whatwg/fetch#276 for context. * Enable an event listener to be invoked just once * Editorial: web compatibility typically remains relevant Fixes whatwg#210. * Shadow: define attachShadow() for custom elements * Meta: make it easier to reference participate in a tree PR: whatwg#216 * Define node document for new Text nodes Fixes whatwg#224 and part of whatwg#212. Also fix part of whatwg#209 by stating these algorithms can rethrow exceptions. * Use a single concept for attribute changes This setup is still a little sketchy I think, but not more so than the insertion and removing steps. * SVGEvent is only Gecko, Blink also has SVGEvents As pointed out by zcorpan in whatwg#227. * Set createDocument()'s content type based on namespace Fixes whatwg#217. PR: whatwg#218 * Make document.createEvent("touchevent") sometimes throw Browsers typically disable touch events on non-touch devices, and there exists web content that detects this difference using document.createEvent(). Fixes whatwg#227. * Shadow: define slotchange event Shadow: define slotchange event Fixes WICG/webcomponents#288. This defines the slotchange event in response to remove/insert operations, changes to a slot’s name attribute, and changes to an element’s slot attribute. This also introduces the assigned nodes concept for slots, and assigned slot concept for slotables. Slotables now also have a name, rather than a “get name”. The slotchange event dispatches just after mutation observers have their callbacks invoked. The slotchange event is not yet marked scoped as scoped events are not yet defined in the DOM Standard. Note: although the original issue did not mention it, this also suppresses signaling when slots are removed from a tree. Not just when they are inserted. * Editorial: update custom element cross-spec references * Editorial: fix a few cross-linking missteps * Editorial: make "is" and "prefix" optional in "create an element" * Use "create an element" in createHTMLDocument Takes care of part of whatwg#212. * Editorial: align exception language with IDL * Editorial: introduce more shadow-including terms for CSS Fixes whatwg#225. * Editorial: distributed -> flattened * Meta: export more terms Fixes whatwg#233. * Editorial: add "shadow host" and "assigned" as terms This makes a couple of non-null checks read better and enshrines a term we had already been using. * Editorial: flip non-null/otherwise conditions PR: whatwg#234 * Shadow: <slot> is now defined in HTML * Remove passive as event listener key This changes makes passive no longer contribute to the uniqueness of an event listener. It therefore also no longer needs to be supported as part of removeEventListener(). Fixes WICG/EventListenerOptions#27. PR: whatwg#236 * Meta: point out event's timeStamp is likely to change See whatwg#23 for details. * Add [CEReactions] annotations to mutating methods Part of WICG/webcomponents#186, and furthering whatwg/html@27aa7bc. Linking [CEREactions] will happen once speced/bikeshed#677 is fixed. * Editorial: check stop propagation flag at start of invoke * Editorial: deduplicate Veli Şenol * Editorial: define defaults for EventListenerOptions Although this is also done in prose, this nonetheless simplifies the prose a bit and makes it clearer to those skimming the standard what is going on (although skimming is not recommended). Fixes whatwg#239. * Meta: link to Japanese translation See triple-underscore/triple-underscore.github.io#1 for more details.
At the moment, the following code installs two listeners (
handler
will get invoked twice):@annevk points out this may not make sense - it may be better to treat them as the same.
If we want to change this, we have to define what the second call does. Is it just ignored? Or maybe a listener can be "upgraded" from
passive
to blocking but not the other way around?I was really just following the precedent set by
capture
here - no real argument one way or the other. Can anyone shed light into whycapture
behaves this way? That seems odd / useless also.Is there a good reason we'd want
capture
to have different semantics thanpassive
(and presumably new options)? Maybecapture
can just be forever odd for legacy compat reasons?This is an edge case I think is unlikely to affect any real code, so I think the compat risk of changing this is minimal.
The text was updated successfully, but these errors were encountered: