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

Classes

  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  • Other releases
  • Nette homepage
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://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:         $wrapper = & $this->wrappers['control'];
164:         foreach ($this->form->getControls() as $control) {
165:             if ($control->isRequired() && isset($wrapper['.required'])) {
166:                 $control->getLabelPrototype()->class($wrapper['.required'], TRUE);
167:             }
168: 
169:             $el = $control->getControlPrototype();
170:             if ($el->getName() === 'input' && isset($wrapper['.' . $el->type])) {
171:                 $el->class($wrapper['.' . $el->type], TRUE);
172:             }
173:         }
174:     }
175: 
176: 
177:     /**
178:      * Renders form begin.
179:      * @return string
180:      */
181:     public function renderBegin()
182:     {
183:         $this->counter = 0;
184: 
185:         foreach ($this->form->getControls() as $control) {
186:             $control->setOption('rendered', FALSE);
187:         }
188: 
189:         if (strcasecmp($this->form->getMethod(), 'get') === 0) {
190:             $el = clone $this->form->getElementPrototype();
191:             $url = explode('?', (string) $el->action, 2);
192:             $el->action = $url[0];
193:             $s = '';
194:             if (isset($url[1])) {
195:                 foreach (preg_split('#[;&]#', $url[1]) as $param) {
196:                     $parts = explode('=', $param, 2);
197:                     $name = urldecode($parts[0]);
198:                     if (!isset($this->form[$name])) {
199:                         $s .= NHtml::el('input', array('type' => 'hidden', 'name' => $name, 'value' => urldecode($parts[1])));
200:                     }
201:                 }
202:                 $s = "\n\t" . $this->getWrapper('hidden container')->setHtml($s);
203:             }
204:             return $el->startTag() . $s;
205: 
206: 
207:         } else {
208:             return $this->form->getElementPrototype()->startTag();
209:         }
210:     }
211: 
212: 
213:     /**
214:      * Renders form end.
215:      * @return string
216:      */
217:     public function renderEnd()
218:     {
219:         $s = '';
220:         foreach ($this->form->getControls() as $control) {
221:             if ($control instanceof NHiddenField && !$control->getOption('rendered')) {
222:                 $s .= (string) $control->getControl();
223:             }
224:         }
225:         if (iterator_count($this->form->getComponents(TRUE, 'NTextInput')) < 2) {
226:             $s .= '<!--[if IE]><input type=IEbug disabled style="display:none"><![endif]-->';
227:         }
228:         if ($s) {
229:             $s = $this->getWrapper('hidden container')->setHtml($s) . "\n";
230:         }
231: 
232:         return $s . $this->form->getElementPrototype()->endTag() . "\n";
233:     }
234: 
235: 
236:     /**
237:      * Renders validation errors (per form or per control).
238:      * @return string
239:      */
240:     public function renderErrors(IFormControl $control = NULL)
241:     {
242:         $errors = $control === NULL ? $this->form->getErrors() : $control->getErrors();
243:         if (count($errors)) {
244:             $ul = $this->getWrapper('error container');
245:             $li = $this->getWrapper('error item');
246: 
247:             foreach ($errors as $error) {
248:                 $item = clone $li;
249:                 if ($error instanceof NHtml) {
250:                     $item->add($error);
251:                 } else {
252:                     $item->setText($error);
253:                 }
254:                 $ul->add($item);
255:             }
256:             return "\n" . $ul->render(0);
257:         }
258:     }
259: 
260: 
261:     /**
262:      * Renders form body.
263:      * @return string
264:      */
265:     public function renderBody()
266:     {
267:         $s = $remains = '';
268: 
269:         $defaultContainer = $this->getWrapper('group container');
270:         $translator = $this->form->getTranslator();
271: 
272:         foreach ($this->form->getGroups() as $group) {
273:             if (!$group->getControls() || !$group->getOption('visual')) {
274:                 continue;
275:             }
276: 
277:             $container = $group->getOption('container', $defaultContainer);
278:             $container = $container instanceof NHtml ? clone $container : NHtml::el($container);
279: 
280:             $s .= "\n" . $container->startTag();
281: 
282:             $text = $group->getOption('label');
283:             if ($text instanceof NHtml) {
284:                 $s .= $text;
285: 
286:             } elseif (is_string($text)) {
287:                 if ($translator !== NULL) {
288:                     $text = $translator->translate($text);
289:                 }
290:                 $s .= "\n" . $this->getWrapper('group label')->setText($text) . "\n";
291:             }
292: 
293:             $text = $group->getOption('description');
294:             if ($text instanceof NHtml) {
295:                 $s .= $text;
296: 
297:             } elseif (is_string($text)) {
298:                 if ($translator !== NULL) {
299:                     $text = $translator->translate($text);
300:                 }
301:                 $s .= $this->getWrapper('group description')->setText($text) . "\n";
302:             }
303: 
304:             $s .= $this->renderControls($group);
305: 
306:             $remains = $container->endTag() . "\n" . $remains;
307:             if (!$group->getOption('embedNext')) {
308:                 $s .= $remains;
309:                 $remains = '';
310:             }
311:         }
312: 
313:         $s .= $remains . $this->renderControls($this->form);
314: 
315:         $container = $this->getWrapper('form container');
316:         $container->setHtml($s);
317:         return $container->render(0);
318:     }
319: 
320: 
321:     /**
322:      * Renders group of controls.
323:      * @param  NFormContainer|NFormGroup
324:      * @return string
325:      */
326:     public function renderControls($parent)
327:     {
328:         if (!($parent instanceof NFormContainer || $parent instanceof NFormGroup)) {
329:             throw new InvalidArgumentException('Argument must be FormContainer or FormGroup instance.');
330:         }
331: 
332:         $container = $this->getWrapper('controls container');
333: 
334:         $buttons = NULL;
335:         foreach ($parent->getControls() as $control) {
336:             if ($control->getOption('rendered') || $control instanceof NHiddenField || $control->getForm(FALSE) !== $this->form) {
337:                 // skip
338: 
339:             } elseif ($control instanceof NButton) {
340:                 $buttons[] = $control;
341: 
342:             } else {
343:                 if ($buttons) {
344:                     $container->add($this->renderPairMulti($buttons));
345:                     $buttons = NULL;
346:                 }
347:                 $container->add($this->renderPair($control));
348:             }
349:         }
350: 
351:         if ($buttons) {
352:             $container->add($this->renderPairMulti($buttons));
353:         }
354: 
355:         $s = '';
356:         if (count($container)) {
357:             $s .= "\n" . $container . "\n";
358:         }
359: 
360:         return $s;
361:     }
362: 
363: 
364:     /**
365:      * Renders single visual row.
366:      * @return string
367:      */
368:     public function renderPair(IFormControl $control)
369:     {
370:         $pair = $this->getWrapper('pair container');
371:         $pair->add($this->renderLabel($control));
372:         $pair->add($this->renderControl($control));
373:         $pair->class($this->getValue($control->isRequired() ? 'pair .required' : 'pair .optional'), TRUE);
374:         $pair->class($control->getOption('class'), TRUE);
375:         if (++$this->counter % 2) {
376:             $pair->class($this->getValue('pair .odd'), TRUE);
377:         }
378:         $pair->id = $control->getOption('id');
379:         return $pair->render(0);
380:     }
381: 
382: 
383:     /**
384:      * Renders single visual row of multiple controls.
385:      * @param  IFormControl[]
386:      * @return string
387:      */
388:     public function renderPairMulti(array $controls)
389:     {
390:         $s = array();
391:         foreach ($controls as $control) {
392:             if (!$control instanceof IFormControl) {
393:                 throw new InvalidArgumentException('Argument must be array of IFormControl instances.');
394:             }
395:             $s[] = (string) $control->getControl();
396:         }
397:         $pair = $this->getWrapper('pair container');
398:         $pair->add($this->renderLabel($control));
399:         $pair->add($this->getWrapper('control container')->setHtml(implode(' ', $s)));
400:         return $pair->render(0);
401:     }
402: 
403: 
404:     /**
405:      * Renders 'label' part of visual row of controls.
406:      * @return string
407:      */
408:     public function renderLabel(IFormControl $control)
409:     {
410:         $head = $this->getWrapper('label container');
411: 
412:         if ($control instanceof NCheckbox || $control instanceof NButton) {
413:             return $head->setHtml(($head->getName() === 'td' || $head->getName() === 'th') ? '&nbsp;' : '');
414: 
415:         } else {
416:             $label = $control->getLabel();
417:             $suffix = $this->getValue('label suffix') . ($control->isRequired() ? $this->getValue('label requiredsuffix') : '');
418:             if ($label instanceof NHtml) {
419:                 $label->setHtml($label->getHtml() . $suffix);
420:                 $suffix = '';
421:             }
422:             return $head->setHtml((string) $label . $suffix);
423:         }
424:     }
425: 
426: 
427:     /**
428:      * Renders 'control' part of visual row of controls.
429:      * @return string
430:      */
431:     public function renderControl(IFormControl $control)
432:     {
433:         $body = $this->getWrapper('control container');
434:         if ($this->counter % 2) {
435:             $body->class($this->getValue('control .odd'), TRUE);
436:         }
437: 
438:         $description = $control->getOption('description');
439:         if ($description instanceof NHtml) {
440:             $description = ' ' . $control->getOption('description');
441: 
442:         } elseif (is_string($description)) {
443:             $description = ' ' . $this->getWrapper('control description')->setText($control->translate($description));
444: 
445:         } else {
446:             $description = '';
447:         }
448: 
449:         if ($control->isRequired()) {
450:             $description = $this->getValue('control requiredsuffix') . $description;
451:         }
452: 
453:         if ($this->getValue('control errors')) {
454:             $description .= $this->renderErrors($control);
455:         }
456: 
457:         if ($control instanceof NCheckbox || $control instanceof NButton) {
458:             return $body->setHtml((string) $control->getControl() . (string) $control->getLabel() . $description);
459: 
460:         } else {
461:             return $body->setHtml((string) $control->getControl() . $description);
462:         }
463:     }
464: 
465: 
466:     /**
467:      * @param  string
468:      * @return NHtml
469:      */
470:     protected function getWrapper($name)
471:     {
472:         $data = $this->getValue($name);
473:         return $data instanceof NHtml ? clone $data : NHtml::el($data);
474:     }
475: 
476: 
477:     /**
478:      * @param  string
479:      * @return string
480:      */
481:     protected function getValue($name)
482:     {
483:         $name = explode(' ', $name);
484:         $data = & $this->wrappers[$name[0]][$name[1]];
485:         return $data;
486:     }
487: 
488: }
489: 
Nette Framework 2.0.18 (for PHP 5.2, prefixed) API documentation generated by ApiGen 2.8.0