From f70ea07d7f47d46f9a8bb096d0a820676ba16f66 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 9 Oct 2024 19:24:04 +0200 Subject: [PATCH] Implement naive set_inner_html --- .../html-api/class-wp-html-processor.php | 106 +++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/html-api/class-wp-html-processor.php b/src/wp-includes/html-api/class-wp-html-processor.php index ed6ac0299b3c3..033ea86b0b56f 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -355,6 +355,109 @@ public static function create_full_parser( $html, $known_definite_encoding = 'UT return $processor; } + public function set_inner_html( $html ) { + if ( $this->is_virtual() ) { + return false; + } + + if ( $this->get_token_type() !== '#tag' ) { + return false; + } + + if ( $this->is_tag_closer() ) { + return false; + } + + if ( ! $this->expects_closer() ) { + return false; + } + + if ( + 'html' !== $this->state->current_token->namespace && + $this->state->current_token->has_self_closing_flag + ) { + return false; + } + + $html_for_replacement = $this->normalize( $html ); + if ( empty( $html_for_replacement ) ) { + return false; + } + + // @todo apply modifications if there are any??? + + if ( ! parent::set_bookmark( 'SET_INNER_HTML: opener' ) ) { + return false; + } + + if ( ! $this->seek_to_matching_closer() ) { + parent::seek( 'SET_INNER_HTML: opener' ); + return false; + } + + if ( ! parent::set_bookmark( 'SET_INNER_HTML: closer' ) ) { + return false; + } + + $inner_html_start = $this->bookmarks['SET_INNER_HTML: opener']->start + $this->bookmarks['SET_INNER_HTML: opener']->length; + $inner_html_length = $this->bookmarks['SET_INNER_HTML: closer']->start - $inner_html_start; + + echo 'INNER HTML: ' . substr( $this->html, $inner_html_start, $inner_html_length ) . "\n"; + + echo "BEFORE:\n"; + var_dump( $this->get_updated_html() ); + + $this->lexical_updates['innerHTML'] = new WP_HTML_Text_Replacement( + $inner_html_start, + $inner_html_length, + $html_for_replacement + ); + + parent::seek( 'SET_INNER_HTML: opener' ); + parent::release_bookmark( 'SET_INNER_HTML: opener' ); + parent::release_bookmark( 'SET_INNER_HTML: closer' ); + echo "AFTER:\n"; + var_dump( $this->get_updated_html() ); + + // @todo check for whether that html will make a mess! + // Will it break out of tags? + + return true; + } + + public function seek_to_matching_closer(): bool { + $tag_name = $this->get_tag(); + + if ( null === $tag_name ) { + return false; + } + + if ( $this->is_tag_closer() ) { + return false; + } + + if ( ! $this->expects_closer() ) { + return false; + } + + $breadcrumbs = $this->breadcrumbs; + array_pop( $breadcrumbs ); + + // @todo Can't use these queries together + while ( $this->next_tag( + array( + 'tag_name' => $this->get_tag(), + 'tag_closers' => 'visit', + ) + ) ) { + if ( $this->get_breadcrumbs() === $breadcrumbs ) { + return true; + } + } + return false; + } + + /** * Constructor. * @@ -522,6 +625,7 @@ public function get_unsupported_exception() { * 1 for "first" tag, 3 for "third," etc. * Defaults to first tag. * @type string|null $class_name Tag must contain this whole class name to match. + * @type string $tag_name Tag name to match. * @type string[] $breadcrumbs DOM sub-path at which element is found, e.g. `array( 'FIGURE', 'IMG' )`. * May also contain the wildcard `*` which matches a single element, e.g. `array( 'SECTION', '*' )`. * } @@ -545,7 +649,7 @@ public function next_tag( $query = null ): bool { } if ( is_string( $query ) ) { - $query = array( 'breadcrumbs' => array( $query ) ); + $query = array( 'tag_name' => $query ); } if ( ! is_array( $query ) ) {