Skip to content

Commit

Permalink
In table body rules
Browse files Browse the repository at this point in the history
  • Loading branch information
sirreal committed Feb 5, 2024
1 parent 701001c commit 2f55c91
Showing 1 changed file with 137 additions and 3 deletions.
140 changes: 137 additions & 3 deletions src/wp-includes/html-api/class-wp-html-processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,12 @@ public function step( $node_to_process = self::PROCESS_NEXT_NODE ) {
case WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE:
return $this->step_in_table();

case WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE_BODY:
return $this->step_in_table_body();

default:
echo "\n MODE: " . $this->state->insertion_mode . "\n";

$this->last_error = self::ERROR_UNSUPPORTED;
throw new WP_HTML_Unsupported_Exception( "No support for parsing in the '{$this->state->insertion_mode}' state." );
}
Expand Down Expand Up @@ -1495,9 +1500,111 @@ private function step_in_table() {
$this->last_error = self::ERROR_UNSUPPORTED;
throw new WP_HTML_Unsupported_Exception( "Cannot process {$tag_name} element." );
}
}

$this->last_error = self::ERROR_UNSUPPORTED;
throw new WP_HTML_Unsupported_Exception( "Cannot process {$tag_name} element." );
/**
* Parses next element in the 'in table body' insertion mode.
*
* This internal function performs the 'in table body' insertion mode
* logic for the generalized WP_HTML_Processor::step() function.
*
* @since 6.5.0
*
* @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input.
*
* @see https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-intbody
* @see WP_HTML_Processor::step
*
* @return bool Whether an element was found.
*/
private function step_in_table_body() {
$tag_name = $this->get_tag();
$op_sigil = $this->is_tag_closer() ? '-' : '+';
$op = "{$op_sigil}{$tag_name}";

switch ( $op ) {
/*
* > A start tag whose tag name is "tr"
*/
case '+TR':
$this->clear_stack_to_table_body_context();
$this->insert_html_element( $this->state->current_token );
$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_ROW;
return true;

/*
* > A start tag whose tag name is one of: "th", "td"
*/
case '+TH':
case '+TD':
// parse error
$this->clear_stack_to_table_body_context();
$this->insert_html_element(
new WP_HTML_Token( null, 'TR', false )
);
$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_ROW;
return $this->step( self::REPROCESS_CURRENT_NODE );

/*
* > An end tag whose tag name is one of: "tbody", "tfoot", "thead"
*/
case '-TBODY':
case '-TFOOT':
case '-THEAD':
if (
! $this->state->stack_of_open_elements->has_element_in_table_scope( $tag_name )
) {
// parse error
return $this->step();
}
$this->state->stack_of_open_elements->pop();
$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE;
return true;

/*
* > A start tag whose tag name is one of: "caption", "col", "colgroup", "tbody", "tfoot", "thead"
* > An end tag whose tag name is "table"
*/
case '+CAPTION':
case '+COL':
case '+COLGROUP':
case '+TBODY':
case '+TFOOT':
case '+THEAD':
case '-TABLE':
if (
! $this->state->stack_of_open_elements->has_element_in_table_scope( 'TBODY' ) &&
! $this->state->stack_of_open_elements->has_element_in_table_scope( 'THEAD' ) &&
! $this->state->stack_of_open_elements->has_element_in_table_scope( 'TFOOT' )
) {
// parse error
return $this->step();
}
$this->clear_stack_to_table_body_context();
$this->state->stack_of_open_elements->pop();
$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE;
return $this->step( self::REPROCESS_CURRENT_NODE );

/*
* > An end tag whose tag name is one of: "body", "caption", "col", "colgroup", "html", "td", "th", "tr"
*/
case '-BODY':
case '-CAPTION':
case '-COL':
case '-COLGROUP':
case '-HTML':
case '-TD':
case '-TH':
case '-TR':
// parse error
return $this->step();
}

/*
* > Anything else
* > Process the token using the rules for the "in table" insertion mode.
*/
return $this->step_in_table();
}

/*
Expand Down Expand Up @@ -1533,10 +1640,11 @@ private function bookmark_tag() {
* > that the UA must, while the current node is not a table, template, or html element, pop
* > elements from the stack of open elements.
*
* @todo move this to open elements class.
*
* @see https://html.spec.whatwg.org/multipage/parsing.html#clear-the-stack-back-to-a-table-context
*/
private function clear_stack_to_table_context() {
// @todo we could add saftey here checking insertion modes…
foreach ( $this->state->stack_of_open_elements->walk_up() as $item ) {
if (
$item->node_name === 'TABLE' ||
Expand All @@ -1549,6 +1657,32 @@ private function clear_stack_to_table_context() {
}
}

/**
* Clear the stack back to a table body context.
*
* > When the steps above require the UA to clear the stack back to a table body context, it
* > means that the UA must, while the current node is not a tbody, tfoot, thead, template, or
* > html element, pop elements from the stack of open elements.
*
* @todo move this to open elements class.
*
* @see https://html.spec.whatwg.org/multipage/parsing.html#clear-the-stack-back-to-a-table-body-context
*/
private function clear_stack_to_table_body_context() {
foreach ( $this->state->stack_of_open_elements->walk_up() as $item ) {
if (
$item->node_name === 'TBODY' ||
$item->node_name === 'TFOOT' ||
$item->node_name === 'THEAD' ||
$item->node_name === 'TEMPLATE' ||
$item->node_name === 'HTML'
) {
break;
}
$this->state->stack_of_open_elements->remove_node( $item );
}
}

/*
* HTML semantic overrides for Tag Processor
*/
Expand Down

0 comments on commit 2f55c91

Please sign in to comment.