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

Editorial updates to attribute reflection and enumerated attributes #7956

Merged
merged 6 commits into from
Jun 8, 2022
Merged
Changes from 2 commits
Commits
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
208 changes: 152 additions & 56 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -4589,31 +4589,59 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute

<h4>Keywords and enumerated attributes</h4>

<p>Some attributes are defined as taking one of a finite set of keywords. Such attributes are
called <dfn data-x="enumerated attribute">enumerated attributes</dfn>. The keywords are each
defined to map to a particular <em>state</em> (several keywords might map to the same state, in
which case some of the keywords are synonyms of each other; additionally, some of the keywords can
be said to be non-conforming, and are only in the specification for historical reasons). In
addition, two default states can be given. The first is the <dfn><i>invalid value default</i></dfn>, the
second is the <dfn><i>missing value default</i></dfn>.</p>

<p>If an enumerated attribute is specified, the attribute's value must be an <span>ASCII
case-insensitive</span> match for one of the given keywords that are not said to be
non-conforming, with no leading or trailing whitespace.</p>

<p>When the attribute is specified, if its value is an <span>ASCII case-insensitive</span> match
for one of the given keywords then that keyword's state is the state that the attribute
represents. If the attribute value matches none of the given keywords, but the attribute has an
<i data-x="invalid value default">invalid value default</i>, then the attribute represents that
state. Otherwise, there is no default, and invalid values mean that there is no state
represented.</p>

<p>When the attribute is <em>not</em> specified, if there is a <i data-x="missing value default">missing value default</i> state
defined, then that is the state represented by the (missing) attribute. Otherwise, the absence of
the attribute means that there is no state represented.</p>
<p>Some attributes, called <dfn data-x="enumerated attribute">enumerated attributes</dfn>, take
on a finite set of states. The state for such an attribute is derived by combining the
attribute's value, a set of keyword/state mappings given in the specification of each attribute,
and two possible special states that can also be given in the specification of the attribute.
These special states are the <dfn><i>invalid value default</i></dfn> and the <dfn><i>missing
value default</i></dfn>.</p>

<p class="note">Multiple keywords can map to the same state.</p>

<p class="note">The empty string can be a valid keyword.</p>

<p>To determine the state of an attribute, use the following steps:</p>

<ol>
<li>
<p>If the attribute is not specified:</p>

<ol>
<li><p>If the attribute has a <i data-x="missing value default">missing value default</i>
defined, then return that <i data-x="missing value default">missing value
default</i>.</p></li>

<li><p>Otherwise, return no state.</p></li>
</ol>
</li>

<li><p>If the attribute's value is an <span>ASCII case-insensitive</span> match for one of the
keywords defined for the attribute, then return the state represented by that keyword.</p></li>

<li><p>If the attribute has an <i data-x="invalid value default">invalid value default</i>
defined, then return that <i data-x="invalid value default">invalid value default</i>.</p></li>

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

<p>For authoring conformance purposes, if an enumerated attribute is specified, the attribute's
value must be an <span>ASCII case-insensitive</span> match for one of the given keywords that are
not said to be non-conforming, with no leading or trailing whitespace.</p>
domenic marked this conversation as resolved.
Show resolved Hide resolved

<p>For <span data-x="reflect">reflection</span> purposes, states which have any keywords mapping
annevk marked this conversation as resolved.
Show resolved Hide resolved
to them are said to have a <dfn>canonical keyword</dfn>. This is determined as follows:</p>

<ul>
<li><p>If there is only one keyword mapping to the given state, then it is that keyword.</p></li>

<li><p>If there is only one <em>conforming</em> keyword mapping to the given state, then it is
that conforming keyword.</p></li>
domenic marked this conversation as resolved.
Show resolved Hide resolved

<li><p>Otherwise, the canonical keyword for the state will be explicitly given in the
specification for the attribute.</p></li>
</ul>



<h4>Numbers</h4>

Expand Down Expand Up @@ -7425,40 +7453,108 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
if the content attribute's value is the empty string; and on setting, if the content attribute is
not present, it must first be added.</p>

<p>If a reflecting IDL attribute is a <code data-x="idl-USVString">USVString</code> attribute
whose content attribute is defined to contain a <span>URL</span>, then on getting, if the
content attribute is absent, the IDL attribute must return the empty string. Otherwise, the IDL
attribute must <span data-x="parse a url">parse</span> the value of the content attribute relative
to the element's <span>node document</span> and if that is successful, return the <span>resulting
URL string</span>. If parsing fails, then the value of the content attribute must be returned
instead, <span data-x="concept-idl-convert">converted</span> to a <code
data-x="idl-USVString">USVString</code>. On setting, the content attribute must be set to the
specified new value.</p>

<p>If a reflecting IDL attribute is a <code data-x="idl-DOMString">DOMString</code> attribute
whose content attribute is an <span>enumerated attribute</span>, and the IDL attribute is
<dfn>limited to only known values</dfn>, then, on getting, the IDL attribute must return the
keyword value associated with the state the attribute is in, if any, or the empty string if the
attribute is in a state that has no associated keyword value or if the attribute is not in a
defined state (e.g. the attribute is missing and there is no <i data-x="missing value
default">missing value default</i>). If there are multiple keyword values for the state, then
return the conforming one. If there are multiple conforming keyword values, then one will be
designated the <dfn>canonical keyword</dfn>; choose that one. On setting, the content attribute
must be set to the specified new value.</p>

<p>If a reflecting IDL attribute is a nullable <code data-x="idl-DOMString">DOMString</code>
attribute whose content attribute is an <span>enumerated attribute</span>, then, on getting, if
the corresponding content attribute is in its <i>missing value default</i> state then the IDL
attribute must return null, otherwise, the IDL attribute must return the keyword value associated
with the state the attribute is in. If there are multiple keyword values for the state, then
return the conforming one. If there are multiple conforming keyword values, then one will be
designated the <span>canonical keyword</span>; choose that one. On setting, if the new value is
null, the content attribute must be removed, and otherwise, the content attribute must be set to
the specified new value.</p>

<p>If a reflecting IDL attribute is a <code data-x="idl-DOMString">DOMString</code> or <code
data-x="idl-USVString">USVString</code> attribute but doesn't fall into any of the above
categories, then the getting and setting must be done in a transparent, case-preserving manner.</p>
<p>If a reflecting IDL attribute has the type <code data-x="idl-DOMString">DOMString</code>:</p>

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

<ol>
<li>
<p>If the content attribute is an <span>enumerated attribute</span>, and the IDL attribute is
<dfn>limited to only known values</dfn>:</p>

<ol>
<li><p>If the content attribute is not in any state (e.g. the attribute is missing and there
is no <i data-x="missing value default">missing value default</i>), or the content attribute
is in a state with no associated keyword value, then return the empty string.</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.

Use "no state" here for consistency with the other algorithm?

What is a state with no associated keyword value? Is that "no state" due to lack of an invalid value default?

Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we should get rid of the "no state" state, and require invalid value default and missing value default for all enumerated attributes. I think it would make things simpler and less confusing.

Copy link
Member Author

Choose a reason for hiding this comment

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

What is a state with no associated keyword value? Is that "no state" due to lack of an invalid value default?

No, it's something like the inherit state for contenteditable

I wonder if we should get rid of the "no state" state, and require invalid value default and missing value default for all enumerated attributes. I think it would make things simpler and less confusing.

I was thinking of that. It would amount to introducing a lot of individual "default" states for a few attributes. In particular for: dir="", <link as="">, <meta http-equiv="">, formmethod=""/formenctype="", inputmode="", and enterkeyhint="". It's probably a clarity improvement but it's also a good bit of work.

Copy link
Member

Choose a reason for hiding this comment

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

OK. Considering the risk of introducing bugs, maybe it's not worth it, and it's sufficiently clear with this PR?

Copy link
Member

Choose a reason for hiding this comment

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

contenteditable isn't limited to only known values though. I'm not entirely convinced we ever hit this branch looking through the callers, but we could leave it as follow-up.

Copy link
Member Author

Choose a reason for hiding this comment

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

You're right about contenteditable. I think dir="" hits this branch though. It is limited to only known values, and has no invalid value default or missing value default, so if it's just omitted then it will end up in the "not in any state" case, and return the empty string. http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=10361


<li><p>Return the <span>canonical keyword</span> for the state of the content
attribute.</p></li>
</ol>
</li>

<li>
<p>Otherwise:</p>

<ol>
<li><p>Return the content attribute's value.</p></li>
</ol>
</li>
</ol>
</li>

<li><p>The setter steps are to set the content attribute's value to the given value.</p></li>
</ul>

<p>If a reflecting IDL attribute has the type <code data-x=""><span
data-x="idl-DOMString">DOMString</span>?</code>:</p>

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

<ol>
<li><p>Assert: the content attribute is an <span>enumerated attribute</span>.</p></li>
domenic marked this conversation as resolved.
Show resolved Hide resolved

<li><p>Assert: the content attribute is in some state.</p></li>

<li><p>If the content attribute is in its <i data-x="missing value default">missing value
default</i> state, then return null.</p></li>
domenic marked this conversation as resolved.
Show resolved Hide resolved

<li><p>Return the <span>canonical keyword</span> for the state of the content
attribute.</p></li>
</ol>
</li>

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

<ol>
<li><p>If the given value is null, then remove the content attribute.</p></li>

<li><p>Otherwise, set the content attribute's value to the given value.</p></li>
</ol>
</li>
</ul>

<p>If a reflecting IDL attribute has the type <code data-x="idl-DOMString">USVString</code>:</p>

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

<ol>
<li>
<p>If the content attribute is defined to contain a <span>URL</span>:</p>

<ol>
<li><p>If the content attribute is absent, then return the empty string.</p></li>

<li><p><span data-x="parse a url">Parse</span> the value of the content attribute relative
to the element's <span>node document</span>.</p></li>

<li><p>If that is successful, then return the <span>resulting URL string</span>.</p></li>

<li><p>Otherwise, return the value of the content attribute, <span
data-x="concept-idl-convert">converted</span> to a <code
data-x="idl-USVString">USVString</code>.</p></li>
</ol>
</li>

<li>
<p>Otherwise:</p>
domenic marked this conversation as resolved.
Show resolved Hide resolved

<ol>
<li><p>Return the value of the content attribute, <span
data-x="concept-idl-convert">converted</span> to a <code
data-x="idl-USVString">USVString</code>.</p></li>
</ol>
</ol>
</li>

<li><p>The setter steps are to set the content attribute's value to the given value.</p></li>
</ul>

<p>If a reflecting IDL attribute is a <code data-x="idl-boolean">boolean</code> attribute, then on
getting the IDL attribute must return true if the content attribute is set, and false if it is
Expand Down