Skip to content

Commit e929a45

Browse files
cranycranef3l1x
authored andcommitted
Feature: Bootstrap5 support
1 parent c7ac26b commit e929a45

File tree

3 files changed

+323
-0
lines changed

3 files changed

+323
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Contributte\Forms\Rendering;
4+
5+
use Nette\Forms\Controls;
6+
use Nette\Forms\Form;
7+
use Nette\Forms\IControl;
8+
use Nette\Utils\Html;
9+
10+
class Bootstrap5HorizontalRenderer extends AbstractBootstrapHorizontalRenderer
11+
{
12+
13+
/** @var mixed[] */
14+
public $wrappers = [
15+
'form' => [
16+
'container' => null,
17+
],
18+
'error' => [
19+
'container' => 'div class="alert alert-danger"',
20+
'item' => 'p',
21+
],
22+
'group' => [
23+
'container' => 'fieldset',
24+
'label' => 'legend',
25+
'description' => 'p',
26+
],
27+
'controls' => [
28+
'container' => 'div',
29+
],
30+
'pair' => [
31+
'container' => 'div class="mb-3 row"',
32+
'.required' => 'required',
33+
'.optional' => null,
34+
'.odd' => null,
35+
],
36+
'control' => [
37+
'container' => 'div class="col col-%colsControl%"',
38+
'.odd' => null,
39+
'description' => 'span class="form-text"',
40+
'requiredsuffix' => '',
41+
'errorcontainer' => 'span class="form-text"',
42+
'erroritem' => '',
43+
'.required' => 'required',
44+
'.text' => 'text',
45+
'.password' => 'text',
46+
'.file' => 'text',
47+
'.submit' => 'button',
48+
'.image' => 'imagebutton',
49+
'.button' => 'button',
50+
],
51+
'label' => [
52+
'container' => '',
53+
'suffix' => null,
54+
'requiredsuffix' => '',
55+
],
56+
'hidden' => [
57+
'container' => 'div',
58+
],
59+
];
60+
61+
/**
62+
* Provides complete form rendering.
63+
*
64+
* @param string|null $mode 'begin', 'errors', 'ownerrors', 'body', 'end' or empty to render all
65+
*/
66+
public function render(Form $form, $mode = null): string
67+
{
68+
$form->getElementPrototype()->setNovalidate(true);
69+
70+
$onlyButton = Helpers::onlyOneButton($form);
71+
72+
foreach ($form->getControls() as $control) {
73+
if ($control instanceof Controls\BaseControl
74+
&& !($control instanceof Controls\Checkbox)
75+
&& !($control instanceof Controls\CheckboxList)
76+
&& !($control instanceof Controls\RadioList)) {
77+
$control->getLabelPrototype()->addClass($this->replacePlaceholders('col-form-label col col-%colsLabel%'));
78+
}
79+
80+
switch (true) {
81+
case $control instanceof Controls\Button:
82+
if (!Helpers::htmlClassContains($control->getControlPrototype(), 'btn')) {
83+
$control->getControlPrototype()->addClass($onlyButton ? 'btn btn-primary' : 'btn btn-secondary');
84+
}
85+
86+
break;
87+
88+
case $control instanceof Controls\TextBase:
89+
case $control instanceof Controls\SelectBox:
90+
case $control instanceof Controls\MultiSelectBox:
91+
$control->getControlPrototype()->addClass('form-control');
92+
break;
93+
94+
case $control instanceof Controls\Checkbox:
95+
case $control instanceof Controls\CheckboxList:
96+
case $control instanceof Controls\RadioList:
97+
$control->getSeparatorPrototype()->setName('div')->addClass('form-check');
98+
$control->getControlPrototype()->addClass('form-check-input');
99+
$control->getLabelPrototype()->addClass('form-check-label');
100+
break;
101+
}
102+
}
103+
104+
return parent::render($form, $mode);
105+
}
106+
107+
public function renderLabel(IControl $control): Html
108+
{
109+
$label = parent::renderLabel($control);
110+
if ($control instanceof Controls\Checkbox || $control instanceof Controls\CheckboxList || $control instanceof Controls\RadioList) {
111+
$label->addHtml($this->replacePlaceholders('<div class="col col-%colsLabel%"></div>'));
112+
}
113+
114+
return $label;
115+
}
116+
117+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Contributte\Forms\Rendering;
4+
5+
use Nette\Forms\Controls;
6+
use Nette\Forms\Form;
7+
use Nette\Forms\Rendering\DefaultFormRenderer;
8+
9+
class Bootstrap5InlineRenderer extends DefaultFormRenderer
10+
{
11+
12+
/** @var mixed[] */
13+
public $wrappers = [
14+
'form' => [
15+
'container' => '',
16+
],
17+
'error' => [
18+
'container' => 'div class="alert alert-danger"',
19+
'item' => 'p',
20+
],
21+
'group' => [
22+
'container' => 'fieldset',
23+
'label' => 'legend',
24+
'description' => 'p',
25+
],
26+
'controls' => [
27+
'container' => '',
28+
],
29+
'pair' => [
30+
'container' => 'div class="mb-3"',
31+
'.required' => 'required',
32+
'.optional' => null,
33+
'.odd' => null,
34+
],
35+
'control' => [
36+
'container' => null,
37+
'.odd' => null,
38+
'description' => 'span class="form-text"',
39+
'requiredsuffix' => '',
40+
'errorcontainer' => 'span class="form-text"',
41+
'erroritem' => '',
42+
'.required' => 'required',
43+
'.text' => 'text',
44+
'.password' => 'text',
45+
'.file' => 'text',
46+
'.submit' => 'button',
47+
'.image' => 'imagebutton',
48+
'.button' => 'button',
49+
],
50+
'label' => [
51+
'container' => '',
52+
'suffix' => null,
53+
'requiredsuffix' => '',
54+
],
55+
'hidden' => [
56+
'container' => 'div',
57+
],
58+
];
59+
60+
/**
61+
* Provides complete form rendering.
62+
*
63+
* @param string|null $mode 'begin', 'errors', 'ownerrors', 'body', 'end' or empty to render all
64+
*/
65+
public function render(Form $form, $mode = null): string
66+
{
67+
$form->getElementPrototype()->addClass('d-inline-flex gap-2'); // Bootstrap 5 nahrazení form-inline
68+
69+
$onlyButton = Helpers::onlyOneButton($form);
70+
71+
foreach ($form->getControls() as $control) {
72+
if ($control instanceof Controls\BaseControl) {
73+
$control->getLabelPrototype()->addClass('col-form-label');
74+
}
75+
76+
switch (true) {
77+
case $control instanceof Controls\Button:
78+
if (!Helpers::htmlClassContains($control->getControlPrototype(), 'btn')) {
79+
$control->getControlPrototype()->addClass($onlyButton ? 'btn btn-primary' : 'btn btn-secondary');
80+
}
81+
82+
break;
83+
84+
case $control instanceof Controls\TextBase:
85+
case $control instanceof Controls\SelectBox:
86+
case $control instanceof Controls\MultiSelectBox:
87+
$control->getControlPrototype()->addClass('form-control me-3'); // me-3 místo mx-sm-3
88+
break;
89+
90+
case $control instanceof Controls\Checkbox:
91+
case $control instanceof Controls\CheckboxList:
92+
case $control instanceof Controls\RadioList:
93+
$control->getSeparatorPrototype()->setName('div')->addClass('form-check form-check-inline');
94+
$control->getControlPrototype()->addClass('form-check-input');
95+
$control->getLabelPrototype()->addClass('form-check-label');
96+
break;
97+
}
98+
}
99+
100+
return parent::render($form, $mode);
101+
}
102+
103+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Contributte\Forms\Rendering;
4+
5+
use Nette\Forms\Controls;
6+
use Nette\Forms\Form;
7+
use Nette\Forms\Rendering\DefaultFormRenderer;
8+
9+
class Bootstrap5VerticalRenderer extends DefaultFormRenderer
10+
{
11+
12+
/** @var mixed[] */
13+
public $wrappers = [
14+
'form' => [
15+
'container' => null,
16+
],
17+
'error' => [
18+
'container' => 'div class="alert alert-danger"',
19+
'item' => 'p',
20+
],
21+
'group' => [
22+
'container' => 'fieldset',
23+
'label' => 'legend',
24+
'description' => 'p',
25+
],
26+
'controls' => [
27+
'container' => null,
28+
],
29+
'pair' => [
30+
'container' => 'div class="mb-3"',
31+
'.required' => 'required',
32+
'.optional' => null,
33+
'.odd' => null,
34+
],
35+
'control' => [
36+
'container' => '',
37+
'.odd' => null,
38+
'description' => 'span class="form-text"',
39+
'requiredsuffix' => '',
40+
'errorcontainer' => 'span class="form-text"',
41+
'erroritem' => '',
42+
'.required' => 'required',
43+
'.text' => 'text',
44+
'.password' => 'text',
45+
'.file' => 'text',
46+
'.submit' => 'button',
47+
'.image' => 'imagebutton',
48+
'.button' => 'button',
49+
],
50+
'label' => [
51+
'container' => '',
52+
'suffix' => null,
53+
'requiredsuffix' => '',
54+
],
55+
'hidden' => [
56+
'container' => 'div',
57+
],
58+
];
59+
60+
/**
61+
* Provides complete form rendering.
62+
*
63+
* @param string|null $mode 'begin', 'errors', 'ownerrors', 'body', 'end' or empty to render all
64+
*/
65+
public function render(Form $form, $mode = null): string
66+
{
67+
$form->getElementPrototype()->setNovalidate(true);
68+
69+
$onlyButton = Helpers::onlyOneButton($form);
70+
71+
foreach ($form->getControls() as $control) {
72+
if ($control instanceof Controls\BaseControl) {
73+
$control->getLabelPrototype()->addClass('col-form-label');
74+
}
75+
76+
switch (true) {
77+
case $control instanceof Controls\Button:
78+
if (!Helpers::htmlClassContains($control->getControlPrototype(), 'btn')) {
79+
$control->getControlPrototype()->addClass($onlyButton ? 'btn btn-primary' : 'btn btn-secondary');
80+
}
81+
82+
break;
83+
84+
case $control instanceof Controls\TextBase:
85+
case $control instanceof Controls\SelectBox:
86+
case $control instanceof Controls\MultiSelectBox:
87+
$control->getControlPrototype()->addClass('form-control');
88+
break;
89+
90+
case $control instanceof Controls\Checkbox:
91+
case $control instanceof Controls\CheckboxList:
92+
case $control instanceof Controls\RadioList:
93+
$control->getSeparatorPrototype()->setName('div')->addClass('form-check');
94+
$control->getControlPrototype()->addClass('form-check-input');
95+
$control->getLabelPrototype()->addClass('form-check-label');
96+
break;
97+
}
98+
}
99+
100+
return parent::render($form, $mode);
101+
}
102+
103+
}

0 commit comments

Comments
 (0)