ACC SHELL
<?php
/**
* This file is part of the Nette Framework (http://nette.org)
*
* Copyright (c) 2004 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
namespace Nette\Forms\Rendering;
use Nette,
Nette\Utils\Html;
/**
* Converts a Form into the HTML output.
*
* @author David Grudl
*/
class DefaultFormRenderer extends Nette\Object implements Nette\Forms\IFormRenderer
{
/**
* /--- form.container
*
* /--- if (form.errors) error.container
* .... error.item [.class]
* \---
*
* /--- hidden.container
* .... HIDDEN CONTROLS
* \---
*
* /--- group.container
* .... group.label
* .... group.description
*
* /--- controls.container
*
* /--- pair.container [.required .optional .odd]
*
* /--- label.container
* .... LABEL
* .... label.suffix
* .... label.requiredsuffix
* \---
*
* /--- control.container [.odd]
* .... CONTROL [.required .text .password .file .submit .button]
* .... control.requiredsuffix
* .... control.description
* .... if (control.errors) error.container
* \---
* \---
* \---
* \---
* \--
*
* @var array of HTML tags */
public $wrappers = array(
'form' => array(
'container' => NULL,
'errors' => TRUE,
),
'error' => array(
'container' => 'ul class=error',
'item' => 'li',
),
'group' => array(
'container' => 'fieldset',
'label' => 'legend',
'description' => 'p',
),
'controls' => array(
'container' => 'table',
),
'pair' => array(
'container' => 'tr',
'.required' => 'required',
'.optional' => NULL,
'.odd' => NULL,
),
'control' => array(
'container' => 'td',
'.odd' => NULL,
'errors' => FALSE,
'description' => 'small',
'requiredsuffix' => '',
'.required' => 'required',
'.text' => 'text',
'.password' => 'text',
'.file' => 'text',
'.submit' => 'button',
'.image' => 'imagebutton',
'.button' => 'button',
),
'label' => array(
'container' => 'th',
'suffix' => NULL,
'requiredsuffix' => '',
),
'hidden' => array(
'container' => 'div',
),
);
/** @var Nette\Forms\Form */
protected $form;
/** @var int */
protected $counter;
/**
* Provides complete form rendering.
* @param Nette\Forms\Form
* @param string 'begin', 'errors', 'body', 'end' or empty to render all
* @return string
*/
public function render(Nette\Forms\Form $form, $mode = NULL)
{
if ($this->form !== $form) {
$this->form = $form;
$this->init();
}
$s = '';
if (!$mode || $mode === 'begin') {
$s .= $this->renderBegin();
}
if ((!$mode && $this->getValue('form errors')) || $mode === 'errors') {
$s .= $this->renderErrors();
}
if (!$mode || $mode === 'body') {
$s .= $this->renderBody();
}
if (!$mode || $mode === 'end') {
$s .= $this->renderEnd();
}
return $s;
}
/** @deprecated */
public function setClientScript()
{
trigger_error(__METHOD__ . '() is deprecated; use unobstructive JavaScript instead.', E_USER_WARNING);
return $this;
}
/**
* Initializes form.
* @return void
*/
protected function init()
{
// TODO: only for back compatiblity - remove?
$wrapper = & $this->wrappers['control'];
foreach ($this->form->getControls() as $control) {
if ($control->isRequired() && isset($wrapper['.required'])) {
$control->getLabelPrototype()->class($wrapper['.required'], TRUE);
}
$el = $control->getControlPrototype();
if ($el->getName() === 'input' && isset($wrapper['.' . $el->type])) {
$el->class($wrapper['.' . $el->type], TRUE);
}
}
}
/**
* Renders form begin.
* @return string
*/
public function renderBegin()
{
$this->counter = 0;
foreach ($this->form->getControls() as $control) {
$control->setOption('rendered', FALSE);
}
if (strcasecmp($this->form->getMethod(), 'get') === 0) {
$el = clone $this->form->getElementPrototype();
$url = explode('?', (string) $el->action, 2);
$el->action = $url[0];
$s = '';
if (isset($url[1])) {
foreach (preg_split('#[;&]#', $url[1]) as $param) {
$parts = explode('=', $param, 2);
$name = urldecode($parts[0]);
if (!isset($this->form[$name])) {
$s .= Html::el('input', array('type' => 'hidden', 'name' => $name, 'value' => urldecode($parts[1])));
}
}
$s = "\n\t" . $this->getWrapper('hidden container')->setHtml($s);
}
return $el->startTag() . $s;
} else {
return $this->form->getElementPrototype()->startTag();
}
}
/**
* Renders form end.
* @return string
*/
public function renderEnd()
{
$s = '';
foreach ($this->form->getControls() as $control) {
if ($control instanceof Nette\Forms\Controls\HiddenField && !$control->getOption('rendered')) {
$s .= (string) $control->getControl();
}
}
if (iterator_count($this->form->getComponents(TRUE, 'Nette\Forms\Controls\TextInput')) < 2) {
$s .= '<!--[if IE]><input type=IEbug disabled style="display:none"><![endif]-->';
}
if ($s) {
$s = $this->getWrapper('hidden container')->setHtml($s) . "\n";
}
return $s . $this->form->getElementPrototype()->endTag() . "\n";
}
/**
* Renders validation errors (per form or per control).
* @param Nette\Forms\IControl
* @return string
*/
public function renderErrors(Nette\Forms\IControl $control = NULL)
{
$errors = $control === NULL ? $this->form->getErrors() : $control->getErrors();
if (count($errors)) {
$ul = $this->getWrapper('error container');
$li = $this->getWrapper('error item');
foreach ($errors as $error) {
$item = clone $li;
if ($error instanceof Html) {
$item->add($error);
} else {
$item->setText($error);
}
$ul->add($item);
}
return "\n" . $ul->render(0);
}
}
/**
* Renders form body.
* @return string
*/
public function renderBody()
{
$s = $remains = '';
$defaultContainer = $this->getWrapper('group container');
$translator = $this->form->getTranslator();
foreach ($this->form->getGroups() as $group) {
if (!$group->getControls() || !$group->getOption('visual')) {
continue;
}
$container = $group->getOption('container', $defaultContainer);
$container = $container instanceof Html ? clone $container : Html::el($container);
$s .= "\n" . $container->startTag();
$text = $group->getOption('label');
if ($text instanceof Html) {
$s .= $text;
} elseif (is_string($text)) {
if ($translator !== NULL) {
$text = $translator->translate($text);
}
$s .= "\n" . $this->getWrapper('group label')->setText($text) . "\n";
}
$text = $group->getOption('description');
if ($text instanceof Html) {
$s .= $text;
} elseif (is_string($text)) {
if ($translator !== NULL) {
$text = $translator->translate($text);
}
$s .= $this->getWrapper('group description')->setText($text) . "\n";
}
$s .= $this->renderControls($group);
$remains = $container->endTag() . "\n" . $remains;
if (!$group->getOption('embedNext')) {
$s .= $remains;
$remains = '';
}
}
$s .= $remains . $this->renderControls($this->form);
$container = $this->getWrapper('form container');
$container->setHtml($s);
return $container->render(0);
}
/**
* Renders group of controls.
* @param Nette\Forms\Container|FormGroup
* @return string
*/
public function renderControls($parent)
{
if (!($parent instanceof Nette\Forms\Container || $parent instanceof Nette\Forms\ControlGroup)) {
throw new Nette\InvalidArgumentException("Argument must be FormContainer or FormGroup instance.");
}
$container = $this->getWrapper('controls container');
$buttons = NULL;
foreach ($parent->getControls() as $control) {
if ($control->getOption('rendered') || $control instanceof Nette\Forms\Controls\HiddenField || $control->getForm(FALSE) !== $this->form) {
// skip
} elseif ($control instanceof Nette\Forms\Controls\Button) {
$buttons[] = $control;
} else {
if ($buttons) {
$container->add($this->renderPairMulti($buttons));
$buttons = NULL;
}
$container->add($this->renderPair($control));
}
}
if ($buttons) {
$container->add($this->renderPairMulti($buttons));
}
$s = '';
if (count($container)) {
$s .= "\n" . $container . "\n";
}
return $s;
}
/**
* Renders single visual row.
* @param Nette\Forms\IControl
* @return string
*/
public function renderPair(Nette\Forms\IControl $control)
{
$pair = $this->getWrapper('pair container');
$pair->add($this->renderLabel($control));
$pair->add($this->renderControl($control));
$pair->class($this->getValue($control->isRequired() ? 'pair .required' : 'pair .optional'), TRUE);
$pair->class($control->getOption('class'), TRUE);
if (++$this->counter % 2) {
$pair->class($this->getValue('pair .odd'), TRUE);
}
$pair->id = $control->getOption('id');
return $pair->render(0);
}
/**
* Renders single visual row of multiple controls.
* @param IFormControl[]
* @return string
*/
public function renderPairMulti(array $controls)
{
$s = array();
foreach ($controls as $control) {
if (!$control instanceof Nette\Forms\IControl) {
throw new Nette\InvalidArgumentException("Argument must be array of IFormControl instances.");
}
$s[] = (string) $control->getControl();
}
$pair = $this->getWrapper('pair container');
$pair->add($this->renderLabel($control));
$pair->add($this->getWrapper('control container')->setHtml(implode(" ", $s)));
return $pair->render(0);
}
/**
* Renders 'label' part of visual row of controls.
* @param Nette\Forms\IControl
* @return string
*/
public function renderLabel(Nette\Forms\IControl $control)
{
$head = $this->getWrapper('label container');
if ($control instanceof Nette\Forms\Controls\Checkbox || $control instanceof Nette\Forms\Controls\Button) {
return $head->setHtml(($head->getName() === 'td' || $head->getName() === 'th') ? ' ' : '');
} else {
$label = $control->getLabel();
$suffix = $this->getValue('label suffix') . ($control->isRequired() ? $this->getValue('label requiredsuffix') : '');
if ($label instanceof Html) {
$label->setHtml($label->getHtml() . $suffix);
$suffix = '';
}
return $head->setHtml((string) $label . $suffix);
}
}
/**
* Renders 'control' part of visual row of controls.
* @param Nette\Forms\IControl
* @return string
*/
public function renderControl(Nette\Forms\IControl $control)
{
$body = $this->getWrapper('control container');
if ($this->counter % 2) {
$body->class($this->getValue('control .odd'), TRUE);
}
$description = $control->getOption('description');
if ($description instanceof Html) {
$description = ' ' . $control->getOption('description');
} elseif (is_string($description)) {
$description = ' ' . $this->getWrapper('control description')->setText($control->translate($description));
} else {
$description = '';
}
if ($control->isRequired()) {
$description = $this->getValue('control requiredsuffix') . $description;
}
if ($this->getValue('control errors')) {
$description .= $this->renderErrors($control);
}
if ($control instanceof Nette\Forms\Controls\Checkbox || $control instanceof Nette\Forms\Controls\Button) {
return $body->setHtml((string) $control->getControl() . (string) $control->getLabel() . $description);
} else {
return $body->setHtml((string) $control->getControl() . $description);
}
}
/**
* @param string
* @return Nette\Utils\Html
*/
protected function getWrapper($name)
{
$data = $this->getValue($name);
return $data instanceof Html ? clone $data : Html::el($data);
}
/**
* @param string
* @return string
*/
protected function getValue($name)
{
$name = explode(' ', $name);
$data = & $this->wrappers[$name[0]][$name[1]];
return $data;
}
}
ACC SHELL 2018