Skip to content

Commit 23c69a8

Browse files
committed
Add v-html text content without modification
Prior to this commit, if the value for `v-html` did not begin with an HTML element tag, it would be wrapped in a `<p>` tag before being added to its node. This introduced inconsistency in rendering, for example: - `'plain text'` became `'<p>plain text</p>'` - but `'<span>span content</span>'` would remain as-is An additional problem is that if the string began with plain text, but contained an element not allowed in a `<p>`, that `<p>` wrapper would be closed early, potentially creating an even more complex structure than expected. for example: - input: `'beginning <div>internal text</div> ending'` - output: `'<p>beginning </p><div>internal text</div> ending'` This wrapping/modification is prevented by wrapping the string in a `<body>` tag before it is given to the HtmlParser. This `<body>` tag is only used as a temporary container. Before, it was added in the parser as an implied tag. Adding it explicitly serves the same function of providing a temporary node to extract childNodes from, without the `<p>` side effect. Additionally, the tests for `v-html` are collected into one, using dataProvider function to cover the variations Bug: T402295
1 parent f866348 commit 23c69a8

File tree

2 files changed

+52
-42
lines changed

2 files changed

+52
-42
lines changed

src/Component.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,10 @@ private function handleFor( DOMNode $node, array $data ) {
323323

324324
private function appendHTML( DOMNode $parent, $source ) {
325325
$htmlParser = new HtmlParser();
326-
$tmpDoc = $htmlParser->parseHtml( $source );
326+
327+
// Wrapping $source in a <body> tag prevents the addition of an implied <p> tag when the
328+
// $source starts with plain text
329+
$tmpDoc = $htmlParser->parseHtml( '<body>' . $source . '</body>' );
327330
foreach ( $htmlParser->getBodyElement( $tmpDoc )->childNodes as $node ) {
328331
$node = $parent->ownerDocument->importNode( $node, true );
329332
$parent->appendChild( $node );

tests/php/TemplatingTest.php

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -93,49 +93,56 @@ public function testTemplateWithVariableAndValueInKorean_ReplacesVariableWithEnc
9393
$this->assertSame( '<p>한국어</p>', $result );
9494
}
9595

96-
public function testTemplateWithVhtmlVariable_ReplacesVariableWithGivenValue() {
97-
$result = $this->createAndRender(
98-
'<div><div v-html="value"></div></div>',
99-
[ 'value' => '<p>some value</p>' ]
100-
);
101-
102-
$this->assertSame( '<div><div><p>some value</p></div></div>', $result );
103-
}
104-
105-
public function testTemplateWithVhtmlVariableNestedData_ReplacesVariableWithGivenValue() {
106-
$result = $this->createAndRender(
107-
'<div><div v-html="value.html"></div></div>',
108-
[ 'value' => [ 'html' => '<p>some value</p>' ] ]
109-
);
110-
111-
$this->assertSame( '<div><div><p>some value</p></div></div>', $result );
112-
}
113-
114-
public function testTemplateWithVhtmlVariableAndAttributeBinding_ReplacesBoth(): void {
115-
$result = $this->createAndRender(
116-
'<div><div :data-a="a" v-html="html"></div></div>',
117-
[ 'a' => 'A', 'html' => '<p>HTML</p>' ]
118-
);
119-
120-
$this->assertSame( '<div><div data-a="A"><p>HTML</p></div></div>', $result );
121-
}
122-
123-
public function testTemplateWithVhtmlAndDiacritcsInValue_ReplacesVariableWithEncodedValue() {
124-
$result = $this->createAndRender(
125-
'<div><div v-html="value"></div></div>',
126-
[ 'value' => '<p>inglés</p>' ]
127-
);
128-
129-
$this->assertSame( '<div><div><p>inglés</p></div></div>', $result );
96+
public static function provideVHtmlValues(): iterable {
97+
return [
98+
'plain text does not get wrapped' => [
99+
'<div v-html="value"></div>',
100+
[ 'value' => 'plain text' ],
101+
'<div>plain text</div>',
102+
],
103+
'starting with plain text, containing html tag' => [
104+
'<div v-html="value"></div>',
105+
[ 'value' => 'beginning text <div>internal div</div> ending text' ],
106+
'<div>beginning text <div>internal div</div> ending text</div>',
107+
],
108+
'variable in child node is replaced' => [
109+
'<div><div v-html="value"></div></div>',
110+
[ 'value' => '<p>some value</p>' ],
111+
'<div><div><p>some value</p></div></div>',
112+
],
113+
'variable with nested value' => [
114+
'<div><div v-html="value.html"></div></div>',
115+
[ 'value' => [ 'html' => '<p>some value</p>' ] ],
116+
'<div><div><p>some value</p></div></div>'
117+
],
118+
'template with v-html and attribute binding' => [
119+
'<div><div :data-a="a" v-html="html"></div></div>',
120+
[ 'a' => 'A', 'html' => '<p>HTML</p>' ],
121+
'<div><div data-a="A"><p>HTML</p></div></div>'
122+
],
123+
'with diacritics in the value' => [
124+
'<div><div v-html="value"></div></div>',
125+
[ 'value' => '<p>inglés</p>' ],
126+
'<div><div><p>inglés</p></div></div>'
127+
],
128+
'with value in Korean' => [
129+
'<div><div v-html="value"></div></div>',
130+
[ 'value' => '<p>한국어</p>' ],
131+
'<div><div><p>한국어</p></div></div>'
132+
]
133+
];
130134
}
131135

132-
public function testTemplateWithVhtmlAndValueInKorean_ReplacesVariableWithEncodedValue() {
133-
$result = $this->createAndRender(
134-
'<div><div v-html="value"></div></div>',
135-
[ 'value' => '<p>한국어</p>' ]
136-
);
137-
138-
$this->assertSame( '<div><div><p>한국어</p></div></div>', $result );
136+
/**
137+
* @dataProvider provideVHtmlValues
138+
*/
139+
public function testTemplateWithVHtmlVariable(
140+
string $template,
141+
array $data,
142+
string $expected
143+
) {
144+
$result = $this->createAndRender( $template, $data );
145+
$this->assertSame( $expected, $result );
139146
}
140147

141148
public function testTemplateWithMustacheVariable_VariableIsUndefined_ThrowsException() {

0 commit comments

Comments
 (0)