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

Correct setting of target and relatedTargets post-dispatch #585

Merged
merged 14 commits into from
Mar 28, 2018

Conversation

annevk
Copy link
Member

@annevk annevk commented Mar 8, 2018

@whatwg/components this fixes the following:

  • Adds "touch target list" as a concept hold by event, so touch events can be retargeted. (This will require some special handling for Touch objects, but I think it's workable.)
  • It now resets target/relatedTarget/touch target list post-dispatch based on pre-dispatch conditions.
  • It makes dispatch account for non-nodes.

(The one thing remaining here is having a good look at event constructors and making sure we can make that work for the relatedTargets design. I think that requires some kind of callback type thing.)


Preview | Diff

@annevk annevk changed the title Correct setting of target and relatedTargets post-dispatch Correct setting of target and relatedTargets post-dispatch Mar 8, 2018
annevk added a commit to web-platform-tests/wpt that referenced this pull request Mar 8, 2018
@annevk annevk added the topic: shadow Relates to shadow trees (as defined in DOM) label Mar 8, 2018
@hayatoito
Copy link
Member

I would like to take a look, however, I will take a vacation for a few days. Let me review in the next week.

dom.bs Outdated

<li><p>If <var>target</var> is <var>relatedTarget</var> and <var>target</var> is not
<var>event</var>'s <a for=Event>relatedTarget</a>, then return true.
<li><p>If <var>relatedTargets</var> <a for=list>contains</a> <var>target</var> and
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I doubt this is quite right in Touch case. Need to think this case some more.
I have some such case in mind where one of the relatedTargets does contain target before retargeting and then retargeting makes also some other relatedTarget to be target.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems https://github.com/w3c/web-platform-tests/blob/master/touch-events/touch-retargeting.html can be extended somehow for more test coverage for touch. It's not entirely clear to me how that works given that on desktop the events are not really exposed.

dom.bs Outdated
<li><p>Otherwise, if <var>parent</var> and <var>relatedTarget</var> are identical, then set
<var>parent</var> to null.
<li><p>Otherwise, if <var>relatedTargets</var> <a for=list>contains</a> <var>parent</var>, then
set <var>parent</var> to null.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gut feeling is that also this has similar problem.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, I confirmed the Blink's implementation.
We need to distinguish relatedTarget and relatedTargets somehow because only relatedTarget (in the sense of before this PR) should be considered here.
"relaterTagets contains parent" causes a sort of false positive.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How should touch targets be adjusted though?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the feedback I got before was that whenever we have relatedTarget handling, we also need to consider touch target handling.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These steps always need some time to understand its intention exactly. :(

My intention is:

  • All touch targets should be adjusted in the same way as relatedTarget should be adjusted. They both should be adjusted.
  • However, there is one difference between relatedTarget and touch targets. Only relatedTarget should be used to decide to exit this while loop "11. While parent is non-null". This step sets parent to null, thus I think this is an attempt to exit the loop.
    To decide to exit this loop or not, in other words, to decide whether an event should be stopped at a shadow root or not, only relatedTarget should be used as its judgement. Touch targets shouldn't be used there.

Since TouchEvent doesn't look to have a relatedTarget to me, TouchEvent never set parent to null here. In other words, TouchEvent is never stopped at a shadow root even if its target and one of touch targets are same.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so we effectively need to have relatedTarget as an internal slot and touchTargets as an internal slot and most of the time we do the same thing for both, but not there and not at the other place @smaug---- pointed out (which is hidden now for some reason).

I can make that change. I'd love some help with tests for touch targets btw since I don't really have a good way to run them here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(The alternative option is that we keep one slot but branch on event interface, but that seems a little icky, but let me know if you'd prefer that.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would love to help to write more tests, though I'm afraid I can write tests only for synthetic TouchEvents. I am not sure how to write a test for non-synthetic TouchEvents.

(The alternative option is that we keep one slot but branch on event interface, but that seems a little icky, but let me know if you'd prefer that.)

I don't have any preference.

btw, I am wondering how these relatedTargets will be used in TouchEvent spec.
TouchEvents has 3 relatedTargets lists.

    readonly        attribute TouchList touches;
    readonly        attribute TouchList targetTouches;
    readonly        attribute TouchList changedTouches;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking that since those lists are all immutable, a flattened list backing them is fine, but that only works if retargeting is consistent regardless of which list.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Your assumption is correct. Retargeting is consistent regardless of which list.

dom.bs Outdated
<a for=tree>root</a> is a <a>shadow-including inclusive ancestor</a> of <var>B</var>, then return
<var>A</var>.
<li><p>If <var>A</var> is a {{Window}} object, then set <var>A</var> to <var>A</var>'s
<a>associated <code>Document</code></a>.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, retargeting Window gives Document? Shouldn't this just return Window

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm yeah, I guess we just want it to behave as if you passed document.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I should just remove this step altogether then?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because window is not an instance of a Node, it falls into the line 5767 (A is not a node)?
Sounds good - but wondering what's the reasoning behind adding this line.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this because of #580 (comment), but I didn't really think it through.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think removing this step is not enough.
e.g. If A is a node in a shadow tree and B is a Window, we should loop until A reaches the outer most shadow host.

The following should work, I think.

  1. If one of the following is true

    • A is not a node
    • A’s root is not a shadow root
    • B is a node and A’s root is a shadow-including inclusive ancestor of B

    then return A.

  2. Set A to A’s root’s host.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that does look good.

dom.bs Outdated

<ul class=brief>
<li><var>A</var> is not a <a>node</a>
<li><var>B</var> is not a <a>node</a>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically the change for retargeting algorithm from the original is these 2 lines above, am I understanding correct?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah.

@annevk
Copy link
Member Author

annevk commented Mar 14, 2018

The PR now separates relatedTarget and touch target list and only has the special cases for relatedTarget. I still need to define an event creation callback of sorts so we can define TouchTarget / FocusEvent et al properly. I was also thinking of incorporating #402 here since we'll have to test that case anyway.

dom.bs Outdated

<li><p>If <var>target</var> is <var>relatedTarget</var> and <var>target</var> is not
<var>event</var>'s <a for=Event>relatedTarget</a>, then return true.
<!-- XXX Since we return early, we might want to unset more flags here. See #402. -->
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also unset target et al here if clearTargetsPostDispatch is true? It seems that would be consistent... (If that's the case it seems we should turn this into a short algorithm that we invoke here and later on.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have never thought about this case seriously so far. In this early return, I assume that any event listener is never called.

In this case, we don't have to worry about any leaking of a node in a shadow tree via an event object. Users don't have any change to access an event object, other than the original event dispatcher.

btw, the consistency may matter. I'm fine to reset target, relatedTarget, and touch target list here too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm mostly wondering about it from a consistency perspective. I could see you'd have some custom dispatching code and later store the event object after dispatch in a global place and maybe you don't want things to be leaked there ever. Doesn't seem like a sound setup, but other than this case we do provide the guarantee that nothing would leak.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now made this change.

@annevk
Copy link
Member Author

annevk commented Mar 15, 2018

I consider this ready apart from the event construction specification callback, which is being discussed in #414. The ongoing feedback here is much appreciated though, please keep it coming.

@@ -10070,6 +10112,7 @@ Tab Atkins,
Takashi Sakamoto,
Takayoshi Kochi,
Theresa O'Connor,
Theodore Dubois,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this related to this pr?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes: #392.

<li><p>Set <var>event</var>'s <a for=Event>relatedTarget</a> to <var>tuple</var>'s
<a for=Event/path>relatedTarget</a>.

<li><p>Set <var>event</var>'s <a for=Event>touch target list</a> to <var>tuple</var>'s
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, perhaps a bit confusing, but I guess should be enough for touch objects. They just need to have a pointer to the event, so that they can update their target form there (basically map their original target to retargeted target or so)

Copy link
Collaborator

@smaug---- smaug---- left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks ok. It is possible that touch target list stuff will need some tweaking when Touch spec is updated

@hayatoito
Copy link
Member

Looks okay to me. Thank you for updating this!

@annevk
Copy link
Member Author

annevk commented Mar 20, 2018

So thinking about this in light of the tests at shadow-dom/event-post-dispatch.html it seems this is still not entirely correct. With the patch is proposed, you can observe whether an event started out in a shadow tree or not.

I think clearTargets should instead be based on event's path. You find the last tuple in event's path with a non-null target. And then if that tuple contains a node inside a shadow tree in one of the three target fields, you set clearTargets to true.

@annevk
Copy link
Member Author

annevk commented Mar 20, 2018

Hmm, and should https://whatpr.org/dom/585.html#concept-event-listener-invoke be updated to check the propagation flag later, so target et al still get updated? That would lead to problems too otherwise I think.

@hayatoito
Copy link
Member

Does this need another review? Please ping me if the PR is ready.

@annevk
Copy link
Member Author

annevk commented Mar 26, 2018

@hayatoito I'd like input from you and @smaug---- on #585 (comment) (and the next comment) and what a solution to that might look like. The other thing we need here are more tests I suppose.

@smaug----
Copy link
Collaborator

smaug---- commented Mar 26, 2018

I think that approach sounds good. So, in case all the targets after actual dispatch are in light DOM, targets wouldn't get cleared.
And whether those targets are in light DOM is calculated before the dispatch.

@hayatoito
Copy link
Member

I think clearTargets should instead be based on event's path. You find the last tuple in event's path with a non-null target. And then if that tuple contains a node inside a shadow tree in one of the three target fields, you set clearTargets to true.

I see. This sounds a reasonable change. Nice catch.

@annevk annevk force-pushed the annevk/null-at-end-of-dispatch branch from d7a2136 to 67e64b4 Compare March 27, 2018 10:29
@annevk
Copy link
Member Author

annevk commented Mar 27, 2018

Tentative commit message:

Shadow: fix event dispatch

This makes a number of large changes to event dispatch:

* The algorithm can no longer return early with true. The observable
  aspect is that the event object is "uninitialized" and false might 
  be returned if the event object was already canceled.
* It accounts for Touch Events in shadow trees by adding the 
  "touch target list" which is somewhat similar to relatedTarget.
* Retargeting is now solely controlled by the event dispatch 
  algorithm. The hook for other specifications is removed.
* Retargeting now properly accounts for non-node objects.
* Dispatch in general accounts for non-node objects too now.
* If targets need to be unset to prevent exposure of a shadow tree
  this is now calculated prior to invoking listeners.

Initializing relatedTarget and "touch target list" is up to the event
classes that need it. #614 will add "event constructing steps" that
enable this.

Tests: https://github.com/w3c/web-platform-tests/pull/9919
(probably still needs work given today's changes)

This closes #402, fixes #561, fixes #562, fixes #580, and fixes #602.

So more review is welcome here (for the last four commits and this commit message in particular) and more tests.

Sorry it got so big, but I'm not sure this could be elegantly made smaller.

@hayatoito
Copy link
Member

I've reviewed it, and it looks okay to me. A really great work!

annevk added a commit to web-platform-tests/wpt that referenced this pull request Mar 28, 2018
@annevk
Copy link
Member Author

annevk commented Mar 28, 2018

@annevk annevk merged commit fc16564 into master Mar 28, 2018
@annevk annevk deleted the annevk/null-at-end-of-dispatch branch March 28, 2018 12:56
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this pull request Apr 15, 2018
Automatic update from web-platform-testsDOM: reset target/relatedTarget

For whatwg/dom#585.

wpt-commits: 2f758ac5c16e44915f270ceec31a84eed8f85769
wpt-pr: 9919
wpt-commits: 2f758ac5c16e44915f270ceec31a84eed8f85769
wpt-pr: 9919
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this pull request Oct 2, 2019
Automatic update from web-platform-testsDOM: reset target/relatedTarget

For whatwg/dom#585.

wpt-commits: 2f758ac5c16e44915f270ceec31a84eed8f85769
wpt-pr: 9919
wpt-commits: 2f758ac5c16e44915f270ceec31a84eed8f85769
wpt-pr: 9919

UltraBlame original commit: 2d92f37b4443fac2124163799a2cb0c9f1835f95
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this pull request Oct 2, 2019
Automatic update from web-platform-testsDOM: reset target/relatedTarget

For whatwg/dom#585.

wpt-commits: 2f758ac5c16e44915f270ceec31a84eed8f85769
wpt-pr: 9919
wpt-commits: 2f758ac5c16e44915f270ceec31a84eed8f85769
wpt-pr: 9919

UltraBlame original commit: 2d92f37b4443fac2124163799a2cb0c9f1835f95
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this pull request Oct 2, 2019
Automatic update from web-platform-testsDOM: reset target/relatedTarget

For whatwg/dom#585.

wpt-commits: 2f758ac5c16e44915f270ceec31a84eed8f85769
wpt-pr: 9919
wpt-commits: 2f758ac5c16e44915f270ceec31a84eed8f85769
wpt-pr: 9919

UltraBlame original commit: 2d92f37b4443fac2124163799a2cb0c9f1835f95
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: events topic: shadow Relates to shadow trees (as defined in DOM)
Development

Successfully merging this pull request may close these issues.

4 participants