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