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.
Метод класса: WP_HTML_Processor{}
Хуков нет.
Возвращает
true|false
. Whether an element was found.
Использование
// private - только в коде основоного (родительского) класса $result = $this->step_in_body(): bool;
Заметки
- Смотрите: https://html.spec.whatwg.org/#parsing-main-inbody
- Смотрите: WP_HTML_Processor::step
Список изменений
С версии 6.4.0 | Введена. |
Код WP_HTML_Processor::step_in_body() WP HTML Processor::step in body WP 6.8.2
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; }