-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Interactivity API: Skip instead of bail out if HTML contains SVG or MATH #6091
Changes from 5 commits
cd9aa70
4f4e576
5cff5e6
e3b5349
23f25c1
8ea4a69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -180,6 +180,39 @@ private function get_balanced_tag_bookmarks() { | |
return array( $opener_tag, $closer_tag ); | ||
} | ||
|
||
/** | ||
* Skips processing the content between tags. | ||
* | ||
* It positions the cursor in the closer tag of the foreign element, if it | ||
* exists. | ||
* | ||
* This function is intended to skip processing SVG and MathML inner content | ||
* instead of bailing out the whole processing. | ||
* | ||
* @since 6.5.0 | ||
* | ||
* @access private | ||
* | ||
* @return bool Whether the foreign content was successfully skipped. | ||
*/ | ||
public function jump_to_tag_closer(): bool { | ||
$depth = 1; | ||
$tag_name = $this->get_tag(); | ||
while ( $depth > 0 && $this->next_tag( | ||
array( | ||
'tag_name' => $tag_name, | ||
'tag_closers' => 'visit', | ||
) | ||
) ) { | ||
if ( $this->has_self_closing_flag() ) { | ||
continue; | ||
} | ||
$depth += $this->is_tag_closer() ? -1 : 1; | ||
Comment on lines
+207
to
+210
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dmsnell What about a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @westonruter this is a great question, and you're right. it's not RCDATA when found inside SVG. this is all the more reason to focus only on SVG and MathML tags and ignore the others. in #6006 what I'm looking to do is have the HTML Processor tell the Tag Processor that it's inside foreign content, and while that flag is active, we'll disable the special handling of tokens like TITLE and the others. it's complicated and we explored trying to put the foreign-content handling code inside the Tag Processor, but that ended up demanding that we re-implement much of the HTML Processor's functionality there, so it will probably be the case that you need the HTML Processor to adequately parse inside SVG and MathML. in the meantime, if one overlooks the HTML elements which break out into the nearest "integration point," then I think that skipping from SVG tag to SVG tag will be reliable enough for now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. aha I misread your statement @westonruter concerning |
||
} | ||
|
||
return 0 === $depth; | ||
} | ||
|
||
/** | ||
* Finds the matching closing tag for an opening tag. | ||
* | ||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -11,7 +11,7 @@ | |||||||
* | ||||||||
* @coversDefaultClass WP_Interactivity_API | ||||||||
*/ | ||||||||
class Tests_WP_Interactivity_API extends WP_UnitTestCase { | ||||||||
class Tests_Interactivity_API_WpInteractivityAPI extends WP_UnitTestCase { | ||||||||
/** | ||||||||
* Instance of WP_Interactivity_API. | ||||||||
* | ||||||||
|
@@ -508,50 +508,131 @@ public function test_process_directives_doesnt_change_html_if_contains_unbalance | |||||||
} | ||||||||
|
||||||||
/** | ||||||||
* Tests that the `process_directives` returns the same HTML if it finds an | ||||||||
* SVG tag. | ||||||||
* Tests that the `process_directives` process the HTML outside a SVG tag. | ||||||||
* | ||||||||
* @ticket 60356 | ||||||||
* @ticket 60517 | ||||||||
* | ||||||||
* @covers ::process_directives | ||||||||
*/ | ||||||||
public function test_process_directives_doesnt_change_html_if_contains_svgs() { | ||||||||
$this->interactivity->state( 'myPlugin', array( 'id' => 'some-id' ) ); | ||||||||
public function test_process_directives_changes_html_if_contains_svgs() { | ||||||||
$this->interactivity->state( | ||||||||
'myPlugin', | ||||||||
array( | ||||||||
'id' => 'some-id', | ||||||||
'width' => '100', | ||||||||
) | ||||||||
); | ||||||||
$html = ' | ||||||||
<div data-wp-bind--id="myPlugin::state.id"> | ||||||||
<svg height="100" width="100"> | ||||||||
<header> | ||||||||
<svg height="100" data-wp-bind--width="myPlugin::state.width"> | ||||||||
<title>Red Circle</title> | ||||||||
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" /> | ||||||||
</svg> | ||||||||
</div> | ||||||||
</svg> | ||||||||
<div data-wp-bind--id="myPlugin::state.id"></div> | ||||||||
<div data-wp-bind--id="myPlugin::state.width"></div> | ||||||||
</header> | ||||||||
'; | ||||||||
$processed_html = $this->interactivity->process_directives( $html ); | ||||||||
$p = new WP_HTML_Tag_Processor( $processed_html ); | ||||||||
$p->next_tag(); | ||||||||
$p->next_tag( 'svg' ); | ||||||||
$this->assertNull( $p->get_attribute( 'width' ) ); | ||||||||
$p->next_tag( 'div' ); | ||||||||
$this->assertEquals( 'some-id', $p->get_attribute( 'id' ) ); | ||||||||
$p->next_tag( 'div' ); | ||||||||
$this->assertEquals( '100', $p->get_attribute( 'id' ) ); | ||||||||
} | ||||||||
|
||||||||
/** | ||||||||
* Tests that the `process_directives` does not process the HTML | ||||||||
* inside SVG tags. | ||||||||
* | ||||||||
* @ticket 60517 | ||||||||
* | ||||||||
* @covers ::process_directives | ||||||||
*/ | ||||||||
public function test_process_directives_does_not_change_inner_html_in_svgs() { | ||||||||
$this->interactivity->state( | ||||||||
'myPlugin', | ||||||||
array( | ||||||||
'id' => 'some-id', | ||||||||
) | ||||||||
); | ||||||||
$html = ' | ||||||||
<header> | ||||||||
<svg height="100"> | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's add a
Suggested change
|
||||||||
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" /> | ||||||||
<g data-wp-bind--id="myPlugin::state.id" /> | ||||||||
</svg> | ||||||||
</header> | ||||||||
'; | ||||||||
$processed_html = $this->interactivity->process_directives( $html ); | ||||||||
$p = new WP_HTML_Tag_Processor( $processed_html ); | ||||||||
$p->next_tag( 'div' ); | ||||||||
$this->assertNull( $p->get_attribute( 'id' ) ); | ||||||||
} | ||||||||
|
||||||||
/** | ||||||||
* Tests that the `process_directives` returns the same HTML if it finds an | ||||||||
* Tests that the `process_directives` process the HTML outside the | ||||||||
* MathML tag. | ||||||||
* | ||||||||
* @ticket 60356 | ||||||||
* @ticket 60517 | ||||||||
* | ||||||||
* @covers ::process_directives | ||||||||
*/ | ||||||||
public function test_process_directives_doesnt_change_html_if_contains_math() { | ||||||||
$this->interactivity->state( 'myPlugin', array( 'id' => 'some-id' ) ); | ||||||||
public function test_process_directives_change_html_if_contains_math() { | ||||||||
$this->interactivity->state( | ||||||||
'myPlugin', | ||||||||
array( | ||||||||
'id' => 'some-id', | ||||||||
'math' => 'ml-id', | ||||||||
) | ||||||||
); | ||||||||
$html = ' | ||||||||
<div data-wp-bind--id="myPlugin::state.id"> | ||||||||
<math> | ||||||||
<header> | ||||||||
<math data-wp-bind--id="myPlugin::state.math"> | ||||||||
<mi>x</mi> | ||||||||
<mo>=</mo> | ||||||||
<mi>1</mi> | ||||||||
</math> | ||||||||
</div> | ||||||||
<div data-wp-bind--id="myPlugin::state.id"></div> | ||||||||
</header> | ||||||||
'; | ||||||||
$processed_html = $this->interactivity->process_directives( $html ); | ||||||||
$p = new WP_HTML_Tag_Processor( $processed_html ); | ||||||||
$p->next_tag(); | ||||||||
$p->next_tag( 'math' ); | ||||||||
$this->assertNull( $p->get_attribute( 'id' ) ); | ||||||||
$p->next_tag( 'div' ); | ||||||||
$this->assertEquals( 'some-id', $p->get_attribute( 'id' ) ); | ||||||||
} | ||||||||
|
||||||||
/** | ||||||||
* Tests that the `process_directives` does not process the HTML | ||||||||
* inside MathML tags. | ||||||||
* | ||||||||
* @ticket 60517 | ||||||||
* | ||||||||
* @covers ::process_directives | ||||||||
*/ | ||||||||
public function test_process_directives_does_not_change_inner_html_in_math() { | ||||||||
$this->interactivity->state( | ||||||||
'myPlugin', | ||||||||
array( | ||||||||
'id' => 'some-id', | ||||||||
) | ||||||||
); | ||||||||
$html = ' | ||||||||
<header> | ||||||||
<math data-wp-bind--id="myPlugin::state.math"> | ||||||||
<mrow data-wp-bind--id="myPlugin::state.id" /> | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indentation nit.
Suggested change
|
||||||||
<mi>x</mi> | ||||||||
<mo>=</mo> | ||||||||
<mi>1</mi> | ||||||||
</math> | ||||||||
</header> | ||||||||
'; | ||||||||
$processed_html = $this->interactivity->process_directives( $html ); | ||||||||
$p = new WP_HTML_Tag_Processor( $processed_html ); | ||||||||
$p->next_tag( 'div' ); | ||||||||
$this->assertNull( $p->get_attribute( 'id' ) ); | ||||||||
} | ||||||||
|
||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just realized that
skip
is the terminology used in the tag processor and also in the description so it would probably be better here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true.