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

WIP dialog closedby attribute spec #10157

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
221 changes: 218 additions & 3 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -61158,6 +61158,7 @@ interface <dfn interface>HTMLDetailsElement</dfn> : <span>HTMLElement</span> {
<dd><span>Flow content</span>.</dd>
<dt><span data-x="concept-element-attributes">Content attributes</span>:</dt>
<dd><span>Global attributes</span></dd>
<dd><code data-x="attr-dialog-closedby">closedby</code></dd>
<dd><code data-x="attr-dialog-open">open</code></dd>
<dt><span
data-x="concept-element-accessibility-considerations">Accessibility considerations</span>:</dt>
Expand All @@ -61171,6 +61172,7 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {

[<span>CEReactions</span>] attribute boolean <span data-x="dom-dialog-open">open</span>;
attribute DOMString <span data-x="dom-dialog-returnValue">returnValue</span>;
[<span>CEReactions</span>] attribute DOMString <span data-x="dom-dialog-closedBy">closedBy</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);
Expand Down Expand Up @@ -61266,6 +61268,38 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
is a <span>boolean attribute</span>. When specified, it indicates that the <code>dialog</code>
element is active and that the user can interact with it.</p>

<p>The <dfn element-attr for="dialog"><code data-x="attr-dialog-closedby">closedby</code></dfn>
content attribute is an <span>enumerated attribute</span> with the following keywords and
states:</p>

<table>
<thead>
<tr>
<th>Keyword
<th>State
<th>Brief description
<tbody>
<tr>
<td><dfn attr-value for="dialog/closedby"><code data-x="attr-closedby-any">any</code></dfn>
<td><dfn data-x="attr-closedby-any-state">Any</dfn>
<td><span data-x="close request">Close requests</span> or clicking outside closes the dialog.
<tr>
<td><dfn attr-value for="dialog/closedby"><code data-x="attr-closedby-closerequest">closerequest</code></dfn>
<td><dfn data-x="attr-closedby-closerequest-state">Close Request</dfn>
<td><span data-x="close request">Close requests</span> close the dialog.
<tr>
<td><dfn attr-value for="dialog/closedby"><code data-x="attr-closedby-none">none</code></dfn>
<td><dfn data-x="attr-closedby-none-state">None</dfn>
<td>Nothing automatically closes the dialog.
</table>

<p>The <code data-x="attr-dialog-closedby">closedby</code> attribute's <i data-x="invalid value
default">invalid value default</i> and <i data-x="missing value default">missing value
default</i> are both the <dfn data-x="attr-closedby-auto-state">Auto</dfn> state. The <span
data-x="attr-closedby-auto-state">auto</span> state matches <span
data-x="attr-closedby-closerequest-state">closerequest</span> when the element is modal;
otherwise <span data-x="attr-closedby-none-state">none</span>.</p>

<div w-nodev>

<p>A <code>dialog</code> element without an <code data-x="attr-dialog-open">open</code> attribute
Expand Down Expand Up @@ -61343,6 +61377,27 @@ 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 <span>this</span>'s <span data-x="dialog-close-watcher">close watcher</span> to the
result of <span data-x="establish a close watcher">establishing a close watcher</span> given
<span>this</span>'s <span>relevant global object</span>, with:</p>

<ul>
<li><p><i data-x="create-close-watcher-cancelAction">cancelAction</i> being to return the
result of <span data-x="concept-event-fire">firing an event</span> named <code
data-x="event-cancel">cancel</code> at <span>this</span>, with the <code
data-x="dom-Event-cancelable">cancelable</code> attribute initialized to true.</p></li>

<li><p><i data-x="create-close-watcher-closeAction">closeAction</i> being to <span>close the
dialog</span> given <span>this</span> and null.</p></li>

<li><p><i data-x="create-close-watcher-enabled">enabled</i> being true if <span>this</span>'s
<code data-x="attr-dialog-closedby">closedby</code> attribute state is <span
data-x="attr-closedby-any-state">Any</span> or <span
data-x="attr-closedby-closerequest-state">Close Request</span>; otherwise false.</p></li>
</ul>
</li>

<li><p>Set <span>this</span>'s <span>previously focused element</span> to the
<span>focused</span> element.</p></li>

Expand Down Expand Up @@ -61409,6 +61464,12 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {

<li><p><i data-x="create-close-watcher-closeAction">closeAction</i> being to <span>close the
dialog</span> given <span>this</span> and null.</p></li>

<li><p><i data-x="create-close-watcher-enabled">enabled</i> being true if <span>this</span>'s
<code data-x="attr-dialog-closedby">closedby</code> attribute is in the <span
data-x="attr-closedby-any-state">Any</span>, <span
data-x="attr-closedby-closerequest-state">Close Request</span>, or <span
data-x="attr-closedby-auto-state">Auto</span> state; otherwise false.</p></li>
</ul>
</li>

Expand Down Expand Up @@ -61599,6 +61660,9 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {

<hr>
Copy link
Member Author

Choose a reason for hiding this comment

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

Do we want to close the dialog here or do we actually want to do cancel and close (aka requestClose())?

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 think it makes sense to fire cancel and then fire close as a follow up if not cancelled?

Copy link
Member Author

Choose a reason for hiding this comment

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

openui/open-ui#950 (reply in thread) - Based on this comment, I need to change this to be cancel + close not just close.


<p>The <code>Document</code> has a <dfn>dialog pointerdown target</dfn>, which is an <span
data-x="HTMLDialogElement">HTML dialog element</span> or null, initially null.</p>

<p>Each <code>dialog</code> element has a <dfn data-x="dialog-close-watcher">close watcher</dfn>,
which is a <span>close watcher</span> or null, initially null.</p>
Copy link
Member Author

Choose a reason for hiding this comment

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

Need to make a PR for this spec like the popover one to call this function.

Copy link
Member

Choose a reason for hiding this comment

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

It'd be best to have a single hook from pointer events into HTML, I think. So we should either combine this with light dismiss open popovers or create a wrapper algorithm around both of them.


Expand All @@ -61613,8 +61677,42 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
attribute set this element to the currently <span>focused</span> element during the <span
data-x="show popover">show popover algorithm</span>.</p>

<p>The following <span data-x="concept-element-attributes-change-ext">attribute change
steps</span>, given <var>element</var>, <var>localName</var>, <var>oldValue</var>,
<var>value</var>, and <var>namespace</var>, are used for <span data-x="HTMLDialogElement">HTML
dialog elements</span>:</p>

<ol>
<li><p>If <var>namespace</var> is not null, then return.</p></li>

<li><p>If <var>localName</var> is not <code data-x="attr-dialog-closedby">closedby</code>, then
return.</p></li>

<li><p>If <var>element</var> has no <span data-x="attr-dialog-open">open</span> attribute, then
return.</p></li>

<li><p>If <var>oldValue</var> and <var>value</var> are in the same <span
data-x="attr-dialog-closedby">state</span>, then return.</p></li>

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

<li><p>If <var>value</var> is in the <span data-x="attr-closedby-any-state">Any</span> state,
or <span data-x="attr-closedby-closerequest-state">Close Request</span> state,
or <span data-x="attr-closedby-auto-state">Auto</span> state and <var>element</var>'s <span>is
modal</span> flag is true, then let <var>enabled</var> to true; otherwise false.</p></li>

<li><p>Set <var>element</var>'s <span data-x="dialog-close-watcher">close watcher</span>'s <span
data-x="close-watcher-enabled">enabled</span> boolean to <var>enabled</var>.</p></li>
</ol>

<hr>

<p>The <dfn attribute for="HTMLDialogElement"><code
data-x="dom-dialog-closedBy">closedBy</code></dfn> IDL attribute must <span>reflect</span> the
<code data-x="attr-dialog-closedby">closedby</code> content attribute, <span>limited to only
known values</span>.</p>

<p>The <dfn attribute for="HTMLDialogElement"><code data-x="dom-dialog-open">open</code></dfn> IDL
attribute must <span>reflect</span> the <code data-x="attr-dialog-open">open</code> content
attribute.</p>
Expand All @@ -61635,7 +61733,110 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
&lt;/dialog></code></pre>
</div>

<h4><dfn>Dialog light dismiss</dfn></h4>

<p class="note">"Light dismiss" means that clicking outside of a dialog whose <code
data-x="attr-dialog-closedby">closedby</code> attribute is in the <span
data-x="attr-closedby-any-state">any</span> state will close the dialog. This is in addition to
how such dialogs respond to <span data-x="close request">close requests</span>.</p>

<p>To <dfn>light dismiss open dialogs</dfn>, given an <code>Event</code> <var>event</var>:</p>

<ol>
<li><p><span>Assert</span>: <var>event</var>'s <code
data-x="dom-Event-isTrusted">isTrusted</code> attribute is true.</p></li>

<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>If <var>document</var>'s <span>showing any dialog list</span> is empty, then
return.</p></li>

<li><p>If <var>event</var> is a <code>PointerEvent</code> and <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 <span>dialog pointerdown target</span> to the result of running
<span>topmost clicked dialog</span> given <var>target</var>.</p></li>

<li>
<p>If <var>event</var> is a <code>PointerEvent</code> and <var>event</var>'s <code
data-x="dom-Event-type">type</code> is "<code data-x="event-pointerup">pointerup</code>",
then:</p>

<ol>
<li><p>Let <var>clickedDialog</var> be the result of running <span>topmost clicked
dialog</span> given <var>target</var>.</p></li>

<li><p>Let <var>topDialog</var> be <var>document</var>'s <span>showing any dialog
list</span>'s last element.</p></li>

<li><p>Let <var>clickedTopDialog</var> be <var>clickedDialog</var> is <var>topDialog</var>, or
<var>clickedDialog</var> is <span>dialog pointerdown target</span></p></li>

<li><p>Set <var>document</var>'s <span>dialog pointerdown target</span> to null.</p></li>

<li><p>If <var>clickedTopDialog</var>, then return.</p></li>

<li><p>Perform <span>close the dialog</span> given <var>topDialog</var>.</p></li>
</ol>
</li>
</ol>

<p class="XXX"><span>Light dismiss open dialogs</span> will be called by the <a
href="https://github.com/w3c/pointerevents">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>:</p>

<ol>
<li><p>Let <var>clickedDialog</var> be the result of running <span>nearest inclusive open
dialog</span> given <var>node</var>.</p></li>

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

<p>To get the <dfn id="any-dialog-list">showing any 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>top layer</span>: if <var>element</var> is a <code
data-x="HTMLDialogElement">dialog element</code>, <var>element</var>'s <code
data-x="attr-dialog-closedby">closedby</code> attribute is in the <span
data-x="attr-closedby-any-state">any state</span> and <var>element</var> has an <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>

<p>To find the <dfn>nearest inclusive open dialog</dfn> given a <code>Node</code>
<var>node</var>, perform the following steps. They return an <span
data-x="HTMLDialogElement">HTML dialog element</span> or null.</p>

<ol>
<li><p>Let <var>currentNode</var> be <var>node</var>.</p></li>

<li>
<p>While <var>currentNode</var> is not null:</p>

<ol>
<li><p>If <var>currentNode</var> is an <span data-x="HTMLDialogElement">HTML dialog
element</span>, <var>currentNode</var>'s <code data-x="attr-dialog-closedby">closedby</code>
attribute is in the <span data-x="attr-closedby-any-state">any</span> state and
<var>currentNode</var> has an <code data-x="attr-dialog-open">open</code> attribute, then
return <var>currentNode</var>.</p></li>

<li><p>Set <var>currentNode</var> to <var>currentNode</var>'s parent in the <span>flat
tree</span>.</p></li>
</ol>
</li>

<li><p>Return null.</p></li>
</ol>


<h3 split-filename="scripting">Scripting</h3>
Expand Down Expand Up @@ -82112,6 +82313,8 @@ body { display:none }

<li><p>An <dfn data-x="close-watcher-is-running-cancel">is running cancel action</dfn>
boolean.</p></li>

<li><p>An <dfn data-x="close-watcher-enabled">enabled</dfn> boolean.</p></li>
</ul>

<p>A <span>close watcher</span> <var>closeWatcher</var> <dfn data-x="close-watcher-active">is
Expand All @@ -82122,8 +82325,10 @@ body { display:none }
<hr>

<p>To <dfn>establish a close watcher</dfn> given a <code>Window</code> <var>window</var>, a list
of steps <dfn data-x="create-close-watcher-cancelAction"><var>cancelAction</var></dfn>, and a
list of steps <dfn data-x="create-close-watcher-closeAction"><var>closeAction</var></dfn>:</p>
of steps <dfn data-x="create-close-watcher-cancelAction"><var>cancelAction</var></dfn>, a
list of steps <dfn data-x="create-close-watcher-closeAction"><var>closeAction</var></dfn>,
and an optional boolean <dfn data-x="create-close-watcher-enabled"><var>enabled</var></dfn>
(default true):</p>

<ol>
<li><p><span>Assert</span>: <var>window</var>'s <span
Expand All @@ -82145,6 +82350,9 @@ body { display:none }

<dt><span data-x="close-watcher-is-running-cancel">is running cancel action</span></dt>
<dd>false</dd>

<dt><span data-x="close-watcher-enabled">enabled</span></dt>
<dd><var>enabled</var></dd>
</dl>
</li>

Expand Down Expand Up @@ -82184,6 +82392,9 @@ body { display:none }
<li><p>If <var>closeWatcher</var> <span data-x="close-watcher-active">is not active</span>, then
return true.</p></li>

<li><p>If <var>closeWatcher</var>'s <span data-x="close-watcher-enabled">enabled</span> is false,
then return true.</p></li>

<li><p>If <var>closeWatcher</var>'s <span data-x="close-watcher-is-running-cancel">is running
cancel action</span> is true, then return true.</p></li>

Expand Down Expand Up @@ -82239,6 +82450,9 @@ body { display:none }
<li><p>If <var>closeWatcher</var> <span data-x="close-watcher-active">is not active</span>, then
return.</p></li>

<li><p>If <var>closeWatcher</var>'s <span data-x="close-watcher-enabled">enabled</span> is false,
then return true.</p></li>

<li><p>If <var>closeWatcher</var>'s <span data-x="close-watcher-window">window</span>'s <span
data-x="concept-document-window">associated <code>Document</code></span> is not <span>fully
active</span>, then return.</p></li>
Expand Down Expand Up @@ -82286,7 +82500,8 @@ body { display:none }
in reverse order:</p>
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 groups not empty check should probably be a check that there's a group with an enabled close watcher in?

And <var>group</var> needs to be the last group with an enabled close watcher in


<ol>
<li><p>Set <var>processedACloseWatcher</var> to true.</p></li>
<li><p>If <var>closeWatcher</var>'s <span data-x="close-watcher-enabled">enabled</span> is
true, set <var>processedACloseWatcher</var> to true.</p></li>

<li><p>Let <var>shouldProceed</var> be the result of <span
data-x="close-watcher-request-close">requesting to close</span>
Expand Down