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

popover focus state weirdness #9152

Closed
jakearchibald opened this issue Apr 12, 2023 · 7 comments · Fixed by #9186
Closed

popover focus state weirdness #9152

jakearchibald opened this issue Apr 12, 2023 · 7 comments · Fixed by #9186
Labels
topic: popover The popover attribute and friends

Comments

@jakearchibald
Copy link
Contributor

https://html.spec.whatwg.org/multipage/popover.html#popover-target-attribute-activation-behavior

  1. Set popover's popover invoker to node.
  2. Run show popover given popover and false.

The invoker is set, then the popover attempts to show. However, that might not succeed for a number of reasons (there are 4 early returns in the show algorithm). If this happens, the invoker is left as-is.

That means, if showPopover() is called later, the invoker will be incorrect.

I guess showPopover() should clear the invoker? Or maybe it needs to be cleared earlier? It isn't really clear to me how the invoker is used.


https://html.spec.whatwg.org/multipage/interaction.html#associated-focus-navigation-owner

  1. If element is in the popover showing state and has a popover invoker set, then return element.

Is that right? All of the other steps in this algorithm seem to be returning something 'parent', this is the only one that returns itself. That means that a popover's focus navigation scope is itself.

@jakearchibald
Copy link
Contributor Author

cc @mfreed7

@nt1m nt1m added the topic: popover The popover attribute and friends label Apr 12, 2023
@hidde
Copy link
Member

hidde commented Apr 13, 2023

This was just discussed in Open UI.

Minutes JakeA: this is something I encountered in the spec. This [shares scree] is the algorithm when the button for the popover is pressed… at some point it sets the popover's popover invoker to the button…

JakeA: the popover invoker isn't then later removed, I'm not sure how bad that is?

keith: it is for restoring the focus when the popover is hidden

masonf: it's related to focus… in the implementation there is a previouslyfocusedelement too. The 'invoker' is used to manage order of focus

JakeA: so this probably should not hang around if the popover didn't show?

masonf: probably true… almost like a noop, but we probably should clean it up

JakeA: if the popover is shown by some other means that doesn't change the popover invoker, it would still be there

masonf: yes you're right, good catch

JakeA: when I was trying to figure out what the invoker was for… I saw step 5 in the algorithm for the associated focus navigation owner… step 5 seems to be 'off' ?

JakeA: it seems odd for it to return itself

masonf: I think you're right, it probably should return the invoker there

masonf: would need to read it a little more carefully… the relationship is … the invoker is the owner… so you should probably be returning the invoker here… we probably already do this in the Chromium implementation, otherwise it wouldn't work

masonf: so it sounds like we need to fix a few issues in spec and potentially implementation too

@mfreed7
Copy link
Contributor

mfreed7 commented Apr 13, 2023

Per the meeting, both things seem like issues that we need to correct in both the implementation and spec, and @josepharhar and I will take a look. Thanks for raising these.

@mfreed7
Copy link
Contributor

mfreed7 commented Apr 15, 2023

The invoker is set, then the popover attempts to show. However, that might not succeed for a number of reasons (there are 4 early returns in the show algorithm). If this happens, the invoker is left as-is.

That means, if showPopover() is called later, the invoker will be incorrect.

I guess showPopover() should clear the invoker? Or maybe it needs to be cleared earlier? It isn't really clear to me how the invoker is used.

Ok, taking a closer look at this. I'm not sure exactly which "4 early returns" you are talking about, but certainly there are cases where the attempt to invoke the popover might fail. One is the check popover validity call, but that should always pass given the pre-condition that the popover target element is non-null. However, the event handler does fire, and that could change pre-conditions and result in the popover not actually being shown. (Did I miss another condition?)

This begs the question though: so what? If the invoker is left set even though the popover never was shown, I don't think anything bad happens. The invoker is used for focus management (here), and that first makes sure the popover is in the showing state. So if it isn't, nothing happens, and it doesn't matter that the invoker is set. Right?

I'm not sure anything needs to change here.

https://html.spec.whatwg.org/multipage/interaction.html#associated-focus-navigation-owner

  1. If element is in the popover showing state and has a popover invoker set, then return element.

Is that right? All of the other steps in this algorithm seem to be returning something 'parent', this is the only one that returns itself. That means that a popover's focus navigation scope is itself.

Double-checking the Chromium implementation, and it does appear this spec text should return the popover invoker and not the popover. The owner of a popover, for focus navigation purposes, is its invoker. (This should also resolve #9168.) @josepharhar mind putting up a quick PR to do that?

@jakearchibald
Copy link
Contributor Author

This begs the question though: so what?

  1. Try to open a popover via a button.
  2. It now has the button as the invoker.
  3. beforetoggle is cancelled, so the popover doesn't open.
  4. Call showPopover() on the popover.
  5. It opens successfully.

However, the invoker is still set to the button, even though it wasn't the invoker. It feels like, at the very least, showPopover should clear the invoker, because there was no invoker.

Does that make sense?

@mfreed7
Copy link
Contributor

mfreed7 commented Apr 16, 2023

Does that make sense?

Yep, makes total sense - that seems bad. Thanks for explaining in more detail! I think I agree that the fix is to always set invoker in showPopover() either to the invoker or to null. I’ll prototype that to make sure, and then we can put up a PR.

chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Apr 17, 2023
As was pointed out in [1], if we don't reset invoker, it is possible
to get into a state where a closed popover still has an invoker. The
new test case in this CL shows that problem.

[1] whatwg/html#9152

Bug: 1307772
Change-Id: I1511ec8f0e9e0193f0c8b5ce834d20de9d8b46e9
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Apr 19, 2023
As was pointed out in [1], if we don't reset invoker, it is possible
to get into a state where a closed popover still has an invoker. The
new test case in this CL shows that problem.

[1] whatwg/html#9152

Bug: 1307772
Change-Id: I1511ec8f0e9e0193f0c8b5ce834d20de9d8b46e9
josepharhar added a commit to josepharhar/html that referenced this issue Apr 19, 2023
Fixes whatwg#9152

If we don't reset invoker, it is possible to get into a state where a
closed popover still has an invoker.
josepharhar added a commit to josepharhar/html that referenced this issue Apr 19, 2023
Fixes whatwg#9152

If we don't reset invoker, it is possible to get into a state where a
closed popover still has an invoker.
@josepharhar
Copy link
Contributor

I opened a PR: #9186

chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Apr 20, 2023
As was pointed out in [1], if we don't reset invoker, it is possible
to get into a state where a closed popover still has an invoker. The
new test case in this CL shows that problem.

[1] whatwg/html#9152

Bug: 1307772
Change-Id: I1511ec8f0e9e0193f0c8b5ce834d20de9d8b46e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4435697
Reviewed-by: Joey Arhar <jarhar@chromium.org>
Commit-Queue: Tommy Steimel <steimel@chromium.org>
Code-Coverage: Findit <findit-for-me@appspot.gserviceaccount.com>
Auto-Submit: Mason Freed <masonf@chromium.org>
Reviewed-by: Tommy Steimel <steimel@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1133290}
aarongable pushed a commit to chromium/chromium that referenced this issue Apr 20, 2023
As was pointed out in [1], if we don't reset invoker, it is possible
to get into a state where a closed popover still has an invoker. The
new test case in this CL shows that problem.

[1] whatwg/html#9152

Bug: 1307772
Change-Id: I1511ec8f0e9e0193f0c8b5ce834d20de9d8b46e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4435697
Reviewed-by: Joey Arhar <jarhar@chromium.org>
Commit-Queue: Tommy Steimel <steimel@chromium.org>
Code-Coverage: Findit <findit-for-me@appspot.gserviceaccount.com>
Auto-Submit: Mason Freed <masonf@chromium.org>
Reviewed-by: Tommy Steimel <steimel@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1133290}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Apr 20, 2023
As was pointed out in [1], if we don't reset invoker, it is possible
to get into a state where a closed popover still has an invoker. The
new test case in this CL shows that problem.

[1] whatwg/html#9152

Bug: 1307772
Change-Id: I1511ec8f0e9e0193f0c8b5ce834d20de9d8b46e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4435697
Reviewed-by: Joey Arhar <jarhar@chromium.org>
Commit-Queue: Tommy Steimel <steimel@chromium.org>
Code-Coverage: Findit <findit-for-me@appspot.gserviceaccount.com>
Auto-Submit: Mason Freed <masonf@chromium.org>
Reviewed-by: Tommy Steimel <steimel@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1133290}
cookiecrook pushed a commit to cookiecrook/wpt that referenced this issue Apr 21, 2023
As was pointed out in [1], if we don't reset invoker, it is possible
to get into a state where a closed popover still has an invoker. The
new test case in this CL shows that problem.

[1] whatwg/html#9152

Bug: 1307772
Change-Id: I1511ec8f0e9e0193f0c8b5ce834d20de9d8b46e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4435697
Reviewed-by: Joey Arhar <jarhar@chromium.org>
Commit-Queue: Tommy Steimel <steimel@chromium.org>
Code-Coverage: Findit <findit-for-me@appspot.gserviceaccount.com>
Auto-Submit: Mason Freed <masonf@chromium.org>
Reviewed-by: Tommy Steimel <steimel@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1133290}
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue Apr 22, 2023
…r()`, a=testonly

Automatic update from web-platform-tests
Reset the popover invoker in `showPopover()`

As was pointed out in [1], if we don't reset invoker, it is possible
to get into a state where a closed popover still has an invoker. The
new test case in this CL shows that problem.

[1] whatwg/html#9152

Bug: 1307772
Change-Id: I1511ec8f0e9e0193f0c8b5ce834d20de9d8b46e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4435697
Reviewed-by: Joey Arhar <jarhar@chromium.org>
Commit-Queue: Tommy Steimel <steimel@chromium.org>
Code-Coverage: Findit <findit-for-me@appspot.gserviceaccount.com>
Auto-Submit: Mason Freed <masonf@chromium.org>
Reviewed-by: Tommy Steimel <steimel@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1133290}

--

wpt-commits: cc0704e3a1741d28d2bef73c6e84796b7c928849
wpt-pr: 39589
annevk pushed a commit that referenced this issue Apr 24, 2023
Otherwise it's possible to get in a state where a shown-again popover has its initial invoker.

Tests: web-platform-tests/wpt#39589.

Fixes #9152.
jamienicol pushed a commit to jamienicol/gecko that referenced this issue Apr 24, 2023
…r()`, a=testonly

Automatic update from web-platform-tests
Reset the popover invoker in `showPopover()`

As was pointed out in [1], if we don't reset invoker, it is possible
to get into a state where a closed popover still has an invoker. The
new test case in this CL shows that problem.

[1] whatwg/html#9152

Bug: 1307772
Change-Id: I1511ec8f0e9e0193f0c8b5ce834d20de9d8b46e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4435697
Reviewed-by: Joey Arhar <jarhar@chromium.org>
Commit-Queue: Tommy Steimel <steimel@chromium.org>
Code-Coverage: Findit <findit-for-me@appspot.gserviceaccount.com>
Auto-Submit: Mason Freed <masonf@chromium.org>
Reviewed-by: Tommy Steimel <steimel@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1133290}

--

wpt-commits: cc0704e3a1741d28d2bef73c6e84796b7c928849
wpt-pr: 39589
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this issue May 1, 2023
…r()`, a=testonly

Automatic update from web-platform-tests
Reset the popover invoker in `showPopover()`

As was pointed out in [1], if we don't reset invoker, it is possible
to get into a state where a closed popover still has an invoker. The
new test case in this CL shows that problem.

[1] whatwg/html#9152

Bug: 1307772
Change-Id: I1511ec8f0e9e0193f0c8b5ce834d20de9d8b46e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4435697
Reviewed-by: Joey Arhar <jarharchromium.org>
Commit-Queue: Tommy Steimel <steimelchromium.org>
Code-Coverage: Findit <findit-for-meappspot.gserviceaccount.com>
Auto-Submit: Mason Freed <masonfchromium.org>
Reviewed-by: Tommy Steimel <steimelchromium.org>
Cr-Commit-Position: refs/heads/main{#1133290}

--

wpt-commits: cc0704e3a1741d28d2bef73c6e84796b7c928849
wpt-pr: 39589

UltraBlame original commit: cea57aad3268804342d5b82c3ae3a22d51ac1e8a
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this issue May 1, 2023
…r()`, a=testonly

Automatic update from web-platform-tests
Reset the popover invoker in `showPopover()`

As was pointed out in [1], if we don't reset invoker, it is possible
to get into a state where a closed popover still has an invoker. The
new test case in this CL shows that problem.

[1] whatwg/html#9152

Bug: 1307772
Change-Id: I1511ec8f0e9e0193f0c8b5ce834d20de9d8b46e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4435697
Reviewed-by: Joey Arhar <jarharchromium.org>
Commit-Queue: Tommy Steimel <steimelchromium.org>
Code-Coverage: Findit <findit-for-meappspot.gserviceaccount.com>
Auto-Submit: Mason Freed <masonfchromium.org>
Reviewed-by: Tommy Steimel <steimelchromium.org>
Cr-Commit-Position: refs/heads/main{#1133290}

--

wpt-commits: cc0704e3a1741d28d2bef73c6e84796b7c928849
wpt-pr: 39589

UltraBlame original commit: cea57aad3268804342d5b82c3ae3a22d51ac1e8a
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this issue May 1, 2023
…r()`, a=testonly

Automatic update from web-platform-tests
Reset the popover invoker in `showPopover()`

As was pointed out in [1], if we don't reset invoker, it is possible
to get into a state where a closed popover still has an invoker. The
new test case in this CL shows that problem.

[1] whatwg/html#9152

Bug: 1307772
Change-Id: I1511ec8f0e9e0193f0c8b5ce834d20de9d8b46e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4435697
Reviewed-by: Joey Arhar <jarharchromium.org>
Commit-Queue: Tommy Steimel <steimelchromium.org>
Code-Coverage: Findit <findit-for-meappspot.gserviceaccount.com>
Auto-Submit: Mason Freed <masonfchromium.org>
Reviewed-by: Tommy Steimel <steimelchromium.org>
Cr-Commit-Position: refs/heads/main{#1133290}

--

wpt-commits: cc0704e3a1741d28d2bef73c6e84796b7c928849
wpt-pr: 39589

UltraBlame original commit: cea57aad3268804342d5b82c3ae3a22d51ac1e8a
webkit-commit-queue pushed a commit to rwlbuis/WebKit that referenced this issue May 12, 2023
https://bugs.webkit.org/show_bug.cgi?id=256636

Reviewed by Tim Nguyen.

Address this issue:
whatwg/html#9152

* LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-invoker-reset-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-invoker-reset.html: Added.
* Source/WebCore/html/HTMLElement.cpp:
(WebCore::HTMLElement::showPopover):
* Source/WebCore/html/HTMLElement.h:
* Source/WebCore/html/HTMLFormControlElement.cpp:
(WebCore::HTMLFormControlElement::handlePopoverTargetAction const):

Canonical link: https://commits.webkit.org/264006@main
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue Jun 7, 2023
As discussed in [1], we need to reset invoker in showPopover(). If not,
It's possible that a closed popover still has an invoker.

[1] whatwg/html#9152

Differential Revision: https://phabricator.services.mozilla.com/D179195
ErichDonGubler pushed a commit to erichdongubler-mozilla/firefox that referenced this issue Jun 8, 2023
As discussed in [1], we need to reset invoker in showPopover(). If not,
It's possible that a closed popover still has an invoker.

[1] whatwg/html#9152

Differential Revision: https://phabricator.services.mozilla.com/D179195
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: popover The popover attribute and friends
Development

Successfully merging a pull request may close this issue.

5 participants