Make WordPress Core


Ignore:
Timestamp:
01/10/2024 02:03:57 PM (16 months 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.