Skip to content

Commit 1ca540f

Browse files
committed
added LatteMacros
1 parent 3ec0e59 commit 1ca540f

File tree

8 files changed

+318
-0
lines changed

8 files changed

+318
-0
lines changed

examples/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
log
2+
temp
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<link
5+
rel="stylesheet"
6+
href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
7+
integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu"
8+
crossorigin="anonymous">
9+
<title>LatteMacros demo</title>
10+
</head>
11+
<body>
12+
<div class="container">
13+
<h1>Form LatteMacros rendering</h1>
14+
<hr>
15+
{form form class => form-horizontal}
16+
<div class="form-group">
17+
{label text class => "label-control col-sm-3"}
18+
<div class="col-sm-9">{input text}{inputError text}</div>
19+
</div>
20+
<div class="form-group">
21+
<div class="col-sm-9 col-sm-offset-3">
22+
<div class="checkbox">
23+
{label checkbox}{input checkbox}{/label}
24+
</div>
25+
{inputError checkbox}
26+
</div>
27+
</div>
28+
29+
<div class="form-group">
30+
{label checkbox_list class => "label-control col-sm-3"}
31+
<div class="col-sm-9">{input checkbox_list}{inputError checkbox_list}</div>
32+
</div>
33+
<div class="form-group">
34+
{label integer class => "label-control col-sm-3"}
35+
<div class="col-sm-9">{input integer}{inputError integer}</div>
36+
</div>
37+
<div class="form-group">
38+
{label multi_select class => "label-control col-sm-3"}
39+
<div class="col-sm-9">{input multi_select}{inputError multi_select}</div>
40+
</div>
41+
<div class="form-group">
42+
{label password class => "label-control col-sm-3"}
43+
<div class="col-sm-9">{input password}{inputError password}</div>
44+
</div>
45+
<div class="form-group">
46+
{label radio_list class => "label-control col-sm-3"}
47+
<div class="col-sm-9">{input radio_list}{inputError radio_list}</div>
48+
</div>
49+
<div class="form-group">
50+
{label select class => "label-control col-sm-3"}
51+
<div class="col-sm-9">{input select}{inputError select}</div>
52+
</div>
53+
<div class="form-group">
54+
{label textarea class => "label-control col-sm-3"}
55+
<div class="col-sm-9">{input textarea}{inputError textarea}</div>
56+
</div>
57+
<div class="form-group">
58+
{label multi_upload class => "label-control col-sm-3"}
59+
<div class="col-sm-9">{input multi_upload}{inputError multi_upload}</div>
60+
</div>
61+
<div class="form-group">
62+
<div class="col-sm-9 col-sm-offset-3">
63+
{input save class => btn-primary}&nbsp;
64+
{input secondary class => btn-default}
65+
</div>
66+
</div>
67+
{/form}
68+
</div>
69+
</body>
70+
</html>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace NextrasDemos\FormsRendering\LatteMacros;
4+
5+
use Nette\Application\UI\Form;
6+
use Nette\Application\UI\Presenter;
7+
8+
9+
class LatteMacrosPresenter extends Presenter
10+
{
11+
public function actionDefault()
12+
{
13+
}
14+
15+
16+
public function createComponentForm()
17+
{
18+
$form = new Form();
19+
$form->addText('text', 'Name');
20+
$form->addCheckbox('checkbox', 'Do you agree?');
21+
$form->addCheckboxList('checkbox_list', 'CheckboxList', ['A', 'B', 'C']);
22+
$form->addInteger('integer', 'How much?');
23+
$form->addMultiSelect('multi_select', 'MultiSelect', ['A', 'B', 'C']);
24+
$form->addPassword('password', 'Password');
25+
$form->addRadioList('radio_list', 'RadioList', ['1', '2', '3']);
26+
$form->addSelect('select', 'Select', ['Y', 'X', 'C']);
27+
$form->addTextArea('textarea', 'Textarea');
28+
$form->addMultiUpload('multi_upload', 'MultiUpload');
29+
$form->addSubmit('save', 'Send');
30+
$form->addSubmit('secondary', 'Secondary');
31+
32+
$form->onSuccess[] = function ($form, $values) {
33+
dump($values);
34+
};
35+
return $form;
36+
}
37+
38+
39+
public function formatTemplateFiles(): array
40+
{
41+
return [__DIR__ . '/LatteMacrosPresenter.latte'];
42+
}
43+
}

examples/lattemacros/config.neon

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
application:
2+
scanDirs: false
3+
mapping:
4+
*: NextrasDemos\FormsRendering\LatteMacros\*Module\*Presenter
5+
6+
latte:
7+
macros:
8+
- Nextras\FormsRendering\LatteMacros\Bs3InputMacros::install
9+
10+
services:
11+
routing.router: Nette\Application\Routers\SimpleRouter('LatteMacros:default')

examples/lattemacros/index.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace NextrasDemos\FormsRendering\LatteMacros;
4+
5+
use Nette\Application\Application;
6+
use Nette\Configurator;
7+
8+
require_once __DIR__ . '/../../vendor/autoload.php';
9+
10+
11+
$configurator = new Configurator;
12+
$configurator->enableDebugger(__DIR__ . '/log');
13+
$configurator->setTempDirectory(__DIR__ . '/temp');
14+
$configurator->createRobotLoader()->addDirectory(__DIR__)->register();
15+
$configurator->addConfig(__DIR__ . '/config.neon');
16+
17+
$container = $configurator->createContainer();
18+
$app = $container->getByType(Application::class);
19+
$app->run();

readme.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ Form renderers:
1111
- *Bs3Renderer* - renderer for Bootstrap 3 with horizontal mode only;
1212
- *Bs4Renderer* - renderer for Bootstrap 4 with support for horizontal, vertial and inline mode;
1313

14+
Latte Macros renderers:
15+
- *Bs3InputMacros* - modifies Form Macros to add Bootstrap 3 classes automatically;
16+
1417
### Installation
1518

1619
The best way to install is using [Composer](http://getcomposer.org/):
@@ -19,6 +22,14 @@ The best way to install is using [Composer](http://getcomposer.org/):
1922
$ composer require nextras/forms-rendering
2023
```
2124

25+
Register Bs3InputMacros using Nette DI config:
26+
27+
```yaml
28+
latte:
29+
macros:
30+
- Nextras\FormsRendering\LatteMacros\Bs3InputMacros::install
31+
```
32+
2233
### Documentation
2334
2435
See examples directory.
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php declare(strict_types = 1);
2+
3+
/**
4+
* This file is part of the Nextras community extensions of Nette Framework
5+
*
6+
* @license MIT
7+
* @link https://github.com/nextras/forms-rendering
8+
*/
9+
10+
namespace Nextras\FormsRendering\LatteMacros;
11+
12+
use Latte\CompileException;
13+
use Latte\Compiler;
14+
use Latte\MacroNode;
15+
use Latte\Macros\MacroSet;
16+
use Latte\PhpWriter;
17+
use Nette\Forms\Controls\BaseControl;
18+
use Nette\Utils\Html;
19+
use Nextras;
20+
21+
22+
abstract class BaseInputMacros extends MacroSet
23+
{
24+
/**
25+
* @return self
26+
*/
27+
public static function install(Compiler $compiler): self
28+
{
29+
$me = new static($compiler);
30+
$me->addMacro('input', [$me, 'macroInput']);
31+
$me->addMacro('label', [$me, 'macroLabel'], [$me, 'macroLabelEnd']);
32+
return $me;
33+
}
34+
35+
36+
/**
37+
* {label ...}
38+
*/
39+
public function macroLabel(MacroNode $node, PhpWriter $writer): string
40+
{
41+
$class = get_class($this);
42+
$words = $node->tokenizer->fetchWords();
43+
if (!$words) {
44+
throw new CompileException("Missing name in {{$node->name}}.");
45+
}
46+
$name = array_shift($words);
47+
return $writer->write(
48+
($name[0] === '$'
49+
? '$_input = is_object(%0.word) ? %0.word : end($this->global->formsStack)[%0.word];'
50+
: '$_input = end($this->global->formsStack)[%0.word];'
51+
) . 'if ($_label = $_input->%1.raw) echo ' . $class . '::label($_label->addAttributes(%node.array), $_input, %2.var)',
52+
$name,
53+
$words ? ('getLabelPart(' . implode(', ', array_map([$writer, 'formatWord'], $words)) . ')') : 'getLabel()',
54+
(bool) $words
55+
);
56+
}
57+
58+
59+
/**
60+
* {/label}
61+
*/
62+
public function macroLabelEnd(MacroNode $node, PhpWriter $writer): string
63+
{
64+
if ($node->content != null) {
65+
$node->openingCode = rtrim($node->openingCode, '?> ') . '->startTag() ?>';
66+
return $writer->write('if ($_label) echo $_label->endTag()');
67+
} else {
68+
return '';
69+
}
70+
}
71+
72+
73+
/**
74+
* {input ...}
75+
*/
76+
public function macroInput(MacroNode $node, PhpWriter $writer): string
77+
{
78+
$class = get_class($this);
79+
$words = $node->tokenizer->fetchWords();
80+
if (!$words) {
81+
throw new CompileException("Missing name in {{$node->name}}.");
82+
}
83+
$name = array_shift($words);
84+
return $writer->write(
85+
($name[0] === '$'
86+
? '$_input = is_object(%0.word) ? %0.word : end($this->global->formsStack)[%0.word];'
87+
: '$_input = end($this->global->formsStack)[%0.word];'
88+
) . 'echo ' . $class . '::input($_input->%1.raw->addAttributes(%node.array), $_input, %2.var)',
89+
$name,
90+
$words ? 'getControlPart(' . implode(', ', array_map([
91+
$writer,
92+
'formatWord',
93+
], $words)) . ')' : 'getControl()',
94+
(bool) $words
95+
);
96+
}
97+
98+
99+
public static function label(Html $label, BaseControl $control, bool $isSubItem): Html
100+
{
101+
return $label;
102+
}
103+
104+
105+
public static function input(Html $input, BaseControl $control, bool $isSubItem): Html
106+
{
107+
return $input;
108+
}
109+
}

src/LatteMacros/Bs3InputMacros.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php declare(strict_types = 1);
2+
3+
/**
4+
* This file is part of the Nextras community extensions of Nette Framework
5+
*
6+
* @license MIT
7+
* @link https://github.com/nextras/forms-rendering
8+
*/
9+
10+
namespace Nextras\FormsRendering\LatteMacros;
11+
12+
use Nette\Forms\Controls\BaseControl;
13+
use Nette\Forms\Controls\CheckboxList;
14+
use Nette\Forms\Controls\RadioList;
15+
use Nette\Utils\Html;
16+
use Nextras;
17+
18+
19+
class Bs3InputMacros extends BaseInputMacros
20+
{
21+
public static function label(Html $label, BaseControl $control, bool $isSubItem): Html
22+
{
23+
if ($label->getName() === 'label' && !$isSubItem) {
24+
$label->addClass('control-label');
25+
}
26+
27+
return $label;
28+
}
29+
30+
31+
public static function input(Html $input, BaseControl $control, bool $isSubItem): Html
32+
{
33+
static $inputControls = ['radio', 'checkbox', 'file', 'hidden', 'range', 'image', 'submit', 'reset'];
34+
$name = $input->getName();
35+
if (
36+
$name === 'select' ||
37+
$name === 'textarea' ||
38+
($name === 'input' && !in_array($input->type, $inputControls, true))
39+
) {
40+
$input->addClass('form-control');
41+
} elseif ($name === 'input' && ($input->type === 'submit' || $input->type === 'reset')) {
42+
$input->setName('button');
43+
$input->addHtml($input->value);
44+
$input->addClass('btn');
45+
} elseif (($control instanceof RadioList) && !$isSubItem) {
46+
$input = Html::el('div')->addAttributes(['class' => 'radio'])->addHtml($input);
47+
} elseif (($control instanceof CheckboxList) && !$isSubItem) {
48+
$input = Html::el('div')->addAttributes(['class' => 'checkbox'])->addHtml($input);
49+
}
50+
51+
return $input;
52+
}
53+
}

0 commit comments

Comments
 (0)