WP_HTML_Processor::step_in_table()privateWP 6.7.0

Parses next element in the 'in table' insertion mode.

This internal function performs the 'in table' insertion mode logic for the generalized WP_HTML_Processor::step() function.

Method of the class: WP_HTML_Processor{}

No Hooks.

Return

true|false. Whether an element was found.

Usage

// private - for code of main (parent) class only
$result = $this->step_in_table(): bool;

Notes

Changelog

Since 6.7.0 Introduced.

WP_HTML_Processor::step_in_table() code WP 6.7.1

private function step_in_table(): bool {
	$token_name = $this->get_token_name();
	$token_type = $this->get_token_type();
	$op_sigil   = '#tag' === $token_type ? ( parent::is_tag_closer() ? '-' : '+' ) : '';
	$op         = "{$op_sigil}{$token_name}";

	switch ( $op ) {
		/*
		 * > A character token, if the current node is table,
		 * > tbody, template, tfoot, thead, or tr element
		 */
		case '#text':
			$current_node      = $this->state->stack_of_open_elements->current_node();
			$current_node_name = $current_node ? $current_node->node_name : null;
			if (
				$current_node_name && (
					'TABLE' === $current_node_name ||
					'TBODY' === $current_node_name ||
					'TEMPLATE' === $current_node_name ||
					'TFOOT' === $current_node_name ||
					'THEAD' === $current_node_name ||
					'TR' === $current_node_name
				)
			) {
				/*
				 * If the text is empty after processing HTML entities and stripping
				 * U+0000 NULL bytes then ignore the token.
				 */
				if ( parent::TEXT_IS_NULL_SEQUENCE === $this->text_node_classification ) {
					return $this->step();
				}

				/*
				 * This follows the rules for "in table text" insertion mode.
				 *
				 * Whitespace-only text nodes are inserted in-place. Otherwise
				 * foster parenting is enabled and the nodes would be
				 * inserted out-of-place.
				 *
				 * > If any of the tokens in the pending table character tokens
				 * > list are character tokens that are not ASCII whitespace,
				 * > then this is a parse error: reprocess the character tokens
				 * > in the pending table character tokens list using the rules
				 * > given in the "anything else" entry in the "in table"
				 * > insertion mode.
				 * >
				 * > Otherwise, insert the characters given by the pending table
				 * > character tokens list.
				 *
				 * @see https://html.spec.whatwg.org/#parsing-main-intabletext
				 */
				if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) {
					$this->insert_html_element( $this->state->current_token );
					return true;
				}

				// Non-whitespace would trigger fostering, unsupported at this time.
				$this->bail( 'Foster parenting is not supported.' );
				break;
			}
			break;

		/*
		 * > A comment token
		 */
		case '#comment':
		case '#funky-comment':
		case '#presumptuous-tag':
			$this->insert_html_element( $this->state->current_token );
			return true;

		/*
		 * > A DOCTYPE token
		 */
		case 'html':
			// Parse error: ignore the token.
			return $this->step();

		/*
		 * > A start tag whose tag name is "caption"
		 */
		case '+CAPTION':
			$this->state->stack_of_open_elements->clear_to_table_context();
			$this->state->active_formatting_elements->insert_marker();
			$this->insert_html_element( $this->state->current_token );
			$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_CAPTION;
			return true;

		/*
		 * > A start tag whose tag name is "colgroup"
		 */
		case '+COLGROUP':
			$this->state->stack_of_open_elements->clear_to_table_context();
			$this->insert_html_element( $this->state->current_token );
			$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_COLUMN_GROUP;
			return true;

		/*
		 * > A start tag whose tag name is "col"
		 */
		case '+COL':
			$this->state->stack_of_open_elements->clear_to_table_context();

			/*
			 * > Insert an HTML element for a "colgroup" start tag token with no attributes,
			 * > then switch the insertion mode to "in column group".
			 */
			$this->insert_virtual_node( 'COLGROUP' );
			$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_COLUMN_GROUP;
			return $this->step( self::REPROCESS_CURRENT_NODE );

		/*
		 * > A start tag whose tag name is one of: "tbody", "tfoot", "thead"
		 */
		case '+TBODY':
		case '+TFOOT':
		case '+THEAD':
			$this->state->stack_of_open_elements->clear_to_table_context();
			$this->insert_html_element( $this->state->current_token );
			$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE_BODY;
			return true;

		/*
		 * > A start tag whose tag name is one of: "td", "th", "tr"
		 */
		case '+TD':
		case '+TH':
		case '+TR':
			$this->state->stack_of_open_elements->clear_to_table_context();
			/*
			 * > Insert an HTML element for a "tbody" start tag token with no attributes,
			 * > then switch the insertion mode to "in table body".
			 */
			$this->insert_virtual_node( 'TBODY' );
			$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE_BODY;
			return $this->step( self::REPROCESS_CURRENT_NODE );

		/*
		 * > A start tag whose tag name is "table"
		 *
		 * This tag in the IN TABLE insertion mode is a parse error.
		 */
		case '+TABLE':
			if ( ! $this->state->stack_of_open_elements->has_element_in_table_scope( 'TABLE' ) ) {
				return $this->step();
			}

			$this->state->stack_of_open_elements->pop_until( 'TABLE' );
			$this->reset_insertion_mode_appropriately();
			return $this->step( self::REPROCESS_CURRENT_NODE );

		/*
		 * > An end tag whose tag name is "table"
		 */
		case '-TABLE':
			if ( ! $this->state->stack_of_open_elements->has_element_in_table_scope( 'TABLE' ) ) {
				// @todo Indicate a parse error once it's possible.
				return $this->step();
			}

			$this->state->stack_of_open_elements->pop_until( 'TABLE' );
			$this->reset_insertion_mode_appropriately();
			return true;

		/*
		 * > An end tag whose tag name is one of: "body", "caption", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr"
		 */
		case '-BODY':
		case '-CAPTION':
		case '-COL':
		case '-COLGROUP':
		case '-HTML':
		case '-TBODY':
		case '-TD':
		case '-TFOOT':
		case '-TH':
		case '-THEAD':
		case '-TR':
			// Parse error: ignore the token.
			return $this->step();

		/*
		 * > A start tag whose tag name is one of: "style", "script", "template"
		 * > An end tag whose tag name is "template"
		 */
		case '+STYLE':
		case '+SCRIPT':
		case '+TEMPLATE':
		case '-TEMPLATE':
			/*
			 * > Process the token using the rules for the "in head" insertion mode.
			 */
			return $this->step_in_head();

		/*
		 * > A start tag whose tag name is "input"
		 *
		 * > If the token does not have an attribute with the name "type", or if it does, but
		 * > that attribute's value is not an ASCII case-insensitive match for the string
		 * > "hidden", then: act as described in the "anything else" entry below.
		 */
		case '+INPUT':
			$type_attribute = $this->get_attribute( 'type' );
			if ( ! is_string( $type_attribute ) || 'hidden' !== strtolower( $type_attribute ) ) {
				goto anything_else;
			}
			// @todo Indicate a parse error once it's possible.
			$this->insert_html_element( $this->state->current_token );
			return true;

		/*
		 * > A start tag whose tag name is "form"
		 *
		 * This tag in the IN TABLE insertion mode is a parse error.
		 */
		case '+FORM':
			if (
				$this->state->stack_of_open_elements->has_element_in_scope( 'TEMPLATE' ) ||
				isset( $this->state->form_element )
			) {
				return $this->step();
			}

			// This FORM is special because it immediately closes and cannot have other children.
			$this->insert_html_element( $this->state->current_token );
			$this->state->form_element = $this->state->current_token;
			$this->state->stack_of_open_elements->pop();
			return true;
	}

	/*
	 * > Anything else
	 * > Parse error. Enable foster parenting, process the token using the rules for the
	 * > "in body" insertion mode, and then disable foster parenting.
	 *
	 * @todo Indicate a parse error once it's possible.
	 */
	anything_else:
	$this->bail( 'Foster parenting is not supported.' );
}