Skip to content

Commit

Permalink
Apply feedback requests.
Browse files Browse the repository at this point in the history
  • Loading branch information
dmsnell committed Jul 5, 2024
1 parent eb126e8 commit f2e1d03
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 30 deletions.
21 changes: 10 additions & 11 deletions src/wp-includes/html-api/class-wp-html-open-elements.php
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,6 @@ public function current_node_is( string $identity ): bool {
/**
* Returns whether an element is in a specific scope.
*
* ## HTML Support
*
* This function skips checking for the termination list because there
* are no supported elements which appear in the termination list.
*
* @since 6.4.0
*
* @see https://html.spec.whatwg.org/#has-an-element-in-the-specific-scope
Expand Down Expand Up @@ -311,18 +306,22 @@ public function has_element_in_table_scope( $tag_name ) {
/**
* Returns whether a particular element is in select scope.
*
* This test differs from the others like it, in that its rules are inverted.
* Instead of arriving at a match when one of any tag in a termination group
* is reached, this one terminates if any other tag is reached.
*
* > The stack of open elements is said to have a particular element in select scope when it has
* > that element in the specific scope consisting of all element types except the following:
* > - optgroup in the HTML namespace
* > - option in the HTML namespace
*
* @since 6.4.0 Stub implementation (throws).
* @since 6.7.0 Full implementation.
*
* @see https://html.spec.whatwg.org/#has-an-element-in-select-scope
*
* > The stack of open elements is said to have a particular element in select scope when it has
* > that element in the specific scope consisting of all element types except the following:
* > - optgroup in the HTML namespace
* > - option in the HTML namespace
*
* @param string $tag_name Name of tag to check.
* @return bool Whether given element is in scope.
* @return bool Whether the given element is in SELECT scope.
*/
public function has_element_in_select_scope( $tag_name ) {
foreach ( $this->walk_up() as $node ) {
Expand Down
76 changes: 57 additions & 19 deletions src/wp-includes/html-api/class-wp-html-processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -1351,25 +1351,22 @@ private function step_in_body() {
$this->insert_html_element( $this->state->current_token );
$this->state->frameset_ok = false;

/*
* If the insertion mode is one of
* - "in table"
* - "in caption"
* - "in table body"
* - "in row"
* - "in cell"
* then switch the insertion mode to "in select in table"
*
* Otherwise, switch the insertion mode to "in select".
*/
switch ( $this->state->insertion_mode ) {
/*
* > If the insertion mode is one of "in table", "in caption", "in table body", "in row",
* > or "in cell", then switch the insertion mode to "in select in table".
*/
case WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE:
case WP_HTML_Processor_State::INSERTION_MODE_IN_CAPTION:
case WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE_BODY:
case WP_HTML_Processor_State::INSERTION_MODE_IN_ROW:
case WP_HTML_Processor_State::INSERTION_MODE_IN_CELL:
$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_SELECT_IN_TABLE;
break;

/*
* > Otherwise, switch the insertion mode to "in select".
*/
default:
$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_SELECT;
break;
Expand Down Expand Up @@ -1496,13 +1493,13 @@ private function step_in_body() {
}
}

/*
/**
* Parses next element in the 'in head' insertion mode.
*
* This internal function performs the 'in head' insertion mode
* logic for the generalized WP_HTML_Processor::step() function.
*
* @since 6.7.0
* @since 6.7.0 Stub implementation.
*
* @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input.
*
Expand Down Expand Up @@ -1542,6 +1539,23 @@ private function step_in_select() {
* > Any other character token
*/
case '#text':
$current_token = $this->bookmarks[ $this->state->current_token->bookmark_name ];

/*
* > A character token that is U+0000 NULL
*
* If a text node only comprises null bytes then it should be
* entirely ignored and should not return to calling code.
*/
if (
1 <= $current_token->length &&
"\x00" === $this->html[ $current_token->start ] &&
strspn( $this->html, "\x00", $current_token->start, $current_token->length ) === $current_token->length
) {
// Parse error: ignore the token.
return $this->step();
}

$this->insert_html_element( $this->state->current_token );
return true;

Expand All @@ -1558,7 +1572,7 @@ private function step_in_select() {
* > A DOCTYPE token
*/
case 'html':
// Parse error. Ignore the token.
// Parse error: ignore the token.
return $this->step();

/*
Expand Down Expand Up @@ -1615,6 +1629,7 @@ private function step_in_select() {
$this->state->stack_of_open_elements->pop();
return true;
}

// Parse error: ignore the token.
return $this->step();

Expand All @@ -1626,31 +1641,36 @@ private function step_in_select() {
$this->state->stack_of_open_elements->pop();
return true;
}

// Parse error: ignore the token.
return $this->step();

/*
* > An end tag whose tag name is "select"
* > A start tag whose tag name is "select"
*
* > It just gets treated like an end tag.
*/
case '-SELECT':
case '+SELECT':
if ( ! $this->state->stack_of_open_elements->has_element_in_select_scope( 'SELECT' ) ) {
// Parse error: ignore the token.
return $this->step();
}
$this->state->stack_of_open_elements->pop_until( 'SELECT' );
$this->state->stack_of_open_elements->pop();
$this->reset_insertion_mode();
return true;

/*
* > A start tag whose tag name is one of: "input", "keygen", "textarea"
*
* All three of these tags are considered a parse error when found in this insertion mode.
*/
case '+INPUT':
case '+KEYGEN':
case '+TEXTAREA':
// Parse error.
if ( ! $this->state->stack_of_open_elements->has_element_in_select_scope( 'SELECT' ) ) {
// Ignore the token.
return $this->step();
}
$this->state->stack_of_open_elements->pop_until( 'SELECT' );
Expand Down Expand Up @@ -2262,7 +2282,7 @@ private function close_a_p_element() {
* Closes elements that have implied end tags.
*
* @since 6.4.0
* @since 6.7.0 Support "option" and "optgroup".
* @since 6.7.0 Full spec support.
*
* @see https://html.spec.whatwg.org/#generate-implied-end-tags
*
Expand All @@ -2276,11 +2296,16 @@ private function generate_implied_end_tags( $except_for_this_element = null ) {
'OPTGROUP',
'OPTION',
'P',
'RB',
'RP',
'RT',
'RTC',
);

$current_node = $this->state->stack_of_open_elements->current_node();
$no_exclusions = ! isset( $except_for_this_element );

while (
$current_node && $current_node->node_name !== $except_for_this_element &&
( $no_exclusions || ! $this->state->stack_of_open_elements->current_node_is( $except_for_this_element ) ) &&
in_array( $this->state->stack_of_open_elements->current_node(), $elements_with_implied_end_tags, true )
) {
$this->state->stack_of_open_elements->pop();
Expand All @@ -2294,18 +2319,31 @@ private function generate_implied_end_tags( $except_for_this_element = null ) {
* different from generating end tags in the normal sense.
*
* @since 6.4.0
* @since 6.7.0 Full spec support.
*
* @see WP_HTML_Processor::generate_implied_end_tags
* @see https://html.spec.whatwg.org/#generate-implied-end-tags
*/
private function generate_implied_end_tags_thoroughly() {
$elements_with_implied_end_tags = array(
'CAPTION',
'COLGROUP',
'DD',
'DT',
'LI',
'OPTGROUP',
'OPTION',
'P',
'RB',
'RP',
'RT',
'RTC',
'TBODY',
'TD',
'TFOOT',
'TH',
'THEAD',
'TR',
);

while ( in_array( $this->state->stack_of_open_elements->current_node(), $elements_with_implied_end_tags, true ) ) {
Expand Down

0 comments on commit f2e1d03

Please sign in to comment.