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