Packages

  • Nette
    • Application
    • Caching
    • Collections
    • Config
    • Forms
    • IO
    • Loaders
    • Mail
    • Reflection
    • Security
    • Templates
    • Web
  • None
  • PHP

Classes

  • NButton
  • NCheckbox
  • NConventionalRenderer
  • NFileUpload
  • NForm
  • NFormContainer
  • NFormGroup
  • NHiddenField
  • NImageButton
  • NInstantClientScript
  • NMultiSelectBox
  • NRadioList
  • NRule
  • NRules
  • NSelectBox
  • NSubmitButton
  • NTextArea
  • NTextBase
  • NTextInput

Interfaces

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