diff --git a/src/Tags/Concerns/RendersAttributes.php b/src/Tags/Concerns/RendersAttributes.php index 5953ed570e..c5bb8a02db 100644 --- a/src/Tags/Concerns/RendersAttributes.php +++ b/src/Tags/Concerns/RendersAttributes.php @@ -37,15 +37,12 @@ protected function renderAttributes($attributes) /** * Render HTML attributes from tag params. * - * Parameters that are not prefixed with attr: will be automatically removed. - * + * @param array $except Parameters that should be excluded. Typically used for tag parameters that control behavior. * @return string */ - protected function renderAttributesFromParams() + protected function renderAttributesFromParams(array $except = []) { - $params = $this->params->filter(function ($value, $attribute) { - return preg_match('/^attr:/', $attribute); - })->all(); + $params = $this->params->reject(fn ($v, $attr) => in_array($attr, $except))->all(); return $this->renderAttributes($params); } @@ -55,11 +52,11 @@ protected function renderAttributesFromParams() * * @return string */ - protected function renderAttributesFromParamsWith(array $attrs) + protected function renderAttributesFromParamsWith(array $attrs, array $except = []) { return collect([ $this->renderAttributes($attrs), - $this->renderAttributesFromParams(), + $this->renderAttributesFromParams($except), ])->filter()->implode(' '); } } diff --git a/src/Tags/Concerns/RendersForms.php b/src/Tags/Concerns/RendersForms.php index 2f74515451..f80ba5c479 100644 --- a/src/Tags/Concerns/RendersForms.php +++ b/src/Tags/Concerns/RendersForms.php @@ -70,7 +70,10 @@ protected function formOpen($action, $method = 'POST', $knownTagParams = [], $ad $attrs['enctype'] = 'multipart/form-data'; } - $attrs = $this->renderAttributesFromParamsWith($attrs); + $attrs = $this->renderAttributesFromParamsWith( + $attrs, + except: array_merge(['method', 'action'], $knownTagParams) + ); $html = collect(['filter()->implode(' ').'>'; diff --git a/src/Tags/Svg.php b/src/Tags/Svg.php index 5f3c9775ff..eabcdf34c8 100644 --- a/src/Tags/Svg.php +++ b/src/Tags/Svg.php @@ -48,7 +48,7 @@ public function index() $svg = $this->params->get('src'); } - $attributes = $this->renderAttributesFromParams(); + $attributes = $this->renderAttributesFromParams(except: ['src', 'title', 'desc', 'sanitize']); if ($this->params->get('title') || $this->params->get('desc')) { $svg = $this->setTitleAndDesc($svg); diff --git a/tests/Fieldtypes/IconTest.php b/tests/Fieldtypes/IconTest.php index 258fc40339..7500fdb0cb 100644 --- a/tests/Fieldtypes/IconTest.php +++ b/tests/Fieldtypes/IconTest.php @@ -21,7 +21,7 @@ public function it_finds_default_icons() /** @test */ public function it_accepts_svg_strings() { - $result = (string) Antlers::parse('{{ svg :src="test" attr:class="w-4 h-4" sanitize="false" }}', ['test' => new Value('add', $this->fieldtype())]); + $result = (string) Antlers::parse('{{ svg :src="test" class="w-4 h-4" sanitize="false" }}', ['test' => new Value('add', $this->fieldtype())]); $this->assertStringContainsString('assertEquals('', $this->tag->renderAttributes([])); $output = $this->tag->renderAttributes([ - 'attr:class' => 'm-0 mb-2', - 'attr::name' => 'first_name', - 'attr:disabled' => 'true', - 'attr:autocomplete' => true, - 'attr:focusable' => false, - 'attr:dont_render_nulls' => null, + 'class' => 'm-0 mb-2', + ':name' => 'first_name', + 'disabled' => 'true', + 'autocomplete' => true, + 'focusable' => false, + 'dont_render_nulls' => null, ]); $this->assertEquals('class="m-0 mb-2" :name="first_name" disabled="true" autocomplete="true" focusable="false"', $output); @@ -43,18 +43,64 @@ public function it_renders_attributes_from_params() $output = $this->tag ->setContext(['first_name' => 'Han']) ->setParameters([ - 'attr:class' => 'm-0 mb-2', - ':attr:name' => 'first_name', + 'class' => 'm-0 mb-2', + ':name' => 'first_name', 'attr:src' => 'avatar.jpg', - 'attr:focusable' => false, - 'attr:dont_render_nulls' => null, - 'attr:disabled' => 'true', - 'attr:autocomplete' => true, + 'focusable' => false, + 'dont_render_nulls' => null, + 'disabled' => 'true', + 'autocomplete' => true, ]) ->renderAttributesFromParams(); $this->assertEquals('class="m-0 mb-2" name="Han" src="avatar.jpg" focusable="false" disabled="true" autocomplete="true"', $output); } + + /** @test */ + public function it_wont_render_attributes_for_known_params_unless_attr_prepended() + { + $output = $this->tag + ->setParameters([ + 'class' => 'm-0 mb-2', + 'src' => 'avatar.jpg', + 'name' => 'Han', + ]) + ->renderAttributesFromParams(except: ['src', 'name']); + + $this->assertEquals('class="m-0 mb-2"', $output); + + $output = $this->tag + ->setParameters([ + 'class' => 'm-0 mb-2', + 'attr:src' => 'avatar.jpg', + 'name' => 'Han', + ]) + ->renderAttributesFromParams(['src', 'name']); + + $this->assertEquals('class="m-0 mb-2" src="avatar.jpg"', $output); + } + + /** @test */ + public function it_will_render_falsy_attributes() + { + $this->assertEquals('', $this->tag->renderAttributesFromParams()); + + $output = $this->tag + ->setContext(['first_name' => 'Han']) + ->setParameters([ + 'class' => 'm-0 mb-2', + ':name' => 'first_name', + 'attr:src' => 'avatar.jpg', + 'focusable' => false, + 'dont_render_nulls' => null, + 'disabled' => 'true', + 'autocomplete' => true, + 'aria-hidden' => true, + ]) + ->renderAttributesFromParams(); + + $this->assertEquals('class="m-0 mb-2" name="Han" src="avatar.jpg" focusable="false" disabled="true" autocomplete="true" aria-hidden="true"', $output); + } } class FakeTagWithRendersAttributes extends Tags diff --git a/tests/Tags/Concerns/RendersFormsTest.php b/tests/Tags/Concerns/RendersFormsTest.php index f84597ebd7..ceae4c5bf5 100644 --- a/tests/Tags/Concerns/RendersFormsTest.php +++ b/tests/Tags/Concerns/RendersFormsTest.php @@ -47,7 +47,7 @@ public function it_renders_form_open_tags_with_custom_attributes() { $output = $this->tag ->setParameters([ - 'attr:class' => 'mb-2', + 'class' => 'mb-2', 'attr:id' => 'form', 'method' => 'this should not render', 'action' => 'this should not render', diff --git a/tests/Tags/Form/FormCreateTest.php b/tests/Tags/Form/FormCreateTest.php index 805ad4d43c..d097f5d699 100644 --- a/tests/Tags/Form/FormCreateTest.php +++ b/tests/Tags/Form/FormCreateTest.php @@ -36,7 +36,7 @@ public function it_renders_form() /** @test */ public function it_renders_form_with_params() { - $output = $this->tag('{{ form:contact redirect="/submitted" error_redirect="/errors" attr:class="form" attr:id="form" }}{{ /form:contact }}'); + $output = $this->tag('{{ form:contact redirect="/submitted" error_redirect="/errors" class="form" id="form" }}{{ /form:contact }}'); $this->assertStringStartsWith('
', $output); $this->assertStringContainsString('', $output); diff --git a/tests/Tags/SvgTagTest.php b/tests/Tags/SvgTagTest.php index 40a8155da0..d2c82f12b1 100644 --- a/tests/Tags/SvgTagTest.php +++ b/tests/Tags/SvgTagTest.php @@ -30,7 +30,7 @@ public function it_renders_svg() /** @test */ public function it_renders_svg_with_additional_params() { - $this->assertStringStartsWith('assertStringStartsWith('tag('{{ user:forgot_password_form redirect="/submitted" error_redirect="/errors" reset_url="/resetting" attr:class="form" attr:id="form" }}{{ /user:forgot_password_form }}'); + $output = $this->tag('{{ user:forgot_password_form redirect="/submitted" error_redirect="/errors" reset_url="/resetting" class="form" id="form" }}{{ /user:forgot_password_form }}'); $this->assertStringStartsWith('
', $output); $this->assertStringContainsString('', $output); diff --git a/tests/Tags/User/LoginFormTest.php b/tests/Tags/User/LoginFormTest.php index 75fc7c8df4..0f6c069508 100644 --- a/tests/Tags/User/LoginFormTest.php +++ b/tests/Tags/User/LoginFormTest.php @@ -30,7 +30,7 @@ public function it_renders_form() /** @test */ public function it_renders_form_with_params() { - $output = $this->tag('{{ user:login_form redirect="/submitted" error_redirect="/errors" attr:class="form" attr:id="form" }}{{ /user:login_form }}'); + $output = $this->tag('{{ user:login_form redirect="/submitted" error_redirect="/errors" class="form" id="form" }}{{ /user:login_form }}'); $this->assertStringStartsWith('
', $output); $this->assertStringContainsString('', $output); diff --git a/tests/Tags/User/PasswordFormTest.php b/tests/Tags/User/PasswordFormTest.php index 495b757b4e..f7383cd71d 100644 --- a/tests/Tags/User/PasswordFormTest.php +++ b/tests/Tags/User/PasswordFormTest.php @@ -34,7 +34,7 @@ public function it_renders_form_with_params() { $this->actingAs(User::make()->password('mypassword')->save()); - $output = $this->tag('{{ user:password_form redirect="/submitted" error_redirect="/errors" attr:class="form" attr:id="form" }}{{ /user:password_form }}'); + $output = $this->tag('{{ user:password_form redirect="/submitted" error_redirect="/errors" class="form" id="form" }}{{ /user:password_form }}'); $this->assertStringStartsWith('
', $output); $this->assertStringContainsString('', $output); diff --git a/tests/Tags/User/ProfileFormTest.php b/tests/Tags/User/ProfileFormTest.php index 450213814b..6abfc404c7 100644 --- a/tests/Tags/User/ProfileFormTest.php +++ b/tests/Tags/User/ProfileFormTest.php @@ -35,7 +35,7 @@ public function it_renders_form_with_params() { $this->actingAs(User::make()->save()); - $output = $this->tag('{{ user:profile_form redirect="/submitted" error_redirect="/errors" attr:class="form" attr:id="form" }}{{ /user:profile_form }}'); + $output = $this->tag('{{ user:profile_form redirect="/submitted" error_redirect="/errors" class="form" id="form" }}{{ /user:profile_form }}'); $this->assertStringStartsWith('
', $output); $this->assertStringContainsString('', $output); diff --git a/tests/Tags/User/RegisterFormTest.php b/tests/Tags/User/RegisterFormTest.php index 77c7d4df04..d83f5a7934 100644 --- a/tests/Tags/User/RegisterFormTest.php +++ b/tests/Tags/User/RegisterFormTest.php @@ -36,7 +36,7 @@ public function it_renders_form() /** @test */ public function it_renders_form_with_params() { - $output = $this->tag('{{ user:register_form redirect="/submitted" error_redirect="/errors" attr:class="form" attr:id="form" }}{{ /user:register_form }}'); + $output = $this->tag('{{ user:register_form redirect="/submitted" error_redirect="/errors" class="form" id="form" }}{{ /user:register_form }}'); $this->assertStringStartsWith('
', $output); $this->assertStringContainsString('', $output);