-
Notifications
You must be signed in to change notification settings - Fork 11
SSR: Add wp-show
attribute directive processor
#141
Changes from all commits
446ca57
8a66bac
bc4adf3
4e288c8
86d5d4a
bb9b748
929a6f2
fd977a1
5b63332
6f281f9
d5ade51
f8e005c
f4fa160
cef691c
9eae803
ba75900
7eb3777
665b4cb
f1eee33
d2e68d3
059fe61
87f0532
042501d
e3d1743
229c304
e864093
81a9846
d9e5271
e431beb
39ccb18
40ee90d
4d88309
2a70577
9430be8
1dc96a2
f1a473a
e892856
9c95d2d
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 |
---|---|---|
@@ -0,0 +1,176 @@ | ||
<?php | ||
/** | ||
* data-wp-show tag directive test. | ||
*/ | ||
|
||
require_once __DIR__ . '/../../../src/directives/attributes/wp-show.php'; | ||
|
||
require_once __DIR__ . '/../../../src/directives/class-wp-directive-context.php'; | ||
require_once __DIR__ . '/../../../src/directives/class-wp-directive-processor.php'; | ||
|
||
require_once __DIR__ . '/../../../src/directives/wp-html.php'; | ||
|
||
/** | ||
* Tests for the wp-show tag directive. | ||
* | ||
* @group directives | ||
* @covers process_wp_show | ||
*/ | ||
class Tests_Directives_WpShow extends WP_UnitTestCase { | ||
public function test_directive_leaves_content_unchanged_if_when_is_true() { | ||
$markup = '<div data-wp-show="context.myblock.open">I should be shown!</div>'; | ||
$tags = new WP_Directive_Processor( $markup ); | ||
$tags->next_tag(); | ||
|
||
$context_before = new WP_Directive_Context( array( 'myblock' => array( 'open' => true ) ) ); | ||
$context = clone $context_before; | ||
process_wp_show( $tags, $context ); | ||
|
||
$tags->next_tag( array( 'tag_closers' => 'visit' ) ); | ||
process_wp_show( $tags, $context ); | ||
|
||
$this->assertSame( $markup, $tags->get_updated_html() ); | ||
$this->assertSame( $context_before->get_context(), $context->get_context(), 'data-wp-show directive changed context' ); | ||
} | ||
|
||
public function test_directive_wraps_content_in_template_if_when_is_false() { | ||
$markup = '<div data-wp-show="context.myblock.open">I should not be shown!</div>'; | ||
|
||
$tags = new WP_Directive_Processor( $markup ); | ||
$tags->next_tag(); | ||
|
||
$context_before = new WP_Directive_Context( array( 'myblock' => array( 'open' => false ) ) ); | ||
$context = clone $context_before; | ||
process_wp_show( $tags, $context ); | ||
|
||
$tags->next_tag( array( 'tag_closers' => 'visit' ) ); | ||
process_wp_show( $tags, $context ); | ||
|
||
$updated_markup = '<template data-wp-show="context.myblock.open"><div >I should not be shown!</div></template>'; | ||
|
||
$this->assertSame( $updated_markup, $tags->get_updated_html() ); | ||
$this->assertSame( $context_before->get_context(), $context->get_context(), 'data-wp-show directive changed context' ); | ||
} | ||
|
||
public function test_directive_does_not_wrap_template_in_template() { | ||
$markup = '<template data-wp-show="context.myblock.open">I should not be shown!</template>'; | ||
|
||
$tags = new WP_Directive_Processor( $markup ); | ||
$tags->next_tag(); | ||
|
||
$context_before = new WP_Directive_Context( array( 'myblock' => array( 'open' => false ) ) ); | ||
$context = clone $context_before; | ||
process_wp_show( $tags, $context ); | ||
|
||
$tags->next_tag( array( 'tag_closers' => 'visit' ) ); | ||
process_wp_show( $tags, $context ); | ||
|
||
$this->assertSame( $markup, $tags->get_updated_html() ); | ||
$this->assertSame( $context_before->get_context(), $context->get_context(), 'data-wp-show directive changed context' ); | ||
} | ||
|
||
public function test_directive_wraps_content_preceded_by_other_html_in_template_if_when_is_false() { | ||
$markup = '<p>Some text</p><div data-wp-show="context.myblock.open">I should not be shown!</div>'; | ||
|
||
$tags = new WP_Directive_Processor( $markup ); | ||
$tags->next_tag( 'div' ); | ||
|
||
$context_before = new WP_Directive_Context( array( 'myblock' => array( 'open' => false ) ) ); | ||
$context = clone $context_before; | ||
process_wp_show( $tags, $context ); | ||
|
||
$tags->next_tag( array( 'tag_closers' => 'visit' ) ); | ||
process_wp_show( $tags, $context ); | ||
|
||
$updated_markup = '<p>Some text</p><template data-wp-show="context.myblock.open"><div >I should not be shown!</div></template>'; | ||
|
||
$this->assertSame( $updated_markup, $tags->get_updated_html() ); | ||
$this->assertSame( $context_before->get_context(), $context->get_context(), 'data-wp-show directive changed context' ); | ||
} | ||
|
||
public function test_directive_wraps_void_tag_in_template_if_when_is_false() { | ||
$markup = '<img data-wp-show="context.myblock.open">'; | ||
$tags = new WP_Directive_Processor( $markup ); | ||
$tags->next_tag(); | ||
|
||
$context_before = new WP_Directive_Context( array( 'myblock' => array( 'open' => false ) ) ); | ||
$context = clone $context_before; | ||
process_wp_show( $tags, $context ); | ||
|
||
$tags->next_tag( array( 'tag_closers' => 'visit' ) ); | ||
process_wp_show( $tags, $context ); | ||
|
||
$updated_markup = '<template data-wp-show="context.myblock.open"><img ></template>'; | ||
|
||
$this->assertSame( $updated_markup, $tags->get_updated_html() ); | ||
$this->assertSame( $context_before->get_context(), $context->get_context(), 'data-wp-show directive changed context' ); | ||
} | ||
|
||
public function test_nested_directives_within_wp_show_with_truthy_value() { | ||
$markup = <<<END | ||
<div data-wp-show="context.myBlock.open"> | ||
I should be shown! | ||
<div data-wp-show="context.myOtherBlock.open">I should be shown!</div> | ||
<div data-wp-show="!context.myOtherBlock.open">I should not be shown!</div> | ||
</div> | ||
END; | ||
|
||
$context_before = new WP_Directive_Context( | ||
array( | ||
'myBlock' => array( 'open' => true ), | ||
'myOtherBlock' => array( 'open' => true ), | ||
) | ||
); | ||
$context = clone $context_before; | ||
|
||
$tags = new WP_Directive_Processor( $markup ); | ||
|
||
while ( $tags->next_tag( array( 'tag_closers' => 'visit' ) ) ) { | ||
process_wp_show( $tags, $context ); | ||
} | ||
|
||
$updated_markup = <<<END | ||
<div data-wp-show="context.myBlock.open"> | ||
I should be shown! | ||
<div data-wp-show="context.myOtherBlock.open">I should be shown!</div> | ||
<template data-wp-show="!context.myOtherBlock.open"><div >I should not be shown!</div></template> | ||
</div> | ||
END; | ||
$this->assertSame( $updated_markup, $tags->get_updated_html() ); | ||
$this->assertSame( $context_before->get_context(), $context->get_context(), 'data-wp-show directive changed context' ); | ||
} | ||
|
||
public function test_nested_directives_within_wp_show_with_falsy_value() { | ||
$markup = <<<END | ||
<div data-wp-show="context.myBlock.open"> | ||
I should not be shown! | ||
<div data-wp-show="context.myOtherBlock.open">I should be shown!</div> | ||
<div data-wp-show="!context.myOtherBlock.open">I should not be shown!</div> | ||
</div> | ||
END; | ||
|
||
$context_before = new WP_Directive_Context( | ||
array( | ||
'myBlock' => array( 'open' => false ), | ||
'myOtherBlock' => array( 'open' => true ), | ||
) | ||
); | ||
$context = clone $context_before; | ||
|
||
$tags = new WP_Directive_Processor( $markup ); | ||
|
||
while ( $tags->next_tag( array( 'tag_closers' => 'visit' ) ) ) { | ||
process_wp_show( $tags, $context ); | ||
} | ||
|
||
$updated_markup = <<<END | ||
<template data-wp-show="context.myBlock.open"><div > | ||
I should not be shown! | ||
<div data-wp-show="context.myOtherBlock.open">I should be shown!</div> | ||
<template data-wp-show="!context.myOtherBlock.open"><div >I should not be shown!</div></template> | ||
</div></template> | ||
END; | ||
$this->assertSame( $updated_markup, $tags->get_updated_html() ); | ||
$this->assertSame( $context_before->get_context(), $context->get_context(), 'data-wp-show directive changed context' ); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php | ||
/** | ||
* Process wp-show directive attribute. | ||
* | ||
* @package wp-directives | ||
*/ | ||
|
||
/** Utility functions */ | ||
require_once __DIR__ . '/../utils.php'; | ||
|
||
/** | ||
* Process wp-show directive attribute. | ||
* | ||
* @param WP_Directive_Processor $tags Tags. | ||
* @param WP_Directive_Context $context Directive context. | ||
*/ | ||
function process_wp_show( $tags, $context ) { | ||
if ( $tags->is_tag_closer() ) { | ||
return; | ||
} | ||
|
||
$value = $tags->get_attribute( 'data-wp-show' ); | ||
if ( null === $value ) { | ||
return; | ||
} | ||
|
||
$show = evaluate( $value, $context->get_context() ); | ||
if ( $show ) { | ||
return; | ||
} | ||
|
||
if ( 'TEMPLATE' === $tags->get_tag() ) { | ||
return; // Don't wrap a `<template>` in a `<template>`. | ||
} | ||
|
||
$wrapper_bookmark = $tags->wrap_in_tag( 'TEMPLATE' ); | ||
$tags->seek( $wrapper_bookmark ); | ||
$tags->set_attribute( 'data-wp-show', $value ); | ||
$tags->next_tag(); | ||
$tags->remove_attribute( 'data-wp-show' ); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -131,6 +131,84 @@ public function get_balanced_tag_bookmarks() { | |
return array( $start_name, $end_name ); | ||
} | ||
|
||
/** | ||
* Wrap the current node in a given tag. | ||
* | ||
* When positioned on a tag opener, locate its matching closer, and wrap everything | ||
* in the tag specified as an argument. When positioned on a void element, wrap that | ||
* element in the argument tag. | ||
* | ||
* Note that the internal pointer will continue to point to the same tag as before | ||
* calling the function. | ||
* | ||
* @param string $tag An HTML tag, specified in uppercase (e.g. "DIV"). | ||
* @return string|false The name of a bookmark pointing to the wrapping tag opener | ||
* if successful; false otherwise. | ||
* | ||
* @todo Allow passing in tags with attributes, e.g. <template id="abc">? | ||
Comment on lines
+144
to
+148
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. Note that we're only accepting an uppercase HTML tag such as We can eschew most of these questions by only allowing a tag name; handling of attributes can be done after the fact and separately in 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. maybe we could call the argument |
||
*/ | ||
public function wrap_in_tag( $tag ) { | ||
if ( $this->is_tag_closer() ) { | ||
return false; | ||
} | ||
|
||
if ( self::is_html_void_element( $tag ) ) { | ||
// _doing_it_wrong( | ||
// __METHOD__, | ||
// __( 'Cannot wrap HTML in void tag.' ), | ||
// '6.3.0' | ||
// ); | ||
return false; | ||
} | ||
|
||
$this->get_updated_html(); // Apply potential previous updates. | ||
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. After applying the fix in 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. And this is the test I used to reproduce… public function blahblahblah() {
$p = new WP_Directive_Processor( '<div><img hidden></div>' );
$p->next_tag();
$p->next_tag('img');
$p->set_attribute( 'inert', true );
$p->remove_attribute( 'hidden' );
$b = $p->wrap_in_tag( 'figure' );
$this->assertSame( 'IMG', $p->get_tag() );
$p->seek( $b );
$this->assertSame( 'FIGURE', $p->get_tag() );
$p->next_tag();
$this->assertSame( 'IMG', $p->get_tag() );
$this->assertSame( '<div><figure><img inert ></figure></div>', $p->get_updated_html() );
} 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. Thank you! I just tested your patch (plus the removal of that On a sidenote -- it strikes me as odd that we need to remove 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. Also, the tests that are currently failing on this branch are still failing with your patch applied and that To verify that your patch was properly picked up, I copied the test from WordPress/wordpress-develop#4345 into 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.
yeah I've been working on figuring this out better
this is why I had tried to carefully word that my patch fixed my tests as I suspected we could still have more in this PR. 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. For the record, I've filed a PR against 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. Noting that @dmsnell managed to reduce that test case to be more minimal and has filed a PR with a tentative fix: WordPress/wordpress-develop#4371 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. and it's fixed now! |
||
|
||
if ( self::is_html_void_element( $this->get_tag() ) ) { | ||
// We don't have direct access to the start and end position of the | ||
// current tag. As a workaround, we set a bookmark that we then | ||
// release immediately. | ||
$i = 0; | ||
while ( array_key_exists( 'void' . $i, $this->bookmarks ) ) { | ||
++$i; | ||
} | ||
$start_name = 'void' . $i; | ||
|
||
$this->set_bookmark( $start_name ); | ||
|
||
$start = $this->bookmarks[ $start_name ]->start; | ||
$end = $this->bookmarks[ $start_name ]->end + 1; | ||
} else { | ||
$bookmarks = $this->get_balanced_tag_bookmarks(); | ||
if ( ! $bookmarks ) { | ||
return false; | ||
} | ||
list( $start_name, $end_name ) = $bookmarks; | ||
|
||
$start = $this->bookmarks[ $start_name ]->start; | ||
$end = $this->bookmarks[ $end_name ]->end + 1; | ||
|
||
$this->release_bookmark( $end_name ); | ||
} | ||
|
||
$tag = strtolower( $tag ); | ||
$this->lexical_updates[] = new WP_HTML_Text_Replacement( $start, $start, "<$tag>" ); | ||
$this->lexical_updates[] = new WP_HTML_Text_Replacement( $end, $end, "</$tag>" ); | ||
|
||
$this->seek( $start_name ); // Return to original position. | ||
$this->release_bookmark( $start_name ); | ||
|
||
$i = 0; | ||
while ( array_key_exists( $tag . $i, $this->bookmarks ) ) { | ||
++$i; | ||
} | ||
$bookmark_name = $tag . $i; | ||
$this->bookmarks[ $bookmark_name ] = new WP_HTML_Span( | ||
$start, | ||
$start + strlen( $tag ) + 2 | ||
); | ||
return $bookmark_name; | ||
} | ||
|
||
/** | ||
* Whether a given HTML element is void (e.g. <br>). | ||
* | ||
|
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.
Should it convert
div
totemplate
inside anothertemplate
? That was the reason I wanted to see those tests, so they cover edge cases like that.