Skip to content

Commit

Permalink
Customizable column widths for horizontal Bootstrap forms
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinMystikJonas authored and f3l1x committed Jul 26, 2022
1 parent fd8627c commit d71fa5a
Show file tree
Hide file tree
Showing 22 changed files with 221 additions and 87 deletions.
39 changes: 39 additions & 0 deletions src/Rendering/AbstractBootstrapHorizontalRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php declare(strict_types = 1);

namespace Contributte\Forms\Rendering;

use Nette\Forms\Rendering\DefaultFormRenderer;

class AbstractBootstrapHorizontalRenderer extends DefaultFormRenderer
{

/** @var int */
protected $colsLabel = 3;

/** @var int */
protected $colsControl = 9;

public function setColumns(int $colsLabel, int $colsControl): void
{
$this->colsLabel = $colsLabel;
$this->colsControl = $colsControl;
}

protected function getValue(string $name)
{
$value = parent::getValue($name);
if (is_string($value)) {
$value = $this->replacePlaceholders($value);
}

return $value;
}

protected function replacePlaceholders(string $value): string
{
$value = str_replace('%colsLabel%', (string) $this->colsLabel, $value);
$value = str_replace('%colsControl%', (string) $this->colsControl, $value);
return $value;
}

}
11 changes: 4 additions & 7 deletions src/Rendering/Bootstrap3HorizontalRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@

use Nette\Forms\Controls;
use Nette\Forms\Form;
use Nette\Forms\Rendering\DefaultFormRenderer;

class Bootstrap3HorizontalRenderer extends DefaultFormRenderer
class Bootstrap3HorizontalRenderer extends AbstractBootstrapHorizontalRenderer
{

/** @var mixed[] */
Expand Down Expand Up @@ -34,7 +33,7 @@ class Bootstrap3HorizontalRenderer extends DefaultFormRenderer
'.error' => 'has-error',
],
'control' => [
'container' => 'div class=col-sm-9',
'container' => 'div class=col-sm-%colsControl%',
'.odd' => null,
'description' => 'span class=help-block',
'requiredsuffix' => '',
Expand All @@ -49,7 +48,7 @@ class Bootstrap3HorizontalRenderer extends DefaultFormRenderer
'.button' => 'button',
],
'label' => [
'container' => 'div class="col-sm-3 control-label"',
'container' => 'div class="col-sm-%colsLabel% control-label"',
'suffix' => null,
'requiredsuffix' => '',
],
Expand All @@ -75,9 +74,7 @@ public function render(Form $form, $mode = null): string
foreach ($form->getControls() as $control) {
switch (true) {
case $control instanceof Controls\Button:
/** @var string|null $class */
$class = $control->getControlPrototype()->getAttribute('class');
if ($class === null || mb_strpos($class, 'btn') === false) {
if (!Helpers::htmlClassContains($control->getControlPrototype(), 'btn')) {
$control->getControlPrototype()->addClass($usedPrimary === false ? 'btn btn-primary' : 'btn btn-default');
$usedPrimary = true;
}
Expand Down
4 changes: 1 addition & 3 deletions src/Rendering/Bootstrap3InlineRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,7 @@ public function render(Form $form, $mode = null): string
foreach ($form->getControls() as $control) {
switch (true) {
case $control instanceof Controls\Button:
/** @var string|null $class */
$class = $control->getControlPrototype()->getAttribute('class');
if ($class === null || mb_strpos($class, 'btn') === false) {
if (!Helpers::htmlClassContains($control->getControlPrototype(), 'btn')) {
$control->getControlPrototype()->addClass($usedPrimary === false ? 'btn btn-primary' : 'btn btn-default');
$usedPrimary = true;
}
Expand Down
4 changes: 1 addition & 3 deletions src/Rendering/Bootstrap3VerticalRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,7 @@ public function render(Form $form, $mode = null): string
foreach ($form->getControls() as $control) {
switch (true) {
case $control instanceof Controls\Button:
/** @var string|null $class */
$class = $control->getControlPrototype()->getAttribute('class');
if ($class === null || mb_strpos($class, 'btn') === false) {
if (!Helpers::htmlClassContains($control->getControlPrototype(), 'btn')) {
$control->getControlPrototype()->addClass($usedPrimary === false ? 'btn btn-primary' : 'btn btn-default');
$usedPrimary = true;
}
Expand Down
13 changes: 5 additions & 8 deletions src/Rendering/Bootstrap4HorizontalRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
use Nette\Forms\Controls;
use Nette\Forms\Form;
use Nette\Forms\IControl;
use Nette\Forms\Rendering\DefaultFormRenderer;
use Nette\Utils\Html;

class Bootstrap4HorizontalRenderer extends DefaultFormRenderer
class Bootstrap4HorizontalRenderer extends AbstractBootstrapHorizontalRenderer
{

/** @var mixed[] */
Expand All @@ -35,7 +34,7 @@ class Bootstrap4HorizontalRenderer extends DefaultFormRenderer
'.odd' => null,
],
'control' => [
'container' => 'div class="col col-sm-9"',
'container' => 'div class="col col-sm-%colsControl%"',
'.odd' => null,
'description' => 'span class="form-text"',
'requiredsuffix' => '',
Expand Down Expand Up @@ -76,14 +75,12 @@ public function render(Form $form, $mode = null): string
&& !($control instanceof Controls\Checkbox)
&& !($control instanceof Controls\CheckboxList)
&& !($control instanceof Controls\RadioList)) {
$control->getLabelPrototype()->addClass('col-form-label col col-sm-3');
$control->getLabelPrototype()->addClass($this->replacePlaceholders('col-form-label col col-sm-%colsLabel%'));
}

switch (true) {
case $control instanceof Controls\Button:
/** @var string|null $class */
$class = $control->getControlPrototype()->getAttribute('class');
if ($class === null || mb_strpos($class, 'btn') === false) {
if (!Helpers::htmlClassContains($control->getControlPrototype(), 'btn')) {
$control->getControlPrototype()->addClass($usedPrimary === false ? 'btn btn-primary' : 'btn btn-secondary');
$usedPrimary = true;
}
Expand Down Expand Up @@ -111,7 +108,7 @@ public function renderLabel(IControl $control): Html
{
$label = parent::renderLabel($control);
if ($control instanceof Controls\Checkbox || $control instanceof Controls\CheckboxList || $control instanceof Controls\RadioList) {
$label->addHtml('<div class="col col-sm-3"></div>');
$label->addHtml($this->replacePlaceholders('<div class="col col-sm-%colsLabel%"></div>'));
}

return $label;
Expand Down
4 changes: 1 addition & 3 deletions src/Rendering/Bootstrap4InlineRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,7 @@ public function render(Form $form, $mode = null): string

switch (true) {
case $control instanceof Controls\Button:
/** @var string|null $class */
$class = $control->getControlPrototype()->getAttribute('class');
if ($class === null || mb_strpos($class, 'btn') === false) {
if (!Helpers::htmlClassContains($control->getControlPrototype(), 'btn')) {
$control->getControlPrototype()->addClass($usedPrimary === false ? 'btn btn-primary' : 'btn btn-secondary');
$usedPrimary = true;
}
Expand Down
4 changes: 1 addition & 3 deletions src/Rendering/Bootstrap4VerticalRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,7 @@ public function render(Form $form, $mode = null): string

switch (true) {
case $control instanceof Controls\Button:
/** @var string|null $class */
$class = $control->getControlPrototype()->getAttribute('class');
if ($class === null || mb_strpos($class, 'btn') === false) {
if (!Helpers::htmlClassContains($control->getControlPrototype(), 'btn')) {
$control->getControlPrototype()->addClass($usedPrimary === false ? 'btn btn-primary' : 'btn btn-secondary');
$usedPrimary = true;
}
Expand Down
21 changes: 21 additions & 0 deletions src/Rendering/Helpers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php declare(strict_types = 1);

namespace Contributte\Forms\Rendering;

use Nette\Utils\Html;

class Helpers
{

public static function htmlClassContains(Html $html, string $contains): bool
{
/** @var string|string[]|null $class */
$class = $html->getAttribute('class');
if (is_array($class)) {
$class = implode(' ', array_keys($class));
}

return $class !== null && mb_strpos($class, $contains) !== false;
}

}
27 changes: 19 additions & 8 deletions tests/cases/Rendering/Bootstrap3HorizontalRenderer.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,25 @@ use Tester\Assert;

require_once __DIR__ . '/../../bootstrap.php';

$form = new Form();
$form->addText('text1', 'Text 1');
$form->addText('text2', 'Text 2');
$form->addSelect('select', 'Select', ['1' => 'Option 1', '2' => 'Option 2']);
$form->addCheckbox('checkbox', 'Checkbox');
$form->addSubmit('button', 'Button');

test(function () use ($form): void {
test(function (): void {
$form = new Form();
$form->addText('text1', 'Text 1');
$form->addText('text2', 'Text 2')->setHtmlAttribute('class', 'my-text');
$form->addSelect('select', 'Select', ['1' => 'Option 1', '2' => 'Option 2']);
$form->addCheckbox('checkbox', 'Checkbox');
$form->addSubmit('button', 'Button')->setHtmlAttribute('class', 'my-button');
$renderer = new Bootstrap3HorizontalRenderer();
Assert::matchFile(__DIR__ . '/expected/bootstrap3horizontal.html', $renderer->render($form));
});

test(function (): void {
$form = new Form();
$form->addText('text1', 'Text 1');
$form->addText('text2', 'Text 2')->setHtmlAttribute('class', 'my-text');
$form->addSelect('select', 'Select', ['1' => 'Option 1', '2' => 'Option 2']);
$form->addCheckbox('checkbox', 'Checkbox');
$form->addSubmit('button', 'Button')->setHtmlAttribute('class', 'my-button');
$renderer = new Bootstrap3HorizontalRenderer();
$renderer->setColumns(2, 10);
Assert::matchFile(__DIR__ . '/expected/bootstrap3horizontal.cols.html', $renderer->render($form));
});
15 changes: 7 additions & 8 deletions tests/cases/Rendering/Bootstrap3InlineRenderer.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ use Tester\Assert;

require_once __DIR__ . '/../../bootstrap.php';

$form = new Form();
$form->addText('text1', 'Text 1');
$form->addText('text2', 'Text 2');
$form->addSelect('select', 'Select', ['1' => 'Option 1', '2' => 'Option 2']);
$form->addCheckbox('checkbox', 'Checkbox');
$form->addSubmit('button', 'Button');

test(function () use ($form): void {
test(function (): void {
$form = new Form();
$form->addText('text1', 'Text 1');
$form->addText('text2', 'Text 2')->setHtmlAttribute('class', 'my-text');
$form->addSelect('select', 'Select', ['1' => 'Option 1', '2' => 'Option 2']);
$form->addCheckbox('checkbox', 'Checkbox');
$form->addSubmit('button', 'Button')->setHtmlAttribute('class', 'my-button');
$renderer = new Bootstrap3InlineRenderer();
Assert::matchFile(__DIR__ . '/expected/bootstrap3inline.html', $renderer->render($form));
});
15 changes: 7 additions & 8 deletions tests/cases/Rendering/Bootstrap3VerticalRenderer.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ use Tester\Assert;

require_once __DIR__ . '/../../bootstrap.php';

$form = new Form();
$form->addText('text1', 'Text 1');
$form->addText('text2', 'Text 2');
$form->addSelect('select', 'Select', ['1' => 'Option 1', '2' => 'Option 2']);
$form->addCheckbox('checkbox', 'Checkbox');
$form->addSubmit('button', 'Button');

test(function () use ($form): void {
test(function (): void {
$form = new Form();
$form->addText('text1', 'Text 1');
$form->addText('text2', 'Text 2')->setHtmlAttribute('class', 'my-text');
$form->addSelect('select', 'Select', ['1' => 'Option 1', '2' => 'Option 2']);
$form->addCheckbox('checkbox', 'Checkbox');
$form->addSubmit('button', 'Button')->setHtmlAttribute('class', 'my-button');
$renderer = new Bootstrap3VerticalRenderer();
Assert::matchFile(__DIR__ . '/expected/bootstrap3vertical.html', $renderer->render($form));
});
27 changes: 19 additions & 8 deletions tests/cases/Rendering/Bootstrap4HorizontalRenderer.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,25 @@ use Tester\Assert;

require_once __DIR__ . '/../../bootstrap.php';

$form = new Form();
$form->addText('text1', 'Text 1');
$form->addText('text2', 'Text 2');
$form->addSelect('select', 'Select', ['1' => 'Option 1', '2' => 'Option 2']);
$form->addCheckbox('checkbox', 'Checkbox');
$form->addSubmit('button', 'Button');

test(function () use ($form): void {
test(function (): void {
$form = new Form();
$form->addText('text1', 'Text 1');
$form->addText('text2', 'Text 2')->setHtmlAttribute('class', 'my-text');
$form->addSelect('select', 'Select', ['1' => 'Option 1', '2' => 'Option 2']);
$form->addCheckbox('checkbox', 'Checkbox');
$form->addSubmit('button', 'Button')->setHtmlAttribute('class', 'my-button');
$renderer = new Bootstrap4HorizontalRenderer();
Assert::matchFile(__DIR__ . '/expected/bootstrap4horizontal.html', $renderer->render($form));
});

test(function (): void {
$form = new Form();
$form->addText('text1', 'Text 1');
$form->addText('text2', 'Text 2')->setHtmlAttribute('class', 'my-text');
$form->addSelect('select', 'Select', ['1' => 'Option 1', '2' => 'Option 2']);
$form->addCheckbox('checkbox', 'Checkbox');
$form->addSubmit('button', 'Button')->setHtmlAttribute('class', 'my-button');
$renderer = new Bootstrap4HorizontalRenderer();
$renderer->setColumns(2, 10);
Assert::matchFile(__DIR__ . '/expected/bootstrap4horizontal.cols.html', $renderer->render($form));
});
15 changes: 7 additions & 8 deletions tests/cases/Rendering/Bootstrap4InlineRenderer.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ use Tester\Assert;

require_once __DIR__ . '/../../bootstrap.php';

$form = new Form();
$form->addText('text1', 'Text 1');
$form->addText('text2', 'Text 2');
$form->addSelect('select', 'Select', ['1' => 'Option 1', '2' => 'Option 2']);
$form->addCheckbox('checkbox', 'Checkbox');
$form->addSubmit('button', 'Button');

test(function () use ($form): void {
test(function (): void {
$form = new Form();
$form->addText('text1', 'Text 1');
$form->addText('text2', 'Text 2')->setHtmlAttribute('class', 'my-text');
$form->addSelect('select', 'Select', ['1' => 'Option 1', '2' => 'Option 2']);
$form->addCheckbox('checkbox', 'Checkbox');
$form->addSubmit('button', 'Button')->setHtmlAttribute('class', 'my-button');
$renderer = new Bootstrap4InlineRenderer();
Assert::matchFile(__DIR__ . '/expected/bootstrap4inline.html', $renderer->render($form));
});
15 changes: 7 additions & 8 deletions tests/cases/Rendering/Bootstrap4VerticalRenderer.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ use Tester\Assert;

require_once __DIR__ . '/../../bootstrap.php';

$form = new Form();
$form->addText('text1', 'Text 1');
$form->addText('text2', 'Text 2');
$form->addSelect('select', 'Select', ['1' => 'Option 1', '2' => 'Option 2']);
$form->addCheckbox('checkbox', 'Checkbox');
$form->addSubmit('button', 'Button');

test(function () use ($form): void {
test(function (): void {
$form = new Form();
$form->addText('text1', 'Text 1');
$form->addText('text2', 'Text 2')->setHtmlAttribute('class', 'my-text');
$form->addSelect('select', 'Select', ['1' => 'Option 1', '2' => 'Option 2']);
$form->addCheckbox('checkbox', 'Checkbox');
$form->addSubmit('button', 'Button')->setHtmlAttribute('class', 'my-button');
$renderer = new Bootstrap4VerticalRenderer();
Assert::matchFile(__DIR__ . '/expected/bootstrap4vertical.html', $renderer->render($form));
});
35 changes: 35 additions & 0 deletions tests/cases/Rendering/expected/bootstrap3horizontal.cols.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<form action="" method="post" novalidate class="form-horizontal">

<div>
<div class="form-group">
<div class="col-sm-2 control-label"><label for="frm-text1">Text 1</label></div>

<div class="col-sm-10"><input type="text" name="text1" class="form-control text" id="frm-text1"></div>
</div>

<div class="form-group">
<div class="col-sm-2 control-label"><label for="frm-text2">Text 2</label></div>

<div class="col-sm-10"><input type="text" name="text2" class="my-text form-control text" id="frm-text2"></div>
</div>

<div class="form-group">
<div class="col-sm-2 control-label"><label for="frm-select">Select</label></div>

<div class="col-sm-10"><select name="select" class="form-control" id="frm-select"><option value="1">Option 1</option><option value="2">Option 2</option></select></div>
</div>

<div class="form-group">
<div class="col-sm-2 control-label"></div>

<div class="col-sm-10"><div class="checkbox"><label for="frm-checkbox"><input type="checkbox" name="checkbox" id="frm-checkbox">Checkbox</label></div></div>
</div>

<div class="form-group">
<div class="col-sm-2 control-label"></div>

<div class="col-sm-10"><input type="submit" name="button" class="my-button btn btn-primary button" value="Button"></div>
</div>
</div>

</form>
Loading

0 comments on commit d71fa5a

Please sign in to comment.