Skip to content

Commit 8ec0306

Browse files
committed
WP_HTML_Tag_Processor: Add add_lexical_update() method
1 parent 4ea8fa6 commit 8ec0306

1 file changed

Lines changed: 62 additions & 12 deletions

File tree

lib/experimental/html/class-wp-html-tag-processor.php

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,18 @@ class WP_HTML_Tag_Processor {
424424
*/
425425
private $lexical_updates = array();
426426

427+
/**
428+
* Attribute replacements to apply to input HTML document.
429+
*
430+
* Unlike more generic lexical updates, attribute updates are stored
431+
* in an associative array, where the keys are (lowercase-normalized)
432+
* attribute names, in order to avoid duplication.
433+
*
434+
* @since 6.2.0
435+
* @var WP_HTML_Text_Replacement[]
436+
*/
437+
private $attribute_updates = array();
438+
427439
/**
428440
* Tracks how many times we've performed a `seek()`
429441
* so that we can prevent accidental infinite loops.
@@ -1103,7 +1115,8 @@ private function skip_whitespace() {
11031115
* @return void
11041116
*/
11051117
private function after_tag() {
1106-
$this->class_name_updates_to_lexical_updates();
1118+
$this->class_name_updates_to_attribute_updates();
1119+
$this->attribute_updates_to_lexical_updates();
11071120
$this->apply_lexical_updates();
11081121
$this->tag_name_starts_at = null;
11091122
$this->tag_name_length = null;
@@ -1113,20 +1126,20 @@ private function after_tag() {
11131126
}
11141127

11151128
/**
1116-
* Converts class name updates into tag lexical updates
1129+
* Converts class name updates into tag attribute updates
11171130
* (they are accumulated in different data formats for performance).
11181131
*
1119-
* This method is only meant to run right before the lexical updates are applied.
1132+
* This method is only meant to run right before the attribute updates are applied.
11201133
* The behavior in all other cases is undefined.
11211134
*
11221135
* @return void
11231136
* @since 6.2.0
11241137
*
11251138
* @see $classname_updates
1126-
* @see $lexical_updates
1139+
* @see $attribute_updates
11271140
*/
1128-
private function class_name_updates_to_lexical_updates() {
1129-
if ( count( $this->classname_updates ) === 0 || isset( $this->lexical_updates['class'] ) ) {
1141+
private function class_name_updates_to_attribute_updates() {
1142+
if ( count( $this->classname_updates ) === 0 || isset( $this->attribute_updates['class'] ) ) {
11301143
$this->classname_updates = array();
11311144
return;
11321145
}
@@ -1241,6 +1254,26 @@ private function class_name_updates_to_lexical_updates() {
12411254
}
12421255
}
12431256

1257+
/**
1258+
* Converts attribute updates into lexical updates.
1259+
*
1260+
* This method is only meant to run right before the attribute updates are applied.
1261+
* The behavior in all other cases is undefined.
1262+
*
1263+
* @return void
1264+
* @since 6.2.0
1265+
*
1266+
* @see $attribute_updates
1267+
* @see $lexical_updates
1268+
*/
1269+
private function attribute_updates_to_lexical_updates() {
1270+
$this->lexical_updates = array_merge(
1271+
$this->lexical_updates,
1272+
array_values( $this->attribute_updates )
1273+
);
1274+
$this->attribute_updates = array();
1275+
}
1276+
12441277
/**
12451278
* Applies updates to attributes.
12461279
*
@@ -1501,6 +1534,18 @@ public function is_tag_closer() {
15011534
return $this->is_closing_tag;
15021535
}
15031536

1537+
/**
1538+
* Add a lexical update, i.e. a replacement of HTML at a given position.
1539+
*
1540+
* @param int $start The start offset of the replacement.
1541+
* @param int $end The end offset of the replacement.
1542+
* @param string $text The replacement.
1543+
* @return void
1544+
*/
1545+
protected function add_lexical_update( $start, $end, $text ) {
1546+
$this->lexical_updates[] = new WP_HTML_Text_Replacement( $start, $end, $text );
1547+
}
1548+
15041549
/**
15051550
* Updates or creates a new attribute on the currently matched tag with the value passed.
15061551
*
@@ -1604,8 +1649,8 @@ public function set_attribute( $name, $value ) {
16041649
*
16051650
* Result: <div id="new"/>
16061651
*/
1607-
$existing_attribute = $this->attributes[ $comparable_name ];
1608-
$this->lexical_updates[ $name ] = new WP_HTML_Text_Replacement(
1652+
$existing_attribute = $this->attributes[ $comparable_name ];
1653+
$this->attribute_updates[ $name ] = new WP_HTML_Text_Replacement(
16091654
$existing_attribute->start,
16101655
$existing_attribute->end,
16111656
$updated_attribute
@@ -1622,7 +1667,7 @@ public function set_attribute( $name, $value ) {
16221667
*
16231668
* Result: <div id="new"/>
16241669
*/
1625-
$this->lexical_updates[ $comparable_name ] = new WP_HTML_Text_Replacement(
1670+
$this->attribute_updates[ $comparable_name ] = new WP_HTML_Text_Replacement(
16261671
$this->tag_name_starts_at + $this->tag_name_length,
16271672
$this->tag_name_starts_at + $this->tag_name_length,
16281673
' ' . $updated_attribute
@@ -1662,7 +1707,7 @@ public function remove_attribute( $name ) {
16621707
*
16631708
* Result: <div />
16641709
*/
1665-
$this->lexical_updates[ $name ] = new WP_HTML_Text_Replacement(
1710+
$this->attribute_updates[ $name ] = new WP_HTML_Text_Replacement(
16661711
$this->attributes[ $name ]->start,
16671712
$this->attributes[ $name ]->end,
16681713
''
@@ -1724,7 +1769,11 @@ public function __toString() {
17241769
*/
17251770
public function get_updated_html() {
17261771
// Short-circuit if there are no new updates to apply.
1727-
if ( ! count( $this->classname_updates ) && ! count( $this->lexical_updates ) ) {
1772+
if (
1773+
! count( $this->classname_updates ) &&
1774+
! count( $this->attribute_updates ) &&
1775+
! count( $this->lexical_updates )
1776+
) {
17281777
return $this->updated_html . substr( $this->html, $this->updated_bytes );
17291778
}
17301779

@@ -1737,7 +1786,8 @@ public function get_updated_html() {
17371786
$updated_html_up_to_current_tag_name_end = $this->updated_html . $delta_between_updated_html_end_and_current_tag_end;
17381787

17391788
// 1. Apply the attributes updates to the original HTML
1740-
$this->class_name_updates_to_lexical_updates();
1789+
$this->class_name_updates_to_attribute_updates();
1790+
$this->attribute_updates_to_lexical_updates();
17411791
$this->apply_lexical_updates();
17421792

17431793
// 2. Replace the original HTML with the updated HTML

0 commit comments

Comments
 (0)