Make WordPress Core


Ignore:
Timestamp:
01/10/2024 02:03:57 PM (3 years ago)
Author:
dmsnell
Message:

HTML API: Add support for list elements.

Adds support for the following HTML elements to the HTML Processor:

  • LI, OL, UL.
  • DD, DL, DT.

Previously, these elements were not supported and the HTML Processor would bail when encountering them.
With this patch it will proceed to parse an HTML document when encountering those tags as long as other normal conditions don't cause it to bail (such as complicated format reconstruction).

Props audrasjb, jonsurrell, bernhard-reiter.
Fixes #60215.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/html-api/class-wp-html-processor.php

    r57248 r57264  
    106106 *  - Heading elements: H1, H2, H3, H4, H5, H6, HGROUP.
    107107 *  - Links: A.
    108  *  - Lists: DL.
     108 *  - Lists: DD, DL, DT, LI, OL, LI.
    109109 *  - Media elements: AUDIO, CANVAS, FIGCAPTION, FIGURE, IMG, MAP, PICTURE, VIDEO.
    110110 *  - Paragraph: P.
     
    649649                        case '+MENU':
    650650                        case '+NAV':
     651                        case '+OL':
    651652                        case '+P':
    652653                        case '+SEARCH':
    653654                        case '+SECTION':
    654655                        case '+SUMMARY':
     656                        case '+UL':
    655657                                if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) {
    656658                                        $this->close_a_p_element();
     
    686688                        case '-MENU':
    687689                        case '-NAV':
     690                        case '-OL':
    688691                        case '-SEARCH':
    689692                        case '-SECTION':
    690693                        case '-SUMMARY':
     694                        case '-UL':
    691695                                if ( ! $this->state->stack_of_open_elements->has_element_in_scope( $tag_name ) ) {
    692696                                        // @todo Report parse error.
     
    754758
    755759                                $this->state->stack_of_open_elements->pop_until( '(internal: H1 through H6 - do not use)' );
     760                                return true;
     761
     762                        /*
     763                         * > A start tag whose tag name is "li"
     764                         * > A start tag whose tag name is one of: "dd", "dt"
     765                         */
     766                        case '+DD':
     767                        case '+DT':
     768                        case '+LI':
     769                                $this->state->frameset_ok = false;
     770                                $node                     = $this->state->stack_of_open_elements->current_node();
     771                                $is_li                    = 'LI' === $tag_name;
     772
     773                                in_body_list_loop:
     774                                /*
     775                                 * The logic for LI and DT/DD is the same except for one point: LI elements _only_
     776                                 * close other LI elements, but a DT or DD element closes _any_ open DT or DD element.
     777                                 */
     778                                if ( $is_li ? 'LI' === $node->node_name : ( 'DD' === $node->node_name || 'DT' === $node->node_name ) ) {
     779                                        $node_name = $is_li ? 'LI' : $node->node_name;
     780                                        $this->generate_implied_end_tags( $node_name );
     781                                        if ( $node_name !== $this->state->stack_of_open_elements->current_node()->node_name ) {
     782                                                // @todo Indicate a parse error once it's possible. This error does not impact the logic here.
     783                                        }
     784
     785                                        $this->state->stack_of_open_elements->pop_until( $node_name );
     786                                        goto in_body_list_done;
     787                                }
     788
     789                                if (
     790                                        'ADDRESS' !== $node->node_name &&
     791                                        'DIV' !== $node->node_name &&
     792                                        'P' !== $node->node_name &&
     793                                        $this->is_special( $node->node_name )
     794                                ) {
     795                                        /*
     796                                         * > If node is in the special category, but is not an address, div,
     797                                         * > or p element, then jump to the step labeled done below.
     798                                         */
     799                                        goto in_body_list_done;
     800                                } else {
     801                                        /*
     802                                         * > Otherwise, set node to the previous entry in the stack of open elements
     803                                         * > and return to the step labeled loop.
     804                                         */
     805                                        foreach ( $this->state->stack_of_open_elements->walk_up( $node ) as $item ) {
     806                                                $node = $item;
     807                                                break;
     808                                        }
     809                                        goto in_body_list_loop;
     810                                }
     811
     812                                in_body_list_done:
     813                                if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) {
     814                                        $this->close_a_p_element();
     815                                }
     816
     817                                $this->insert_html_element( $this->state->current_token );
     818                                return true;
     819
     820                        /*
     821                         * > An end tag whose tag name is "li"
     822                         * > An end tag whose tag name is one of: "dd", "dt"
     823                         */
     824                        case '-DD':
     825                        case '-DT':
     826                        case '-LI':
     827                                if (
     828                                        /*
     829                                         * An end tag whose tag name is "li":
     830                                         * If the stack of open elements does not have an li element in list item scope,
     831                                         * then this is a parse error; ignore the token.
     832                                         */
     833                                        (
     834                                                'LI' === $tag_name &&
     835                                                ! $this->state->stack_of_open_elements->has_element_in_list_item_scope( 'LI' )
     836                                        ) ||
     837                                        /*
     838                                         * An end tag whose tag name is one of: "dd", "dt":
     839                                         * If the stack of open elements does not have an element in scope that is an
     840                                         * HTML element with the same tag name as that of the token, then this is a
     841                                         * parse error; ignore the token.
     842                                         */
     843                                        (
     844                                                'LI' !== $tag_name &&
     845                                                ! $this->state->stack_of_open_elements->has_element_in_scope( $tag_name )
     846                                        )
     847                                ) {
     848                                        /*
     849                                         * This is a parse error, ignore the token.
     850                                         *
     851                                         * @todo Indicate a parse error once it's possible.
     852                                         */
     853                                        return $this->step();
     854                                }
     855
     856                                $this->generate_implied_end_tags( $tag_name );
     857
     858                                if ( $tag_name !== $this->state->stack_of_open_elements->current_node()->node_name ) {
     859                                        // @todo Indicate a parse error once it's possible. This error does not impact the logic here.
     860                                }
     861
     862                                $this->state->stack_of_open_elements->pop_until( $tag_name );
    756863                                return true;
    757864
     
    12241331        private function generate_implied_end_tags( $except_for_this_element = null ) {
    12251332                $elements_with_implied_end_tags = array(
     1333                        'DD',
     1334                        'DT',
     1335                        'LI',
    12261336                        'P',
    12271337                );
     
    12491359        private function generate_implied_end_tags_thoroughly() {
    12501360                $elements_with_implied_end_tags = array(
     1361                        'DD',
     1362                        'DT',
     1363                        'LI',
    12511364                        'P',
    12521365                );
Note: See TracChangeset for help on using the changeset viewer.