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 declarative Shadow DOM features #858

Closed
wants to merge 13 commits into from
114 changes: 85 additions & 29 deletions dom.bs
Original file line number Diff line number Diff line change
Expand Up @@ -4232,8 +4232,8 @@ elements. SVG ought to do the same for its <{script}> elements, but does not cal
at the moment.

<p>To <dfn export id=concept-node-clone lt="clone a node" local-lt="clone">clone</dfn> a
<var>node</var>, with an optional <var>document</var> and <i>clone children flag</i>, run these
steps:
<var>node</var>, with an optional <var>document</var>, <i>clone children flag</i>, and
<i>clone shadows flag</i>, run these steps:
<!-- This algorithm is used by dom-Node-cloneNode, dom-Document-importNode,
dom-Range-extractContents, dom-Range-cloneContents -->

Expand Down Expand Up @@ -4307,6 +4307,22 @@ dom-Range-extractContents, dom-Range-cloneContents -->
<a>children</a> of <var>node</var> and append them to <var>copy</var>, with
<var>document</var> as specified and the <i>clone children flag</i> being set.

<li>If <var>node</var> is a <a for=Element>shadow host</a> and the <i>clone shadows flag</i> is set, run these steps:

<ol>
<li><p>Run <a>attach a shadow root</a> with <var>shadow host</var> equal to <var>copy</var>,
<var>mode</var> equal to <var>node</var>'s <a for=/>shadow root</a>'s <a for=ShadowRoot>mode</a>, and <var>delegates focus</var>
equal to <var>node</var>'s <a for=/>shadow root</a>'s <a>delegates focus</a>.</p></li>

<li><p>If <var>node</var>'s <a for=/>shadow root</a>'s <a for=ShadowRoot>is declarative shadow root</a> is true, then
set <var>copy</var>'s <a for=/>shadow root</a>'s <a for=ShadowRoot>is declarative shadow root</a> property to true.</p></li>

<li>If the <i>clone children flag</i> is set, <a lt="clone a node">clone</a> all the
<a>children</a> of <var>node</var>'s <a for=/>shadow root</a> and append them to <var>copy</var>'s <a for=/>shadow root</a>, with
<var>document</var> as specified, the <i>clone children flag</i> being set, and the <i>clone shadows flag</i> being set.

</ol>

<li>Return <var>copy</var>.
</ol>

Expand All @@ -4318,7 +4334,10 @@ invoked, must run these steps:
"{{NotSupportedError!!exception}}" {{DOMException}}.

<li><p>Return a <a lt="clone a node">clone</a> of <a>this</a>, with the
<i>clone children flag</i> set if <var>deep</var> is true.
<i>clone children flag</i> set if <var>deep</var> is true, and the
<i>clone shadows flag</i> set if <a>this</a> is a {{DocumentFragment}} whose
<a for=DocumentFragment>host</a> is an HTML <{template}> element.

</ol>

A <a>node</a> <var>A</var>
Expand Down Expand Up @@ -5727,6 +5746,9 @@ or "<code>closed</code>").</p>
<p><a for=/>Shadow roots</a> have an associated <dfn export for=ShadowRoot>delegates focus</dfn>.
It is initially set to false.</p>

<p><a for=/>Shadow roots</a> have an associated <dfn export for=ShadowRoot>is declarative shadow root</dfn>.
It is initially set to false.</p>

<p><a for=/>Shadow roots</a>'s associated <a for=DocumentFragment>host</a> is never null.</p>
<!-- If we ever change this, e.g., add a ShadowRoot object constructor, that would have serious
consequences for innerHTML. -->
Expand Down Expand Up @@ -5864,6 +5886,8 @@ interface Element : Node {
HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
HTMLCollection getElementsByClassName(DOMString classNames);

DOMString getInnerHTML(GetInnerHTMLOptions options);

[CEReactions] Element? insertAdjacentElement(DOMString where, Element element); // historical
void insertAdjacentText(DOMString where, DOMString data); // historical
};
Expand All @@ -5872,6 +5896,11 @@ dictionary ShadowRootInit {
required ShadowRootMode mode;
boolean delegatesFocus = false;
};

dictionary GetInnerHTMLOptions {
boolean includeShadowRoots = true;
Copy link
Member

Choose a reason for hiding this comment

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

At the very least this should say OpenShadowRoots, but it seems better to me if we did not have a separate API here for open and closed.

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've added the "rest" of this interface, as explained here in the explainer. In particular, the section just below that, Closed shadow roots goes into the details of the interface. You essentially get two knobs. includeShadowRoots is an opt-in for any shadow roots to be serialized. The second input, closedRoots is a list of closed shadow roots that you would like to be included. If a closed shadow root is encountered that is not in the list, it will be skipped to preserve encapsulation.

I am going to add the corresponding change to my HTML spec PR.

LMK if the above clarifies the situation, or if you have further questions.

sequence&lt;ShadowRoot> closedRoots;
};
</pre>

<p>{{Element}} <a for=/>nodes</a> are simply known as
Expand Down Expand Up @@ -6694,11 +6723,35 @@ when invoked, must run these steps:
invoked, must run these steps:

<ol>
<li><p>If <a>this</a>'s <a for=Element>namespace</a> is not the <a>HTML namespace</a>,

<li><p>Run <a>attach a shadow root</a> with <var>shadow host</var> equal to <a>this</a>,
<var>mode</var> equal to <var>init</var>'s {{ShadowRootInit/mode}}, and <var>delegates focus</var>
equal to <var>init</var>'s {{ShadowRootInit/delegatesFocus}}.</p></li>

<li><p>Return <a>this</a>'s <a for=Element>shadow root</a>.</p></li>

</ol>

<p>The <dfn attribute for=Element><code>shadowRoot</code></dfn> attribute's getter must run these
steps:

<ol>
<li><p>Let <var>shadow</var> be <a>this</a>'s <a for=Element>shadow root</a>.

<li><p>If <var>shadow</var> is null or its <a for=ShadowRoot>mode</a> is "<code>closed</code>",
then return null.</p></li>

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

<p>To <dfn id=concept-attach-a-shadow-root>attach a shadow root</dfn>, given a
<var>shadow host</var>, <var>mode</var>, and <var>delegates focus</var>, run these steps:</p>

<ol>
<li><p>If <var>shadow host</var>'s <a for=Element>namespace</a> is <em>not</em> the <a>HTML namespace</a>,
then <a>throw</a> a "{{NotSupportedError!!exception}}" {{DOMException}}.

<li>
<p>If <a>this</a>'s <a for=Element>local name</a> is not one of the following:
<li><p>If <var>shadow host</var>'s <a for=Element>local name</a> is <em>not</em> a

<ul class=brief>
<li>a <a>valid custom element name</a>
Expand Down Expand Up @@ -6726,13 +6779,13 @@ invoked, must run these steps:
</li>

<li>
<p>If <a>this</a>'s <a for=Element>local name</a> is a <a>valid custom element name</a>, or
<a>this</a>'s <a for=Element><code>is</code> value</a> is not null, then:
<p>If <var>shadow host</var>'s <a for=Element>local name</a> is a <a>valid custom element name</a>, or
<var>shadow host</var>'s <a for=Element><code>is</code> value</a> is not null, then:

<ol>
<li><p>Let <var>definition</var> be the result of
<a lt="look up a custom element definition">looking up a custom element definition</a> given
<a>this</a>'s <a for=Node>node document</a>, its <a for=Element>namespace</a>, its
<var>shadow host</var>'s <a for=Node>node document</a>, its <a for=Element>namespace</a>, its
<a for=Element>local name</a>, and its <a for=Element><code>is</code> value</a>.

<li><p>If <var>definition</var> is not null and <var>definition</var>'s
Expand All @@ -6741,31 +6794,27 @@ invoked, must run these steps:
</ol>
</li>

<li><p>If <a>this</a> is a <a for=Element>shadow host</a>, then <a>throw</a> an
"{{NotSupportedError!!exception}}" {{DOMException}}.

<li><p>Let <var>shadow</var> be a new <a for=/>shadow root</a> whose <a for=Node>node document</a>
is <a>this</a>'s <a for=Node>node document</a>, <a for=DocumentFragment>host</a> is <a>this</a>,
and <a for=ShadowRoot>mode</a> is <var>init</var>'s {{ShadowRootInit/mode}}.

<li><p>Set <var>shadow</var>'s <a for=ShadowRoot>delegates focus</a> to <var>init</var>'s
{{ShadowRootInit/delegatesFocus}}.
<li><p>If <var>shadow host</var> has a non-null <a for=/>shadow root</a>, then:
<ol>
<li><p>If <var>shadow host</var>'s <a for=/>shadow root</a>'s <a for=ShadowRoot>is declarative
shadow root</a> property is false, then <a>throw</a> an "{{NotSupportedError!!exception}}" {{DOMException}}.

<li><p>Set <a>this</a>'s <a for=Element>shadow root</a> to <var>shadow</var>.
<li><p>Otherwise, <a for=/>remove</a> all of <a for=/>shadow root</a>'s <a>children</a>, in
<a>tree order</a>. Return <var>shadow host</var>'s <a for=/>shadow root</a>.

<li><p>Return <var>shadow</var>.
</ol>
<p class="note">This means that if multiple declarative shadow roots are contained within a single shadow host,
only the last one will remain.
</ol>

<p>The <dfn attribute for=Element><code>shadowRoot</code></dfn> attribute's getter must run these
steps:
<li><p>Let <var>shadow</var> be a new <a for=/>shadow root</a> whose <a for=Node>node document</a>
is <var>shadow host</var>'s <a for=Node>node document</a>, <a for=DocumentFragment>host</a> is <var>shadow host</var>,
and <a for=ShadowRoot>mode</a> is <var>mode</var>.

<ol>
<li><p>Let <var>shadow</var> be <a>this</a>'s <a for=Element>shadow root</a>.
<li><p>Set <var>shadow</var>'s <a for=ShadowRoot>delegates focus</a> to <var>delegates focus</var>.

<li><p>If <var>shadow</var> is null or its <a for=ShadowRoot>mode</a> is "<code>closed</code>",
then return null.</p></li>
<li><p>Set <var>shadow</var>'s <a for=ShadowRoot>is declarative shadow root</a> property to false.

<li><p>Return <var>shadow</var>.
<li><p>Set <var>shadow host</var>'s <a for=Element>shadow root</a> to <var>shadow</var>.
</ol>

<hr>
Expand Down Expand Up @@ -6875,9 +6924,15 @@ for <a>this</a>.
<dd><p><a>Throw</a> a "{{SyntaxError!!exception}}" {{DOMException}}.
</dl>

<p>The
<dfn method for=Element><code>getInnerHTML(<var>options</var>)</code></dfn>
method, when invoked, must return the result of running <a>HTML fragment serialization algorithm</a>,
given <a>this</a> as <var>node</var>, <i>options.includeShadowRoots</i> as <i>include shadow roots</i>,
and <i>options.closedRoots</i> as <i>closed shadow roots</i>.

<p>The
<dfn method for=Element><code>insertAdjacentElement(<var>where</var>, <var>element</var>)</code></dfn>
method, when invoked, must return the result of running <a>insert adjacent</a>, give <a>this</a>,
method, when invoked, must return the result of running <a>insert adjacent</a>, given <a>this</a>,
<var>where</var>, and <var>element</var>.

<p>The
Expand Down Expand Up @@ -10133,6 +10188,7 @@ Manish Tripathi,
Marcos Caceres,
Mark Miller,
Martijn van der Ven,
Mason Freed, <!-- mfreed7 on GitHub -->
Mats Palmgren,
Mounir Lamouri,
Michael Stramel,
Expand Down