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