diff --git a/BootstrapWidgetTrait.php b/BootstrapWidgetTrait.php new file mode 100644 index 0000000..a1d09cb --- /dev/null +++ b/BootstrapWidgetTrait.php @@ -0,0 +1,101 @@ + + * @author Qiang Xue + * @author Paul Klimov + * @since 2.0.5 + */ +trait BootstrapWidgetTrait +{ + /** + * @var array the options for the underlying Bootstrap JS plugin. + * Please refer to the corresponding Bootstrap plugin Web page for possible options. + * For example, [this page](http://getbootstrap.com/javascript/#modals) shows + * how to use the "Modal" plugin and the supported options (e.g. "remote"). + */ + public $clientOptions = []; + /** + * @var array the event handlers for the underlying Bootstrap JS plugin. + * Please refer to the corresponding Bootstrap plugin Web page for possible events. + * For example, [this page](http://getbootstrap.com/javascript/#modals) shows + * how to use the "Modal" plugin and the supported events (e.g. "shown"). + */ + public $clientEvents = []; + + + /** + * Initializes the widget. + * This method will register the bootstrap asset bundle. If you override this method, + * make sure you call the parent implementation first. + */ + public function init() + { + parent::init(); + if (!isset($this->options['id'])) { + $this->options['id'] = $this->getId(); + } + } + + /** + * Registers a specific Bootstrap plugin and the related events + * @param string $name the name of the Bootstrap plugin + */ + protected function registerPlugin($name) + { + $view = $this->getView(); + + BootstrapPluginAsset::register($view); + + $id = $this->options['id']; + + if ($this->clientOptions !== false) { + $options = empty($this->clientOptions) ? '' : Json::htmlEncode($this->clientOptions); + $js = "jQuery('#$id').$name($options);"; + $view->registerJs($js); + } + + $this->registerClientEvents(); + } + + /** + * Registers JS event handlers that are listed in [[clientEvents]]. + * @since 2.0.2 + */ + protected function registerClientEvents() + { + if (!empty($this->clientEvents)) { + $id = $this->options['id']; + $js = []; + foreach ($this->clientEvents as $event => $handler) { + $js[] = "jQuery('#$id').on('$event', $handler);"; + } + $this->getView()->registerJs(implode("\n", $js)); + } + } +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fc21df..07887e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Yii Framework 2 bootstrap extension Change Log - Enh #42: Added support for the glyphicons via `yii\bootstrap\Html::icon()` (klimov-paul) - Enh #43: Added support for the static form controls via `yii\bootstrap\Html` (klimov-paul) - Enh #44: Fixed `yii\bootstrap\ButtonDropdown` renders two buttons have same with id if 'split' is enabled (klimov-paul) +- Enh #45: Added support for Bootstrap checkbox/radio toggle buttons (RomeroMsk, klimov-paul) 2.0.4 May 10, 2015 diff --git a/InputWidget.php b/InputWidget.php new file mode 100644 index 0000000..2f3b3e1 --- /dev/null +++ b/InputWidget.php @@ -0,0 +1,19 @@ + + * @since 2.0.5 + */ +class InputWidget extends \yii\widgets\InputWidget +{ + use BootstrapWidgetTrait; +} \ No newline at end of file diff --git a/ToggleButtonGroup.php b/ToggleButtonGroup.php new file mode 100644 index 0000000..dcd280c --- /dev/null +++ b/ToggleButtonGroup.php @@ -0,0 +1,107 @@ +field($model, 'item_id')->widget(\yii\bootstrap\ToggleButtonGroup::classname(), [ + * // configure additional widget properties here + * ]) ?> + * ``` + * + * @see http://getbootstrap.com/javascript/#buttons-checkbox-radio + * + * @author Paul Klimov + * @since 2.0.5 + */ +class ToggleButtonGroup extends InputWidget +{ + /** + * @var string input type, can be: + * - 'checkbox' + * - 'radio' + */ + public $type; + /** + * @var array the data item used to generate the checkboxes. + * The array values are the labels, while the array keys are the corresponding checkbox or radio values. + */ + public $items = []; + /** + * @var array, the HTML attributes for the label (button) tag. + * @see Html::checkbox() + * @see Html::radio() + */ + public $labelOptions = []; + /** + * @var boolean whether the items labels should be HTML-encoded. + */ + public $encodeLabels = true; + + + /** + * @inheritdoc + */ + public function init() + { + parent::init(); + $this->registerPlugin('button'); + Html::addCssClass($this->options, 'btn-group'); + $this->options['data-toggle'] = 'buttons'; + } + + /** + * @inheritdoc + */ + public function run() + { + if (!isset($this->options['item'])) { + $this->options['item'] = [$this, 'renderItem']; + } + switch ($this->type) { + case 'checkbox' : + return Html::activeCheckboxList($this->model, $this->attribute, $this->items, $this->options); + case 'radio': + return Html::activeRadioList($this->model, $this->attribute, $this->items, $this->options); + default: + throw new InvalidConfigException("Unsupported type '{$this->type}'"); + } + } + + /** + * Default callback for checkbox/radio list item rendering. + * @param integer $index item index. + * @param string $label item label. + * @param string $name input name. + * @param boolean $checked whether value is checked or not. + * @param string $value input value. + * @return string generated HTML. + * @see Html::checkbox() + * @see Html::radio() + */ + public function renderItem($index, $label, $name, $checked, $value) + { + $labelOptions = $this->labelOptions; + Html::addCssClass($labelOptions, 'btn'); + if ($checked) { + Html::addCssClass($labelOptions, 'active'); + } + $type = $this->type; + if ($this->encodeLabels) { + $label = Html::encode($label); + } + return Html::$type($name, $checked, ['label' => $label, 'labelOptions' => $labelOptions, 'value' => $value]); + } +} \ No newline at end of file diff --git a/Widget.php b/Widget.php index dc07f4f..3be95f3 100644 --- a/Widget.php +++ b/Widget.php @@ -7,9 +7,6 @@ namespace yii\bootstrap; -use Yii; -use yii\helpers\Json; - /** * \yii\bootstrap\Widget is the base class for all bootstrap widgets. * @@ -19,74 +16,11 @@ use yii\helpers\Json; */ class Widget extends \yii\base\Widget { + use BootstrapWidgetTrait; + /** * @var array the HTML attributes for the widget container tag. * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. */ public $options = []; - /** - * @var array the options for the underlying Bootstrap JS plugin. - * Please refer to the corresponding Bootstrap plugin Web page for possible options. - * For example, [this page](http://getbootstrap.com/javascript/#modals) shows - * how to use the "Modal" plugin and the supported options (e.g. "remote"). - */ - public $clientOptions = []; - /** - * @var array the event handlers for the underlying Bootstrap JS plugin. - * Please refer to the corresponding Bootstrap plugin Web page for possible events. - * For example, [this page](http://getbootstrap.com/javascript/#modals) shows - * how to use the "Modal" plugin and the supported events (e.g. "shown"). - */ - public $clientEvents = []; - - - /** - * Initializes the widget. - * This method will register the bootstrap asset bundle. If you override this method, - * make sure you call the parent implementation first. - */ - public function init() - { - parent::init(); - if (!isset($this->options['id'])) { - $this->options['id'] = $this->getId(); - } - } - - /** - * Registers a specific Bootstrap plugin and the related events - * @param string $name the name of the Bootstrap plugin - */ - protected function registerPlugin($name) - { - $view = $this->getView(); - - BootstrapPluginAsset::register($view); - - $id = $this->options['id']; - - if ($this->clientOptions !== false) { - $options = empty($this->clientOptions) ? '' : Json::htmlEncode($this->clientOptions); - $js = "jQuery('#$id').$name($options);"; - $view->registerJs($js); - } - - $this->registerClientEvents(); - } - - /** - * Registers JS event handlers that are listed in [[clientEvents]]. - * @since 2.0.2 - */ - protected function registerClientEvents() - { - if (!empty($this->clientEvents)) { - $id = $this->options['id']; - $js = []; - foreach ($this->clientEvents as $event => $handler) { - $js[] = "jQuery('#$id').on('$event', $handler);"; - } - $this->getView()->registerJs(implode("\n", $js)); - } - } } diff --git a/tests/ToggleButtonGroupTest.php b/tests/ToggleButtonGroupTest.php new file mode 100644 index 0000000..d701337 --- /dev/null +++ b/tests/ToggleButtonGroupTest.php @@ -0,0 +1,57 @@ + 'checkbox', + 'model' => new ToggleButtonGroupTestModel(), + 'attribute' => 'value', + 'items' => [ + '1' => 'item 1', + '2' => 'item 2', + ], + ]); + + $expectedHtml = <<
+
+HTML; + $this->assertEqualsWithoutLE($expectedHtml, $html); + } + + public function testRadio() + { + ToggleButtonGroup::$counter = 0; + $html = ToggleButtonGroup::widget([ + 'type' => 'radio', + 'model' => new ToggleButtonGroupTestModel(), + 'attribute' => 'value', + 'items' => [ + '1' => 'item 1', + '2' => 'item 2', + ], + ]); + + $expectedHtml = <<
+
+HTML; + $this->assertEqualsWithoutLE($expectedHtml, $html); + } +} + +class ToggleButtonGroupTestModel extends Model +{ + public $value; +} \ No newline at end of file