From f89eb5d7bb512b181eba1e865f829e4bc6007a45 Mon Sep 17 00:00:00 2001 From: Brent Roose Date: Fri, 15 Nov 2024 13:25:10 +0100 Subject: [PATCH] fix(view): attributes for raw elements (#734) --- .../View/src/Elements/ElementFactory.php | 46 +++++++++---------- src/Tempest/View/src/Elements/RawElement.php | 36 ++++++++++++++- .../TempestViewRendererDataPassingTest.php | 24 ++++++++++ 3 files changed, 80 insertions(+), 26 deletions(-) diff --git a/src/Tempest/View/src/Elements/ElementFactory.php b/src/Tempest/View/src/Elements/ElementFactory.php index 9678b53c3..4d30e4ee0 100644 --- a/src/Tempest/View/src/Elements/ElementFactory.php +++ b/src/Tempest/View/src/Elements/ElementFactory.php @@ -52,12 +52,28 @@ private function makeElement(DOMNode $node, ?Element $parent): ?Element ); } - if ( - ! $node instanceof DOMElement + $attributes = []; + + /** @var DOMAttr $attribute */ + foreach ($node->attributes as $attribute) { + $name = str($attribute->name)->camel()->toString(); + + $attributes[$name] = $attribute->value; + } + + if (! $node instanceof DOMElement || $node->tagName === 'pre' - || $node->tagName === 'code' - ) { - return new RawElement($node->ownerDocument->saveHTML($node)); + || $node->tagName === 'code') { + $content = ''; + foreach ($node->childNodes as $child) { + $content .= $node->ownerDocument->saveHTML($child); + } + + return new RawElement( + tag: $node->tagName ?? null, + content: $content, + attributes: $attributes, + ); } if ($viewComponentClass = $this->viewConfig->viewComponents[$node->tagName] ?? null) { @@ -65,34 +81,16 @@ private function makeElement(DOMNode $node, ?Element $parent): ?Element $viewComponentClass = $this->container->get($viewComponentClass); } - $attributes = []; - - /** @var DOMAttr $attribute */ - foreach ($node->attributes as $attribute) { - $name = (string)str($attribute->name)->camel(); - - $attributes[$name] = $attribute->value; - } - $element = new ViewComponentElement( $this->compiler, $viewComponentClass, - $attributes + $attributes, ); } elseif ($node->tagName === 'x-slot') { $element = new SlotElement( name: $node->getAttribute('name') ?: 'slot', ); } else { - $attributes = []; - - /** @var DOMAttr $attribute */ - foreach ($node->attributes as $attribute) { - $name = (string)str($attribute->name)->camel(); - - $attributes[$name] = $attribute->value; - } - $element = new GenericElement( tag: $node->tagName, attributes: $attributes, diff --git a/src/Tempest/View/src/Elements/RawElement.php b/src/Tempest/View/src/Elements/RawElement.php index 793a622f0..c2b2ef923 100644 --- a/src/Tempest/View/src/Elements/RawElement.php +++ b/src/Tempest/View/src/Elements/RawElement.php @@ -4,6 +4,7 @@ namespace Tempest\View\Elements; +use function Tempest\Support\str; use Tempest\View\Element; final class RawElement implements Element @@ -11,12 +12,43 @@ final class RawElement implements Element use IsElement; public function __construct( - private readonly string $html, + private readonly ?string $tag, + private readonly string $content, + array $attributes, ) { + $this->attributes = $attributes; } public function compile(): string { - return $this->html; + if ($this->tag === null) { + return $this->content; + } + + $attributes = []; + + foreach ($this->getAttributes() as $name => $value) { + $name = str($name); + + if ($name->startsWith(':')) { + $name = ':' . $name->kebab()->toString(); + } else { + $name = $name->kebab()->toString(); + } + + if ($value) { + $attributes[] = $name . '="' . $value . '"'; + } else { + $attributes[] = $name; + } + } + + $attributes = implode(' ', $attributes); + + if ($attributes !== '') { + $attributes = ' ' . $attributes; + } + + return "<{$this->tag}{$attributes}>{$this->content}tag}>"; } } diff --git a/tests/Integration/View/TempestViewRendererDataPassingTest.php b/tests/Integration/View/TempestViewRendererDataPassingTest.php index 266545578..0f6d78d5d 100644 --- a/tests/Integration/View/TempestViewRendererDataPassingTest.php +++ b/tests/Integration/View/TempestViewRendererDataPassingTest.php @@ -262,4 +262,28 @@ public function test_boolean_attributes(): void HTML, value: 'value', selected: false, name: 'name'), ); } + + public function test_expression_attribute_in_raw_element(): void + { + $this->registerViewComponent( + 'x-test', + <<<'HTML' +
+ HTML, + ); + + $html = $this->render(<<<'HTML' + +
foo

bar

+
+ HTML, language: 'php'); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'HTML' +
foo

bar

+
+ HTML, + $html + ); + } }