Skip to content

Commit

Permalink
Relax <select> parser
Browse files Browse the repository at this point in the history
This patch makes the parser allow additional tags in <select> besides
<option>, <optgroup>, and <hr>, mostly by removing the "in select" and
"in select in table" parser modes.

In order to replicate the behavior where opening a <select> tag within
another open <select> tag inserts a </select> close tag, a traversal
through the stack of open elements was added which I borrowed from the
<button> part of the parser.

This will need test changes to be implemented in html5lib.

Fixes whatwg#10310
  • Loading branch information
josepharhar committed Jul 16, 2024
1 parent baeea82 commit 94a5778
Showing 1 changed file with 26 additions and 281 deletions.
307 changes: 26 additions & 281 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -124295,25 +124295,22 @@ dictionary <dfn dictionary>StorageEventInit</dfn> : <span>EventInit</span> {
caption">in caption</span>", "<span data-x="insertion mode: in column group">in column
group</span>", "<span data-x="insertion mode: in table body">in table body</span>", "<span
data-x="insertion mode: in row">in row</span>", "<span data-x="insertion mode: in cell">in
cell</span>", "<span data-x="insertion mode: in select">in select</span>", "<span data-x="insertion
mode: in select in table">in select in table</span>", "<span data-x="insertion mode: in
template">in template</span>", "<span data-x="insertion mode: after body">after body</span>",
"<span data-x="insertion mode: in frameset">in frameset</span>", "<span data-x="insertion mode:
after frameset">after frameset</span>", "<span data-x="insertion mode: after after body">after
after body</span>", and "<span data-x="insertion mode: after after frameset">after after
frameset</span>" during the course of the parsing, as described in the <span>tree
construction</span> stage. The insertion mode affects how tokens are processed and whether CDATA
sections are supported.</p>
cell</span>", "<span data-x="insertion mode: in template">in template</span>", "<span
data-x="insertion mode: after body">after body</span>", "<span data-x="insertion mode: in
frameset">in frameset</span>", "<span data-x="insertion mode: after frameset">after
frameset</span>", "<span data-x="insertion mode: after after body">after after body</span>", and
"<span data-x="insertion mode: after after frameset">after after frameset</span>" during the
course of the parsing, as described in the <span>tree construction</span> stage. The insertion
mode affects how tokens are processed and whether CDATA sections are supported.</p>

<p>Several of these modes, namely "<span data-x="insertion mode: in head">in head</span>", "<span
data-x="insertion mode: in body">in body</span>", "<span data-x="insertion mode: in table">in
table</span>", and "<span data-x="insertion mode: in select">in select</span>", are special, in
that the other modes defer to them at various times. When the algorithm below says that the user
agent is to do something "<dfn>using the rules for</dfn> the <var>m</var> insertion
mode", where <var>m</var> is one of these modes, the user agent must use the rules
described under the <var>m</var> <span>insertion mode</span>'s section, but must leave
the <span>insertion mode</span> unchanged unless the rules in <var>m</var> themselves
switch the <span>insertion mode</span> to a new value.</p>
data-x="insertion mode: in body">in body</span>", and "<span data-x="insertion mode: in table">in
table</span>", are special, in that the other modes defer to them at various times. When the
algorithm below says that the user agent is to do something "<dfn>using the rules for</dfn> the
<var>m</var> insertion mode", where <var>m</var> is one of these modes, the user agent must use
the rules described under the <var>m</var> <span>insertion mode</span>'s section, but must leave
the <span>insertion mode</span> unchanged unless the rules in <var>m</var> themselves switch the
<span>insertion mode</span> to a new value.</p>

<p>When the insertion mode is switched to "<span data-x="insertion mode: text">text</span>" or
"<span data-x="insertion mode: in table text">in table text</span>", the <dfn>original insertion
Expand Down Expand Up @@ -124344,37 +124341,6 @@ dictionary <dfn dictionary>StorageEventInit</dfn> : <span>EventInit</span> {
parsing algorithm</span> (<span>fragment case</span>), set <var>node</var> to the <var
data-x="concept-frag-parse-context">context</var> element passed to that algorithm.</p></li>

<li>
<p>If <var>node</var> is a <code>select</code> element, run these substeps:</p>

<ol>
<li><p>If <var>last</var> is true, jump to the step below labeled
<i>done</i>.</p></li>

<li><p>Let <var>ancestor</var> be <var>node</var>.</p></li>

<li><p><i>Loop</i>: If <var>ancestor</var> is the first node in the <span>stack of
open elements</span>, jump to the step below labeled <i>done</i>.</p></li>

<li><p>Let <var>ancestor</var> be the node before <var>ancestor</var> in the
<span>stack of open elements</span>.</p></li>

<li><p>If <var>ancestor</var> is a <code>template</code> node, jump to the step below
labeled <i>done</i>.</p></li>

<li><p>If <var>ancestor</var> is a <code>table</code> node, switch the <span>insertion
mode</span> to "<span data-x="insertion mode: in select in table">in select in table</span>"
and return.</p></li> <!-- consider
<table><tr><td><select><template></template><caption></table>
https://software.hixie.ch/utilities/js/live-dom-viewer/?saved=2374 -->

<li><p>Jump back to the step labeled <i>loop</i>.</p></li>

<li><p><i>Done</i>: Switch the <span>insertion mode</span> to "<span data-x="insertion mode: in
select">in select</span>" and return.</p></li>
</ol>
</li>

<li><p>If <var>node</var> is a <code>td</code> or <code>th</code> element and <var>last</var> is
false, then switch the <span>insertion mode</span> to "<span data-x="insertion mode: in cell">in
cell</span>" and return.</p></li>
Expand Down Expand Up @@ -129334,19 +129300,23 @@ document.body.appendChild(text);

<dt>A start tag whose tag name is "select"</dt>
<dd>
<p>If the <span>stack of open elements</span> <span data-x="has an element in scope">has a
<code>select</code> element in scope</span>, then run these substeps:</p>

<ol>
<li><p><span>Parse error</span>.</p></li>

<li><p><span>Generate implied end tags</span>.</p></li>

<li><p>Pop elements from the <span>stack of open elements</span> until a <code>select</code>
elementhas been popped from the stack.</p></li>
</ol>

<p><span>Reconstruct the active formatting elements</span>, if any.</p>

<p><span>Insert an HTML element</span> for the token.</p>

<p>Set the <span>frameset-ok flag</span> to "not ok".</p>

<p>If the <span>insertion mode</span> is one of "<span data-x="insertion mode: in table">in
table</span>", "<span data-x="insertion mode: in caption">in caption</span>", "<span
data-x="insertion mode: in table body">in table body</span>", "<span data-x="insertion mode: in
row">in row</span>", or "<span data-x="insertion mode: in cell">in cell</span>", then switch the
<span>insertion mode</span> to "<span data-x="insertion mode: in select in table">in select in
table</span>". Otherwise, switch the <span>insertion mode</span> to "<span data-x="insertion
mode: in select">in select</span>".</p>
</dd>

<dt>A start tag whose tag name is one of: "optgroup", "option"</dt>
Expand Down Expand Up @@ -130480,231 +130450,6 @@ document.body.appendChild(text);
same time, nor can it have neither when the <span>close the cell</span> algorithm is invoked.</p>


<h6 id="parsing-main-inselect">The "<dfn data-x="insertion mode: in select">in select</dfn>" insertion mode</h6>

<p>When the user agent is to apply the rules for the "<span data-x="insertion mode: in select">in
select</span>" <span>insertion mode</span>, the user agent must handle the token as follows:</p>

<dl class="switch">

<dt>A character token that is U+0000 NULL</dt>
<dd>
<p><span>Parse error</span>. Ignore the token.</p>
</dd>

<dt>Any other character token</dt>
<dd>
<p><span data-x="insert a character">Insert the token's character</span>.</p>
</dd>

<dt>A comment token</dt>
<dd>
<p><span>Insert a comment</span>.</p>
</dd>

<dt>A DOCTYPE token</dt>
<dd>
<p><span>Parse error</span>. Ignore the token.</p>
</dd>

<dt>A start tag whose tag name is "html"</dt>
<dd>
<p>Process the token <span>using the rules for</span> the "<span data-x="insertion mode: in
body">in body</span>" <span>insertion mode</span>.</p>
</dd>

<dt>A start tag whose tag name is "option"</dt>
<dd>
<!-- fake </option> (maybe) -->
<p>If the <span>current node</span> is an <code>option</code> element, pop that node from the
<span>stack of open elements</span>.</p>
<!-- end of fake </option> -->

<p><span>Insert an HTML element</span> for the token.</p>
</dd>

<dt>A start tag whose tag name is "optgroup"</dt>
<dd>
<!-- fake </option> (maybe) -->
<p>If the <span>current node</span> is an <code>option</code> element, pop that node from the
<span>stack of open elements</span>.</p>
<!-- end of fake </option> -->

<!-- fake </optgroup> (maybe) -->
<p>If the <span>current node</span> is an <code>optgroup</code> element, pop that node from the
<span>stack of open elements</span>.</p>
<!-- end of fake </optgroup> -->

<p><span>Insert an HTML element</span> for the token.</p>
</dd>

<dt>A start tag whose tag name is "hr"</dt>
<dd>
<!-- fake </option> (maybe) -->
<p>If the <span>current node</span> is an <code>option</code> element, pop that node from the
<span>stack of open elements</span>.</p>
<!-- end of fake </option> -->

<!-- fake </optgroup> (maybe) -->
<p>If the <span>current node</span> is an <code>optgroup</code> element, pop that node from the
<span>stack of open elements</span>.</p>
<!-- end of fake </optgroup> -->

<p><span>Insert an HTML element</span> for the token. Immediately pop the <span>current
node</span> off the <span>stack of open elements</span>.</p>

<p><span data-x="acknowledge self-closing flag">Acknowledge the token's <i data-x="self-closing
flag">self-closing flag</i></span>, if it is set.</p>
</dd>

<dt>An end tag whose tag name is "optgroup"</dt>
<dd>
<!-- fake </option> (maybe) -->
<p>First, if the <span>current node</span> is an <code>option</code> element, and the node
immediately before it in the <span>stack of open elements</span> is an <code>optgroup</code>
element, then pop the <span>current node</span> from the <span>stack of open
elements</span>.</p>
<!-- end of fake </option> -->

<p>If the <span>current node</span> is an <code>optgroup</code> element, then pop that node from
the <span>stack of open elements</span>. Otherwise, this is a <span>parse error</span>; ignore
the token.</p>
</dd>

<dt>An end tag whose tag name is "option"</dt>
<dd>
<p>If the <span>current node</span> is an <code>option</code> element, then pop that node from
the <span>stack of open elements</span>. Otherwise, this is a <span>parse error</span>; ignore
the token.</p>
</dd>

<dt>An end tag whose tag name is "select"</dt>
<dd>
<p>If the <span>stack of open elements</span> does not <span data-x="has an element in select
scope">have a <code>select</code> element in select scope</span>, this is a <span>parse
error</span>; ignore the token. (<span>fragment case</span>)</p>

<p>Otherwise:</p>

<p>Pop elements from the <span>stack of open elements</span> until a <code>select</code> element
has been popped from the stack.</p>

<p><span>Reset the insertion mode appropriately</span>.</p>
</dd>

<dt>A start tag whose tag name is "select"</dt>
<dd>
<p><span>Parse error</span>.</p>

<!-- fake </select> -->
<p>If the <span>stack of open elements</span> does not <span data-x="has an element in select
scope">have a <code>select</code> element in select scope</span>, ignore the token.
(<span>fragment case</span>)</p>

<p>Otherwise:</p>

<p>Pop elements from the <span>stack of open elements</span> until a <code>select</code> element
has been popped from the stack.</p>

<p><span>Reset the insertion mode appropriately</span>.</p>
<!-- end of fake </select> -->

<p class="note">It just gets treated like an end tag.</p>
</dd>

<dt>A start tag whose tag name is one of: "input", "keygen", "textarea"</dt>
<dd>
<p><span>Parse error</span>.</p>

<!-- fake </select> -->
<p>If the <span>stack of open elements</span> does not <span data-x="has an element in select
scope">have a <code>select</code> element in select scope</span>, ignore the token.
(<span>fragment case</span>)</p>

<p>Otherwise:</p>

<p>Pop elements from the <span>stack of open elements</span> until a <code>select</code> element
has been popped from the stack.</p>

<p><span>Reset the insertion mode appropriately</span>.</p>
<!-- end of fake </select> -->

<p>Reprocess the token.</p>
</dd>

<dt>A start tag whose tag name is one of: "script", "template"</dt>
<dt>An end tag whose tag name is "template"</dt>
<dd>
<p>Process the token <span>using the rules for</span> the "<span data-x="insertion mode: in
head">in head</span>" <span>insertion mode</span>.</p>
</dd>

<dt>An end-of-file token</dt>
<dd>
<p>Process the token <span>using the rules for</span> the "<span data-x="insertion mode: in
body">in body</span>" <span>insertion mode</span>.</p>
</dd>

<dt>Anything else</dt>
<dd>
<p><span>Parse error</span>. Ignore the token.</p>
</dd>
</dl>


<h6 id="parsing-main-inselectintable">The "<dfn data-x="insertion mode: in select in table">in select in table</dfn>" insertion mode</h6>

<p>When the user agent is to apply the rules for the "<span data-x="insertion mode: in select in
table">in select in table</span>" <span>insertion mode</span>, the user agent must handle the
token as follows:</p>

<dl class="switch">

<dt>A start tag whose tag name is one of: "caption", "table", "tbody", "tfoot", "thead", "tr",
"td", "th"</dt>
<dd>
<p><span>Parse error</span>.</p>

<!-- fake </select> -->
<p>Pop elements from the <span>stack of open elements</span> until a <code>select</code> element
has been popped from the stack.</p>

<p><span>Reset the insertion mode appropriately</span>.</p>
<!-- end of fake </select> -->

<p>Reprocess the token.</p>
</dd>

<dt>An end tag whose tag name is one of: "caption", "table", "tbody", "tfoot", "thead", "tr",
"td", "th"</dt>
<dd>
<p><span>Parse error</span>.</p>

<p>If the <span>stack of open elements</span> does not <span data-x="has an element in table
scope">have an element in table scope</span> that is an <span data-x="HTML elements">HTML
element</span> with the same tag name as that of the token, then ignore the token.</p>

<p>Otherwise:</p>

<!-- fake </select> -->
<p>Pop elements from the <span>stack of open elements</span> until a <code>select</code> element
has been popped from the stack.</p>

<p><span>Reset the insertion mode appropriately</span>.</p>
<!-- end of fake </select> -->

<p>Reprocess the token.</p>
</dd>

<dt>Anything else</dt>
<dd>
<p>Process the token <span>using the rules for</span> the "<span data-x="insertion mode: in
select">in select</span>" <span>insertion mode</span>.</p>
</dd>
</dl>



<h6 id="parsing-main-intemplate">The "<dfn data-x="insertion mode: in template">in template</dfn>" insertion mode</h6>

<p>When the user agent is to apply the rules for the "<span data-x="insertion mode: in template">in
Expand Down

0 comments on commit 94a5778

Please sign in to comment.