Packages

  • 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

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