From 7208f1aae4c15b4d336a4032971c385003fce503 Mon Sep 17 00:00:00 2001 From: Timm Ortloff Date: Tue, 14 Feb 2023 11:17:56 +0100 Subject: [PATCH 1/2] composer.json: Add ipl-html tests Namespace to autoload --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 90173f1f..96a9b1e5 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ }, "autoload-dev": { "psr-4": { - "ipl\\Tests\\Web\\": "tests" + "ipl\\Tests\\Web\\": "tests", + "ipl\\Tests\\Html\\": "vendor/ipl/html/tests" } }, "require": { From 811318c6ed7167b75840e9092f14614ee0ce91f0 Mon Sep 17 00:00:00 2001 From: Timm Ortloff Date: Tue, 14 Feb 2023 11:19:15 +0100 Subject: [PATCH 2/2] Create invisible duplicate submit button if more than one `submitElements` is present --- asset/css/primary-submit-btn-duplicate.less | 16 ++++ src/Compat/CompatForm.php | 41 +++++++++ tests/Compat/CompatFormTest.php | 97 +++++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 asset/css/primary-submit-btn-duplicate.less create mode 100644 tests/Compat/CompatFormTest.php diff --git a/asset/css/primary-submit-btn-duplicate.less b/asset/css/primary-submit-btn-duplicate.less new file mode 100644 index 00000000..aae545f0 --- /dev/null +++ b/asset/css/primary-submit-btn-duplicate.less @@ -0,0 +1,16 @@ +/** + Automatically set CSS class for duplicated submit buttons + used for implicit form submission that should be invisible + and not take up any space. `display: none` is not an option, + because at least Safari will then ignore the element completely + when submitting a form. + */ +.primary-submit-btn-duplicate { + border: 0; + height: 0; + margin: 0; + padding: 0; + visibility: hidden; + width: 0; + position: absolute; +} diff --git a/src/Compat/CompatForm.php b/src/Compat/CompatForm.php index b759b8fa..e918b228 100644 --- a/src/Compat/CompatForm.php +++ b/src/Compat/CompatForm.php @@ -2,7 +2,11 @@ namespace ipl\Web\Compat; +use ipl\Html\Contract\FormSubmitElement; use ipl\Html\Form; +use ipl\Html\FormElement\SubmitElement; +use ipl\Html\HtmlDocument; +use ipl\Html\HtmlString; use ipl\I18n\Translation; use ipl\Web\FormDecorator\IcingaFormDecorator; @@ -12,6 +16,27 @@ class CompatForm extends Form protected $defaultAttributes = ['class' => 'icinga-form icinga-controls']; + /** + * Render the content of the element to HTML + * + * A duplicate of the primary submit button is being prepended if there is more than one present + * + * @return string + */ + public function renderContent(): string + { + if (count($this->submitElements) > 1) { + return (new HtmlDocument()) + ->setHtmlContent( + $this->duplicateSubmitButton($this->submitButton), + new HtmlString(parent::renderContent()) + ) + ->render(); + } + + return parent::renderContent(); + } + public function hasDefaultElementDecorator() { if (parent::hasDefaultElementDecorator()) { @@ -22,4 +47,20 @@ public function hasDefaultElementDecorator() return true; } + + /** + * Return a duplicate of the given submit button with the `class` attribute fixed to `primary-submit-btn-duplicate` + * + * @param FormSubmitElement $originalSubmitButton + * + * @return SubmitElement + */ + public function duplicateSubmitButton(FormSubmitElement $originalSubmitButton): SubmitElement + { + $attributes = (clone $originalSubmitButton->getAttributes()) + ->set('class', 'primary-submit-btn-duplicate'); + $attributes->remove('id'); + + return new SubmitElement($originalSubmitButton->getName(), $attributes); + } } diff --git a/tests/Compat/CompatFormTest.php b/tests/Compat/CompatFormTest.php new file mode 100644 index 00000000..ef81ee76 --- /dev/null +++ b/tests/Compat/CompatFormTest.php @@ -0,0 +1,97 @@ +form = new CompatForm(); + } + + public function testDuplicateSubmitButtonApplied(): void + { + $this->form->addElement('submit', 'submitCreate'); + $this->form->addElement('submit', 'submitDelete'); + + $expected = <<<'HTML' +
+ +
+ +
+
+ +
+
+HTML; + + $this->assertHtml($expected, $this->form); + } + + public function testDuplicateSubmitButtonOmitted(): void + { + $this->form->addElement('submit', 'submitCreate'); + + $expected = <<<'HTML' +
+
+ +
+
+HTML; + + $this->assertHtml($expected, $this->form); + } + + public function testDuplicateSubmitButtonAddedOnlyOnce(): void + { + $this->form->addElement('submit', 'submitCreate', ['id' => 'submit_id']); + $this->form->addElement('submit', 'submitDelete'); + + $expected = <<<'HTML' +
+ +
+ +
+
+ +
+
+HTML; + + // Call render twice to ensure that the submit button is only prepended once. + $this->form->render(); + $this->assertHtml($expected, $this->form); + } + + public function testDuplicateSubmitButtonRespectsOriginalAttributes(): void + { + $submitButton = new SubmitElement('test_submit', [ + 'class' => 'autosubmit', + 'formnovalidate' => true + ]); + + $prefixButton = $this->form->duplicateSubmitButton($submitButton); + + // Name should stay the same + $this->assertSame($submitButton->getName(), 'test_submit'); + $this->assertSame($prefixButton->getName(), 'test_submit'); + + // Added attributes should stay the same + $this->assertSame($submitButton->getAttributes()->get('formnovalidate')->getValue(), true); + $this->assertSame($prefixButton->getAttributes()->get('formnovalidate')->getValue(), true); + + // Class attribute should change to `primary-submit-btn-duplicate` + $this->assertSame($submitButton->getAttributes()->get('class')->getValue(), 'autosubmit'); + $this->assertSame($prefixButton->getAttributes()->get('class')->getValue(), 'primary-submit-btn-duplicate'); + } +}