Skip to content

Commit

Permalink
added LatteMacros
Browse files Browse the repository at this point in the history
  • Loading branch information
hrach committed Apr 7, 2019
1 parent 3ec0e59 commit 1ca540f
Show file tree
Hide file tree
Showing 8 changed files with 318 additions and 0 deletions.
2 changes: 2 additions & 0 deletions examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
log
temp
70 changes: 70 additions & 0 deletions examples/lattemacros/LatteMacrosPresenter.latte
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link
rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu"
crossorigin="anonymous">
<title>LatteMacros demo</title>
</head>
<body>
<div class="container">
<h1>Form LatteMacros rendering</h1>
<hr>
{form form class => form-horizontal}
<div class="form-group">
{label text class => "label-control col-sm-3"}
<div class="col-sm-9">{input text}{inputError text}</div>
</div>
<div class="form-group">
<div class="col-sm-9 col-sm-offset-3">
<div class="checkbox">
{label checkbox}{input checkbox}{/label}
</div>
{inputError checkbox}
</div>
</div>

<div class="form-group">
{label checkbox_list class => "label-control col-sm-3"}
<div class="col-sm-9">{input checkbox_list}{inputError checkbox_list}</div>
</div>
<div class="form-group">
{label integer class => "label-control col-sm-3"}
<div class="col-sm-9">{input integer}{inputError integer}</div>
</div>
<div class="form-group">
{label multi_select class => "label-control col-sm-3"}
<div class="col-sm-9">{input multi_select}{inputError multi_select}</div>
</div>
<div class="form-group">
{label password class => "label-control col-sm-3"}
<div class="col-sm-9">{input password}{inputError password}</div>
</div>
<div class="form-group">
{label radio_list class => "label-control col-sm-3"}
<div class="col-sm-9">{input radio_list}{inputError radio_list}</div>
</div>
<div class="form-group">
{label select class => "label-control col-sm-3"}
<div class="col-sm-9">{input select}{inputError select}</div>
</div>
<div class="form-group">
{label textarea class => "label-control col-sm-3"}
<div class="col-sm-9">{input textarea}{inputError textarea}</div>
</div>
<div class="form-group">
{label multi_upload class => "label-control col-sm-3"}
<div class="col-sm-9">{input multi_upload}{inputError multi_upload}</div>
</div>
<div class="form-group">
<div class="col-sm-9 col-sm-offset-3">
{input save class => btn-primary}&nbsp;
{input secondary class => btn-default}
</div>
</div>
{/form}
</div>
</body>
</html>
43 changes: 43 additions & 0 deletions examples/lattemacros/LatteMacrosPresenter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php declare(strict_types = 1);

namespace NextrasDemos\FormsRendering\LatteMacros;

use Nette\Application\UI\Form;
use Nette\Application\UI\Presenter;


class LatteMacrosPresenter extends Presenter
{
public function actionDefault()
{
}


public function createComponentForm()
{
$form = new Form();
$form->addText('text', 'Name');
$form->addCheckbox('checkbox', 'Do you agree?');
$form->addCheckboxList('checkbox_list', 'CheckboxList', ['A', 'B', 'C']);
$form->addInteger('integer', 'How much?');
$form->addMultiSelect('multi_select', 'MultiSelect', ['A', 'B', 'C']);
$form->addPassword('password', 'Password');
$form->addRadioList('radio_list', 'RadioList', ['1', '2', '3']);
$form->addSelect('select', 'Select', ['Y', 'X', 'C']);
$form->addTextArea('textarea', 'Textarea');
$form->addMultiUpload('multi_upload', 'MultiUpload');
$form->addSubmit('save', 'Send');
$form->addSubmit('secondary', 'Secondary');

$form->onSuccess[] = function ($form, $values) {
dump($values);
};
return $form;
}


public function formatTemplateFiles(): array
{
return [__DIR__ . '/LatteMacrosPresenter.latte'];
}
}
11 changes: 11 additions & 0 deletions examples/lattemacros/config.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
application:
scanDirs: false
mapping:
*: NextrasDemos\FormsRendering\LatteMacros\*Module\*Presenter

latte:
macros:
- Nextras\FormsRendering\LatteMacros\Bs3InputMacros::install

services:
routing.router: Nette\Application\Routers\SimpleRouter('LatteMacros:default')
19 changes: 19 additions & 0 deletions examples/lattemacros/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types = 1);

namespace NextrasDemos\FormsRendering\LatteMacros;

use Nette\Application\Application;
use Nette\Configurator;

require_once __DIR__ . '/../../vendor/autoload.php';


$configurator = new Configurator;
$configurator->enableDebugger(__DIR__ . '/log');
$configurator->setTempDirectory(__DIR__ . '/temp');
$configurator->createRobotLoader()->addDirectory(__DIR__)->register();
$configurator->addConfig(__DIR__ . '/config.neon');

$container = $configurator->createContainer();
$app = $container->getByType(Application::class);
$app->run();
11 changes: 11 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ Form renderers:
- *Bs3Renderer* - renderer for Bootstrap 3 with horizontal mode only;
- *Bs4Renderer* - renderer for Bootstrap 4 with support for horizontal, vertial and inline mode;

Latte Macros renderers:
- *Bs3InputMacros* - modifies Form Macros to add Bootstrap 3 classes automatically;

### Installation

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

Register Bs3InputMacros using Nette DI config:

```yaml
latte:
macros:
- Nextras\FormsRendering\LatteMacros\Bs3InputMacros::install
```
### Documentation
See examples directory.
Expand Down
109 changes: 109 additions & 0 deletions src/LatteMacros/BaseInputMacros.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php declare(strict_types = 1);

/**
* This file is part of the Nextras community extensions of Nette Framework
*
* @license MIT
* @link https://github.com/nextras/forms-rendering
*/

namespace Nextras\FormsRendering\LatteMacros;

use Latte\CompileException;
use Latte\Compiler;
use Latte\MacroNode;
use Latte\Macros\MacroSet;
use Latte\PhpWriter;
use Nette\Forms\Controls\BaseControl;
use Nette\Utils\Html;
use Nextras;


abstract class BaseInputMacros extends MacroSet
{
/**
* @return self
*/
public static function install(Compiler $compiler): self
{
$me = new static($compiler);
$me->addMacro('input', [$me, 'macroInput']);
$me->addMacro('label', [$me, 'macroLabel'], [$me, 'macroLabelEnd']);
return $me;
}


/**
* {label ...}
*/
public function macroLabel(MacroNode $node, PhpWriter $writer): string
{
$class = get_class($this);
$words = $node->tokenizer->fetchWords();
if (!$words) {
throw new CompileException("Missing name in {{$node->name}}.");
}
$name = array_shift($words);
return $writer->write(
($name[0] === '$'
? '$_input = is_object(%0.word) ? %0.word : end($this->global->formsStack)[%0.word];'
: '$_input = end($this->global->formsStack)[%0.word];'
) . 'if ($_label = $_input->%1.raw) echo ' . $class . '::label($_label->addAttributes(%node.array), $_input, %2.var)',
$name,
$words ? ('getLabelPart(' . implode(', ', array_map([$writer, 'formatWord'], $words)) . ')') : 'getLabel()',
(bool) $words
);
}


/**
* {/label}
*/
public function macroLabelEnd(MacroNode $node, PhpWriter $writer): string
{
if ($node->content != null) {
$node->openingCode = rtrim($node->openingCode, '?> ') . '->startTag() ?>';
return $writer->write('if ($_label) echo $_label->endTag()');
} else {
return '';
}
}


/**
* {input ...}
*/
public function macroInput(MacroNode $node, PhpWriter $writer): string
{
$class = get_class($this);
$words = $node->tokenizer->fetchWords();
if (!$words) {
throw new CompileException("Missing name in {{$node->name}}.");
}
$name = array_shift($words);
return $writer->write(
($name[0] === '$'
? '$_input = is_object(%0.word) ? %0.word : end($this->global->formsStack)[%0.word];'
: '$_input = end($this->global->formsStack)[%0.word];'
) . 'echo ' . $class . '::input($_input->%1.raw->addAttributes(%node.array), $_input, %2.var)',
$name,
$words ? 'getControlPart(' . implode(', ', array_map([
$writer,
'formatWord',
], $words)) . ')' : 'getControl()',
(bool) $words
);
}


public static function label(Html $label, BaseControl $control, bool $isSubItem): Html
{
return $label;
}


public static function input(Html $input, BaseControl $control, bool $isSubItem): Html
{
return $input;
}
}
53 changes: 53 additions & 0 deletions src/LatteMacros/Bs3InputMacros.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php declare(strict_types = 1);

/**
* This file is part of the Nextras community extensions of Nette Framework
*
* @license MIT
* @link https://github.com/nextras/forms-rendering
*/

namespace Nextras\FormsRendering\LatteMacros;

use Nette\Forms\Controls\BaseControl;
use Nette\Forms\Controls\CheckboxList;
use Nette\Forms\Controls\RadioList;
use Nette\Utils\Html;
use Nextras;


class Bs3InputMacros extends BaseInputMacros
{
public static function label(Html $label, BaseControl $control, bool $isSubItem): Html
{
if ($label->getName() === 'label' && !$isSubItem) {
$label->addClass('control-label');
}

return $label;
}


public static function input(Html $input, BaseControl $control, bool $isSubItem): Html
{
static $inputControls = ['radio', 'checkbox', 'file', 'hidden', 'range', 'image', 'submit', 'reset'];
$name = $input->getName();
if (
$name === 'select' ||
$name === 'textarea' ||
($name === 'input' && !in_array($input->type, $inputControls, true))
) {
$input->addClass('form-control');
} elseif ($name === 'input' && ($input->type === 'submit' || $input->type === 'reset')) {
$input->setName('button');
$input->addHtml($input->value);
$input->addClass('btn');
} elseif (($control instanceof RadioList) && !$isSubItem) {
$input = Html::el('div')->addAttributes(['class' => 'radio'])->addHtml($input);
} elseif (($control instanceof CheckboxList) && !$isSubItem) {
$input = Html::el('div')->addAttributes(['class' => 'checkbox'])->addHtml($input);
}

return $input;
}
}

0 comments on commit 1ca540f

Please sign in to comment.