Skip to content

Commit

Permalink
Add reflection for ID-referencing attributes
Browse files Browse the repository at this point in the history
This is notably planned to be used by the ARIA specification.

Co-authored-by: Alice Boxhall <[email protected]>

Closes #3917 by superseding it.
  • Loading branch information
mrego authored Jun 10, 2022
1 parent b154c38 commit c3d7391
Showing 1 changed file with 304 additions and 2 deletions.
306 changes: 304 additions & 2 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -2725,6 +2725,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
<li><dfn data-x-href="https://webidl.spec.whatwg.org/#include">include</dfn></li>
<li><dfn data-x-href="https://webidl.spec.whatwg.org/#dfn-inherit">inherit</dfn></li>
<li><dfn data-x-href="https://webidl.spec.whatwg.org/#dfn-interface-prototype-object">interface prototype object</dfn></li>
<li><dfn data-x-href="https://webidl.spec.whatwg.org/#implements">implements</dfn></li>
<li><dfn data-x-href="https://webidl.spec.whatwg.org/#es-platform-objects">[[Realm]] field of a platform object</dfn></li>
<li><dfn data-x-href="https://webidl.spec.whatwg.org/#dfn-callback-context">callback context</dfn></li>
<li><dfn data-x-href="https://webidl.spec.whatwg.org/#dfn-frozen-array-type">frozen array</dfn> and
Expand Down Expand Up @@ -3059,6 +3060,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
<li>The <dfn data-x-href="https://dom.spec.whatwg.org/#concept-tree-root">root</dfn> and <dfn data-x-href="https://dom.spec.whatwg.org/#concept-shadow-including-root">shadow-including root</dfn> concepts</li>
<li>The <dfn data-x-href="https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor">inclusive ancestor</dfn>,
<dfn data-x-href="https://dom.spec.whatwg.org/#concept-tree-descendant">descendant</dfn>,
<dfn data-x="concept-shadow-including-ancestor" data-x-href="https://dom.spec.whatwg.org/#concept-shadow-including-ancestor">shadow-including ancestor</dfn>,
<dfn data-x-href="https://dom.spec.whatwg.org/#concept-shadow-including-descendant">shadow-including descendant</dfn>,
<dfn data-x-href="https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-descendant">shadow-including inclusive descendant</dfn>, and
<dfn data-x-href="https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor">shadow-including inclusive ancestor</dfn> concepts</li>
Expand Down Expand Up @@ -7682,8 +7684,308 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
return a <code>DOMTokenList</code> object whose associated element is the element in question and
whose associated attribute's local name is the name of the attribute in question.</p>

</div>
<p>If a reflecting IDL attribute <var>attr</var> has the type <code
data-x=""><var>T</var>?</code>, where <var>T</var> is either <code>Element</code> or an
interface that inherits from <code>Element</code>, then:

<ul>
<li><p>Elements of the type this IDL attribute appears on have an <dfn>explicitly set
<var>attr</var>-element</dfn>, which is a weak reference to an element or null. It is initially
null.</p></li>

<li>
<p>Elements of the type this IDL attribute appears on have an <dfn for="Element"
export><var>attr</var>-associated element</dfn>. To compute the <span><var>attr</var>-associated
element</span> for such an element <var>element</var>:</p>

<ol>
<li>
<p>If <var>element</var>'s <span>explicitly set <var>attr</var>-element</span> is not null:</p>
<ul>
<li><p>If <var>element</var>'s <span>explicitly set <var>attr</var>-element</span> is a
<span>descendant</span> of any of <var>element</var>'s <span
data-x="concept-shadow-including-ancestor">shadow-including ancestors</span>, then return
<var>element</var>'s <span>explicitly set <var>attr</var>-element</span>.</p></li>
<li><p>Otherwise, return null.</p></li>
</ul>
</li>

<li>
<p>Otherwise, if the content attribute is present on <var>element</var>, then return the first
element <var>candidate</var>, in <span>tree order</span>, that meets the following
criteria:</p>

<ul class="brief">
<li><var>candidate</var>'s <span>root</span> is the same as <var>element</var>'s
<span>root</span>,</li>
<li><var>candidate</var>'s <span data-x="concept-ID">ID</span> is the value of the content
attribute, and</li>
<li><var>candidate</var> <span>implements</span> <var>T</var>.</li>
</ul>

<p>If no such element exists, then return null.</p>
</li>

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

<p class="note">Other parts of this specification, or other specifications using attribute
reflection, are expected to consult an element's <span><var>attr</var>-associated
element</span>. An element's <span>explicitly set <var>attr</var>-element</span> is an internal
implementation detail of its <span><var>attr</var>-associated element</span> and is not to be
used directly.</p>
</li>

<li><p>The getter steps are to return <span>this</span>'s <span><var>attr</var>-associated
element</span>.</p></li>

<li>
<p>The setter steps are:</p>
<ol>
<li>
<p>If the given value is null, then:</p>

<ol>
<li><p>Set <span>this</span>'s <span>explicitly set <var>attr</var>-element</span> to
null.</p></li>

<li><p>Remove the content attribute from <span>this</span>.</p></li>

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

<li><p>Let <var>id</var> be the empty string.</p></li>

<li>
<p>If the given value:</p>

<ul class="brief">
<li>has the same <span>root</span> as <span>this</span>, and</li>
<li>has an <code data-x="attr-id">id</code> attribute, and</li>
<li>is the first element in <span>this</span>'s <span>node tree</span> whose <span
data-x="concept-ID">ID</span> is the value of that <code data-x="attr-id">id</code>
attribute,</li>
</ul>

<p>then set <var>id</var> to the given value's <span data-x="concept-ID">ID</span>.</p>
</li>

<li><p>Set the content attribute's value for <span>this</span> to <var>id</var>.</p></li>

<li><p>Set <span>this</span>'s <span>explicitly set <var>attr</var>-element</span> to a weak
reference to the given value.</p></li>
</ol>
</li>

<li>
<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 to synchronize between the content
attribute and the IDL attribute:</p>
<ol>
<li><p>If <var>localName</var> is not the content attribute's local name, or
<var>namespace</var> is not null, then return.</p></li>

<li><p>Set <var>element</var>'s <span>explicitly set <var>attr</var>-element</span> to
null.</p></li>
</ol>
</li>
</ul>

<p>If a reflecting IDL attribute <var>attr</var> has the type <code
data-x="">FrozenArray&lt;<var>T</var>&gt;?</code>, where <var>T</var> is either
<code>Element</code> or an interface that inherits from <code>Element</code>, then:</p>

<ul>
<li><p>Elements of the type this IDL attribute appears on have <dfn>explicitly set
<var>attr</var>-elements</dfn>, which is either a <span>list</span> of weak references to elements
or null. It is initially null.</p></li>

<li><p>Elements of the type this IDL attribute appears on have <dfn>cached
<var>attr</var>-associated elements</dfn>, which is a <code
data-x="">FrozenArray&lt;<var>T</var>&gt;?</code>. It is initially null.</p></li>

<li>
<p>Elements of the type this IDL attribute appears on have <dfn for="Element"
export><var>attr</var>-associated elements</dfn>. To compute the <span><var>attr</var>-associated
elements</span> for such an element <var>element</var>:</p>

<ol>
<li><p>Let <var>elements</var> be an empty <span>list</span>.</p></li>

<li>
<p>If <var>element</var>'s <span>explicitly set <var>attr</var>-elements</span> is not
null, then:</p>

<ol>
<li>
<p><span data-x="list iterate">For each</span> <var>attrElement</var> in the <var>element</var>'s
<span>explicitly set <var>attr</var>-elements</span>:</p>

<ol>
<li><p>If <var>attrElement</var> is not a <span>descendant</span> of any of <var>element</var>'s <span
data-x="concept-shadow-including-ancestor">shadow-including ancestors</span>, then
<span>continue</span>.</p></li>

<li><p><span data-x="list append">Append</span> <var>attrElement</var> to <var>elements</var>.</p></li>
</ol>
</li>
</ol>
</li>

<li>
<p>Otherwise:</p>
<ol>
<li><p>If the content attribute is not present on <var>element</var>, return null.</p></li>

<li><p>Let <var>tokens</var> be the content attribute's value, <span data-x="split a string on
ASCII whitespace">split on ASCII whitespace</span>.

<li>
<p><span data-x="list iterate">For each</span> <var>id</var> in <var>tokens</var>:</p>
<ol>
<li>
<p>Let <var>candidate</var> be the first element, in <span>tree order</span>, that meets the
following criteria:</p>

<ul class="brief">
<li><var>candidate</var>'s <span>root</span> is the same as <var>element</var>'s
<span>root</span>,</li>
<li><var>candidate</var>'s <span data-x="concept-ID">ID</span> is <var>id</var>, and</li>
<li><var>candidate</var> <span>implements</span> <var>T</var>.</li>
</ul>

<p>If no such element exists, then <span>continue</span>.</p>
</li>

<li><p><span data-x="list append">Append</span> <var>candidate</var> to
<var>elements</var>.</p></li>
</ol>
</li>
</ol>
</li>

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

<p class="note">Other parts of this specification, or other specifications using attribute
reflection, are expected to consult an element's <span><var>attr</var>-associated
elements</span>. An element's <span>explicitly set <var>attr</var>-elements</span> is an internal
implementation detail of its <span><var>attr</var>-associated elements</span> and is not to be
used directly. Similarly, the element's <span>cached <var>attr</var>-associated elements</span>
is an internal implementation detail of the IDL attribute's getter.</p>
</li>

<li>
<p>The getter steps are:</p>

<ol>
<li><p>Let <var>elements</var> be <span>this</span>'s <span><var>attr</var>-associated
elements</span>.</p></li>

<li><p>If the contents of <var>elements</var> is equal to the contents of <span>this</span>'s
<span>cached <var>attr</var>-associated elements</span>, then return <span>this</span>'s
<span>cached <var>attr</var>-associated elements</span>.</p></li>

<li><p>Let <var>elementsAsFrozenArray</var> be <var>elements</var>, <span
data-x="concept-idl-convert">converted</span> to a <code
data-x="">FrozenArray&lt;<var>T</var>&gt;?</code>.</p></li>

<li><p>Set <span>this</span>'s <span>cached <var>attr</var>-associated elements</span> to
<var>elementsAsFrozenArray</var>.</p></li>

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

<p class="note">This extra caching layer is necessary to preserve the invariant that <code
data-x="">element.reflectedElements === element.reflectedElements</code>.</p>
</li>

<li>
<p>The setter steps are:</p>
<ol>
<li>
<p>If the given value is null:</p>

<ol>
<li><p>Set <span>this</span>'s <span>explicitly set <var>attr</var>-elements</span> to
null.</p></li>

<li><p>Remove the content attribute from <span>this</span>.</p></li>

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

<li><p>Let <var>value</var> be an empty string.</p></li>

<li>
<p><span data-x="list iterate">For each</span> <var>element</var> in the given value:</p>

<ol>
<li>
<p>If <var>value</var> is empty and <var>elements</var> is non-empty, then:</p>

<ol>
<li><p><span data-x="list append">Append</span> a weak reference to <var>element</var>
to <var>elements</var>.</p></li>

<li><p><span>Continue</span>.</p></li>
</ol>
</li>

<li><p><span data-x="list append">Append</span> a weak reference to <var>element</var> to
<var>elements</var>.</p></li>

<li>
<p>If <var>element</var>:</p>

<ul class="brief">
<li>does not have the same <span>root</span> as <span>this</span>, or</li>
<li>has no <code data-x="attr-id">id</code> attribute, or</li>
<li>is not the first element in <span>this</span>'s <span>node tree</span> whose <span
data-x="concept-ID">ID</span> is the value of that <code data-x="attr-id">id</code>
attribute,</li>
</ul>

<p>then set <var>value</var> to the empty string, and <span>continue</span>.</p>
</li>

<li><p>Let <var>id</var> be <var>element</var>'s <span
data-x="concept-ID">ID</span>.</p></li>

<li><p>If <var>value</var> is not the empty string, then append U+0020 SPACE to
<var>value</var>.</p></li>

<li><p>Append <var>id</var> to <var>value</var>.</p></li>
</ol>
</li>

<li><p>Set the content attribute's value for <span>this</span> to <var>value</var>.</p></li>

<li><p>Set <span>this</span>'s <span>explicitly set <var>attr</var>-elements</span> to
<var>elements</var>.</p></li>
</ol>
</li>

<li>
<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 to synchronize between the content
attribute and the IDL attribute:</p>

<ol>
<li><p>If <var>localName</var> is not the content attribute's local name, or
<var>namespace</var> is not null, then return.</p></li>

<li><p>Set <var>element</var>'s <span>explicitly set <var>attr</var>-elements</span> to
null.</p></li>
</ol>
</li>
</ul>

</div>

<h4>Collections</h4>

Expand Down Expand Up @@ -62472,7 +62774,7 @@ callback <dfn callback>BlobCallback</dfn> = undefined (<span>Blob</span>? blob);
<code>canvas</code> element.</p></li>

<li><p>Set the <span data-x="offscreencanvas-placeholder">placeholder <code>canvas</code>
element</span> of <var>offscreenCanvas</var> to be a weak reference to this <code>canvas</code>
element</span> of <var>offscreenCanvas</var> to a weak reference to this <code>canvas</code>
element.</p></li>

<li><p>Set this <code>canvas</code> element's <span data-x="concept-canvas-context-mode">context
Expand Down

0 comments on commit c3d7391

Please sign in to comment.