Namespaces

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • NetteModule
  • None
  • PHP

Classes

  • DefaultFormRenderer
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  *
  6:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  */
 11: 
 12: namespace Nette\Forms\Rendering;
 13: 
 14: use Nette,
 15:     Nette\Utils\Html;
 16: 
 17: 
 18: /**
 19:  * Converts a Form into the HTML output.
 20:  *
 21:  * @author     David Grudl
 22:  */
 23: class DefaultFormRenderer extends Nette\Object implements Nette\Forms\IFormRenderer
 24: {
 25:     /**
 26:      *  /--- form.container
 27:      *
 28:      *    /--- if (form.errors) error.container
 29:      *      .... error.item [.class]
 30:      *    \---
 31:      *
 32:      *    /--- hidden.container
 33:      *      .... HIDDEN CONTROLS
 34:      *    \---
 35:      *
 36:      *    /--- group.container
 37:      *      .... group.label
 38:      *      .... group.description
 39:      *
 40:      *      /--- controls.container
 41:      *
 42:      *        /--- pair.container [.required .optional .odd]
 43:      *
 44:      *          /--- label.container
 45:      *            .... LABEL
 46:      *            .... label.suffix
 47:      *            .... label.requiredsuffix
 48:      *          \---
 49:      *
 50:      *          /--- control.container [.odd]
 51:      *            .... CONTROL [.required .text .password .file .submit .button]
 52:      *            .... control.requiredsuffix
 53:      *            .... control.description
 54:      *            .... if (control.errors) error.container
 55:      *          \---
 56:      *        \---
 57:      *      \---
 58:      *    \---
 59:      *  \--
 60:      *
 61:      * @var array of HTML tags */
 62:     public $wrappers = array(
 63:         'form' => array(
 64:             'container' => NULL,
 65:             'errors' => TRUE,
 66:         ),
 67: 
 68:         'error' => array(
 69:             'container' => 'ul class=error',
 70:             'item' => 'li',
 71:         ),
 72: 
 73:         'group' => array(
 74:             'container' => 'fieldset',
 75:             'label' => 'legend',
 76:             'description' => 'p',
 77:         ),
 78: 
 79:         'controls' => array(
 80:             'container' => 'table',
 81:         ),
 82: 
 83:         'pair' => array(
 84:             'container' => 'tr',
 85:             '.required' => 'required',
 86:             '.optional' => NULL,
 87:             '.odd' => NULL,
 88:         ),
 89: 
 90:         'control' => array(
 91:             'container' => 'td',
 92:             '.odd' => NULL,
 93: 
 94:             'errors' => FALSE,
 95:             'description' => 'small',
 96:             'requiredsuffix' => '',
 97: 
 98:             '.required' => 'required',
 99:             '.text' => 'text',
100:             '.password' => 'text',
101:             '.file' => 'text',
102:             '.submit' => 'button',
103:             '.image' => 'imagebutton',
104:             '.button' => 'button',
105:         ),
106: 
107:         'label' => array(
108:             'container' => 'th',
109:             'suffix' => NULL,
110:             'requiredsuffix' => '',
111:         ),
112: 
113:         'hidden' => array(
114:             'container' => 'div',
115:         ),
116:     );
117: 
118:     /** @var Nette\Forms\Form */
119:     protected $form;
120: 
121:     /** @var int */
122:     protected $counter;
123: 
124: 
125:     /**
126:      * Provides complete form rendering.
127:      * @param  Nette\Forms\Form
128:      * @param  string 'begin', 'errors', 'body', 'end' or empty to render all
129:      * @return string
130:      */
131:     public function render(Nette\Forms\Form $form, $mode = NULL)
132:     {
133:         if ($this->form !== $form) {
134:             $this->form = $form;
135:             $this->init();
136:         }
137: 
138:         $s = '';
139:         if (!$mode || $mode === 'begin') {
140:             $s .= $this->renderBegin();
141:         }
142:         if ((!$mode && $this->getValue('form errors')) || $mode === 'errors') {
143:             $s .= $this->renderErrors();
144:         }
145:         if (!$mode || $mode === 'body') {
146:             $s .= $this->renderBody();
147:         }
148:         if (!$mode || $mode === 'end') {
149:             $s .= $this->renderEnd();
150:         }
151:         return $s;
152:     }
153: 
154: 
155:     /** @deprecated */
156:     public function setClientScript()
157:     {
158:         trigger_error(__METHOD__ . '() is deprecated; use unobstructive JavaScript instead.', E_USER_WARNING);
159:         return $this;
160:     }
161: 
162: 
163:     /**
164:      * Initializes form.
165:      * @return void
166:      */
167:     protected function init()
168:     {
169:         // TODO: only for back compatiblity - remove?
170:         $wrapper = & $this->wrappers['control'];
171:         foreach ($this->form->getControls() as $control) {
172:             if ($control->isRequired() && isset($wrapper['.required'])) {
173:                 $control->getLabelPrototype()->class($wrapper['.required'], TRUE);
174:             }
175: 
176:             $el = $control->getControlPrototype();
177:             if ($el->getName() === 'input' && isset($wrapper['.' . $el->type])) {
178:                 $el->class($wrapper['.' . $el->type], TRUE);
179:             }
180:         }
181:     }
182: 
183: 
184:     /**
185:      * Renders form begin.
186:      * @return string
187:      */
188:     public function renderBegin()
189:     {
190:         $this->counter = 0;
191: 
192:         foreach ($this->form->getControls() as $control) {
193:             $control->setOption('rendered', FALSE);
194:         }
195: 
196:         if (strcasecmp($this->form->getMethod(), 'get') === 0) {
197:             $el = clone $this->form->getElementPrototype();
198:             $url = explode('?', (string) $el->action, 2);
199:             $el->action = $url[0];
200:             $s = '';
201:             if (isset($url[1])) {
202:                 foreach (preg_split('#[;&]#', $url[1]) as $param) {
203:                     $parts = explode('=', $param, 2);
204:                     $name = urldecode($parts[0]);
205:                     if (!isset($this->form[$name])) {
206:                         $s .= Html::el('input', array('type' => 'hidden', 'name' => $name, 'value' => urldecode($parts[1])));
207:                     }
208:                 }
209:                 $s = "\n\t" . $this->getWrapper('hidden container')->setHtml($s);
210:             }
211:             return $el->startTag() . $s;
212: 
213: 
214:         } else {
215:             return $this->form->getElementPrototype()->startTag();
216:         }
217:     }
218: 
219: 
220:     /**
221:      * Renders form end.
222:      * @return string
223:      */
224:     public function renderEnd()
225:     {
226:         $s = '';
227:         foreach ($this->form->getControls() as $control) {
228:             if ($control instanceof Nette\Forms\Controls\HiddenField && !$control->getOption('rendered')) {
229:                 $s .= (string) $control->getControl();
230:             }
231:         }
232:         if (iterator_count($this->form->getComponents(TRUE, 'Nette\Forms\Controls\TextInput')) < 2) {
233:             $s .= '<!--[if IE]><input type=IEbug disabled style="display:none"><![endif]-->';
234:         }
235:         if ($s) {
236:             $s = $this->getWrapper('hidden container')->setHtml($s) . "\n";
237:         }
238: 
239:         return $s . $this->form->getElementPrototype()->endTag() . "\n";
240:     }
241: 
242: 
243:     /**
244:      * Renders validation errors (per form or per control).
245:      * @return string
246:      */
247:     public function renderErrors(Nette\Forms\IControl $control = NULL)
248:     {
249:         $errors = $control === NULL ? $this->form->getErrors() : $control->getErrors();
250:         if (count($errors)) {
251:             $ul = $this->getWrapper('error container');
252:             $li = $this->getWrapper('error item');
253: 
254:             foreach ($errors as $error) {
255:                 $item = clone $li;
256:                 if ($error instanceof Html) {
257:                     $item->add($error);
258:                 } else {
259:                     $item->setText($error);
260:                 }
261:                 $ul->add($item);
262:             }
263:             return "\n" . $ul->render(0);
264:         }
265:     }
266: 
267: 
268:     /**
269:      * Renders form body.
270:      * @return string
271:      */
272:     public function renderBody()
273:     {
274:         $s = $remains = '';
275: 
276:         $defaultContainer = $this->getWrapper('group container');
277:         $translator = $this->form->getTranslator();
278: 
279:         foreach ($this->form->getGroups() as $group) {
280:             if (!$group->getControls() || !$group->getOption('visual')) {
281:                 continue;
282:             }
283: 
284:             $container = $group->getOption('container', $defaultContainer);
285:             $container = $container instanceof Html ? clone $container : Html::el($container);
286: 
287:             $s .= "\n" . $container->startTag();
288: 
289:             $text = $group->getOption('label');
290:             if ($text instanceof Html) {
291:                 $s .= $text;
292: 
293:             } elseif (is_string($text)) {
294:                 if ($translator !== NULL) {
295:                     $text = $translator->translate($text);
296:                 }
297:                 $s .= "\n" . $this->getWrapper('group label')->setText($text) . "\n";
298:             }
299: 
300:             $text = $group->getOption('description');
301:             if ($text instanceof Html) {
302:                 $s .= $text;
303: 
304:             } elseif (is_string($text)) {
305:                 if ($translator !== NULL) {
306:                     $text = $translator->translate($text);
307:                 }
308:                 $s .= $this->getWrapper('group description')->setText($text) . "\n";
309:             }
310: 
311:             $s .= $this->renderControls($group);
312: 
313:             $remains = $container->endTag() . "\n" . $remains;
314:             if (!$group->getOption('embedNext')) {
315:                 $s .= $remains;
316:                 $remains = '';
317:             }
318:         }
319: 
320:         $s .= $remains . $this->renderControls($this->form);
321: 
322:         $container = $this->getWrapper('form container');
323:         $container->setHtml($s);
324:         return $container->render(0);
325:     }
326: 
327: 
328:     /**
329:      * Renders group of controls.
330:      * @param  Nette\Forms\Container|FormGroup
331:      * @return string
332:      */
333:     public function renderControls($parent)
334:     {
335:         if (!($parent instanceof Nette\Forms\Container || $parent instanceof Nette\Forms\ControlGroup)) {
336:             throw new Nette\InvalidArgumentException("Argument must be FormContainer or FormGroup instance.");
337:         }
338: 
339:         $container = $this->getWrapper('controls container');
340: 
341:         $buttons = NULL;
342:         foreach ($parent->getControls() as $control) {
343:             if ($control->getOption('rendered') || $control instanceof Nette\Forms\Controls\HiddenField || $control->getForm(FALSE) !== $this->form) {
344:                 // skip
345: 
346:             } elseif ($control instanceof Nette\Forms\Controls\Button) {
347:                 $buttons[] = $control;
348: 
349:             } else {
350:                 if ($buttons) {
351:                     $container->add($this->renderPairMulti($buttons));
352:                     $buttons = NULL;
353:                 }
354:                 $container->add($this->renderPair($control));
355:             }
356:         }
357: 
358:         if ($buttons) {
359:             $container->add($this->renderPairMulti($buttons));
360:         }
361: 
362:         $s = '';
363:         if (count($container)) {
364:             $s .= "\n" . $container . "\n";
365:         }
366: 
367:         return $s;
368:     }
369: 
370: 
371:     /**
372:      * Renders single visual row.
373:      * @return string
374:      */
375:     public function renderPair(Nette\Forms\IControl $control)
376:     {
377:         $pair = $this->getWrapper('pair container');
378:         $pair->add($this->renderLabel($control));
379:         $pair->add($this->renderControl($control));
380:         $pair->class($this->getValue($control->isRequired() ? 'pair .required' : 'pair .optional'), TRUE);
381:         $pair->class($control->getOption('class'), TRUE);
382:         if (++$this->counter % 2) {
383:             $pair->class($this->getValue('pair .odd'), TRUE);
384:         }
385:         $pair->id = $control->getOption('id');
386:         return $pair->render(0);
387:     }
388: 
389: 
390:     /**
391:      * Renders single visual row of multiple controls.
392:      * @param  IFormControl[]
393:      * @return string
394:      */
395:     public function renderPairMulti(array $controls)
396:     {
397:         $s = array();
398:         foreach ($controls as $control) {
399:             if (!$control instanceof Nette\Forms\IControl) {
400:                 throw new Nette\InvalidArgumentException("Argument must be array of IFormControl instances.");
401:             }
402:             $s[] = (string) $control->getControl();
403:         }
404:         $pair = $this->getWrapper('pair container');
405:         $pair->add($this->renderLabel($control));
406:         $pair->add($this->getWrapper('control container')->setHtml(implode(" ", $s)));
407:         return $pair->render(0);
408:     }
409: 
410: 
411:     /**
412:      * Renders 'label' part of visual row of controls.
413:      * @return string
414:      */
415:     public function renderLabel(Nette\Forms\IControl $control)
416:     {
417:         $head = $this->getWrapper('label container');
418: 
419:         if ($control instanceof Nette\Forms\Controls\Checkbox || $control instanceof Nette\Forms\Controls\Button) {
420:             return $head->setHtml(($head->getName() === 'td' || $head->getName() === 'th') ? '&nbsp;' : '');
421: 
422:         } else {
423:             $label = $control->getLabel();
424:             $suffix = $this->getValue('label suffix') . ($control->isRequired() ? $this->getValue('label requiredsuffix') : '');
425:             if ($label instanceof Html) {
426:                 $label->setHtml($label->getHtml() . $suffix);
427:                 $suffix = '';
428:             }
429:             return $head->setHtml((string) $label . $suffix);
430:         }
431:     }
432: 
433: 
434:     /**
435:      * Renders 'control' part of visual row of controls.
436:      * @return string
437:      */
438:     public function renderControl(Nette\Forms\IControl $control)
439:     {
440:         $body = $this->getWrapper('control container');
441:         if ($this->counter % 2) {
442:             $body->class($this->getValue('control .odd'), TRUE);
443:         }
444: 
445:         $description = $control->getOption('description');
446:         if ($description instanceof Html) {
447:             $description = ' ' . $control->getOption('description');
448: 
449:         } elseif (is_string($description)) {
450:             $description = ' ' . $this->getWrapper('control description')->setText($control->translate($description));
451: 
452:         } else {
453:             $description = '';
454:         }
455: 
456:         if ($control->isRequired()) {
457:             $description = $this->getValue('control requiredsuffix') . $description;
458:         }
459: 
460:         if ($this->getValue('control errors')) {
461:             $description .= $this->renderErrors($control);
462:         }
463: 
464:         if ($control instanceof Nette\Forms\Controls\Checkbox || $control instanceof Nette\Forms\Controls\Button) {
465:             return $body->setHtml((string) $control->getControl() . (string) $control->getLabel() . $description);
466: 
467:         } else {
468:             return $body->setHtml((string) $control->getControl() . $description);
469:         }
470:     }
471: 
472: 
473:     /**
474:      * @param  string
475:      * @return Nette\Utils\Html
476:      */
477:     protected function getWrapper($name)
478:     {
479:         $data = $this->getValue($name);
480:         return $data instanceof Html ? clone $data : Html::el($data);
481:     }
482: 
483: 
484:     /**
485:      * @param  string
486:      * @return string
487:      */
488:     protected function getValue($name)
489:     {
490:         $name = explode(' ', $name);
491:         $data = & $this->wrappers[$name[0]][$name[1]];
492:         return $data;
493:     }
494: 
495: }
496: 
Nette Framework 2.0.12 API API documentation generated by ApiGen 2.8.0