Skip to content

Commit

Permalink
Create invisible duplicate submit button if more than one `submitElem…
Browse files Browse the repository at this point in the history
…ents` is present
  • Loading branch information
TAINCER committed Feb 14, 2023
1 parent 7208f1a commit 857b6bf
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 0 deletions.
16 changes: 16 additions & 0 deletions asset/css/primary-submit-btn-duplicate.less
Original file line number Diff line number Diff line change
@@ -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;
}
49 changes: 49 additions & 0 deletions src/Compat/CompatForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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()) {
Expand All @@ -22,4 +47,28 @@ 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 = array_reduce(
$originalSubmitButton->getAttributes()->getIterator()->getArrayCopy(),
function ($accumulator, $attribute) {
$accumulator[$attribute->getName()] = $attribute->getValue();
},
[]
);
$attributes['class'] = 'primary-submit-btn-duplicate';

$submit = (new SubmitElement($originalSubmitButton->getName(), $attributes))
->setValue($originalSubmitButton->getValue());

return $submit;
}
}
92 changes: 92 additions & 0 deletions tests/Compat/CompatFormTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

namespace ipl\Tests\Web\Compat;

use ipl\Html\FormElement\SubmitElement;
use ipl\Tests\Html\TestCase;
use ipl\Web\Compat\CompatForm;

class CompatFormTest extends TestCase
{
/** @var CompatForm */
private $form;

protected function setUp(): void
{
$this->form = new CompatForm();
}

public function testDuplicateSubmitButtonApplied(): void
{
$this->form->addElement('submit', 'submitCreate');
$this->form->addElement('submit', 'submitDelete');

$expected = <<<'HTML'
<form class="icinga-form icinga-controls" method="POST">
<input class="primary-submit-btn-duplicate" name="submitCreate" type="submit" value="submitCreate"/>
<div class="control-group form-controls">
<input class="btn-primary" name="submitCreate" type="submit" value="submitCreate"/>
</div>
<div class="control-group form-controls">
<input class="btn-primary" name="submitDelete" type="submit" value="submitDelete"/>
</div>
</form>
HTML;

$this->assertHtml($expected, $this->form);
}

public function testDuplicateSubmitButtonOmitted(): void
{
$this->form->addElement('submit', 'submitCreate');

$expected = <<<'HTML'
<form class="icinga-form icinga-controls" method="POST">
<div class="control-group form-controls">
<input class="btn-primary" name="submitCreate" type="submit" value="submitCreate"/>
</div>
</form>
HTML;

$this->assertHtml($expected, $this->form);
}

public function testDuplicateSubmitButtonAddedOnlyOnce(): void
{
$this->form->addElement('submit', 'submitCreate');
$this->form->addElement('submit', 'submitDelete');

$expected = <<<'HTML'
<form class="icinga-form icinga-controls" method="POST">
<input class="primary-submit-btn-duplicate" name="submitCreate" type="submit" value="submitCreate"/>
<div class="control-group form-controls">
<input class="btn-primary" name="submitCreate" type="submit" value="submitCreate"/>
</div>
<div class="control-group form-controls">
<input class="btn-primary" name="submitDelete" type="submit" value="submitDelete"/>
</div>
</form>
HTML;

$this->form->render();

$this->assertHtml($expected, $this->form);
}

public function testCreatingDuplicateSubmitButton(): void
{
$submitButton = new SubmitElement('test_submit', [
'class' => 'autosubmit'
]);

$prefixButton = $this->form->duplicateSubmitButton($submitButton);

// Name should stay the same
$this->assertSame($submitButton->getName(), 'test_submit');
$this->assertSame($prefixButton->getName(), 'test_submit');

// 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');
}
}

0 comments on commit 857b6bf

Please sign in to comment.