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 dialog light dismiss behavior #10737

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
4a93ad6
Add closedby attribute to <dialog>
mfreed7 Oct 31, 2024
3630019
Small tweaks
mfreed7 Oct 31, 2024
32c2240
Add requestClose()
mfreed7 Oct 31, 2024
78f9789
Fix tag nesting
mfreed7 Oct 31, 2024
b99c5ac
Move note out of OL
mfreed7 Nov 1, 2024
8698d0b
Address comments
mfreed7 Nov 8, 2024
f50198e
Check for open attribute
mfreed7 Nov 8, 2024
fb01762
Adjust algorithm to match impl and tests
mfreed7 Nov 13, 2024
4f205bd
Address comments
mfreed7 Nov 13, 2024
38bdafe
Update attribute index
mfreed7 Nov 13, 2024
873e451
Adjustments from dbaron
mfreed7 Nov 14, 2024
e7fbbec
Fix up the return value
mfreed7 Nov 15, 2024
8b019a4
Fix up closewatcher
mfreed7 Nov 15, 2024
b57968e
Fix up ol/li/p
mfreed7 Nov 15, 2024
ea474af
Some cleanup
mfreed7 Nov 15, 2024
db56191
Fix "empty" xref
mfreed7 Nov 15, 2024
82a4561
Address domenic@ comments
mfreed7 Nov 21, 2024
6a9e20b
Address annevk comments
mfreed7 Dec 2, 2024
20dc2fe
Change behavior to only close topmost dialog
mfreed7 Dec 5, 2024
f5a0919
Remove extra section
mfreed7 Dec 6, 2024
3f413d3
Remove exception
mfreed7 Dec 6, 2024
d9ed19f
Add closewatcher override for requestClose
mfreed7 Dec 6, 2024
ff98f98
Address 2 nits
mfreed7 Dec 9, 2024
2fb87b1
Address domenic comments
mfreed7 Dec 10, 2024
6aa7386
Side-step closewatcher abuse prevention
mfreed7 Dec 10, 2024
344d87f
allowPreventClose -> requireHistoryActionActivation
mfreed7 Dec 11, 2024
76619aa
Change closeWatcher.requestClose() also
mfreed7 Dec 12, 2024
57df925
Address two comments
mfreed7 Dec 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 65 additions & 57 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -10928,6 +10928,9 @@ partial interface <dfn id="document" data-lt="">Document</dfn> {
<span>set</span> of <span data-x="nrr-details-struct">not restored reason details</span>,
initially empty.</p>

<p>Each <code>Document</code> has an <dfn>open dialogs list</dfn>, which is a <span>list</span> of
<code>dialog</code> elements, initially empty.</p>

<h4>The <code>DocumentOrShadowRoot</code> interface</h4>

<p><cite>DOM</cite> defines the <code data-x="DOM
Expand Down Expand Up @@ -61596,7 +61599,7 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
[<span>CEReactions</span>] undefined <span data-x="dom-dialog-show">show</span>();
[<span>CEReactions</span>] undefined <span data-x="dom-dialog-showModal">showModal</span>();
[<span>CEReactions</span>] undefined <span data-x="dom-dialog-close">close</span>(optional DOMString returnValue);
[<span>CEReactions</span>] undefined <span data-x="dom-dialog-request-close">requestClose</span>(optional DOMString returnValue);
[<span>CEReactions</span>] undefined <span data-x="dom-dialog-requestclose">requestClose</span>(optional DOMString returnValue);
mfreed7 marked this conversation as resolved.
Show resolved Hide resolved
};</code></pre>
</dd>
<dd w-dev>Uses <code>HTMLDialogElement</code>.</dd>
Expand Down Expand Up @@ -61776,7 +61779,7 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
<p>The argument, if provided, provides a return value.</p>
</dd>
mfreed7 marked this conversation as resolved.
Show resolved Hide resolved

<dt><code data-x=""><var>dialog</var>.<span subdfn data-x="dom-dialog-request-close">requestClose</span>([ <var>result</var> ])</code></dt>
<dt><code data-x=""><var>dialog</var>.<span subdfn data-x="dom-dialog-requestclose">requestClose</span>([ <var>result</var> ])</code></dt>
<dd>
<p>Acts as if a <span data-x="close request">close request</span> was sent targeting
<var>dialog</var>, by first firing a <code data-x="event-cancel">cancel</code> event, and if
Expand Down Expand Up @@ -61855,8 +61858,8 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
method steps are:</p>

<ol>
<li><p>If <span>this</span> has an <code data-x="attr-dialog-open">open</code> attribute and the
<span>is modal</span> flag of <span>this</span> is false, then return.</p></li>
<li><p>If <span>this</span> has an <code data-x="attr-dialog-open">open</code> attribute and
<span>is modal</span> of <span>this</span> is false, then return.</p></li>

<li><p>If <span>this</span> has an <code data-x="attr-dialog-open">open</code> attribute, then
throw an <span>"<code>InvalidStateError</code>"</span> <code>DOMException</code>.</p></li>
Expand All @@ -61878,6 +61881,13 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
<li><p>Add an <code data-x="attr-dialog-open">open</code> attribute to <span>this</span>, whose
value is the empty string.</p></li>

<li><p><span>Assert</span>: <span>this</span>'s <span>node document</span>'s <span>open
dialogs list</span> does not <span data-x="list contains">contain</span>
<span>this</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 think this assert fails if you do

dialogEl.show();
dialogEl.removeAttribute("open");
dialogEl.show();

#10124 will fix this, but I'm hesitant to block this PR on that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, you're right. The Chromium code has to work around the state of that feature flag.

Since that PR "fixes" the behavior for removing the open attribute, would you be ok with me just removing this Assert, rather than trying to bring in much of that PR?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, as long as you can verify the assert is not load-bearing, then just removing it for now seems reasonable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, it's load bearing in the case you bring up above - removing the open attribute. But the spec isn't super clear about that now anyway, so I guess it only bears code-implementation weight, not spec weight. LMK if that makes sense.


<li><p>Add <span>this</span> to <span>this</span>'s <span>node document</span>'s <span>open
dialogs list</span>.</p></li>

<li><p><span>Set the dialog close watcher</span> with <span>this</span>.</p></li>

<li><p>Set <span>this</span>'s <span>previously focused element</span> to the
Expand All @@ -61899,8 +61909,8 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
data-x="dom-dialog-showModal">showModal()</code></dfn> method steps are:</p>

<ol>
<li><p>If <span>this</span> has an <code data-x="attr-dialog-open">open</code> attribute and the
<span>is modal</span> flag of <span>this</span> is true, then return.</p></li>
<li><p>If <span>this</span> has an <code data-x="attr-dialog-open">open</code> attribute and
domenic marked this conversation as resolved.
Show resolved Hide resolved
<span>is modal</span> of <span>this</span> is true, then return.</p></li>

<li><p>If <span>this</span> has an <code data-x="attr-dialog-open">open</code> attribute, then
throw an <span>"<code>InvalidStateError</code>"</span> <code>DOMException</code>.</p></li>
Expand Down Expand Up @@ -61937,7 +61947,14 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
<li><p>Add an <code data-x="attr-dialog-open">open</code> attribute to <span>this</span>, whose
value is the empty string.</p></li>

<li><p>Set the <span>is modal</span> flag of <span>this</span> to true.</p></li>
<li><p>Set <span>is modal</span> of <span>this</span> to true.</p></li>

<li><p><span>Assert</span>: <span>this</span>'s <span>node document</span>'s <span>open
dialogs list</span> does not <span data-x="list contains">contain</span>
<span>this</span>.</p></li>

<li><p>Add <span>this</span> to <span>this</span>'s <span>node document</span>'s <span>open
dialogs list</span>.</p></li>

<li>
<p>Let <span>this</span>'s <span>node document</span> be <span data-x="blocked by a modal
mfreed7 marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -61993,8 +62010,9 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
value</span>.</p></li>

<li><p><i data-x="create-close-watcher-getEnabledState">getEnabledState</i> being to return
true if <var>dialog</var>'s <span>enable closewatcher for requestclose</span> is true or
<var>dialog</var>'s <span>computed closed-by state</span> is not <span
true if <var>dialog</var>'s <span>enable close watcher for <code
data-x="dom-dialog-requestClose">requestClose()</code></span> is true or <var>dialog</var>'s
<span>computed closed-by state</span> is not <span
data-x="attr-dialog-closedby-none-state">None</span>; otherwise false.</p></li>
</ul>
</li>
Expand Down Expand Up @@ -62080,7 +62098,10 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
data-x="list contains">contains</span> <var>removedNode</var>, then <span>remove an element from
the top layer immediately</span> given <var>removedNode</var>.</p></li>
mfreed7 marked this conversation as resolved.
Show resolved Hide resolved

<li><p>Set the <span>is modal</span> flag of <var>removedNode</var> to false.</p></li>
<li><p>Set <span>is modal</span> of <var>removedNode</var> to false.</p></li>

mfreed7 marked this conversation as resolved.
Show resolved Hide resolved
<li><p><span data-x="list remove">Remove</span> <var>removedNode</var> from
<var>removedNode</var>'s <span>node document</span>'s <span>open dialogs list</span>.</p></li>
</ol>

<p>The <dfn method for="HTMLDialogElement"><code
Expand All @@ -62093,7 +62114,7 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
</ol>

<p>The <dfn method for="HTMLDialogElement"><code
data-x="dom-dialog-request-close">requestClose(<var>returnValue</var>)</code></dfn> method steps
data-x="dom-dialog-requestclose">requestClose(<var>returnValue</var>)</code></dfn> method steps
are:</p>

<ol>
Expand All @@ -62103,8 +62124,8 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
<li><p><span>Assert</span>: <var>this</var>'s <span data-x="dialog-close-watcher">close
watcher</span> is not null.</p></li>

<li><p>Set <var>dialog</var>'s <span>enable closewatcher for requestclose</span> to
true.</p></li>
<li><p>Set <var>dialog</var>'s <span>enable close watcher for <code
data-x="dom-dialog-requestClose">requestClose()</code></span> to true.</p></li>

mfreed7 marked this conversation as resolved.
Show resolved Hide resolved
<li><p>If <var>returnValue</var> is not given, then set it to null.</p></li>

Expand All @@ -62114,8 +62135,8 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
<li><p><span data-x="close-watcher-request-close">Request to close</span> <var>dialog</var>'s
<span data-x="dialog-close-watcher">close watcher</span>.</p></li>

<li><p>Set <var>dialog</var>'s <span>enable closewatcher for requestclose</span> to
false.</p></li>
<li><p>Set <var>dialog</var>'s <span>enable close watcher for <code
data-x="dom-dialog-requestClose">requestClose()</code></span> to false.</p></li>
</ol>

<p>When a <code>dialog</code> element <var>subject</var> is to be <dfn data-x="close the
Expand All @@ -62140,13 +62161,16 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
<li><p>Remove <var>subject</var>'s <code data-x="attr-dialog-open">open</code>
attribute.</p></li>

<li><p>If the <span>is modal</span> flag of <var>subject</var> is true, then <span>request an
<li><p>If <span>is modal</span> of <var>subject</var> is true, then <span>request an
element to be removed from the top layer</span> given <var>subject</var>.</p></li>

<li><p>Let <var>wasModal</var> be the value of <var>subject</var>'s <span>is
modal</span> flag.</p></li>

<li><p>Set the <span>is modal</span> flag of <var>subject</var> to false.</p></li>
<li><p>Set <span>is modal</span> of <var>subject</var> to false.</p></li>

<li><p><span data-x="list remove">Remove</span> <var>subject</var> from <var>subject</var>'s
mfreed7 marked this conversation as resolved.
Show resolved Hide resolved
<span>node document</span>'s <span>open dialogs list</span>.</p></li>

<li><p>If <var>result</var> is not null, then set the <code
data-x="dom-dialog-returnValue">returnValue</code> attribute to <var>result</var>.</p></li>
Expand Down Expand Up @@ -62243,11 +62267,10 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
<p>Each <code>dialog</code> element has a <dfn>request close return value</dfn>, which is a
string, initially null.</p>

<p>Each <code>dialog</code> element has an <dfn>enable closewatcher for requestclose</dfn> flag,
initially false.</p>
<p>Each <code>dialog</code> element has an <dfn>enable close watcher for <code
data-x="dom-dialog-requestClose">requestClose()</code></dfn> boolean, initially false.</p>

<p>Each <code>dialog</code> element has an <dfn>is modal</dfn> flag. When a <code>dialog</code>
element is created, this flag must be set to false.</p>
<p>Each <code>dialog</code> element has an <dfn>is modal</dfn> boolean, initially false.</p>

<p>Each <span data-x="html elements">HTML element</span> has a <dfn>previously focused
element</dfn> which is null or an element, and it is initially null. When <code
Expand Down Expand Up @@ -62297,16 +62320,14 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
<li><p><span>Assert</span>: <var>event</var>'s <code
data-x="dom-Event-isTrusted">isTrusted</code> attribute is true.</p></li>
mfreed7 marked this conversation as resolved.
Show resolved Hide resolved

<li><p>Let <var>target</var> be <var>event</var>'s <span
data-x="concept-event-target">target</span>.</p></li>

<li><p>Let <var>document</var> be <var>target</var>'s <span>node document</span>.</p></li>
<li><p>Let <var>document</var> be <var>event</var>'s <span
data-x="concept-event-target">target</span>'s <span>node document</span>.</p></li>

<li><p>If <var>document</var>'s <span>light dismissible dialog list</span> is
<span data-x="list is empty">empty</span>, then return.</p></li>
<li><p>If <var>document</var>'s <span>open dialogs list</span> is <span
data-x="list is empty">empty</span>, then return.</p></li>

<li><p>Let <var>ancestor</var> be the result of running <span>topmost clicked dialog</span>
given <var>target</var> and <var>event</var>.</p></li>
<li><p>Let <var>ancestor</var> be the result of running <span>nearest clicked dialog</span>
mfreed7 marked this conversation as resolved.
Show resolved Hide resolved
given <var>event</var>.</p></li>

<li><p>If <var>event</var>'s <code data-x="dom-Event-type">type</code> is
"<code data-x="event-pointerdown">pointerdown</code>", then set <var>document</var>'s
Expand All @@ -62324,15 +62345,15 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {

mfreed7 marked this conversation as resolved.
Show resolved Hide resolved
<li><p>If <var>sameTarget</var> is false, then return.</p></li>

<li><p>Let <var>topmostDialog</var> be the last element of <var>document</var>'s <span>light
dismissible dialog list</span>.</p></li>
<li><p>Let <var>topmostDialog</var> be the last element of <var>document</var>'s <span>open
mfreed7 marked this conversation as resolved.
Show resolved Hide resolved
dialogs list</span>.</p></li>

<li><p>If <var>ancestor</var> is <var>topmostDialog</var>, then return.</p></li>

<li><p>If <var>topmostDialog</var>'s <span>computed closed-by state</span> is not <span
mfreed7 marked this conversation as resolved.
Show resolved Hide resolved
data-x="attr-dialog-closedby-any-state">Any</span>, then return.</p></li>

<li><p><span>Assert</span> <var>topmostDialog</var>'s <span
<li><p><span>Assert</span>: <var>topmostDialog</var>'s <span
data-x="dialog-close-watcher">close watcher</span> is not null.</p></li>

mfreed7 marked this conversation as resolved.
Show resolved Hide resolved
<li><p><span data-x="close-watcher-request-close">Request to close</span>
Expand All @@ -62354,22 +62375,25 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
href="https://github.com/w3c/pointerevents/pull/460">Pointer Events spec</a> when the user clicks
or touches anywhere on the page.</p>

<p>To find the <dfn>topmost clicked dialog</dfn>, given a <code>Node</code> <var>node</var> and
a <code>PointerEvent</code> <var>event</var>:</p>
<p>To find the <dfn>nearest clicked dialog</dfn>, given a <code>PointerEvent</code>
<var>event</var>:</p>

mfreed7 marked this conversation as resolved.
Show resolved Hide resolved
<ol>
<li><p>If <var>node</var> is a <code>dialog</code> element, <var>node</var> has an <code
data-x="attr-dialog-open">open</code> attribute, <var>node</var>'s <span>is modal</span> flag is
<li><p>Let <var>target</var> be <var>event</var>'s <span
mfreed7 marked this conversation as resolved.
Show resolved Hide resolved
data-x="concept-event-target">target</span>.</p></li>

<li><p>If <var>target</var> is a <code>dialog</code> element, <var>target</var> has an <code
data-x="attr-dialog-open">open</code> attribute, <var>target</var>'s <span>is modal</span> is
true, and <var>event</var>'s <code data-x="mouseevent-clientx">clientX</code> and
<code data-x="mouseevent-clienty">clientY</code> are outside the bounds of <var>node</var>, then
return null.
<code data-x="mouseevent-clienty">clientY</code> are outside the bounds of <var>target</var>,
then return null.

<p class="note">The check for <code data-x="mouseevent-clientx">clientX</code> and <code
data-x="mouseevent-clienty">clientY</code> is because a pointer event that hits the <code
mfreed7 marked this conversation as resolved.
Show resolved Hide resolved
data-x="">::backdrop</code> pseudo element of a dialog will result in <var>event</var> having a
target of the dialog element itself.</p>

mfreed7 marked this conversation as resolved.
Show resolved Hide resolved
<li><p>Let <var>currentNode</var> be <var>node</var>.</p></li>
<li><p>Let <var>currentNode</var> be <var>target</var>.</p></li>

<li>
<p>While <var>currentNode</var> is not null:</p>
Expand All @@ -62387,22 +62411,6 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
<li><p>Return null.</p></li>
</ol>

<p>To get the <dfn>light dismissible dialog list</dfn> for a <code>Document</code>
<var>document</var>:</p>

<ol>
<li><p>Let <var>dialogs</var> be « ».</p></li>

<li><p><span data-x="list iterate">For each</span> <code>Element</code> <var>element</var> in
<var>document</var>'s <span data-x="shadow-including descendant">shadow-including
descendants</span>, in <span>shadow-including tree order</span>: if <var>element</var> is a
<code>dialog</code> element and <var>element</var> has the <code
data-x="attr-dialog-open">open</code> attribute, then <span data-x="list append">append</span>
<var>element</var> to <var>dialogs</var>.</p></li>

<li><p>Return <var>dialogs</var>.</p></li>
</ol>

<h3 split-filename="scripting">Scripting</h3>

<p>Scripts allow authors to add interactivity to their documents.</p>
Expand Down Expand Up @@ -75213,7 +75221,7 @@ Demos:
element falling into one of the following categories:</p>

<ul>
<li><code>dialog</code> elements whose <span>is modal</span> flag is true</li>
<li><code>dialog</code> elements whose <span>is modal</span> is true</li>

<li>elements whose <span>fullscreen flag</span> is true</li>
</ul>
Expand Down Expand Up @@ -86500,7 +86508,7 @@ dictionary <dfn dictionary>DragEventInit</dfn> : <span>MouseEventInit</span> {
<li><p><var>expectedDocument</var> is not null and <var>element</var>'s <span>node
document</span> is not <var>expectedDocument</var>;</p></li>

<li><p><var>element</var> is a <code>dialog</code> element and its <span>is modal</span> flag
<li><p><var>element</var> is a <code>dialog</code> element and its <span>is modal</span>
is set to true; or</li>

<li><p><var>element</var>'s <span>fullscreen flag</span> is set,</p></li>
Expand Down