PageRenderTime 80ms CodeModel.GetById 21ms RepoModel.GetById 2ms app.codeStats 1ms

/admincrud/extensions/bootstrap/widgets/TbActiveForm.php

https://github.com/max-rautkin/yii-admincrud
PHP | 1130 lines | 512 code | 100 blank | 518 comment | 55 complexity | 9ad56f567e7f2071b9c0fd0cbf58409c MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause
  1. <?php
  2. /*## ActiveForm supporting cool inputs from Bootstrap
  3. *
  4. * @author Christoffer Niska <ChristofferNiska@gmail.com>
  5. * @copyright Copyright &copy; Christoffer Niska 2011-
  6. * @license [New BSD License](http://www.opensource.org/licenses/bsd-license.php)
  7. * @package bootstrap.widgets
  8. */
  9. Yii::import('bootstrap.widgets.input.TbInput');
  10. class TbActiveForm extends CActiveForm
  11. {
  12. // Allowed form types.
  13. const TYPE_VERTICAL = 'vertical';
  14. const TYPE_INLINE = 'inline';
  15. const TYPE_HORIZONTAL = 'horizontal';
  16. const TYPE_SEARCH = 'search';
  17. // Input classes.
  18. const INPUT_HORIZONTAL = 'bootstrap.widgets.input.TbInputHorizontal';
  19. const INPUT_INLINE = 'bootstrap.widgets.input.TbInputInline';
  20. const INPUT_SEARCH = 'bootstrap.widgets.input.TbInputSearch';
  21. const INPUT_VERTICAL = 'bootstrap.widgets.input.TbInputVertical';
  22. /**
  23. * @var string the form type. Allowed types are in `TYPE_*` constants
  24. */
  25. public $type = self::TYPE_VERTICAL;
  26. /**
  27. * @var string input class.
  28. */
  29. public $input;
  30. /**
  31. * @var boolean flag that indicates if the errors should be displayed as blocks.
  32. */
  33. public $inlineErrors;
  34. /**
  35. *### .init()
  36. * Initializes the widget.
  37. * This renders the form open tag.
  38. */
  39. public function init()
  40. {
  41. if (!isset($this->htmlOptions['class'])) {
  42. $this->htmlOptions['class'] = 'form-' . $this->type;
  43. } else {
  44. $this->htmlOptions['class'] .= ' form-' . $this->type;
  45. }
  46. if (!isset($this->inlineErrors)) {
  47. $this->inlineErrors = $this->type === self::TYPE_HORIZONTAL;
  48. }
  49. if ($this->inlineErrors) {
  50. $this->errorMessageCssClass = 'help-inline error';
  51. } else {
  52. $this->errorMessageCssClass = 'help-block error';
  53. }
  54. parent::init();
  55. }
  56. /**
  57. *### .checkBoxRow()
  58. *
  59. * Renders a checkbox input row.
  60. *
  61. * @param CModel $model the data model
  62. * @param string $attribute the attribute
  63. * @param array $htmlOptions additional HTML attributes
  64. *
  65. * @return string the generated row
  66. */
  67. public function checkBoxRow($model, $attribute, $htmlOptions = array())
  68. {
  69. return $this->inputRow(TbInput::TYPE_CHECKBOX, $model, $attribute, null, $htmlOptions);
  70. }
  71. /**
  72. *### .toggleButtonRow()
  73. *
  74. * Renders a toggle input row.
  75. *
  76. * @param CModel $model the data model
  77. * @param string $attribute the attribute
  78. * @param array $htmlOptions additional HTML attributes (options key sets the options for the toggle component)
  79. *
  80. * @return string the generated row
  81. */
  82. public function toggleButtonRow($model, $attribute, $htmlOptions = array())
  83. {
  84. return $this->inputRow(TbInput::TYPE_TOGGLEBUTTON, $model, $attribute, null, $htmlOptions);
  85. }
  86. /**
  87. *### .checkBoxListRow()
  88. *
  89. * Renders a checkbox list input row.
  90. *
  91. * @param CModel $model the data model
  92. * @param string $attribute the attribute
  93. * @param array $data the list data
  94. * @param array $htmlOptions additional HTML attributes
  95. *
  96. * @return string the generated row
  97. */
  98. public function checkBoxListRow($model, $attribute, $data = array(), $htmlOptions = array())
  99. {
  100. return $this->inputRow(TbInput::TYPE_CHECKBOXLIST, $model, $attribute, $data, $htmlOptions);
  101. }
  102. /**
  103. *### .checkBoxListInlineRow()
  104. *
  105. * Renders a checkbox list inline input row.
  106. *
  107. * @param CModel $model the data model
  108. * @param string $attribute the attribute
  109. * @param array $data the list data
  110. * @param array $htmlOptions additional HTML attributes
  111. *
  112. * @return string the generated row
  113. */
  114. public function checkBoxListInlineRow($model, $attribute, $data = array(), $htmlOptions = array())
  115. {
  116. return $this->inputRow(TbInput::TYPE_CHECKBOXLIST_INLINE, $model, $attribute, $data, $htmlOptions);
  117. }
  118. /**
  119. *### .checkBoxGroupsListRow()
  120. *
  121. * Renders a checkbox list input row using Button Groups.
  122. *
  123. * @param CModel $model the data model
  124. * @param string $attribute the attribute
  125. * @param array $data the list data
  126. * @param array $htmlOptions additional HTML attributes
  127. *
  128. * @return string the generated row
  129. */
  130. public function checkBoxGroupsListRow($model, $attribute, $data = array(), $htmlOptions = array())
  131. {
  132. return $this->inputRow(TbInput::TYPE_CHECKBOXGROUPSLIST, $model, $attribute, $data, $htmlOptions);
  133. }
  134. /**
  135. *### dropDownListRow()
  136. *
  137. * Renders a drop-down list input row.
  138. *
  139. * @param CModel $model the data model
  140. * @param string $attribute the attribute
  141. * @param array $data the list data
  142. * @param array $htmlOptions additional HTML attributes
  143. *
  144. * @return string the generated row
  145. */
  146. public function dropDownListRow($model, $attribute, $data = array(), $htmlOptions = array())
  147. {
  148. return $this->inputRow(TbInput::TYPE_DROPDOWN, $model, $attribute, $data, $htmlOptions);
  149. }
  150. /**
  151. *### .fileFieldRow()
  152. *
  153. * Renders a file field input row.
  154. *
  155. * @param CModel $model the data model
  156. * @param string $attribute the attribute
  157. * @param array $htmlOptions additional HTML attributes
  158. *
  159. * @return string the generated row
  160. */
  161. public function fileFieldRow($model, $attribute, $htmlOptions = array())
  162. {
  163. return $this->inputRow(TbInput::TYPE_FILE, $model, $attribute, null, $htmlOptions);
  164. }
  165. /**
  166. *### .passwordFieldRow()
  167. *
  168. * Renders a password field input row.
  169. *
  170. * @param CModel $model the data model
  171. * @param string $attribute the attribute
  172. * @param array $htmlOptions additional HTML attributes
  173. *
  174. * @return string the generated row
  175. */
  176. public function passwordFieldRow($model, $attribute, $htmlOptions = array())
  177. {
  178. return $this->inputRow(TbInput::TYPE_PASSWORD, $model, $attribute, null, $htmlOptions);
  179. }
  180. /**
  181. *### .radioButtonRow()
  182. *
  183. * Renders a radio button input row.
  184. *
  185. * @param CModel $model the data model
  186. * @param string $attribute the attribute
  187. * @param array $htmlOptions additional HTML attributes
  188. *
  189. * @return string the generated row
  190. */
  191. public function radioButtonRow($model, $attribute, $htmlOptions = array())
  192. {
  193. return $this->inputRow(TbInput::TYPE_RADIO, $model, $attribute, null, $htmlOptions);
  194. }
  195. /**
  196. *### .radioButtonListRow()
  197. *
  198. * Renders a radio button list input row.
  199. *
  200. * @param CModel $model the data model
  201. * @param string $attribute the attribute
  202. * @param array $data the list data
  203. * @param array $htmlOptions additional HTML attributes
  204. *
  205. * @return string the generated row
  206. */
  207. public function radioButtonListRow($model, $attribute, $data = array(), $htmlOptions = array())
  208. {
  209. return $this->inputRow(TbInput::TYPE_RADIOLIST, $model, $attribute, $data, $htmlOptions);
  210. }
  211. /**
  212. *### .radioButtonListInlineRow()
  213. *
  214. * Renders a radio button list inline input row.
  215. *
  216. * @param CModel $model the data model
  217. * @param string $attribute the attribute
  218. * @param array $data the list data
  219. * @param array $htmlOptions additional HTML attributes
  220. *
  221. * @return string the generated row
  222. */
  223. public function radioButtonListInlineRow($model, $attribute, $data = array(), $htmlOptions = array())
  224. {
  225. return $this->inputRow(TbInput::TYPE_RADIOLIST_INLINE, $model, $attribute, $data, $htmlOptions);
  226. }
  227. /**
  228. *### .radioButtonGroupsListRow()
  229. *
  230. * Renders a radio button list input row using Button Groups.
  231. *
  232. * @param CModel $model the data model
  233. * @param string $attribute the attribute
  234. * @param array $data the list data
  235. * @param array $htmlOptions additional HTML attributes
  236. *
  237. * @return string the generated row
  238. */
  239. public function radioButtonGroupsListRow($model, $attribute, $data = array(), $htmlOptions = array())
  240. {
  241. return $this->inputRow(TbInput::TYPE_RADIOBUTTONGROUPSLIST, $model, $attribute, $data, $htmlOptions);
  242. }
  243. /**
  244. *### .textFieldRow()
  245. *
  246. * Renders a text field input row.
  247. *
  248. * @param CModel $model the data model
  249. * @param string $attribute the attribute
  250. * @param array $htmlOptions additional HTML attributes
  251. *
  252. * @return string the generated row
  253. */
  254. public function textFieldRow($model, $attribute, $htmlOptions = array())
  255. {
  256. return $this->inputRow(TbInput::TYPE_TEXT, $model, $attribute, null, $htmlOptions);
  257. }
  258. /**
  259. *### .maskedTextFieldRow()
  260. *
  261. * Renders a masked text field input row.
  262. *
  263. * @param CModel $model the data model
  264. * @param string $attribute the attribute
  265. * @param array $mask the mask (see {@link http://digitalbush.com/projects/masked-input-plugin})
  266. * @param array $htmlOptions additional HTML attributes
  267. *
  268. * @return string the generated row
  269. */
  270. public function maskedTextFieldRow($model, $attribute, $mask, $htmlOptions = array())
  271. {
  272. return $this->inputRow(TbInput::TYPE_MASKEDTEXT, $model, $attribute, $mask, $htmlOptions);
  273. }
  274. /**
  275. *### .textAreaRow()
  276. *
  277. * Renders a text area input row.
  278. *
  279. * @param CModel $model the data model
  280. * @param string $attribute the attribute
  281. * @param array $htmlOptions additional HTML attributes
  282. *
  283. * @return string the generated row
  284. */
  285. public function textAreaRow($model, $attribute, $htmlOptions = array())
  286. {
  287. return $this->inputRow(TbInput::TYPE_TEXTAREA, $model, $attribute, null, $htmlOptions);
  288. }
  289. /**
  290. *### .redactorRow()
  291. *
  292. * Renders a WYSIWYG redactor editor
  293. *
  294. * @param CModel $model
  295. * @param string $attribute
  296. * @param array $htmlOptions
  297. *
  298. * @return string
  299. */
  300. public function redactorRow($model, $attribute, $htmlOptions = array())
  301. {
  302. return $this->inputRow(TbInput::TYPE_REDACTOR, $model, $attribute, null, $htmlOptions);
  303. }
  304. /**
  305. *### .markdownEditorRow()
  306. *
  307. * Renders a WYSIWYG Markdown editor
  308. *
  309. * @param CModel $model
  310. * @param string $attribute
  311. * @param array $htmlOptions
  312. *
  313. * @return string
  314. */
  315. public function markdownEditorRow($model, $attribute, $htmlOptions = array())
  316. {
  317. return $this->inputRow(TbInput::TYPE_MARKDOWNEDITOR, $model, $attribute, null, $htmlOptions);
  318. }
  319. /**
  320. *### .html5EditorRow()
  321. *
  322. * Renders a WYSIWYG bootstrap editor
  323. *
  324. * @param CModel $model
  325. * @param string $attribute
  326. * @param array $htmlOptions
  327. *
  328. * @return string
  329. */
  330. public function html5EditorRow($model, $attribute, $htmlOptions = array())
  331. {
  332. return $this->inputRow(TbInput::TYPE_HTML5EDITOR, $model, $attribute, null, $htmlOptions);
  333. }
  334. /**
  335. *### .ckEditorRow()
  336. *
  337. * Renders a WYSIWYG ckeditor
  338. *
  339. * @param CModel $model
  340. * @param string $attribute
  341. * @param array $htmlOptions
  342. *
  343. * @return string
  344. */
  345. public function ckEditorRow($model, $attribute, $htmlOptions = array())
  346. {
  347. return $this->inputRow(TbInput::TYPE_CKEDITOR, $model, $attribute, null, $htmlOptions);
  348. }
  349. /**
  350. *### .captchaRow()
  351. *
  352. * Renders a captcha row.
  353. *
  354. * @param CModel $model the data model
  355. * @param string $attribute the attribute
  356. * @param array $htmlOptions additional HTML attributes
  357. *
  358. * @return string the generated row
  359. *
  360. * @since 0.9.3
  361. */
  362. public function captchaRow($model, $attribute, $htmlOptions = array())
  363. {
  364. return $this->inputRow(TbInput::TYPE_CAPTCHA, $model, $attribute, null, $htmlOptions);
  365. }
  366. /**
  367. *### .uneditableRow()
  368. *
  369. * Renders an uneditable text field row.
  370. *
  371. * @param CModel $model the data model
  372. * @param string $attribute the attribute
  373. * @param array $htmlOptions additional HTML attributes
  374. *
  375. * @return string the generated row
  376. *
  377. * @since 0.9.5
  378. */
  379. public function uneditableRow($model, $attribute, $htmlOptions = array())
  380. {
  381. return $this->inputRow(TbInput::TYPE_UNEDITABLE, $model, $attribute, null, $htmlOptions);
  382. }
  383. /**
  384. *### .datepickerRow()
  385. *
  386. * Renders a datepicker field row.
  387. *
  388. * @param CModel $model the data model
  389. * @param string $attribute the attribute
  390. * @param array $htmlOptions additional HTML attributes. 'events' and 'options' key specify the events
  391. * and configuration options of datepicker respectively.
  392. *
  393. * @return string the generated row
  394. *
  395. * @since 1.0.2 Booster
  396. */
  397. public function datepickerRow($model, $attribute, $htmlOptions = array())
  398. {
  399. return $this->inputRow(TbInput::TYPE_DATEPICKER, $model, $attribute, null, $htmlOptions);
  400. }
  401. /**
  402. *### .colorpickerRow()
  403. *
  404. * Renders a colorpicker field row.
  405. *
  406. * @param CModel $model the data model
  407. * @param string $attribute the attribute
  408. * @param array $htmlOptions additional HTML attributes. 'events' and 'options' key specify the events
  409. * and configuration options of colorpicker respectively.
  410. *
  411. * @return string the generated row
  412. *
  413. * @since 1.0.3 Booster
  414. */
  415. public function colorpickerRow($model, $attribute, $htmlOptions = array())
  416. {
  417. return $this->inputRow(TbInput::TYPE_COLORPICKER, $model, $attribute, null, $htmlOptions);
  418. }
  419. /**
  420. *### .dateRangeRow()
  421. *
  422. * @param CModel $model
  423. * @param string $attribute
  424. * @param array $htmlOptions addition HTML attributes. In order to pass initialization parameters to dateRange, you
  425. * need to set the HTML 'options' key with an array of configuration options.
  426. *
  427. * @return string
  428. */
  429. public function dateRangeRow($model, $attribute, $htmlOptions = array())
  430. {
  431. return $this->inputRow(TbInput::TYPE_DATERANGEPICKER, $model, $attribute, null, $htmlOptions);
  432. }
  433. /**
  434. *### .timepickerRow()
  435. *
  436. * Renders a timepicker field row.
  437. *
  438. * @param CModel $model the data model
  439. * @param string $attribute the attribute
  440. * @param array $htmlOptions additional HTML attributes
  441. *
  442. * @return string the generated row
  443. *
  444. * @since 0.10.0
  445. */
  446. public function timepickerRow($model, $attribute, $htmlOptions = array())
  447. {
  448. return $this->inputRow(TbInput::TYPE_TIMEPICKER, $model, $attribute, null, $htmlOptions);
  449. }
  450. /**
  451. *### .select2Row()
  452. *
  453. * TODO: WTF is a input of type `Select2`? Rename it to something more meaningful!
  454. *
  455. * Renders a select2 field row
  456. *
  457. * @param CModel $model
  458. * @param string $attribute
  459. * @param array $htmlOptions
  460. *
  461. * @return string
  462. */
  463. public function select2Row($model, $attribute, $htmlOptions = array())
  464. {
  465. return $this->inputRow(TbInput::TYPE_SELECT2, $model, $attribute, null, $htmlOptions);
  466. }
  467. /**
  468. * Renders a typeAhead input row
  469. *
  470. * @param CModel $model the data model
  471. * @param string $attribute the attribute
  472. * @param array $widgetOptions
  473. * @param array $htmlOptions additional HTML attributes
  474. *
  475. * @return string the generated row
  476. */
  477. public function typeAheadRow($model, $attribute, $widgetOptions = array(), $htmlOptions = array())
  478. {
  479. return $this->inputRow(TbInput::TYPE_TYPEAHEAD, $model, $attribute, $widgetOptions, $htmlOptions);
  480. }
  481. /**
  482. * Renders a number field input row.
  483. *
  484. * @param CModel $model the data model
  485. * @param string $attribute the attribute
  486. * @param array $htmlOptions additional HTML attributes
  487. *
  488. * @return string the generated row
  489. */
  490. public function numberFieldRow($model, $attribute, $htmlOptions = array())
  491. {
  492. return $this->inputRow(TbInput::TYPE_NUMBER, $model, $attribute, null, $htmlOptions);
  493. }
  494. /**
  495. *### .checkBoxList()
  496. *
  497. * Renders a checkbox list for a model attribute.
  498. *
  499. * This method is a wrapper of {@link CHtml::activeCheckBoxList}.
  500. * Please check {@link CHtml::activeCheckBoxList} for detailed information
  501. * about the parameters for this method.
  502. *
  503. * @param CModel $model the data model
  504. * @param string $attribute the attribute
  505. * @param array $data value-label pairs used to generate the check box list.
  506. * @param array $htmlOptions additional HTML options.
  507. *
  508. * @return string the generated check box list
  509. *
  510. * @since 0.9.5
  511. */
  512. public function checkBoxList($model, $attribute, $data, $htmlOptions = array())
  513. {
  514. return $this->inputsList(true, $model, $attribute, $data, $htmlOptions);
  515. }
  516. /**
  517. *### .checkBoxGroupsList()
  518. *
  519. * Renders a checkbox list for a model attribute using Button Groups.
  520. *
  521. * @param CModel $model the data model
  522. * @param string $attribute the attribute
  523. * @param array $data value-label pairs used to generate the checkbox list.
  524. * @param array $htmlOptions additional HTML options.
  525. *
  526. * @return string the generated checkbox list
  527. *
  528. * @since 0.9.5
  529. */
  530. public function checkBoxGroupsList($model, $attribute, $data, $htmlOptions = array())
  531. {
  532. $buttons = array();
  533. $scripts = array();
  534. $buttonType = isset($htmlOptions['type']) ? $htmlOptions['type'] : null;
  535. $values = CHtml::value($model, $attribute);
  536. if ($values == null) {
  537. $values = array();
  538. }
  539. foreach ($data as $key => $value) {
  540. $btnId = CHtml::getIdByName(get_class($model) . '[' . $attribute . '][' . $key . ']');
  541. $active = in_array($key, $values);
  542. $button = array();
  543. $button['label'] = $value;
  544. $button['active'] = $active;
  545. $button['htmlOptions'] = array('value' => $key, 'id' => $btnId,);
  546. $buttons[] = $button;
  547. // event as ordinary input
  548. $hiddenFieldName = get_class($model) . '[' . $attribute . '][]';
  549. $hiddenFieldId = CHtml::getIdByName(get_class($model) . '[' . $attribute . '][' . $key . '][hidden]');
  550. $scripts[] = "\$('#" . $btnId . "').click(function(){
  551. if (\$('#" . $hiddenFieldId . "').length > 0)
  552. {
  553. \$('#" . $hiddenFieldId . "').remove();
  554. }
  555. else
  556. {
  557. var hidden = \$('<input type=\"hidden\">')
  558. .attr('id', '" . $hiddenFieldId . "')
  559. .attr('name', '" . $hiddenFieldName . "')
  560. .val('" . $key . "');
  561. hidden.appendTo(\$('#" . $btnId . "'));
  562. }
  563. });";
  564. if ($active) {
  565. echo CHtml::hiddenField($hiddenFieldName, $key, array('id' => $hiddenFieldId));
  566. }
  567. }
  568. Yii::app()->controller->widget(
  569. 'bootstrap.widgets.TbButtonGroup',
  570. array(
  571. 'buttonType' => 'button',
  572. 'toggle' => 'checkbox',
  573. 'htmlOptions' => $htmlOptions,
  574. 'buttons' => $buttons,
  575. 'type' => $buttonType,
  576. )
  577. );
  578. Yii::app()->clientScript->registerScript('checkboxgrouplist-' . $attribute, implode("\n", $scripts));
  579. }
  580. /**
  581. *### .radioButtonList()
  582. *
  583. * Renders a radio button list for a model attribute.
  584. *
  585. * This method is a wrapper of {@link CHtml::activeRadioButtonList}.
  586. * Please check {@link CHtml::activeRadioButtonList} for detailed information
  587. * about the parameters for this method.
  588. *
  589. * @param CModel $model the data model
  590. * @param string $attribute the attribute
  591. * @param array $data value-label pairs used to generate the radio button list.
  592. * @param array $htmlOptions additional HTML options.
  593. *
  594. * @return string the generated radio button list
  595. *
  596. * @since 0.9.5
  597. */
  598. public function radioButtonList($model, $attribute, $data, $htmlOptions = array())
  599. {
  600. return $this->inputsList(false, $model, $attribute, $data, $htmlOptions);
  601. }
  602. /**
  603. *### .radioButtonGroupsList()
  604. *
  605. * Renders a radio button list for a model attribute using Button Groups.
  606. *
  607. * @param CModel $model the data model
  608. * @param string $attribute the attribute
  609. * @param array $data value-label pairs used to generate the radio button list.
  610. * @param array $htmlOptions additional HTML options.
  611. *
  612. * @return string the generated radio button list
  613. *
  614. * @since 0.9.5
  615. */
  616. public function radioButtonGroupsList($model, $attribute, $data, $htmlOptions = array())
  617. {
  618. $buttons = array();
  619. $scripts = array();
  620. $hiddenFieldId = CHtml::getIdByName(get_class($model) . '[' . $attribute . ']');
  621. $buttonType = isset($htmlOptions['type']) ? $htmlOptions['type'] : null;
  622. foreach ($data as $key => $value) {
  623. $btnId = CHtml::getIdByName(get_class($model) . '[' . $attribute . '][' . $key . ']');
  624. $button = array();
  625. $button['label'] = $value;
  626. $button['htmlOptions'] = array(
  627. 'value' => $key,
  628. 'id' => $btnId,
  629. 'class' => (isset($model->$attribute) && $model->$attribute == $key ? 'active' : ''),
  630. );
  631. $buttons[] = $button;
  632. // event as ordinary input
  633. $scripts[] = "\$('#" . $btnId . "').click(function(){
  634. \$('#" . $hiddenFieldId . "').val('" . $key . "').trigger('change');
  635. });";
  636. }
  637. Yii::app()->controller->widget(
  638. 'bootstrap.widgets.TbButtonGroup',
  639. array(
  640. 'buttonType' => 'button',
  641. 'toggle' => 'radio',
  642. 'htmlOptions' => $htmlOptions,
  643. 'buttons' => $buttons,
  644. 'type' => $buttonType,
  645. )
  646. );
  647. echo $this->hiddenField($model, $attribute);
  648. Yii::app()->clientScript->registerScript('radiobuttongrouplist-' . $attribute, implode("\n", $scripts));
  649. }
  650. /**
  651. * Renders a masked text field row
  652. *
  653. * @param CModel $model the data model
  654. * @param string $attribute the attribute
  655. * @param array $mask the mask (see {@link http://digitalbush.com/projects/masked-input-plugin})
  656. * @param array $htmlOptions additional HTML options.
  657. *
  658. * @return string the generated masked text field
  659. * @since 0.9.5
  660. */
  661. public function maskedTextField($model, $attribute, $mask, $htmlOptions = array())
  662. {
  663. return Yii::app()->controller->widget(
  664. 'CMaskedTextField',
  665. array(
  666. 'model' => $model,
  667. 'attribute' => $attribute,
  668. 'mask' => $mask,
  669. 'htmlOptions' => $htmlOptions
  670. ),
  671. true
  672. );
  673. }
  674. /**
  675. * Renders a type ahead field row
  676. *
  677. * @param CModel $model the data model
  678. * @param string $attribute the attribute
  679. * @param array $widgetOptions typeAhead options (see {@link http://twitter.github.com/bootstrap/javascript.html#typeahead})
  680. * @param array $htmlOptions additional HTML options.
  681. *
  682. * @throws CException
  683. * @return string the generated typeahead field
  684. * @since 1.0.6
  685. */
  686. public function typeAheadField($model, $attribute, $widgetOptions, $htmlOptions = array())
  687. {
  688. if (!isset($widgetOptions['source'])) {
  689. throw new CException(__CLASS__ . ': \'source\' parameter must be defined. ');
  690. }
  691. $widgetOptions += array(
  692. 'items' => 4,
  693. 'matcher' => 'js:function(item) {
  694. return ~item.toLowerCase().indexOf(this.query.toLowerCase());
  695. }'
  696. );
  697. return Yii::app()->controller->widget(
  698. 'bootstrap.widgets.TbTypeahead',
  699. array(
  700. 'model' => $model,
  701. 'attribute' => $attribute,
  702. 'options' => $widgetOptions,
  703. 'htmlOptions' => $htmlOptions
  704. ),
  705. true
  706. );
  707. }
  708. /**
  709. * Renders an input list.
  710. *
  711. * @param boolean $checkbox flag that indicates if the list is a checkbox-list.
  712. * @param CModel $model the data model
  713. * @param string $attribute the attribute
  714. * @param array $data value-label pairs used to generate the input list.
  715. * @param array $htmlOptions additional HTML options.
  716. *
  717. * @return string the generated input list.
  718. *
  719. * @since 0.9.5
  720. */
  721. protected function inputsList($checkbox, $model, $attribute, $data, $htmlOptions = array())
  722. {
  723. CHtml::resolveNameID($model, $attribute, $htmlOptions);
  724. $select = CHtml::resolveValue($model, $attribute);
  725. if ($model->hasErrors($attribute)) {
  726. if (isset($htmlOptions['class'])) {
  727. $htmlOptions['class'] .= ' ' . CHtml::$errorCss;
  728. } else {
  729. $htmlOptions['class'] = CHtml::$errorCss;
  730. }
  731. }
  732. $name = $htmlOptions['name'];
  733. unset($htmlOptions['name']);
  734. if (array_key_exists('uncheckValue', $htmlOptions)) {
  735. $uncheck = $htmlOptions['uncheckValue'];
  736. unset($htmlOptions['uncheckValue']);
  737. } else {
  738. $uncheck = '';
  739. }
  740. $hiddenOptions = isset($htmlOptions['id']) ? array('id' => CHtml::ID_PREFIX . $htmlOptions['id'])
  741. : array('id' => false);
  742. $hidden = $uncheck !== null ? CHtml::hiddenField($name, $uncheck, $hiddenOptions) : '';
  743. $template = isset($htmlOptions['template']) ? $htmlOptions['template']
  744. : '<label class="{labelCssClass}">{input}{label}</label>';
  745. $container = isset($htmlOptions['container']) ? $htmlOptions['container'] : '';
  746. unset($htmlOptions['template'], $htmlOptions['separator'], $htmlOptions['hint']);
  747. if ($checkbox && substr($name, -2) !== '[]') {
  748. $name .= '[]';
  749. }
  750. $checkAllLast = '';
  751. if (isset($htmlOptions['checkAll'])) {
  752. $checkAllLabel = $htmlOptions['checkAll'];
  753. $checkAllLast = isset($htmlOptions['checkAllLast']) && $htmlOptions['checkAllLast'];
  754. }
  755. unset($htmlOptions['checkAll'], $htmlOptions['checkAllLast']);
  756. $labelOptions = isset($htmlOptions['labelOptions']) ? $htmlOptions['labelOptions'] : array();
  757. unset($htmlOptions['labelOptions']);
  758. $items = array();
  759. $baseID = isset($htmlOptions['baseID']) ? $htmlOptions['baseID'] : CHtml::getIdByName($name);
  760. unset($htmlOptions['baseID']);
  761. $id = 0;
  762. $checkAll = true;
  763. $method = $checkbox ? 'checkBox' : 'radioButton';
  764. $labelCssClass = $checkbox ? 'checkbox' : 'radio';
  765. if (isset($htmlOptions['inline'])) {
  766. $labelCssClass .= ' inline';
  767. unset($htmlOptions['inline']);
  768. }
  769. foreach ($data as $value => $label) {
  770. $checked = !is_array($select) && !strcmp($value, $select) || is_array($select) && in_array($value, $select);
  771. $checkAll = $checkAll && $checked;
  772. $htmlOptions['value'] = $value;
  773. $htmlOptions['id'] = $baseID . '_' . $id++;
  774. $option = CHtml::$method($name, $checked, $htmlOptions);
  775. $label = CHtml::label($label, $htmlOptions['id'], $labelOptions);
  776. $items[] = strtr(
  777. $template,
  778. array(
  779. '{labelCssClass}' => $labelCssClass,
  780. '{input}' => $option,
  781. '{label}' => $label,
  782. )
  783. );
  784. }
  785. if (isset($checkAllLabel)) {
  786. $htmlOptions['value'] = 1;
  787. $htmlOptions['id'] = $id = $baseID . '_all';
  788. $option = CHtml::$method($id, $checkAll, $htmlOptions);
  789. $label = CHtml::label($checkAllLabel, $id, $labelOptions);
  790. $item = strtr(
  791. $template,
  792. array(
  793. '{labelCssClass}' => $labelCssClass,
  794. '{input}' => $option,
  795. '{label}' => $label,
  796. )
  797. );
  798. if ($checkAllLast) {
  799. $items[] = $item;
  800. } else {
  801. array_unshift($items, $item);
  802. }
  803. $name = strtr($name, array('[' => '\\[', ']' => '\\]'));
  804. $js = <<<EOD
  805. jQuery('#$id').click(function() {
  806. $("input[name='$name']").prop('checked', this.checked);
  807. });
  808. jQuery("input[name='$name']").click(function() {
  809. $('#$id').prop('checked', !jQuery("input[name='$name']:not(:checked)").length);
  810. });
  811. jQuery('#$id').prop('checked', !jQuery("input[name='$name']:not(:checked)").length);
  812. EOD;
  813. /** @var $cs CClientScript */
  814. $cs = Yii::app()->getClientScript();
  815. $cs->registerCoreScript('jquery');
  816. $cs->registerScript($id, $js);
  817. }
  818. if (empty($container)) {
  819. return $hidden . implode('', $items);
  820. } else {
  821. return $hidden . CHtml::tag($container, array('id' => $baseID), implode('', $items));
  822. }
  823. }
  824. /**
  825. *### .errorSummary()
  826. *
  827. * Displays a summary of validation errors for one or several models.
  828. *
  829. * This method is very similar to {@link CHtml::errorSummary} except that it also works
  830. * when AJAX validation is performed.
  831. *
  832. * @param mixed $models the models whose input errors are to be displayed. This can be either
  833. * a single model or an array of models.
  834. * @param string $header a piece of HTML code that appears in front of the errors
  835. * @param string $footer a piece of HTML code that appears at the end of the errors
  836. * @param array $htmlOptions additional HTML attributes to be rendered in the container div tag.
  837. *
  838. * @return string the error summary. Empty if no errors are found.
  839. *
  840. * @see CHtml::errorSummary
  841. */
  842. public function errorSummary($models, $header = null, $footer = null, $htmlOptions = array())
  843. {
  844. if (!isset($htmlOptions['class'])) {
  845. $htmlOptions['class'] = 'alert alert-block alert-error';
  846. } // Bootstrap error class as default
  847. return parent::errorSummary($models, $header, $footer, $htmlOptions);
  848. }
  849. /**
  850. *### .error()
  851. *
  852. * Displays the first validation error for a model attribute.
  853. *
  854. * @param CModel $model the data model
  855. * @param string $attribute the attribute name
  856. * @param array $htmlOptions additional HTML attributes to be rendered in the container div tag.
  857. * @param boolean $enableAjaxValidation whether to enable AJAX validation for the specified attribute.
  858. * @param boolean $enableClientValidation whether to enable client-side validation for the specified attribute.
  859. *
  860. * @return string the validation result (error display or success message).
  861. */
  862. public function error(
  863. $model,
  864. $attribute,
  865. $htmlOptions = array(),
  866. $enableAjaxValidation = true,
  867. $enableClientValidation = true
  868. ) {
  869. if (!$this->enableAjaxValidation) {
  870. $enableAjaxValidation = false;
  871. }
  872. if (!$this->enableClientValidation) {
  873. $enableClientValidation = false;
  874. }
  875. if (!isset($htmlOptions['class'])) {
  876. $htmlOptions['class'] = $this->errorMessageCssClass;
  877. }
  878. if (!$enableAjaxValidation && !$enableClientValidation) {
  879. return $this->renderError($model, $attribute, $htmlOptions);
  880. }
  881. $id = CHtml::activeId($model, $attribute);
  882. $inputID = isset($htmlOptions['inputID']) ? $htmlOptions['inputID'] : $id;
  883. unset($htmlOptions['inputID']);
  884. if (!isset($htmlOptions['id'])) {
  885. $htmlOptions['id'] = $inputID . '_em_';
  886. }
  887. $option = array(
  888. 'id' => $id,
  889. 'inputID' => $inputID,
  890. 'errorID' => $htmlOptions['id'],
  891. 'model' => get_class($model),
  892. 'name' => CHtml::resolveName($model, $attribute),
  893. 'enableAjaxValidation' => $enableAjaxValidation,
  894. 'inputContainer' => 'div.control-group', // Bootstrap requires this
  895. );
  896. $optionNames = array(
  897. 'validationDelay',
  898. 'validateOnChange',
  899. 'validateOnType',
  900. 'hideErrorMessage',
  901. 'inputContainer',
  902. 'errorCssClass',
  903. 'successCssClass',
  904. 'validatingCssClass',
  905. 'beforeValidateAttribute',
  906. 'afterValidateAttribute',
  907. );
  908. foreach ($optionNames as $name) {
  909. if (isset($htmlOptions[$name])) {
  910. $option[$name] = $htmlOptions[$name];
  911. }
  912. unset($htmlOptions[$name]);
  913. }
  914. if ($model instanceof CActiveRecord && !$model->isNewRecord) {
  915. $option['status'] = 1;
  916. }
  917. if ($enableClientValidation) {
  918. $validators = isset($htmlOptions['clientValidation']) ? array($htmlOptions['clientValidation']) : array();
  919. $attributeName = $attribute;
  920. if (($pos = strrpos($attribute, ']')) !== false && $pos !== strlen($attribute) - 1) // e.g. [a]name
  921. {
  922. $attributeName = substr($attribute, $pos + 1);
  923. }
  924. foreach ($model->getValidators($attributeName) as $validator) {
  925. /** @var $validator CValidator */
  926. if ($validator->enableClientValidation) {
  927. if (($js = $validator->clientValidateAttribute($model, $attributeName)) != '') {
  928. $validators[] = $js;
  929. }
  930. }
  931. }
  932. if ($validators !== array()) {
  933. $option['clientValidation'] = "js:function(value, messages, attribute) {\n" . implode(
  934. "\n",
  935. $validators
  936. ) . "\n}";
  937. }
  938. }
  939. $html = $this->renderError($model, $attribute, $htmlOptions);
  940. if ($html === '') {
  941. if (isset($htmlOptions['style'])) {
  942. $htmlOptions['style'] = rtrim($htmlOptions['style'], ';') . '; display: none';
  943. } else {
  944. $htmlOptions['style'] = 'display: none';
  945. }
  946. $html = CHtml::tag('span', $htmlOptions, '');
  947. }
  948. $this->attributes[$inputID] = $option;
  949. return $html;
  950. }
  951. /**
  952. * Creates the HTML code wrapping the error text for given model attribute.
  953. *
  954. * @param CModel $model the data model
  955. * @param string $attribute the attribute name
  956. * @param array $htmlOptions additional HTML attributes to be rendered in the container div tag.
  957. *
  958. * @return string the error display. Empty if no errors are found.
  959. *
  960. * @see CModel::getErrors
  961. * @see errorMessageCss
  962. */
  963. protected static function renderError($model, $attribute, $htmlOptions = array())
  964. {
  965. /* Using side effects of `resolveName`:
  966. `$attribute` will be modified: `[a][b]attr` will be turned into `attr` */
  967. CHtml::resolveName($model, $attribute);
  968. $error = $model->getError($attribute);
  969. return $error != '' ? CHtml::tag('span', $htmlOptions, $error) : '';
  970. }
  971. /**
  972. *### .inputRow()
  973. *
  974. * Creates an input row of a specific type.
  975. *
  976. * This is a generic factory method. It is mainly called by various helper methods
  977. * which pass correct type definitions to it.
  978. *
  979. * @param string $type the input type
  980. * @param CModel $model the data model
  981. * @param string $attribute the attribute
  982. * @param array $data the data for list inputs
  983. * @param array $htmlOptions additional HTML attributes
  984. *
  985. * @return string the generated row
  986. */
  987. public function inputRow($type, $model, $attribute, $data = null, $htmlOptions = array())
  988. {
  989. ob_start();
  990. Yii::app()->controller->widget(
  991. $this->getInputClassName(),
  992. array(
  993. 'type' => $type,
  994. 'form' => $this,
  995. 'model' => $model,
  996. 'attribute' => $attribute,
  997. 'data' => $data,
  998. 'htmlOptions' => $htmlOptions,
  999. )
  1000. );
  1001. echo "\n";
  1002. return ob_get_clean();
  1003. }
  1004. /**
  1005. * Returns the input widget class name suitable for the form.
  1006. * @return string the class name
  1007. */
  1008. protected function getInputClassName()
  1009. {
  1010. if (isset($this->input)) {
  1011. return $this->input;
  1012. } else {
  1013. switch ($this->type) {
  1014. case self::TYPE_HORIZONTAL:
  1015. return self::INPUT_HORIZONTAL;
  1016. break;
  1017. case self::TYPE_INLINE:
  1018. return self::INPUT_INLINE;
  1019. break;
  1020. case self::TYPE_SEARCH:
  1021. return self::INPUT_SEARCH;
  1022. break;
  1023. case self::TYPE_VERTICAL:
  1024. default:
  1025. return self::INPUT_VERTICAL;
  1026. break;
  1027. }
  1028. }
  1029. }
  1030. }