1 <?php
2 3 4 5 6 7 8
9
10 Yii::import('bootstrap.widgets.input.TbInput');
11
12 13 14
15 class TbActiveForm extends CActiveForm
16 {
17
18 const TYPE_VERTICAL = 'vertical';
19 const TYPE_INLINE = 'inline';
20 const TYPE_HORIZONTAL = 'horizontal';
21 const TYPE_SEARCH = 'search';
22
23
24 const INPUT_HORIZONTAL = 'bootstrap.widgets.input.TbInputHorizontal';
25 const INPUT_INLINE = 'bootstrap.widgets.input.TbInputInline';
26 const INPUT_SEARCH = 'bootstrap.widgets.input.TbInputSearch';
27 const INPUT_VERTICAL = 'bootstrap.widgets.input.TbInputVertical';
28
29 30 31
32 public $type = self::TYPE_VERTICAL;
33 34 35
36 public $input;
37 38 39
40 public $inlineErrors;
41
42 43 44 45
46 public function init()
47 {
48 if (!isset($this->htmlOptions['class']))
49 $this->htmlOptions['class'] = 'form-'.$this->type;
50 else
51 $this->htmlOptions['class'] .= ' form-'.$this->type;
52
53 if (!isset($this->inlineErrors))
54 $this->inlineErrors = $this->type === self::TYPE_HORIZONTAL;
55
56 if ($this->inlineErrors)
57 $this->errorMessageCssClass = 'help-inline error';
58 else
59 $this->errorMessageCssClass = 'help-block error';
60
61 parent::init();
62 }
63
64 65 66 67 68 69 70
71 public function checkBoxRow($model, $attribute, $htmlOptions = array())
72 {
73 return $this->inputRow(TbInput::TYPE_CHECKBOX, $model, $attribute, null, $htmlOptions);
74 }
75
76 77 78 79 80 81 82 83
84 public function checkBoxListRow($model, $attribute, $data = array(), $htmlOptions = array())
85 {
86 return $this->inputRow(TbInput::TYPE_CHECKBOXLIST, $model, $attribute, $data, $htmlOptions);
87 }
88
89 90 91 92 93 94 95 96
97 public function checkBoxListInlineRow($model, $attribute, $data = array(), $htmlOptions = array())
98 {
99 return $this->inputRow(TbInput::TYPE_CHECKBOXLIST_INLINE, $model, $attribute, $data, $htmlOptions);
100 }
101
102 103 104 105 106 107 108 109
110 public function dropDownListRow($model, $attribute, $data = array(), $htmlOptions = array())
111 {
112 return $this->inputRow(TbInput::TYPE_DROPDOWN, $model, $attribute, $data, $htmlOptions);
113 }
114
115 116 117 118 119 120 121
122 public function fileFieldRow($model, $attribute, $htmlOptions = array())
123 {
124 return $this->inputRow(TbInput::TYPE_FILE, $model, $attribute, null, $htmlOptions);
125 }
126
127 128 129 130 131 132 133
134 public function passwordFieldRow($model, $attribute, $htmlOptions = array())
135 {
136 return $this->inputRow(TbInput::TYPE_PASSWORD, $model, $attribute, null, $htmlOptions);
137 }
138
139 140 141 142 143 144 145
146 public function radioButtonRow($model, $attribute, $htmlOptions = array())
147 {
148 return $this->inputRow(TbInput::TYPE_RADIO, $model, $attribute, null, $htmlOptions);
149 }
150
151 152 153 154 155 156 157 158
159 public function radioButtonListRow($model, $attribute, $data = array(), $htmlOptions = array())
160 {
161 return $this->inputRow(TbInput::TYPE_RADIOLIST, $model, $attribute, $data, $htmlOptions);
162 }
163
164 165 166 167 168 169 170 171
172 public function radioButtonListInlineRow($model, $attribute, $data = array(), $htmlOptions = array())
173 {
174 return $this->inputRow(TbInput::TYPE_RADIOLIST_INLINE, $model, $attribute, $data, $htmlOptions);
175 }
176
177 178 179 180 181 182 183
184 public function textFieldRow($model, $attribute, $htmlOptions = array())
185 {
186 return $this->inputRow(TbInput::TYPE_TEXT, $model, $attribute, null, $htmlOptions);
187 }
188
189 190 191 192 193 194 195
196 public function textAreaRow($model, $attribute, $htmlOptions = array())
197 {
198 return $this->inputRow(TbInput::TYPE_TEXTAREA, $model, $attribute, null, $htmlOptions);
199 }
200
201 202 203 204 205 206 207 208
209 public function captchaRow($model, $attribute, $htmlOptions = array())
210 {
211 return $this->inputRow(TbInput::TYPE_CAPTCHA, $model, $attribute, null, $htmlOptions);
212 }
213
214 215 216 217 218 219 220 221
222 public function uneditableRow($model, $attribute, $htmlOptions = array())
223 {
224 return $this->inputRow(TbInput::TYPE_UNEDITABLE, $model, $attribute, null, $htmlOptions);
225 }
226
227 228 229 230 231 232 233 234 235 236 237 238
239 public function checkBoxList($model, $attribute, $data, $htmlOptions = array())
240 {
241 return $this->inputsList(true, $model, $attribute, $data, $htmlOptions);
242 }
243
244 245 246 247 248 249 250 251 252 253 254 255
256 public function radioButtonList($model, $attribute, $data, $htmlOptions = array())
257 {
258 return $this->inputsList(false, $model, $attribute, $data, $htmlOptions);
259 }
260
261 262 263 264 265 266 267 268 269 270
271 protected function inputsList($checkbox, $model, $attribute, $data, $htmlOptions = array())
272 {
273 CHtml::resolveNameID($model, $attribute, $htmlOptions);
274 $select = CHtml::resolveValue($model, $attribute);
275
276 if ($model->hasErrors($attribute))
277 {
278 if (isset($htmlOptions['class']))
279 $htmlOptions['class'] .= ' '.CHtml::$errorCss;
280 else
281 $htmlOptions['class'] = CHtml::$errorCss;
282 }
283
284 $name = $htmlOptions['name'];
285 unset($htmlOptions['name']);
286
287 if (array_key_exists('uncheckValue', $htmlOptions))
288 {
289 $uncheck = $htmlOptions['uncheckValue'];
290 unset($htmlOptions['uncheckValue']);
291 }
292 else
293 $uncheck = '';
294
295 $hiddenOptions = isset($htmlOptions['id']) ? array('id' => CHtml::ID_PREFIX.$htmlOptions['id']) : array('id' => false);
296 $hidden = $uncheck !== null ? CHtml::hiddenField($name, $uncheck, $hiddenOptions) : '';
297
298 if (isset($htmlOptions['template']))
299 $template = $htmlOptions['template'];
300 else
301 $template = '<label class="{labelCssClass}">{input}{label}</label>';
302
303 unset($htmlOptions['template'], $htmlOptions['separator'], $htmlOptions['hint']);
304
305 if ($checkbox && substr($name, -2) !== '[]')
306 $name .= '[]';
307
308 unset($htmlOptions['checkAll'], $htmlOptions['checkAllLast']);
309
310 $labelOptions = isset($htmlOptions['labelOptions']) ? $htmlOptions['labelOptions'] : array();
311 unset($htmlOptions['labelOptions']);
312
313 $items = array();
314 $baseID = CHtml::getIdByName($name);
315 $id = 0;
316 $method = $checkbox ? 'checkBox' : 'radioButton';
317 $labelCssClass = $checkbox ? 'checkbox' : 'radio';
318
319 if (isset($htmlOptions['inline']))
320 {
321 $labelCssClass .= ' inline';
322 unset($htmlOptions['inline']);
323 }
324
325 foreach ($data as $value => $label)
326 {
327 $checked = !is_array($select) && !strcmp($value, $select) || is_array($select) && in_array($value, $select);
328 $htmlOptions['value'] = $value;
329 $htmlOptions['id'] = $baseID.'_'.$id++;
330 $option = CHtml::$method($name, $checked, $htmlOptions);
331 $label = CHtml::label($label, $htmlOptions['id'], $labelOptions);
332 $items[] = strtr($template, array(
333 '{labelCssClass}' => $labelCssClass,
334 '{input}' => $option,
335 '{label}' => $label,
336 ));
337 }
338
339 return $hidden.implode('', $items);
340 }
341
342 343 344 345 346 347 348 349 350 351 352 353
354 public function errorSummary($models, $header = null, $footer = null, $htmlOptions = array())
355 {
356 if (!isset($htmlOptions['class']))
357 $htmlOptions['class'] = 'alert alert-block alert-error';
358
359 return parent::errorSummary($models, $header, $footer, $htmlOptions);
360 }
361
362 363 364 365 366 367 368 369 370
371 public function error($model, $attribute, $htmlOptions = array(), $enableAjaxValidation = true, $enableClientValidation = true)
372 {
373 if (!$this->enableAjaxValidation)
374 $enableAjaxValidation = false;
375
376 if (!$this->enableClientValidation)
377 $enableClientValidation = false;
378
379 if (!isset($htmlOptions['class']))
380 $htmlOptions['class'] = $this->errorMessageCssClass;
381
382 if (!$enableAjaxValidation && !$enableClientValidation)
383 return $this->renderError($model, $attribute, $htmlOptions);
384
385 $id = CHtml::activeId($model,$attribute);
386 $inputID = isset($htmlOptions['inputID']) ? $htmlOptions['inputID'] : $id;
387 unset($htmlOptions['inputID']);
388 if (!isset($htmlOptions['id']))
389 $htmlOptions['id'] = $inputID.'_em_';
390
391 $option = array(
392 'id'=>$id,
393 'inputID'=>$inputID,
394 'errorID'=>$htmlOptions['id'],
395 'model'=>get_class($model),
396 'name'=>CHtml::resolveName($model, $attribute),
397 'enableAjaxValidation'=>$enableAjaxValidation,
398 'inputContainer'=>'div.control-group',
399 );
400
401 $optionNames = array(
402 'validationDelay',
403 'validateOnChange',
404 'validateOnType',
405 'hideErrorMessage',
406 'inputContainer',
407 'errorCssClass',
408 'successCssClass',
409 'validatingCssClass',
410 'beforeValidateAttribute',
411 'afterValidateAttribute',
412 );
413
414 foreach ($optionNames as $name)
415 {
416 if (isset($htmlOptions[$name]))
417 {
418 $option[$name] = $htmlOptions[$name];
419 unset($htmlOptions[$name]);
420 }
421 }
422
423 if ($model instanceof CActiveRecord && !$model->isNewRecord)
424 $option['status'] = 1;
425
426 if ($enableClientValidation)
427 {
428 $validators = isset($htmlOptions['clientValidation']) ? array($htmlOptions['clientValidation']) : array();
429
430 $attributeName = $attribute;
431 if (($pos = strrpos($attribute, ']')) !== false && $pos !== strlen($attribute) - 1)
432 $attributeName = substr($attribute, $pos + 1);
433
434 foreach ($model->getValidators($attributeName) as $validator)
435 {
436 if ($validator->enableClientValidation)
437 if (($js = $validator->clientValidateAttribute($model, $attributeName)) != '')
438 $validators[] = $js;
439 }
440
441 if ($validators !== array())
442 $option['clientValidation'] = "js:function(value, messages, attribute) {\n".implode("\n", $validators)."\n}";
443 }
444
445 $html = $this->renderError($model, $attribute, $htmlOptions);
446
447 if ($html === '')
448 {
449 if (isset($htmlOptions['style']))
450 $htmlOptions['style'] = rtrim($htmlOptions['style'], ';').'; display: none';
451 else
452 $htmlOptions['style'] = 'display: none';
453
454 $html = CHtml::tag('span', $htmlOptions, '');
455 }
456
457 $this->attributes[$inputID] = $option;
458
459 return $html;
460 }
461
462 463 464 465 466 467 468 469 470
471 protected static function renderError($model, $attribute, $htmlOptions = array())
472 {
473 CHtml::resolveName($model, $attribute);
474 $error = $model->getError($attribute);
475 return $error != '' ? CHtml::tag('span', $htmlOptions, $error) : '';
476 }
477
478 479 480 481 482 483 484 485 486
487 public function inputRow($type, $model, $attribute, $data = null, $htmlOptions = array())
488 {
489 ob_start();
490 Yii::app()->controller->widget($this->getInputClassName(), array(
491 'type'=>$type,
492 'form'=>$this,
493 'model'=>$model,
494 'attribute'=>$attribute,
495 'data'=>$data,
496 'htmlOptions'=>$htmlOptions,
497 ));
498 return ob_get_clean();
499 }
500
501 502 503 504
505 protected function getInputClassName()
506 {
507 if (isset($this->input))
508 return $this->input;
509 else
510 {
511 switch ($this->type)
512 {
513 case self::TYPE_HORIZONTAL:
514 return self::INPUT_HORIZONTAL;
515 break;
516
517 case self::TYPE_INLINE:
518 return self::INPUT_INLINE;
519 break;
520
521 case self::TYPE_SEARCH:
522 return self::INPUT_SEARCH;
523 break;
524
525 case self::TYPE_VERTICAL:
526 default:
527 return self::INPUT_VERTICAL;
528 break;
529 }
530 }
531 }
532 }
533