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

"check popover algorithm" check for open dialogs is weak #9335

Closed
nt1m opened this issue May 25, 2023 · 8 comments · Fixed by #9344
Closed

"check popover algorithm" check for open dialogs is weak #9335

nt1m opened this issue May 25, 2023 · 8 comments · Fixed by #9344
Labels
topic: dialog The <dialog> element. topic: popover The popover attribute and friends

Comments

@nt1m
Copy link
Member

nt1m commented May 25, 2023

https://html.spec.whatwg.org/multipage/popover.html#check-popover-validity

element is a dialog element and has an open attribute

This check doesn't cover this case (in terms of top layer conflicts):

<script>
  onload = () => {
    dialog0.showModal();
    dialog0.open = false;
    dialog0.showPopover();
  };
</script>
<dialog id="dialog0" popover=""></dialog>

Should we change this check to checking whether the dialog is in modal state instead?

cc @annevk @domenic @mfreed7 @josepharhar @emilio @cathiechen

@nt1m nt1m added topic: dialog The <dialog> element. topic: popover The popover attribute and friends labels May 25, 2023
@mfreed7
Copy link
Collaborator

mfreed7 commented May 26, 2023

Hmm, the behavior in Chromium is that dialog0 is left showing as a popover. And that's what I'd expect, I guess, right? Removing the open attribute on the modal dialog closes it, and it's free to be re-opened as a popover.

(This is precisely why I really didn't want to add an open attribute for popovers.)

@nt1m
Copy link
Member Author

nt1m commented May 26, 2023

Removing the open attribute on the modal dialog closes it

This isn't the case per the spec right now, the modal dialog will be hidden (display: none), but still in the top layer.

(WebKit caught this because this triggered an assertion)

@mfreed7
Copy link
Collaborator

mfreed7 commented May 26, 2023

This isn't the case per the spec right now, the modal dialog will be hidden (display: none), but still in the top layer.

Boo. That's the case also in Chromium, but it is rendered display:none. However, the popover behavior does seem to still work correctly I think. There could be some issues behind the scenes.

I wonder if we shouldn't change the spec so that removing open closes the dialog and explicitly removes from the top layer?

@nt1m
Copy link
Member Author

nt1m commented May 26, 2023

I wonder if we shouldn't change the spec so that removing open closes the dialog and explicitly removes from the top layer?

I think this might be an entirely separate discussion, because we'd want to figure out what .open = true does.

However, the popover behavior does seem to still work correctly I think. There could be some issues behind the scenes.

I think we do want to avoid top layer conflicts (e.g. having something that is opened in top layer for 2 different reasons), because it can leave the element in the broken state once you get to the point of removing it from the top layer. Also, it makes the stacking order unclear in the top layer if there are multiple elements.

I'd personally be in favor in changing the check from checking for the "open attribute" to checking for the "modal state", since I think the original intent for the check is to prevent top layer conflicts.

@mfreed7
Copy link
Collaborator

mfreed7 commented May 26, 2023

I wonder if we shouldn't change the spec so that removing open closes the dialog and explicitly removes from the top layer?

I think this might be an entirely separate discussion, because we'd want to figure out what .open = true does.

Yeah, I agree. Again, I wish we could get rid of open.

However, the popover behavior does seem to still work correctly I think. There could be some issues behind the scenes.

I think we do want to avoid top layer conflicts (e.g. having something that is opened in top layer for 2 different reasons), because it can leave the element in the broken state once you get to the point of removing it from the top layer. Also, it makes the stacking order unclear in the top layer if there are multiple elements.

I'd personally be in favor in changing the check from checking for the "open attribute" to checking for the "modal state", since I think the original intent for the check is to prevent top layer conflicts.

Given the above, I agree that it's probably good to change the check from [open] to "is modal". I'm supportive.

@domenic
Copy link
Member

domenic commented May 27, 2023

That separate discussion is #5802, and would be great if people were willing to tackle it.

nt1m added a commit to nt1m/html that referenced this issue May 27, 2023
…r validity' algorithm

The following case currently does not fail:

```
dialog.showModal();
dialog.open = false;
dialog.showPopover();
```

even though it is a top layer conflict:

1. `showModal` pushes to the top layer
2. `.open = false` then hides the dialog, while keeping it in top layer
3. `showPopover` pushes to the top layer again

The check for the open attribute is supposed to prevent top layer conflicts, since those conflicts
can leave the element in a broken state, notably after hiding. For instance, the previous sequence
of actions followed by `dialog.hidePopover()` will leave the `is modal` flag despite the dialog
being completely removed from the top layer.

Fixes whatwg#9335
nt1m added a commit to nt1m/html that referenced this issue May 27, 2023
…r validity' algorithm

The following case currently does not fail:

```
dialog.showModal();
dialog.open = false;
dialog.showPopover();
```

even though it is a top layer conflict:

1. `showModal` pushes to the top layer
2. `.open = false` then hides the dialog, while keeping it in top layer
3. `showPopover` pushes to the top layer again

The check for the open attribute is supposed to prevent top layer conflicts, since those conflicts
can leave the element in a broken state, notably after hiding. For instance, the previous sequence
of actions followed by `dialog.hidePopover()` will leave the `is modal` flag despite the dialog
being completely removed from the top layer.

Fixes whatwg#9335
@nt1m
Copy link
Member Author

nt1m commented May 27, 2023

I created #9344

@nt1m
Copy link
Member Author

nt1m commented May 27, 2023

@mfreed7 FWIW, a side-effect of my PR is that we can call showPopover() on top of show() or any non-modal dialog now. I think it's not particularly troublesome, but if you think it is, I can change the check from "is modal" to "is open or modal".

nt1m added a commit to nt1m/html that referenced this issue May 29, 2023
…r validity' algorithm

The following case currently does not fail:

```
dialog.showModal();
dialog.open = false;
dialog.showPopover();
```

even though it is a top layer conflict:

1. `showModal` pushes to the top layer
2. `.open = false` then hides the dialog, while keeping it in top layer
3. `showPopover` pushes to the top layer again

The check for the open attribute is supposed to prevent top layer conflicts, since those conflicts
can leave the element in a broken state, notably after hiding. For instance, the previous sequence
of actions followed by `dialog.hidePopover()` will leave the `is modal` flag despite the dialog
being completely removed from the top layer.

Also only remove from top layer in `HTMLDialogElement.prototype.close()` when the is modal flag is
true to prevent that method from removing popovers from the top layer.

Fixes whatwg#9335
nt1m added a commit to nt1m/html that referenced this issue May 30, 2023
…r validity' algorithm

The following case currently does not fail:

```
dialog.showModal();
dialog.open = false;
dialog.showPopover();
```

even though it is a top layer conflict:

1. `showModal` pushes to the top layer
2. `.open = false` then hides the dialog, while keeping it in top layer
3. `showPopover` pushes to the top layer again

The check for the open attribute is supposed to prevent top layer conflicts, since those conflicts
can leave the element in a broken state, notably after hiding. For instance, the previous sequence
of actions followed by `dialog.hidePopover()` will leave the `is modal` flag despite the dialog
being completely removed from the top layer.

Also only remove from top layer in `HTMLDialogElement.prototype.close()` when the is modal flag is
true to prevent that method from removing popovers from the top layer.

Fixes whatwg#9335
nt1m added a commit to nt1m/html that referenced this issue Jun 5, 2023
…r validity' algorithm

The following case currently does not fail:

```
dialog.showModal();
dialog.open = false;
dialog.showPopover();
```

even though it is a top layer conflict:

1. `showModal` pushes to the top layer
2. `.open = false` then hides the dialog, while keeping it in top layer
3. `showPopover` pushes to the top layer again

The check for the open attribute is supposed to prevent top layer conflicts, since those conflicts
can leave the element in a broken state, notably after hiding. For instance, the previous sequence
of actions followed by `dialog.hidePopover()` will leave the `is modal` flag despite the dialog
being completely removed from the top layer.

Also only remove from top layer in `HTMLDialogElement.prototype.close()` when the is modal flag is
true to prevent that method from removing popovers from the top layer.

For `dialog.close()` to be symmetric & consistent with `dialog.show()`, we also stop throwing when
`show()` is called on a dialog in the popover showing state.

Fixes whatwg#9335
annevk pushed a commit that referenced this issue Jun 6, 2023
The following case currently does not fail

dialog.showModal();
dialog.open = false;
dialog.showPopover();

even though it is a top layer conflict:

1. showModal() pushes to the top layer.
2. open = false then hides the dialog, while keeping it in top layer.
3. showPopover() pushes to the top layer again.

The check for the open attribute is supposed to prevent top layer conflicts, since those conflicts can leave the element in a broken state, notably after hiding. For instance, the previous sequence of actions followed by dialog.hidePopover() will leave the is modal flag set to true despite the dialog being completely removed from the top layer.

Also only remove from top layer in HTMLDialogElement.prototype.close() when the is modal flag is true to prevent that method from removing popovers from the top layer.

For dialog.close() to be symmetric & consistent with dialog.show(), we also stop throwing when show() is called on a dialog in the popover showing state.

Tests: WebKit/WebKit#14454.

Fixes #9335.
rubberyuzu pushed a commit to rubberyuzu/html that referenced this issue Jul 20, 2023
The following case currently does not fail

dialog.showModal();
dialog.open = false;
dialog.showPopover();

even though it is a top layer conflict:

1. showModal() pushes to the top layer.
2. open = false then hides the dialog, while keeping it in top layer.
3. showPopover() pushes to the top layer again.

The check for the open attribute is supposed to prevent top layer conflicts, since those conflicts can leave the element in a broken state, notably after hiding. For instance, the previous sequence of actions followed by dialog.hidePopover() will leave the is modal flag set to true despite the dialog being completely removed from the top layer.

Also only remove from top layer in HTMLDialogElement.prototype.close() when the is modal flag is true to prevent that method from removing popovers from the top layer.

For dialog.close() to be symmetric & consistent with dialog.show(), we also stop throwing when show() is called on a dialog in the popover showing state.

Tests: WebKit/WebKit#14454.

Fixes whatwg#9335.
rubberyuzu pushed a commit to rubberyuzu/html that referenced this issue Jul 21, 2023
The following case currently does not fail

dialog.showModal();
dialog.open = false;
dialog.showPopover();

even though it is a top layer conflict:

1. showModal() pushes to the top layer.
2. open = false then hides the dialog, while keeping it in top layer.
3. showPopover() pushes to the top layer again.

The check for the open attribute is supposed to prevent top layer conflicts, since those conflicts can leave the element in a broken state, notably after hiding. For instance, the previous sequence of actions followed by dialog.hidePopover() will leave the is modal flag set to true despite the dialog being completely removed from the top layer.

Also only remove from top layer in HTMLDialogElement.prototype.close() when the is modal flag is true to prevent that method from removing popovers from the top layer.

For dialog.close() to be symmetric & consistent with dialog.show(), we also stop throwing when show() is called on a dialog in the popover showing state.

Tests: WebKit/WebKit#14454.

Fixes whatwg#9335.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: dialog The <dialog> element. topic: popover The popover attribute and friends
Development

Successfully merging a pull request may close this issue.

3 participants