WP_HTML_Processor::step_in_body │ private │ WP 6.4.0
Parses next element in the 'in body' insertion mode.
This internal function performs the 'in body' insertion mode logic for the generalized WP_HTML_Processor::step() function.
Method of the class: WP_HTML_Processor{}
No Hooks.
Returns
true|false. Whether an element was found.
Usage
// private - for code of main (parent) class only $result = $this->step_in_body(): bool;
Notes
Changelog
| Since 6.4.0 | Introduced. |
WP_HTML_Processor::step_in_body() WP HTML Processor::step in body code WP 6.9
private function step_in_body(): 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 ) {
case '#text':
/*
* > A character token that is U+0000 NULL
*
* Any successive sequence of NULL bytes is ignored and won't
* trigger active format reconstruction. Therefore, if the text
* only comprises NULL bytes then the token should be ignored
* here, but if there are any other characters in the stream
* the active formats should be reconstructed.
*/
if ( parent::TEXT_IS_NULL_SEQUENCE === $this->text_node_classification ) {
// Parse error: ignore the token.
return $this->step();
}
$this->reconstruct_active_formatting_elements();
/*
* Whitespace-only text does not affect the frameset-ok flag.
* It is probably inter-element whitespace, but it may also
* contain character references which decode only to whitespace.
*/
if ( parent::TEXT_IS_GENERIC === $this->text_node_classification ) {
$this->state->frameset_ok = false;
}
$this->insert_html_element( $this->state->current_token );
return true;
case '#comment':
case '#funky-comment':
case '#presumptuous-tag':
$this->insert_html_element( $this->state->current_token );
return true;
/*
* > A DOCTYPE token
* > Parse error. Ignore the token.
*/
case 'html':
return $this->step();
/*
* > A start tag whose tag name is "html"
*/
case '+HTML':
if ( ! $this->state->stack_of_open_elements->contains( 'TEMPLATE' ) ) {
/*
* > Otherwise, for each attribute on the token, check to see if the attribute
* > is already present on the top element of the stack of open elements. If
* > it is not, add the attribute and its corresponding value to that element.
*
* This parser does not currently support this behavior: ignore the token.
*/
}
// Ignore the token.
return $this->step();
/*
* > A start tag whose tag name is one of: "base", "basefont", "bgsound", "link",
* > "meta", "noframes", "script", "style", "template", "title"
* >
* > An end tag whose tag name is "template"
*/
case '+BASE':
case '+BASEFONT':
case '+BGSOUND':
case '+LINK':
case '+META':
case '+NOFRAMES':
case '+SCRIPT':
case '+STYLE':
case '+TEMPLATE':
case '+TITLE':
case '-TEMPLATE':
return $this->step_in_head();
/*
* > A start tag whose tag name is "body"
*
* This tag in the IN BODY insertion mode is a parse error.
*/
case '+BODY':
if (
1 === $this->state->stack_of_open_elements->count() ||
'BODY' !== ( $this->state->stack_of_open_elements->at( 2 )->node_name ?? null ) ||
$this->state->stack_of_open_elements->contains( 'TEMPLATE' )
) {
// Ignore the token.
return $this->step();
}
/*
* > Otherwise, set the frameset-ok flag to "not ok"; then, for each attribute
* > on the token, check to see if the attribute is already present on the body
* > element (the second element) on the stack of open elements, and if it is
* > not, add the attribute and its corresponding value to that element.
*
* This parser does not currently support this behavior: ignore the token.
*/
$this->state->frameset_ok = false;
return $this->step();
/*
* > A start tag whose tag name is "frameset"
*
* This tag in the IN BODY insertion mode is a parse error.
*/
case '+FRAMESET':
if (
1 === $this->state->stack_of_open_elements->count() ||
'BODY' !== ( $this->state->stack_of_open_elements->at( 2 )->node_name ?? null ) ||
false === $this->state->frameset_ok
) {
// Ignore the token.
return $this->step();
}
/*
* > Otherwise, run the following steps:
*/
$this->bail( 'Cannot process non-ignored FRAMESET tags.' );
break;
/*
* > An end tag whose tag name is "body"
*/
case '-BODY':
if ( ! $this->state->stack_of_open_elements->has_element_in_scope( 'BODY' ) ) {
// Parse error: ignore the token.
return $this->step();
}
/*
* > Otherwise, if there is a node in the stack of open elements that is not either a
* > dd element, a dt element, an li element, an optgroup element, an option element,
* > a p element, an rb element, an rp element, an rt element, an rtc element, a tbody
* > element, a td element, a tfoot element, a th element, a thread element, a tr
* > element, the body element, or the html element, then this is a parse error.
*
* There is nothing to do for this parse error, so don't check for it.
*/
$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_AFTER_BODY;
/*
* The BODY element is not removed from the stack of open elements.
* Only internal state has changed, this does not qualify as a "step"
* in terms of advancing through the document to another token.
* Nothing has been pushed or popped.
* Proceed to parse the next item.
*/
return $this->step();
/*
* > An end tag whose tag name is "html"
*/
case '-HTML':
if ( ! $this->state->stack_of_open_elements->has_element_in_scope( 'BODY' ) ) {
// Parse error: ignore the token.
return $this->step();
}
/*
* > Otherwise, if there is a node in the stack of open elements that is not either a
* > dd element, a dt element, an li element, an optgroup element, an option element,
* > a p element, an rb element, an rp element, an rt element, an rtc element, a tbody
* > element, a td element, a tfoot element, a th element, a thread element, a tr
* > element, the body element, or the html element, then this is a parse error.
*
* There is nothing to do for this parse error, so don't check for it.
*/
$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_AFTER_BODY;
return $this->step( self::REPROCESS_CURRENT_NODE );
/*
* > A start tag whose tag name is one of: "address", "article", "aside",
* > "blockquote", "center", "details", "dialog", "dir", "div", "dl",
* > "fieldset", "figcaption", "figure", "footer", "header", "hgroup",
* > "main", "menu", "nav", "ol", "p", "search", "section", "summary", "ul"
*/
case '+ADDRESS':
case '+ARTICLE':
case '+ASIDE':
case '+BLOCKQUOTE':
case '+CENTER':
case '+DETAILS':
case '+DIALOG':
case '+DIR':
case '+DIV':
case '+DL':
case '+FIELDSET':
case '+FIGCAPTION':
case '+FIGURE':
case '+FOOTER':
case '+HEADER':
case '+HGROUP':
case '+MAIN':
case '+MENU':
case '+NAV':
case '+OL':
case '+P':
case '+SEARCH':
case '+SECTION':
case '+SUMMARY':
case '+UL':
if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) {
$this->close_a_p_element();
}
$this->insert_html_element( $this->state->current_token );
return true;
/*
* > A start tag whose tag name is one of: "h1", "h2", "h3", "h4", "h5", "h6"
*/
case '+H1':
case '+H2':
case '+H3':
case '+H4':
case '+H5':
case '+H6':
if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) {
$this->close_a_p_element();
}
if (
in_array(
$this->state->stack_of_open_elements->current_node()->node_name,
array( 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ),
true
)
) {
// @todo Indicate a parse error once it's possible.
$this->state->stack_of_open_elements->pop();
}
$this->insert_html_element( $this->state->current_token );
return true;
/*
* > A start tag whose tag name is one of: "pre", "listing"
*/
case '+PRE':
case '+LISTING':
if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) {
$this->close_a_p_element();
}
/*
* > If the next token is a U+000A LINE FEED (LF) character token,
* > then ignore that token and move on to the next one. (Newlines
* > at the start of pre blocks are ignored as an authoring convenience.)
*
* This is handled in `get_modifiable_text()`.
*/
$this->insert_html_element( $this->state->current_token );
$this->state->frameset_ok = false;
return true;
/*
* > A start tag whose tag name is "form"
*/
case '+FORM':
$stack_contains_template = $this->state->stack_of_open_elements->contains( 'TEMPLATE' );
if ( isset( $this->state->form_element ) && ! $stack_contains_template ) {
// Parse error: ignore the token.
return $this->step();
}
if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) {
$this->close_a_p_element();
}
$this->insert_html_element( $this->state->current_token );
if ( ! $stack_contains_template ) {
$this->state->form_element = $this->state->current_token;
}
return true;
/*
* > A start tag whose tag name is "li"
* > A start tag whose tag name is one of: "dd", "dt"
*/
case '+DD':
case '+DT':
case '+LI':
$this->state->frameset_ok = false;
$node = $this->state->stack_of_open_elements->current_node();
$is_li = 'LI' === $token_name;
in_body_list_loop:
/*
* The logic for LI and DT/DD is the same except for one point: LI elements _only_
* close other LI elements, but a DT or DD element closes _any_ open DT or DD element.
*/
if ( $is_li ? 'LI' === $node->node_name : ( 'DD' === $node->node_name || 'DT' === $node->node_name ) ) {
$node_name = $is_li ? 'LI' : $node->node_name;
$this->generate_implied_end_tags( $node_name );
if ( ! $this->state->stack_of_open_elements->current_node_is( $node_name ) ) {
// @todo Indicate a parse error once it's possible. This error does not impact the logic here.
}
$this->state->stack_of_open_elements->pop_until( $node_name );
goto in_body_list_done;
}
if (
'ADDRESS' !== $node->node_name &&
'DIV' !== $node->node_name &&
'P' !== $node->node_name &&
self::is_special( $node )
) {
/*
* > If node is in the special category, but is not an address, div,
* > or p element, then jump to the step labeled done below.
*/
goto in_body_list_done;
} else {
/*
* > Otherwise, set node to the previous entry in the stack of open elements
* > and return to the step labeled loop.
*/
foreach ( $this->state->stack_of_open_elements->walk_up( $node ) as $item ) {
$node = $item;
break;
}
goto in_body_list_loop;
}
in_body_list_done:
if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) {
$this->close_a_p_element();
}
$this->insert_html_element( $this->state->current_token );
return true;
case '+PLAINTEXT':
if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) {
$this->close_a_p_element();
}
/*
* @todo This may need to be handled in the Tag Processor and turn into
* a single self-contained tag like TEXTAREA, whose modifiable text
* is the rest of the input document as plaintext.
*/
$this->bail( 'Cannot process PLAINTEXT elements.' );
break;
/*
* > A start tag whose tag name is "button"
*/
case '+BUTTON':
if ( $this->state->stack_of_open_elements->has_element_in_scope( 'BUTTON' ) ) {
// @todo Indicate a parse error once it's possible. This error does not impact the logic here.
$this->generate_implied_end_tags();
$this->state->stack_of_open_elements->pop_until( 'BUTTON' );
}
$this->reconstruct_active_formatting_elements();
$this->insert_html_element( $this->state->current_token );
$this->state->frameset_ok = false;
return true;
/*
* > An end tag whose tag name is one of: "address", "article", "aside", "blockquote",
* > "button", "center", "details", "dialog", "dir", "div", "dl", "fieldset",
* > "figcaption", "figure", "footer", "header", "hgroup", "listing", "main",
* > "menu", "nav", "ol", "pre", "search", "section", "summary", "ul"
*/
case '-ADDRESS':
case '-ARTICLE':
case '-ASIDE':
case '-BLOCKQUOTE':
case '-BUTTON':
case '-CENTER':
case '-DETAILS':
case '-DIALOG':
case '-DIR':
case '-DIV':
case '-DL':
case '-FIELDSET':
case '-FIGCAPTION':
case '-FIGURE':
case '-FOOTER':
case '-HEADER':
case '-HGROUP':
case '-LISTING':
case '-MAIN':
case '-MENU':
case '-NAV':
case '-OL':
case '-PRE':
case '-SEARCH':
case '-SECTION':
case '-SUMMARY':
case '-UL':
if ( ! $this->state->stack_of_open_elements->has_element_in_scope( $token_name ) ) {
// @todo Report parse error.
// Ignore the token.
return $this->step();
}
$this->generate_implied_end_tags();
if ( ! $this->state->stack_of_open_elements->current_node_is( $token_name ) ) {
// @todo Record parse error: this error doesn't impact parsing.
}
$this->state->stack_of_open_elements->pop_until( $token_name );
return true;
/*
* > An end tag whose tag name is "form"
*/
case '-FORM':
if ( ! $this->state->stack_of_open_elements->contains( 'TEMPLATE' ) ) {
$node = $this->state->form_element;
$this->state->form_element = null;
/*
* > If node is null or if the stack of open elements does not have node
* > in scope, then this is a parse error; return and ignore the token.
*
* @todo It's necessary to check if the form token itself is in scope, not
* simply whether any FORM is in scope.
*/
if (
null === $node ||
! $this->state->stack_of_open_elements->has_element_in_scope( 'FORM' )
) {
// Parse error: ignore the token.
return $this->step();
}
$this->generate_implied_end_tags();
if ( $node !== $this->state->stack_of_open_elements->current_node() ) {
// @todo Indicate a parse error once it's possible. This error does not impact the logic here.
$this->bail( 'Cannot close a FORM when other elements remain open as this would throw off the breadcrumbs for the following tokens.' );
}
$this->state->stack_of_open_elements->remove_node( $node );
return true;
} else {
/*
* > If the stack of open elements does not have a form element in scope,
* > then this is a parse error; return and ignore the token.
*
* Note that unlike in the clause above, this is checking for any FORM in scope.
*/
if ( ! $this->state->stack_of_open_elements->has_element_in_scope( 'FORM' ) ) {
// Parse error: ignore the token.
return $this->step();
}
$this->generate_implied_end_tags();
if ( ! $this->state->stack_of_open_elements->current_node_is( 'FORM' ) ) {
// @todo Indicate a parse error once it's possible. This error does not impact the logic here.
}
$this->state->stack_of_open_elements->pop_until( 'FORM' );
return true;
}
break;
/*
* > An end tag whose tag name is "p"
*/
case '-P':
if ( ! $this->state->stack_of_open_elements->has_p_in_button_scope() ) {
$this->insert_html_element( $this->state->current_token );
}
$this->close_a_p_element();
return true;
/*
* > An end tag whose tag name is "li"
* > An end tag whose tag name is one of: "dd", "dt"
*/
case '-DD':
case '-DT':
case '-LI':
if (
/*
* An end tag whose tag name is "li":
* If the stack of open elements does not have an li element in list item scope,
* then this is a parse error; ignore the token.
*/
(
'LI' === $token_name &&
! $this->state->stack_of_open_elements->has_element_in_list_item_scope( 'LI' )
) ||
/*
* An end tag whose tag name is one of: "dd", "dt":
* If the stack of open elements does not have an element in scope that is an
* HTML element with the same tag name as that of the token, then this is a
* parse error; ignore the token.
*/
(
'LI' !== $token_name &&
! $this->state->stack_of_open_elements->has_element_in_scope( $token_name )
)
) {
/*
* This is a parse error, ignore the token.
*
* @todo Indicate a parse error once it's possible.
*/
return $this->step();
}
$this->generate_implied_end_tags( $token_name );
if ( ! $this->state->stack_of_open_elements->current_node_is( $token_name ) ) {
// @todo Indicate a parse error once it's possible. This error does not impact the logic here.
}
$this->state->stack_of_open_elements->pop_until( $token_name );
return true;
/*
* > An end tag whose tag name is one of: "h1", "h2", "h3", "h4", "h5", "h6"
*/
case '-H1':
case '-H2':
case '-H3':
case '-H4':
case '-H5':
case '-H6':
if ( ! $this->state->stack_of_open_elements->has_element_in_scope( '(internal: H1 through H6 - do not use)' ) ) {
/*
* This is a parse error; ignore the token.
*
* @todo Indicate a parse error once it's possible.
*/
return $this->step();
}
$this->generate_implied_end_tags();
if ( ! $this->state->stack_of_open_elements->current_node_is( $token_name ) ) {
// @todo Record parse error: this error doesn't impact parsing.
}
$this->state->stack_of_open_elements->pop_until( '(internal: H1 through H6 - do not use)' );
return true;
/*
* > A start tag whose tag name is "a"
*/
case '+A':
foreach ( $this->state->active_formatting_elements->walk_up() as $item ) {
switch ( $item->node_name ) {
case 'marker':
break 2;
case 'A':
$this->run_adoption_agency_algorithm();
$this->state->active_formatting_elements->remove_node( $item );
$this->state->stack_of_open_elements->remove_node( $item );
break 2;
}
}
$this->reconstruct_active_formatting_elements();
$this->insert_html_element( $this->state->current_token );
$this->state->active_formatting_elements->push( $this->state->current_token );
return true;
/*
* > A start tag whose tag name is one of: "b", "big", "code", "em", "font", "i",
* > "s", "small", "strike", "strong", "tt", "u"
*/
case '+B':
case '+BIG':
case '+CODE':
case '+EM':
case '+FONT':
case '+I':
case '+S':
case '+SMALL':
case '+STRIKE':
case '+STRONG':
case '+TT':
case '+U':
$this->reconstruct_active_formatting_elements();
$this->insert_html_element( $this->state->current_token );
$this->state->active_formatting_elements->push( $this->state->current_token );
return true;
/*
* > A start tag whose tag name is "nobr"
*/
case '+NOBR':
$this->reconstruct_active_formatting_elements();
if ( $this->state->stack_of_open_elements->has_element_in_scope( 'NOBR' ) ) {
// Parse error.
$this->run_adoption_agency_algorithm();
$this->reconstruct_active_formatting_elements();
}
$this->insert_html_element( $this->state->current_token );
$this->state->active_formatting_elements->push( $this->state->current_token );
return true;
/*
* > An end tag whose tag name is one of: "a", "b", "big", "code", "em", "font", "i",
* > "nobr", "s", "small", "strike", "strong", "tt", "u"
*/
case '-A':
case '-B':
case '-BIG':
case '-CODE':
case '-EM':
case '-FONT':
case '-I':
case '-NOBR':
case '-S':
case '-SMALL':
case '-STRIKE':
case '-STRONG':
case '-TT':
case '-U':
$this->run_adoption_agency_algorithm();
return true;
/*
* > A start tag whose tag name is one of: "applet", "marquee", "object"
*/
case '+APPLET':
case '+MARQUEE':
case '+OBJECT':
$this->reconstruct_active_formatting_elements();
$this->insert_html_element( $this->state->current_token );
$this->state->active_formatting_elements->insert_marker();
$this->state->frameset_ok = false;
return true;
/*
* > A end tag token whose tag name is one of: "applet", "marquee", "object"
*/
case '-APPLET':
case '-MARQUEE':
case '-OBJECT':
if ( ! $this->state->stack_of_open_elements->has_element_in_scope( $token_name ) ) {
// Parse error: ignore the token.
return $this->step();
}
$this->generate_implied_end_tags();
if ( ! $this->state->stack_of_open_elements->current_node_is( $token_name ) ) {
// This is a parse error.
}
$this->state->stack_of_open_elements->pop_until( $token_name );
$this->state->active_formatting_elements->clear_up_to_last_marker();
return true;
/*
* > A start tag whose tag name is "table"
*/
case '+TABLE':
/*
* > If the Document is not set to quirks mode, and the stack of open elements
* > has a p element in button scope, then close a p element.
*/
if (
WP_HTML_Tag_Processor::QUIRKS_MODE !== $this->compat_mode &&
$this->state->stack_of_open_elements->has_p_in_button_scope()
) {
$this->close_a_p_element();
}
$this->insert_html_element( $this->state->current_token );
$this->state->frameset_ok = false;
$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE;
return true;
/*
* > An end tag whose tag name is "br"
*
* This is prevented from happening because the Tag Processor
* reports all closing BR tags as if they were opening tags.
*/
/*
* > A start tag whose tag name is one of: "area", "br", "embed", "img", "keygen", "wbr"
*/
case '+AREA':
case '+BR':
case '+EMBED':
case '+IMG':
case '+KEYGEN':
case '+WBR':
$this->reconstruct_active_formatting_elements();
$this->insert_html_element( $this->state->current_token );
$this->state->frameset_ok = false;
return true;
/*
* > A start tag whose tag name is "input"
*/
case '+INPUT':
$this->reconstruct_active_formatting_elements();
$this->insert_html_element( $this->state->current_token );
/*
* > 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: set the frameset-ok flag to "not ok".
*/
$type_attribute = $this->get_attribute( 'type' );
if ( ! is_string( $type_attribute ) || 'hidden' !== strtolower( $type_attribute ) ) {
$this->state->frameset_ok = false;
}
return true;
/*
* > A start tag whose tag name is one of: "param", "source", "track"
*/
case '+PARAM':
case '+SOURCE':
case '+TRACK':
$this->insert_html_element( $this->state->current_token );
return true;
/*
* > A start tag whose tag name is "hr"
*/
case '+HR':
if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) {
$this->close_a_p_element();
}
$this->insert_html_element( $this->state->current_token );
$this->state->frameset_ok = false;
return true;
/*
* > A start tag whose tag name is "image"
*/
case '+IMAGE':
/*
* > Parse error. Change the token's tag name to "img" and reprocess it. (Don't ask.)
*
* Note that this is handled elsewhere, so it should not be possible to reach this code.
*/
$this->bail( "Cannot process an IMAGE tag. (Don't ask.)" );
break;
/*
* > A start tag whose tag name is "textarea"
*/
case '+TEXTAREA':
$this->insert_html_element( $this->state->current_token );
/*
* > If the next token is a U+000A LINE FEED (LF) character token, then ignore
* > that token and move on to the next one. (Newlines at the start of
* > textarea elements are ignored as an authoring convenience.)
*
* This is handled in `get_modifiable_text()`.
*/
$this->state->frameset_ok = false;
/*
* > Switch the insertion mode to "text".
*
* As a self-contained node, this behavior is handled in the Tag Processor.
*/
return true;
/*
* > A start tag whose tag name is "xmp"
*/
case '+XMP':
if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) {
$this->close_a_p_element();
}
$this->reconstruct_active_formatting_elements();
$this->state->frameset_ok = false;
/*
* > Follow the generic raw text element parsing algorithm.
*
* As a self-contained node, this behavior is handled in the Tag Processor.
*/
$this->insert_html_element( $this->state->current_token );
return true;
/*
* A start tag whose tag name is "iframe"
*/
case '+IFRAME':
$this->state->frameset_ok = false;
/*
* > Follow the generic raw text element parsing algorithm.
*
* As a self-contained node, this behavior is handled in the Tag Processor.
*/
$this->insert_html_element( $this->state->current_token );
return true;
/*
* > A start tag whose tag name is "noembed"
* > A start tag whose tag name is "noscript", if the scripting flag is enabled
*
* The scripting flag is never enabled in this parser.
*/
case '+NOEMBED':
$this->insert_html_element( $this->state->current_token );
return true;
/*
* > A start tag whose tag name is "select"
*/
case '+SELECT':
$this->reconstruct_active_formatting_elements();
$this->insert_html_element( $this->state->current_token );
$this->state->frameset_ok = false;
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;
}
return true;
/*
* > A start tag whose tag name is one of: "optgroup", "option"
*/
case '+OPTGROUP':
case '+OPTION':
if ( $this->state->stack_of_open_elements->current_node_is( 'OPTION' ) ) {
$this->state->stack_of_open_elements->pop();
}
$this->reconstruct_active_formatting_elements();
$this->insert_html_element( $this->state->current_token );
return true;
/*
* > A start tag whose tag name is one of: "rb", "rtc"
*/
case '+RB':
case '+RTC':
if ( $this->state->stack_of_open_elements->has_element_in_scope( 'RUBY' ) ) {
$this->generate_implied_end_tags();
if ( $this->state->stack_of_open_elements->current_node_is( 'RUBY' ) ) {
// @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 one of: "rp", "rt"
*/
case '+RP':
case '+RT':
if ( $this->state->stack_of_open_elements->has_element_in_scope( 'RUBY' ) ) {
$this->generate_implied_end_tags( 'RTC' );
$current_node_name = $this->state->stack_of_open_elements->current_node()->node_name;
if ( 'RTC' === $current_node_name || 'RUBY' === $current_node_name ) {
// @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 "math"
*/
case '+MATH':
$this->reconstruct_active_formatting_elements();
/*
* @todo Adjust MathML attributes for the token. (This fixes the case of MathML attributes that are not all lowercase.)
* @todo Adjust foreign attributes for the token. (This fixes the use of namespaced attributes, in particular XLink.)
*
* These ought to be handled in the attribute methods.
*/
$this->state->current_token->namespace = 'math';
$this->insert_html_element( $this->state->current_token );
if ( $this->state->current_token->has_self_closing_flag ) {
$this->state->stack_of_open_elements->pop();
}
return true;
/*
* > A start tag whose tag name is "svg"
*/
case '+SVG':
$this->reconstruct_active_formatting_elements();
/*
* @todo Adjust SVG attributes for the token. (This fixes the case of SVG attributes that are not all lowercase.)
* @todo Adjust foreign attributes for the token. (This fixes the use of namespaced attributes, in particular XLink in SVG.)
*
* These ought to be handled in the attribute methods.
*/
$this->state->current_token->namespace = 'svg';
$this->insert_html_element( $this->state->current_token );
if ( $this->state->current_token->has_self_closing_flag ) {
$this->state->stack_of_open_elements->pop();
}
return true;
/*
* > A start tag whose tag name is one of: "caption", "col", "colgroup",
* > "frame", "head", "tbody", "td", "tfoot", "th", "thead", "tr"
*/
case '+CAPTION':
case '+COL':
case '+COLGROUP':
case '+FRAME':
case '+HEAD':
case '+TBODY':
case '+TD':
case '+TFOOT':
case '+TH':
case '+THEAD':
case '+TR':
// Parse error. Ignore the token.
return $this->step();
}
if ( ! parent::is_tag_closer() ) {
/*
* > Any other start tag
*/
$this->reconstruct_active_formatting_elements();
$this->insert_html_element( $this->state->current_token );
return true;
} else {
/*
* > Any other end tag
*/
/*
* Find the corresponding tag opener in the stack of open elements, if
* it exists before reaching a special element, which provides a kind
* of boundary in the stack. For example, a `</custom-tag>` should not
* close anything beyond its containing `P` or `DIV` element.
*/
foreach ( $this->state->stack_of_open_elements->walk_up() as $node ) {
if ( 'html' === $node->namespace && $token_name === $node->node_name ) {
break;
}
if ( self::is_special( $node ) ) {
// This is a parse error, ignore the token.
return $this->step();
}
}
$this->generate_implied_end_tags( $token_name );
if ( $node !== $this->state->stack_of_open_elements->current_node() ) {
// @todo Record parse error: this error doesn't impact parsing.
}
foreach ( $this->state->stack_of_open_elements->walk_up() as $item ) {
$this->state->stack_of_open_elements->pop();
if ( $node === $item ) {
return true;
}
}
}
$this->bail( 'Should not have been able to reach end of IN BODY processing. Check HTML API code.' );
// This unnecessary return prevents tools from inaccurately reporting type errors.
return false;
}