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

Add "check and possibly close popover stack" algorithm #9048

Closed
wants to merge 5 commits into from

Conversation

josepharhar
Copy link
Contributor

@josepharhar josepharhar commented Mar 17, 2023

The "auto popover list" is constructed by attributes set on buttons. When those buttons are modified, it can break connections in the list. This patch adds checks to spots where buttons can be modified in order to fix up the list by closing all popovers when a connection has been broken.

Fixes #8991


/infrastructure.html ( diff )
/input.html ( diff )
/popover.html ( diff )

The "auto popover list" is constructed by attributes set on buttons.
When those buttons are modified, it can break connections in the list.
This patch adds checks to spots where buttons can be modified in order
to fix up the list by closing all popovers when a connection has been
broken.
Copy link
Member

@nt1m nt1m left a comment

Choose a reason for hiding this comment

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

Thanks! I have a few questions.

source Outdated
Comment on lines 81871 to 81872
<li><p>If <var>localName</var> is <code data-x="attr-fe-disabled">disabled</code> or <code
data-x="attr-fae-form">form</code>, then run <span>check and possibly close popover stack</span>
Copy link
Member

Choose a reason for hiding this comment

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

If someone changes the popovertarget to a different element, should we run the algorithm? We're also effectively breaking the ancestor relationship in that case.

Though the algorithm below would probably no longer work, since the popovertarget attribute is used to get the topmost popover ancestor.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree! I pushed a commit to add popovertarget here, and I started on chromium and WPT changes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Though the algorithm below would probably no longer work, since the popovertarget attribute is used to get the topmost popover ancestor.

I don't understand, the rest of this algorithm only cares if the popover attribute is changed, right?

Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure if "check and possibly close popover stack" runs before or after the attribute change, but this bit relies on checking the invokers:

If the result of running topmost popover ancestor

So if the popovertarget changes, the tree will end up different depending on when this runs, but disabled/form are also similarly affected (since we use the popover target element algorithm).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure if "check and possibly close popover stack" runs before or after the attribute change

In chromium we are definitely doing it after the attribute has been changed. After reading https://dom.spec.whatwg.org/#concept-element-attributes-change it looks like these steps actually run before the attribute has been changed! Maybe we should create an alternative in the DOM spec which runs after the attribute is changed instead of before.

Is that the extent of your concern?

Copy link
Member

Choose a reason for hiding this comment

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

Is that the extent of your concern?

Yep :)

Copy link
Member

Choose a reason for hiding this comment

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

Hmm. Do engines have callbacks before and after or is the DOM Standard wrong here in doing it before?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Based on my brief searching, it looks like in chromium we only look at attribute changes after they happen, not before they happen. I'd be in favor of just changing element attribute changes to run after instead of having two algorithms/definitions.

Copy link
Member

Choose a reason for hiding this comment

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

Agreed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I created a PR here: whatwg/dom#1176

source Show resolved Hide resolved
source Outdated
Comment on lines 82438 to 82439
<p>If the result of running <span>topmost popover ancestor</span> given
<var>stack</var>[<var>index</var>] is not <var>stack</var>[<var>index</var> - 1], then:</p>
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we can do something more simple, like pass the popoverTargetElement then run hide all popovers until popoverTargetElement if it's an auto popover.

I'm having a bit of trouble understanding why this is the right thing to do.

Copy link
Member

Choose a reason for hiding this comment

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

@josepharhar Can you explain what this "check and possibly close popover stack" algorithm does in terms of user experience? Like which cases it will be no-op, which cases it will hide all popovers, this is mostly the part I have trouble wrapping my head around.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you explain what this "check and possibly close popover stack" algorithm does in terms of user experience?

Check and possibly close popover stack recalculates the popover stack being built from the relationships of the popovers to each other in the DOM and from the popover target attributes and reconciles it with the currently open popovers. If they don't match up, it closes all popovers because something must have been modified which messed up the relationships.

Like which cases it will be no-op, which cases it will hide all popovers, this is mostly the part I have trouble wrapping my head around.

When setting disabled in this case, check and possibly close popover stack will be called but no popovers will be closed because outerpopover and innerpopover are associated by their parent-child relationship in the DOM.

<div id=outerpopover popover=auto>
  <div id=innerpopover popover=auto>hello world</div>
</div>
<button id=mybutton>button</button>
<script>
outerpopover.showPopover();
innerpopover.showPopover(); // both can be open since outerpopover is an ancestor
mybutton.disabled = true; // doesn't close any popovers
</script>

However, if we make the button the thing which creates the relationship between outerpopover and innerpopover and allows them to both be open at the same time and then take that away, it will close all popovers:

<div id=outerpopover popover=auto>
  <button id=mybutton popovertarget=innerpopover>toggle popover</button>
</div>
<div id=innerpopover popover=auto>hello world</div>
<script>
outerpopover.showPopover();
innerpopover.showPopover(); // both can be open thanks to mybutton
mybutton.removeAttribute('popovertarget'); // all popovers will be closed since we broke the connection
</script>

There are additional test cases in the WPT. Does this help?

Copy link
Member

@nt1m nt1m Mar 20, 2023

Choose a reason for hiding this comment

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

Yeah, thanks! seems like this is symmetric with the auto popovers hidden by the show popover algo as well, perhaps a note linking the two would be helpful.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok I added a note, how does it look?

source Outdated Show resolved Hide resolved
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Mar 20, 2023
If the popovertarget attribute is changed on an element in a way which
breaks the connection keeping multiple popovers open, then this patch
will close all open popovers. This was pointed out here:
whatwg/html#9048 (comment)

Bug: 1307772, 1408546
Change-Id: I0a42260e97b7ef3fde01f416ef090b50994b8c5d
aarongable pushed a commit to chromium/chromium that referenced this pull request Mar 21, 2023
If the popovertarget attribute is changed on an element in a way which
breaks the connection keeping multiple popovers open, then this patch
will close all open popovers. This was pointed out here:
whatwg/html#9048 (comment)

Bug: 1307772, 1408546
Change-Id: I0a42260e97b7ef3fde01f416ef090b50994b8c5d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4354171
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Reviewed-by: Mason Freed <masonf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1120013}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Mar 21, 2023
If the popovertarget attribute is changed on an element in a way which
breaks the connection keeping multiple popovers open, then this patch
will close all open popovers. This was pointed out here:
whatwg/html#9048 (comment)

Bug: 1307772, 1408546
Change-Id: I0a42260e97b7ef3fde01f416ef090b50994b8c5d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4354171
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Reviewed-by: Mason Freed <masonf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1120013}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Mar 21, 2023
If the popovertarget attribute is changed on an element in a way which
breaks the connection keeping multiple popovers open, then this patch
will close all open popovers. This was pointed out here:
whatwg/html#9048 (comment)

Bug: 1307772, 1408546
Change-Id: I0a42260e97b7ef3fde01f416ef090b50994b8c5d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4354171
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Reviewed-by: Mason Freed <masonf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1120013}
@nt1m
Copy link
Member

nt1m commented Mar 21, 2023

Looks good to me, will leave it to @annevk for a final look, and for the before attribute change vs after attribute change issue.

@nt1m nt1m added the topic: popover The popover attribute and friends label Mar 22, 2023
@nt1m
Copy link
Member

nt1m commented Mar 24, 2023

WebKit implementation bug: https://bugs.webkit.org/show_bug.cgi?id=254382

josepharhar added a commit to josepharhar/dom that referenced this pull request Mar 25, 2023
At least in chromium, synchronous internal listeners for attribute
changes which are run as "attribute change steps" are run after the
attribute is actually changed, not before.

This affects popover attribute related algorithms in HTML:
whatwg/html#9048 (comment)
marcoscaceres pushed a commit to web-platform-tests/wpt that referenced this pull request Mar 28, 2023
If the popovertarget attribute is changed on an element in a way which
breaks the connection keeping multiple popovers open, then this patch
will close all open popovers. This was pointed out here:
whatwg/html#9048 (comment)

Bug: 1307772, 1408546
Change-Id: I0a42260e97b7ef3fde01f416ef090b50994b8c5d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4354171
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Reviewed-by: Mason Freed <masonf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1120013}
cookiecrook pushed a commit to cookiecrook/wpt that referenced this pull request Mar 29, 2023
If the popovertarget attribute is changed on an element in a way which
breaks the connection keeping multiple popovers open, then this patch
will close all open popovers. This was pointed out here:
whatwg/html#9048 (comment)

Bug: 1307772, 1408546
Change-Id: I0a42260e97b7ef3fde01f416ef090b50994b8c5d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4354171
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Reviewed-by: Mason Freed <masonf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1120013}
webkit-commit-queue pushed a commit to rwlbuis/WebKit that referenced this pull request Mar 31, 2023
https://bugs.webkit.org/show_bug.cgi?id=254382

Reviewed by Tim Nguyen.

Implement "check and possibly close popover stack" algorithm as specified here:
whatwg/html#9048

This patch also imports the latest version of popover-target-element-disabled.html.

* LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-target-element-disabled-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-target-element-disabled.html:
* Source/WebCore/html/HTMLElement.cpp:
(WebCore::HTMLElement::checkAndPossiblyClosePopoverStackInternal):
* Source/WebCore/html/HTMLElement.h:
(WebCore::HTMLElement::checkAndPossiblyClosePopoverStack):
* Source/WebCore/html/HTMLFormControlElement.cpp:
(WebCore::HTMLFormControlElement::removedFromAncestor):
(WebCore::HTMLFormControlElement::parseAttribute):
(WebCore::HTMLFormControlElement::disabledStateChanged):
(WebCore::HTMLFormControlElement::didChangeForm):
* Source/WebCore/html/HTMLFormControlElement.h:
* Source/WebCore/html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::updateType):

Canonical link: https://commits.webkit.org/262440@main
cookiecrook pushed a commit to cookiecrook/wpt that referenced this pull request Apr 8, 2023
If the popovertarget attribute is changed on an element in a way which
breaks the connection keeping multiple popovers open, then this patch
will close all open popovers. This was pointed out here:
whatwg/html#9048 (comment)

Bug: 1307772, 1408546
Change-Id: I0a42260e97b7ef3fde01f416ef090b50994b8c5d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4354171
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Reviewed-by: Mason Freed <masonf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1120013}
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this pull request Apr 13, 2023
…ttribute changes, a=testonly

Automatic update from web-platform-tests
Close popover stack when popovertarget attribute changes

If the popovertarget attribute is changed on an element in a way which
breaks the connection keeping multiple popovers open, then this patch
will close all open popovers. This was pointed out here:
whatwg/html#9048 (comment)

Bug: 1307772, 1408546
Change-Id: I0a42260e97b7ef3fde01f416ef090b50994b8c5d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4354171
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Reviewed-by: Mason Freed <masonf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1120013}

--

wpt-commits: 699803ffbe61479119ee4dd8622635b6b0ef715e
wpt-pr: 39083
josepharhar added a commit to josepharhar/html that referenced this pull request Apr 14, 2023
Fixes whatwg#9160

If this patch is merged, then whatwg#9048
is obsolete and can be closed without merging.

Rationale (copied from [masons patch](https://chromium-review.googlesource.com/c/chromium/src/+/4429412)):

Instead of using just
the DOM structure to establish the popover hierarchy, the user's
behavior should matter. For example, if one popover contains a popover
invoker pointing to another popover, it should matter whether that
invoker is *actually used* to open the second popover.

An example:
- Component 1 is a third party widget, which uses popover
- Component 2 is another third party widget, also using popover
- A page wants to use both components separately, from separate
  invoking buttons.
- Component 1 also wants to be able to use Component 2, via a
  button within Component 1.

In this example, the page should be able to still independently use
these components. So a user clicking the page's button for Component 2
is expected to close Component 1 if it's open, because that's a direct
invocation of Component 2. However, if the user clicks the button
within Component 1 to get Component 2, it is natural to leave Component
1 open because this is a nested call.

Important note: this often happens to be the behavior even before this
change, since the user clicking on the page-level Component 2 invoking
button represents a light dismiss signal for Component 1, so it closes
either way. But this patch simplifies the implementation,
removing the need to track all invokers on the page, and also removing
the need to continuously check whether invoker relationships have
changed.
@josepharhar
Copy link
Contributor Author

If #9171 gets merged, then it will make this PR obsolete and I will close this

<li><p>If <var>localName</var> is <code data-x="attr-fe-disabled">disabled</code>, <code
data-x="attr-fae-form">form</code>, or <code data-x="attr-popovertarget">popovertarget</code>,
then run <span>check and possibly close popover stack</span> given <var>element</var>'s
<span>node document</span>.</p></li>
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is correct for form and possibly popovertarget. This algorithm runs whenever the value is set, even when it's set to the same value. Presumably when it's set to the same value we don't want to invalidate.

@annevk annevk closed this in cf9625f May 8, 2023
annevk pushed a commit to whatwg/dom that referenced this pull request Jun 10, 2023
In all implementations, internal listeners for attribute changes which are run as "attribute change steps" are run after the attribute is actually changed, not before.

This affects popover attribute related algorithms in HTML: whatwg/html#9048 (comment).
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 this pull request may close these issues.

WPT tests for unspecified PopoverInvokerElement removing steps
3 participants