You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							386 lines
						
					
					
						
							14 KiB
						
					
					
				
			
		
		
	
	
							386 lines
						
					
					
						
							14 KiB
						
					
					
				| <?php | |
| /** | |
|  * @link http://www.yiiframework.com/ | |
|  * @copyright Copyright (c) 2008 Yii Software LLC | |
|  * @license http://www.yiiframework.com/license/ | |
|  */ | |
|  | |
| namespace yii\bootstrap; | |
|  | |
| use yii\helpers\Html; | |
| use yii\helpers\ArrayHelper; | |
|  | |
| /** | |
|  * A Bootstrap 3 enhanced version of [[\yii\widgets\ActiveField]]. | |
|  * | |
|  * This class adds some useful features to [[\yii\widgets\ActiveField|ActiveField]] to render all | |
|  * sorts of Bootstrap 3 form fields in different form layouts: | |
|  * | |
|  * - [[inputTemplate]] is an optional template to render complex inputs, for example input groups | |
|  * - [[horizontalCssClasses]] defines the CSS grid classes to add to label, wrapper, error and hint | |
|  *   in horizontal forms | |
|  * - [[inline]]/[[inline()]] is used to render inline [[checkboxList()]] and [[radioList()]] | |
|  * - [[enableError]] can be set to `false` to disable to the error | |
|  * - [[enableLabel]] can be set to `false` to disable to the label | |
|  * - [[label()]] can be used with a `boolean` argument to enable/disable the label | |
|  * | |
|  * There are also some new placeholders that you can use in the [[template]] configuration: | |
|  * | |
|  * - `{beginLabel}`: the opening label tag | |
|  * - `{labelTitle}`: the label title for use with `{beginLabel}`/`{endLabel}` | |
|  * - `{endLabel}`: the closing label tag | |
|  * - `{beginWrapper}`: the opening wrapper tag | |
|  * - `{endWrapper}`: the closing wrapper tag | |
|  * | |
|  * The wrapper tag is only used for some layouts and form elements. | |
|  * | |
|  * Note that some elements use slightly different defaults for [[template]] and other options. | |
|  * You may want to override those predefined templates for checkboxes, radio buttons, checkboxLists | |
|  * and radioLists in the [[\yii\widgets\ActiveForm::fieldConfig|fieldConfig]] of the | |
|  * [[\yii\widgets\ActiveForm]]: | |
|  * | |
|  * - [[checkboxTemplate]] the template for checkboxes in default layout | |
|  * - [[radioTemplate]] the template for radio buttons in default layout | |
|  * - [[horizontalCheckboxTemplate]] the template for checkboxes in horizontal layout | |
|  * - [[horizontalRadioTemplate]] the template for radio buttons in horizontal layout | |
|  * - [[inlineCheckboxListTemplate]] the template for inline checkboxLists | |
|  * - [[inlineRadioListTemplate]] the template for inline radioLists | |
|  * | |
|  * Example: | |
|  * | |
|  * ```php | |
|  * use yii\bootstrap\ActiveForm; | |
|  * | |
|  * $form = ActiveForm::begin(['layout' => 'horizontal']); | |
|  * | |
|  * // Form field without label | |
|  * echo $form->field($model, 'demo', [ | |
|  *     'inputOptions' => [ | |
|  *         'placeholder' => $model->getAttributeLabel('demo'), | |
|  *     ], | |
|  * ])->label(false); | |
|  * | |
|  * // Inline radio list | |
|  * echo $form->field($model, 'demo')->inline()->radioList($items); | |
|  * | |
|  * // Control sizing in horizontal mode | |
|  * echo $form->field($model, 'demo', [ | |
|  *     'horizontalCssClasses' => [ | |
|  *         'wrapper' => 'col-sm-2', | |
|  *     ] | |
|  * ]); | |
|  * | |
|  * // With 'default' layout you would use 'template' to size a specific field: | |
|  * echo $form->field($model, 'demo', [ | |
|  *     'template' => '{label} <div class="row"><div class="col-sm-4">{input}{error}{hint}</div></div>' | |
|  * ]); | |
|  * | |
|  * // Input group | |
|  * echo $form->field($model, 'demo', [ | |
|  *     'inputTemplate' => '<div class="input-group"><span class="input-group-addon">@</span>{input}</div>', | |
|  * ]); | |
|  * | |
|  * ActiveForm::end(); | |
|  * ``` | |
|  * | |
|  * @see \yii\bootstrap\ActiveForm | |
|  * @see http://getbootstrap.com/css/#forms | |
|  * | |
|  * @author Michael Härtl <haertl.mike@gmail.com> | |
|  * @since 2.0 | |
|  */ | |
| class ActiveField extends \yii\widgets\ActiveField | |
| { | |
|     /** | |
|      * @var boolean whether to render [[checkboxList()]] and [[radioList()]] inline. | |
|      */ | |
|     public $inline = false; | |
|     /** | |
|      * @var string|null optional template to render the `{input}` placeholder content | |
|      */ | |
|     public $inputTemplate; | |
|     /** | |
|      * @var array options for the wrapper tag, used in the `{beginWrapper}` placeholder | |
|      */ | |
|     public $wrapperOptions = []; | |
|     /** | |
|      * @var null|array CSS grid classes for horizontal layout. This must be an array with these keys: | |
|      *  - 'offset' the offset grid class to append to the wrapper if no label is rendered | |
|      *  - 'label' the label grid class | |
|      *  - 'wrapper' the wrapper grid class | |
|      *  - 'error' the error grid class | |
|      *  - 'hint' the hint grid class | |
|      */ | |
|     public $horizontalCssClasses; | |
|     /** | |
|      * @var string the template for checkboxes in default layout | |
|      */ | |
|     public $checkboxTemplate = "<div class=\"checkbox\">\n{beginLabel}\n{input}\n{labelTitle}\n{endLabel}\n{error}\n{hint}\n</div>"; | |
|     /** | |
|      * @var string the template for radios in default layout | |
|      */ | |
|     public $radioTemplate = "<div class=\"radio\">\n{beginLabel}\n{input}\n{labelTitle}\n{endLabel}\n{error}\n{hint}\n</div>"; | |
|     /** | |
|      * @var string the template for checkboxes in horizontal layout | |
|      */ | |
|     public $horizontalCheckboxTemplate = "{beginWrapper}\n<div class=\"checkbox\">\n{beginLabel}\n{input}\n{labelTitle}\n{endLabel}\n</div>\n{error}\n{endWrapper}\n{hint}"; | |
|     /** | |
|      * @var string the template for radio buttons in horizontal layout | |
|      */ | |
|     public $horizontalRadioTemplate = "{beginWrapper}\n<div class=\"radio\">\n{beginLabel}\n{input}\n{labelTitle}\n{endLabel}\n</div>\n{error}\n{endWrapper}\n{hint}"; | |
|     /** | |
|      * @var string the template for inline checkboxLists | |
|      */ | |
|     public $inlineCheckboxListTemplate = "{label}\n{beginWrapper}\n{input}\n{error}\n{endWrapper}\n{hint}"; | |
|     /** | |
|      * @var string the template for inline radioLists | |
|      */ | |
|     public $inlineRadioListTemplate = "{label}\n{beginWrapper}\n{input}\n{error}\n{endWrapper}\n{hint}"; | |
|     /** | |
|      * @var boolean whether to render the error. Default is `true` except for layout `inline`. | |
|      */ | |
|     public $enableError = true; | |
|     /** | |
|      * @var boolean whether to render the label. Default is `true`. | |
|      */ | |
|     public $enableLabel = true; | |
|  | |
|  | |
|     /** | |
|      * @inheritdoc | |
|      */ | |
|     public function __construct($config = []) | |
|     { | |
|         $layoutConfig = $this->createLayoutConfig($config); | |
|         $config = ArrayHelper::merge($layoutConfig, $config); | |
|         parent::__construct($config); | |
|     } | |
|  | |
|     /** | |
|      * @inheritdoc | |
|      */ | |
|     public function render($content = null) | |
|     { | |
|         if ($content === null) { | |
|             if (!isset($this->parts['{beginWrapper}'])) { | |
|                 $options = $this->wrapperOptions; | |
|                 $tag = ArrayHelper::remove($options, 'tag', 'div'); | |
|                 $this->parts['{beginWrapper}'] = Html::beginTag($tag, $options); | |
|                 $this->parts['{endWrapper}'] = Html::endTag($tag); | |
|             } | |
|             if ($this->enableLabel === false) { | |
|                 $this->parts['{label}'] = ''; | |
|                 $this->parts['{beginLabel}'] = ''; | |
|                 $this->parts['{labelTitle}'] = ''; | |
|                 $this->parts['{endLabel}'] = ''; | |
|             } elseif (!isset($this->parts['{beginLabel}'])) { | |
|                 $this->renderLabelParts(); | |
|             } | |
|             if ($this->enableError === false) { | |
|                 $this->parts['{error}'] = ''; | |
|             } | |
|             if ($this->inputTemplate) { | |
|                 $input = isset($this->parts['{input}']) ? | |
|                     $this->parts['{input}'] : Html::activeTextInput($this->model, $this->attribute, $this->inputOptions); | |
|                 $this->parts['{input}'] = strtr($this->inputTemplate, ['{input}' => $input]); | |
|             } | |
|         } | |
|         return parent::render($content); | |
|     } | |
|  | |
|     /** | |
|      * @inheritdoc | |
|      */ | |
|     public function checkbox($options = [], $enclosedByLabel = true) | |
|     { | |
|         if ($enclosedByLabel) { | |
|             if (!isset($options['template'])) { | |
|                 $this->template = $this->form->layout === 'horizontal' ? | |
|                     $this->horizontalCheckboxTemplate : $this->checkboxTemplate; | |
|             } else { | |
|                 $this->template = $options['template']; | |
|                 unset($options['template']); | |
|             } | |
|             if ($this->form->layout === 'horizontal') { | |
|                 Html::addCssClass($this->wrapperOptions, $this->horizontalCssClasses['offset']); | |
|             } | |
|             $this->labelOptions['class'] = null; | |
|         } | |
|  | |
|         return parent::checkbox($options, false); | |
|     } | |
|  | |
|     /** | |
|      * @inheritdoc | |
|      */ | |
|     public function radio($options = [], $enclosedByLabel = true) | |
|     { | |
|         if ($enclosedByLabel) { | |
|             if (!isset($options['template'])) { | |
|                 $this->template = $this->form->layout === 'horizontal' ? | |
|                     $this->horizontalRadioTemplate : $this->radioTemplate; | |
|             } else { | |
|                 $this->template = $options['template']; | |
|                 unset($options['template']); | |
|             } | |
|             if ($this->form->layout === 'horizontal') { | |
|                 Html::addCssClass($this->wrapperOptions, $this->horizontalCssClasses['offset']); | |
|             } | |
|             $this->labelOptions['class'] = null; | |
|         } | |
|  | |
|         return parent::radio($options, false); | |
|     } | |
|  | |
|     /** | |
|      * @inheritdoc | |
|      */ | |
|     public function checkboxList($items, $options = []) | |
|     { | |
|         if ($this->inline) { | |
|             if (!isset($options['template'])) { | |
|                 $this->template = $this->inlineCheckboxListTemplate; | |
|             } else { | |
|                 $this->template = $options['template']; | |
|                 unset($options['template']); | |
|             } | |
|             if (!isset($options['itemOptions'])) { | |
|                 $options['itemOptions'] = [ | |
|                     'labelOptions' => ['class' => 'checkbox-inline'], | |
|                 ]; | |
|             } | |
|         }  elseif (!isset($options['item'])) { | |
|             $options['item'] = function ($index, $label, $name, $checked, $value) { | |
|                 return '<div class="checkbox">' . Html::checkbox($name, $checked, ['label' => $label, 'value' => $value]) . '</div>'; | |
|             }; | |
|         } | |
|         parent::checkboxList($items, $options); | |
|         return $this; | |
|     } | |
|  | |
|     /** | |
|      * @inheritdoc | |
|      */ | |
|     public function radioList($items, $options = []) | |
|     { | |
|         if ($this->inline) { | |
|             if (!isset($options['template'])) { | |
|                 $this->template = $this->inlineRadioListTemplate; | |
|             } else { | |
|                 $this->template = $options['template']; | |
|                 unset($options['template']); | |
|             } | |
|             if (!isset($options['itemOptions'])) { | |
|                 $options['itemOptions'] = [ | |
|                     'labelOptions' => ['class' => 'radio-inline'], | |
|                 ]; | |
|             } | |
|         }  elseif (!isset($options['item'])) { | |
|             $options['item'] = function ($index, $label, $name, $checked, $value) { | |
|                 return '<div class="radio">' . Html::radio($name, $checked, ['label' => $label, 'value' => $value]) . '</div>'; | |
|             }; | |
|         } | |
|         parent::radioList($items, $options); | |
|         return $this; | |
|     } | |
|  | |
|     /** | |
|      * @inheritdoc | |
|      */ | |
|     public function label($label = null, $options = []) | |
|     { | |
|         if (is_bool($label)) { | |
|             $this->enableLabel = $label; | |
|             if ($label === false && $this->form->layout === 'horizontal') { | |
|                 Html::addCssClass($this->wrapperOptions, $this->horizontalCssClasses['offset']); | |
|             } | |
|         } else { | |
|             $this->enableLabel = true; | |
|             $this->renderLabelParts($label, $options); | |
|             parent::label($label, $options); | |
|         } | |
|         return $this; | |
|     } | |
|  | |
|     /** | |
|      * @param boolean $value whether to render a inline list | |
|      * @return static the field object itself | |
|      * Make sure you call this method before [[checkboxList()]] or [[radioList()]] to have any effect. | |
|      */ | |
|     public function inline($value = true) | |
|     { | |
|         $this->inline = (bool) $value; | |
|         return $this; | |
|     } | |
|  | |
|     /** | |
|      * @param array $instanceConfig the configuration passed to this instance's constructor | |
|      * @return array the layout specific default configuration for this instance | |
|      */ | |
|     protected function createLayoutConfig($instanceConfig) | |
|     { | |
|         $config = [ | |
|             'hintOptions' => [ | |
|                 'tag' => 'p', | |
|                 'class' => 'help-block', | |
|             ], | |
|             'errorOptions' => [ | |
|                 'tag' => 'p', | |
|                 'class' => 'help-block help-block-error', | |
|             ], | |
|             'inputOptions' => [ | |
|                 'class' => 'form-control', | |
|             ], | |
|         ]; | |
|  | |
|         $layout = $instanceConfig['form']->layout; | |
|  | |
|         if ($layout === 'horizontal') { | |
|             $config['template'] = "{label}\n{beginWrapper}\n{input}\n{error}\n{endWrapper}\n{hint}"; | |
|             $cssClasses = [ | |
|                 'offset' => 'col-sm-offset-3', | |
|                 'label' => 'col-sm-3', | |
|                 'wrapper' => 'col-sm-6', | |
|                 'error' => '', | |
|                 'hint' => 'col-sm-3', | |
|             ]; | |
|             if (isset($instanceConfig['horizontalCssClasses'])) { | |
|                 $cssClasses = ArrayHelper::merge($cssClasses, $instanceConfig['horizontalCssClasses']); | |
|             } | |
|             $config['horizontalCssClasses'] = $cssClasses; | |
|             $config['wrapperOptions'] = ['class' => $cssClasses['wrapper']]; | |
|             $config['labelOptions'] = ['class' => 'control-label ' . $cssClasses['label']]; | |
|             $config['errorOptions'] = ['class' => 'help-block help-block-error ' . $cssClasses['error']]; | |
|             $config['hintOptions'] = ['class' => 'help-block ' . $cssClasses['hint']]; | |
|         } elseif ($layout === 'inline') { | |
|             $config['labelOptions'] = ['class' => 'sr-only']; | |
|             $config['enableError'] = false; | |
|         } | |
|  | |
|         return $config; | |
|     } | |
|  | |
|     /** | |
|      * @param string|null $label the label or null to use model label | |
|      * @param array $options the tag options | |
|      */ | |
|     protected function renderLabelParts($label = null, $options = []) | |
|     { | |
|         $options = array_merge($this->labelOptions, $options); | |
|         if ($label === null) { | |
|             if (isset($options['label'])) { | |
|                 $label = $options['label']; | |
|                 unset($options['label']); | |
|             } else { | |
|                 $attribute = Html::getAttributeName($this->attribute); | |
|                 $label = Html::encode($this->model->getAttributeLabel($attribute)); | |
|             } | |
|         } | |
|         if (!isset($options['for'])) { | |
|             $options['for'] = Html::getInputId($this->model, $this->attribute); | |
|         } | |
|         $this->parts['{beginLabel}'] = Html::beginTag('label', $options); | |
|         $this->parts['{endLabel}'] = Html::endTag('label'); | |
|         $this->parts['{labelTitle}'] = $label; | |
|     } | |
| }
 | |
| 
 |