diff --git a/Alert.php b/Alert.php index 15b3342..60c34c8 100644 --- a/Alert.php +++ b/Alert.php @@ -46,105 +46,105 @@ use yii\helpers\Html; */ class Alert extends Widget { - /** - * @var string the body content in the alert component. Note that anything between - * the [[begin()]] and [[end()]] calls of the Alert widget will also be treated - * as the body content, and will be rendered before this. - */ - public $body; - /** - * @var array the options for rendering the close button tag. - * The close button is displayed in the header of the modal window. Clicking - * on the button will hide the modal window. If this is null, no close button will be rendered. - * - * The following special options are supported: - * - * - tag: string, the tag name of the button. Defaults to 'button'. - * - label: string, the label of the button. Defaults to '×'. - * - * The rest of the options will be rendered as the HTML attributes of the button tag. - * Please refer to the [Alert documentation](http://getbootstrap.com/components/#alerts) - * for the supported HTML attributes. - */ - public $closeButton = []; + /** + * @var string the body content in the alert component. Note that anything between + * the [[begin()]] and [[end()]] calls of the Alert widget will also be treated + * as the body content, and will be rendered before this. + */ + public $body; + /** + * @var array the options for rendering the close button tag. + * The close button is displayed in the header of the modal window. Clicking + * on the button will hide the modal window. If this is null, no close button will be rendered. + * + * The following special options are supported: + * + * - tag: string, the tag name of the button. Defaults to 'button'. + * - label: string, the label of the button. Defaults to '×'. + * + * The rest of the options will be rendered as the HTML attributes of the button tag. + * Please refer to the [Alert documentation](http://getbootstrap.com/components/#alerts) + * for the supported HTML attributes. + */ + public $closeButton = []; + /** + * Initializes the widget. + */ + public function init() + { + parent::init(); - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); + $this->initOptions(); - $this->initOptions(); + echo Html::beginTag('div', $this->options) . "\n"; + echo $this->renderBodyBegin() . "\n"; + } - echo Html::beginTag('div', $this->options) . "\n"; - echo $this->renderBodyBegin() . "\n"; - } + /** + * Renders the widget. + */ + public function run() + { + echo "\n" . $this->renderBodyEnd(); + echo "\n" . Html::endTag('div'); - /** - * Renders the widget. - */ - public function run() - { - echo "\n" . $this->renderBodyEnd(); - echo "\n" . Html::endTag('div'); + $this->registerPlugin('alert'); + } - $this->registerPlugin('alert'); - } + /** + * Renders the close button if any before rendering the content. + * @return string the rendering result + */ + protected function renderBodyBegin() + { + return $this->renderCloseButton(); + } - /** - * Renders the close button if any before rendering the content. - * @return string the rendering result - */ - protected function renderBodyBegin() - { - return $this->renderCloseButton(); - } + /** + * Renders the alert body (if any). + * @return string the rendering result + */ + protected function renderBodyEnd() + { + return $this->body . "\n"; + } - /** - * Renders the alert body (if any). - * @return string the rendering result - */ - protected function renderBodyEnd() - { - return $this->body . "\n"; - } + /** + * Renders the close button. + * @return string the rendering result + */ + protected function renderCloseButton() + { + if ($this->closeButton !== null) { + $tag = ArrayHelper::remove($this->closeButton, 'tag', 'button'); + $label = ArrayHelper::remove($this->closeButton, 'label', '×'); + if ($tag === 'button' && !isset($this->closeButton['type'])) { + $this->closeButton['type'] = 'button'; + } - /** - * Renders the close button. - * @return string the rendering result - */ - protected function renderCloseButton() - { - if ($this->closeButton !== null) { - $tag = ArrayHelper::remove($this->closeButton, 'tag', 'button'); - $label = ArrayHelper::remove($this->closeButton, 'label', '×'); - if ($tag === 'button' && !isset($this->closeButton['type'])) { - $this->closeButton['type'] = 'button'; - } - return Html::tag($tag, $label, $this->closeButton); - } else { - return null; - } - } + return Html::tag($tag, $label, $this->closeButton); + } else { + return null; + } + } - /** - * Initializes the widget options. - * This method sets the default values for various options. - */ - protected function initOptions() - { - Html::addCssClass($this->options, 'alert'); - Html::addCssClass($this->options, 'fade'); - Html::addCssClass($this->options, 'in'); + /** + * Initializes the widget options. + * This method sets the default values for various options. + */ + protected function initOptions() + { + Html::addCssClass($this->options, 'alert'); + Html::addCssClass($this->options, 'fade'); + Html::addCssClass($this->options, 'in'); - if ($this->closeButton !== null) { - $this->closeButton = array_merge([ - 'data-dismiss' => 'alert', - 'aria-hidden' => 'true', - 'class' => 'close', - ], $this->closeButton); - } - } + if ($this->closeButton !== null) { + $this->closeButton = array_merge([ + 'data-dismiss' => 'alert', + 'aria-hidden' => 'true', + 'class' => 'close', + ], $this->closeButton); + } + } } diff --git a/BootstrapAsset.php b/BootstrapAsset.php index 93f7728..d5b1244 100644 --- a/BootstrapAsset.php +++ b/BootstrapAsset.php @@ -17,8 +17,8 @@ use yii\web\AssetBundle; */ class BootstrapAsset extends AssetBundle { - public $sourcePath = '@vendor/twbs/bootstrap/dist'; - public $css = [ - 'css/bootstrap.css', - ]; + public $sourcePath = '@vendor/twbs/bootstrap/dist'; + public $css = [ + 'css/bootstrap.css', + ]; } diff --git a/BootstrapPluginAsset.php b/BootstrapPluginAsset.php index c451ff4..13aa162 100644 --- a/BootstrapPluginAsset.php +++ b/BootstrapPluginAsset.php @@ -17,12 +17,12 @@ use yii\web\AssetBundle; */ class BootstrapPluginAsset extends AssetBundle { - public $sourcePath = '@vendor/twbs/bootstrap/dist'; - public $js = [ - 'js/bootstrap.js', - ]; - public $depends = [ - 'yii\web\JqueryAsset', - 'yii\bootstrap\BootstrapAsset', - ]; + public $sourcePath = '@vendor/twbs/bootstrap/dist'; + public $js = [ + 'js/bootstrap.js', + ]; + public $depends = [ + 'yii\web\JqueryAsset', + 'yii\bootstrap\BootstrapAsset', + ]; } diff --git a/BootstrapThemeAsset.php b/BootstrapThemeAsset.php index fa424f9..093350c 100644 --- a/BootstrapThemeAsset.php +++ b/BootstrapThemeAsset.php @@ -17,11 +17,11 @@ use yii\web\AssetBundle; */ class BootstrapThemeAsset extends AssetBundle { - public $sourcePath = '@vendor/twbs/bootstrap/dist'; - public $css = [ - 'css/bootstrap-theme.css', - ]; - public $depends = [ - 'yii\bootstrap\BootstrapAsset', - ]; + public $sourcePath = '@vendor/twbs/bootstrap/dist'; + public $css = [ + 'css/bootstrap-theme.css', + ]; + public $depends = [ + 'yii\bootstrap\BootstrapAsset', + ]; } diff --git a/Button.php b/Button.php index e1af489..d13c9e9 100644 --- a/Button.php +++ b/Button.php @@ -26,37 +26,36 @@ use yii\helpers\Html; */ class Button extends Widget { - /** - * @var string the tag to use to render the button - */ - public $tagName = 'button'; - /** - * @var string the button label - */ - public $label = 'Button'; - /** - * @var boolean whether the label should be HTML-encoded. - */ - public $encodeLabel = true; + /** + * @var string the tag to use to render the button + */ + public $tagName = 'button'; + /** + * @var string the button label + */ + public $label = 'Button'; + /** + * @var boolean whether the label should be HTML-encoded. + */ + public $encodeLabel = true; + /** + * Initializes the widget. + * If you override this method, make sure you call the parent implementation first. + */ + public function init() + { + parent::init(); + $this->clientOptions = false; + Html::addCssClass($this->options, 'btn'); + } - /** - * Initializes the widget. - * If you override this method, make sure you call the parent implementation first. - */ - public function init() - { - parent::init(); - $this->clientOptions = false; - Html::addCssClass($this->options, 'btn'); - } - - /** - * Renders the widget. - */ - public function run() - { - echo Html::tag($this->tagName, $this->encodeLabel ? Html::encode($this->label) : $this->label, $this->options); - $this->registerPlugin('button'); - } + /** + * Renders the widget. + */ + public function run() + { + echo Html::tag($this->tagName, $this->encodeLabel ? Html::encode($this->label) : $this->label, $this->options); + $this->registerPlugin('button'); + } } diff --git a/ButtonDropdown.php b/ButtonDropdown.php index 434f214..dedf8db 100644 --- a/ButtonDropdown.php +++ b/ButtonDropdown.php @@ -33,91 +33,92 @@ use yii\helpers\Html; */ class ButtonDropdown extends Widget { - /** - * @var string the button label - */ - public $label = 'Button'; - /** - * @var array the HTML attributes of the button. - * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. - */ - public $options = []; - /** - * @var array the configuration array for [[Dropdown]]. - */ - public $dropdown = []; - /** - * @var boolean whether to display a group of split-styled button group. - */ - public $split = false; - /** - * @var string the tag to use to render the button - */ - public $tagName = 'button'; - /** - * @var boolean whether the label should be HTML-encoded. - */ - public $encodeLabel = true; + /** + * @var string the button label + */ + public $label = 'Button'; + /** + * @var array the HTML attributes of the button. + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. + */ + public $options = []; + /** + * @var array the configuration array for [[Dropdown]]. + */ + public $dropdown = []; + /** + * @var boolean whether to display a group of split-styled button group. + */ + public $split = false; + /** + * @var string the tag to use to render the button + */ + public $tagName = 'button'; + /** + * @var boolean whether the label should be HTML-encoded. + */ + public $encodeLabel = true; + /** + * Renders the widget. + */ + public function run() + { + echo $this->renderButton() . "\n" . $this->renderDropdown(); + $this->registerPlugin('button'); + } - /** - * Renders the widget. - */ - public function run() - { - echo $this->renderButton() . "\n" . $this->renderDropdown(); - $this->registerPlugin('button'); - } + /** + * Generates the button dropdown. + * @return string the rendering result. + */ + protected function renderButton() + { + Html::addCssClass($this->options, 'btn'); + $label = $this->label; + if ($this->encodeLabel) { + $label = Html::encode($label); + } + if ($this->split) { + $options = $this->options; + $this->options['data-toggle'] = 'dropdown'; + Html::addCssClass($this->options, 'dropdown-toggle'); + $splitButton = Button::widget([ + 'label' => '', + 'encodeLabel' => false, + 'options' => $this->options, + 'view' => $this->getView(), + ]); + } else { + $label .= ' '; + $options = $this->options; + if (!isset($options['href'])) { + $options['href'] = '#'; + } + Html::addCssClass($options, 'dropdown-toggle'); + $options['data-toggle'] = 'dropdown'; + $splitButton = ''; + } - /** - * Generates the button dropdown. - * @return string the rendering result. - */ - protected function renderButton() - { - Html::addCssClass($this->options, 'btn'); - $label = $this->label; - if ($this->encodeLabel) { - $label = Html::encode($label); - } - if ($this->split) { - $options = $this->options; - $this->options['data-toggle'] = 'dropdown'; - Html::addCssClass($this->options, 'dropdown-toggle'); - $splitButton = Button::widget([ - 'label' => '', - 'encodeLabel' => false, - 'options' => $this->options, - 'view' => $this->getView(), - ]); - } else { - $label .= ' '; - $options = $this->options; - if (!isset($options['href'])) { - $options['href'] = '#'; - } - Html::addCssClass($options, 'dropdown-toggle'); - $options['data-toggle'] = 'dropdown'; - $splitButton = ''; - } - return Button::widget([ - 'tagName' => $this->tagName, - 'label' => $label, - 'options' => $options, - 'encodeLabel' => false, - 'view' => $this->getView(), - ]) . "\n" . $splitButton; - } + return Button::widget([ + 'tagName' => $this->tagName, + 'label' => $label, + 'options' => $options, + 'encodeLabel' => false, + 'view' => $this->getView(), + ]) . "\n" . $splitButton; + } - /** - * Generates the dropdown menu. - * @return string the rendering result. - */ - protected function renderDropdown() - { - $config = $this->dropdown; - $config['clientOptions'] = false; - $config['view'] = $this->getView(); - return Dropdown::widget($config); - } + /** + * Generates the dropdown menu. + * @return string the rendering result. + */ + protected function renderDropdown() + { + $config = $this->dropdown; + $config['clientOptions'] = false; + $config['view'] = $this->getView(); + + return Dropdown::widget($config); + } } diff --git a/ButtonGroup.php b/ButtonGroup.php index 66d2cc0..8b08b61 100644 --- a/ButtonGroup.php +++ b/ButtonGroup.php @@ -39,60 +39,60 @@ use yii\helpers\Html; */ class ButtonGroup extends Widget { - /** - * @var array list of buttons. Each array element represents a single button - * which can be specified as a string or an array of the following structure: - * - * - label: string, required, the button label. - * - options: array, optional, the HTML attributes of the button. - */ - public $buttons = []; - /** - * @var boolean whether to HTML-encode the button labels. - */ - public $encodeLabels = true; + /** + * @var array list of buttons. Each array element represents a single button + * which can be specified as a string or an array of the following structure: + * + * - label: string, required, the button label. + * - options: array, optional, the HTML attributes of the button. + */ + public $buttons = []; + /** + * @var boolean whether to HTML-encode the button labels. + */ + public $encodeLabels = true; + /** + * Initializes the widget. + * If you override this method, make sure you call the parent implementation first. + */ + public function init() + { + parent::init(); + Html::addCssClass($this->options, 'btn-group'); + } - /** - * Initializes the widget. - * If you override this method, make sure you call the parent implementation first. - */ - public function init() - { - parent::init(); - Html::addCssClass($this->options, 'btn-group'); - } + /** + * Renders the widget. + */ + public function run() + { + echo Html::tag('div', $this->renderButtons(), $this->options); + BootstrapAsset::register($this->getView()); + } - /** - * Renders the widget. - */ - public function run() - { - echo Html::tag('div', $this->renderButtons(), $this->options); - BootstrapAsset::register($this->getView()); - } + /** + * Generates the buttons that compound the group as specified on [[items]]. + * @return string the rendering result. + */ + protected function renderButtons() + { + $buttons = []; + foreach ($this->buttons as $button) { + if (is_array($button)) { + $label = ArrayHelper::getValue($button, 'label'); + $options = ArrayHelper::getValue($button, 'options'); + $buttons[] = Button::widget([ + 'label' => $label, + 'options' => $options, + 'encodeLabel' => $this->encodeLabels, + 'view' => $this->getView() + ]); + } else { + $buttons[] = $button; + } + } - /** - * Generates the buttons that compound the group as specified on [[items]]. - * @return string the rendering result. - */ - protected function renderButtons() - { - $buttons = []; - foreach ($this->buttons as $button) { - if (is_array($button)) { - $label = ArrayHelper::getValue($button, 'label'); - $options = ArrayHelper::getValue($button, 'options'); - $buttons[] = Button::widget([ - 'label' => $label, - 'options' => $options, - 'encodeLabel' => $this->encodeLabels, - 'view' => $this->getView() - ]); - } else { - $buttons[] = $button; - } - } - return implode("\n", $buttons); - } + return implode("\n", $buttons); + } } diff --git a/Carousel.php b/Carousel.php index eaeb6a5..40291a2 100644 --- a/Carousel.php +++ b/Carousel.php @@ -39,132 +39,133 @@ use yii\helpers\Html; */ class Carousel extends Widget { - /** - * @var array|boolean the labels for the previous and the next control buttons. - * If false, it means the previous and the next control buttons should not be displayed. - */ - public $controls = ['‹', '›']; - /** - * @var array list of slides in the carousel. Each array element represents a single - * slide with the following structure: - * - * ```php - * [ - * // required, slide content (HTML), such as an image tag - * 'content' => '', - * // optional, the caption (HTML) of the slide - * 'caption' => '

This is title

This is the caption text

', - * // optional the HTML attributes of the slide container - * 'options' => [], - * ] - * ``` - */ - public $items = []; + /** + * @var array|boolean the labels for the previous and the next control buttons. + * If false, it means the previous and the next control buttons should not be displayed. + */ + public $controls = ['‹', '›']; + /** + * @var array list of slides in the carousel. Each array element represents a single + * slide with the following structure: + * + * ```php + * [ + * // required, slide content (HTML), such as an image tag + * 'content' => '', + * // optional, the caption (HTML) of the slide + * 'caption' => '

This is title

This is the caption text

', + * // optional the HTML attributes of the slide container + * 'options' => [], + * ] + * ``` + */ + public $items = []; + /** + * Initializes the widget. + */ + public function init() + { + parent::init(); + Html::addCssClass($this->options, 'carousel'); + } - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - Html::addCssClass($this->options, 'carousel'); - } + /** + * Renders the widget. + */ + public function run() + { + echo Html::beginTag('div', $this->options) . "\n"; + echo $this->renderIndicators() . "\n"; + echo $this->renderItems() . "\n"; + echo $this->renderControls() . "\n"; + echo Html::endTag('div') . "\n"; + $this->registerPlugin('carousel'); + } - /** - * Renders the widget. - */ - public function run() - { - echo Html::beginTag('div', $this->options) . "\n"; - echo $this->renderIndicators() . "\n"; - echo $this->renderItems() . "\n"; - echo $this->renderControls() . "\n"; - echo Html::endTag('div') . "\n"; - $this->registerPlugin('carousel'); - } + /** + * Renders carousel indicators. + * @return string the rendering result + */ + public function renderIndicators() + { + $indicators = []; + for ($i = 0, $count = count($this->items); $i < $count; $i++) { + $options = ['data-target' => '#' . $this->options['id'], 'data-slide-to' => $i]; + if ($i === 0) { + Html::addCssClass($options, 'active'); + } + $indicators[] = Html::tag('li', '', $options); + } - /** - * Renders carousel indicators. - * @return string the rendering result - */ - public function renderIndicators() - { - $indicators = []; - for ($i = 0, $count = count($this->items); $i < $count; $i++) { - $options = ['data-target' => '#' . $this->options['id'], 'data-slide-to' => $i]; - if ($i === 0) { - Html::addCssClass($options, 'active'); - } - $indicators[] = Html::tag('li', '', $options); - } - return Html::tag('ol', implode("\n", $indicators), ['class' => 'carousel-indicators']); - } + return Html::tag('ol', implode("\n", $indicators), ['class' => 'carousel-indicators']); + } - /** - * Renders carousel items as specified on [[items]]. - * @return string the rendering result - */ - public function renderItems() - { - $items = []; - for ($i = 0, $count = count($this->items); $i < $count; $i++) { - $items[] = $this->renderItem($this->items[$i], $i); - } - return Html::tag('div', implode("\n", $items), ['class' => 'carousel-inner']); - } + /** + * Renders carousel items as specified on [[items]]. + * @return string the rendering result + */ + public function renderItems() + { + $items = []; + for ($i = 0, $count = count($this->items); $i < $count; $i++) { + $items[] = $this->renderItem($this->items[$i], $i); + } - /** - * Renders a single carousel item - * @param string|array $item a single item from [[items]] - * @param integer $index the item index as the first item should be set to `active` - * @return string the rendering result - * @throws InvalidConfigException if the item is invalid - */ - public function renderItem($item, $index) - { - if (is_string($item)) { - $content = $item; - $caption = null; - $options = []; - } elseif (isset($item['content'])) { - $content = $item['content']; - $caption = ArrayHelper::getValue($item, 'caption'); - if ($caption !== null) { - $caption = Html::tag('div', $caption, ['class' => 'carousel-caption']); - } - $options = ArrayHelper::getValue($item, 'options', []); - } else { - throw new InvalidConfigException('The "content" option is required.'); - } + return Html::tag('div', implode("\n", $items), ['class' => 'carousel-inner']); + } - Html::addCssClass($options, 'item'); - if ($index === 0) { - Html::addCssClass($options, 'active'); - } + /** + * Renders a single carousel item + * @param string|array $item a single item from [[items]] + * @param integer $index the item index as the first item should be set to `active` + * @return string the rendering result + * @throws InvalidConfigException if the item is invalid + */ + public function renderItem($item, $index) + { + if (is_string($item)) { + $content = $item; + $caption = null; + $options = []; + } elseif (isset($item['content'])) { + $content = $item['content']; + $caption = ArrayHelper::getValue($item, 'caption'); + if ($caption !== null) { + $caption = Html::tag('div', $caption, ['class' => 'carousel-caption']); + } + $options = ArrayHelper::getValue($item, 'options', []); + } else { + throw new InvalidConfigException('The "content" option is required.'); + } - return Html::tag('div', $content . "\n" . $caption, $options); - } + Html::addCssClass($options, 'item'); + if ($index === 0) { + Html::addCssClass($options, 'active'); + } - /** - * Renders previous and next control buttons. - * @throws InvalidConfigException if [[controls]] is invalid. - */ - public function renderControls() - { - if (isset($this->controls[0], $this->controls[1])) { - return Html::a($this->controls[0], '#' . $this->options['id'], [ - 'class' => 'left carousel-control', - 'data-slide' => 'prev', - ]) . "\n" - . Html::a($this->controls[1], '#' . $this->options['id'], [ - 'class' => 'right carousel-control', - 'data-slide' => 'next', - ]); - } elseif ($this->controls === false) { - return ''; - } else { - throw new InvalidConfigException('The "controls" property must be either false or an array of two elements.'); - } - } + return Html::tag('div', $content . "\n" . $caption, $options); + } + + /** + * Renders previous and next control buttons. + * @throws InvalidConfigException if [[controls]] is invalid. + */ + public function renderControls() + { + if (isset($this->controls[0], $this->controls[1])) { + return Html::a($this->controls[0], '#' . $this->options['id'], [ + 'class' => 'left carousel-control', + 'data-slide' => 'prev', + ]) . "\n" + . Html::a($this->controls[1], '#' . $this->options['id'], [ + 'class' => 'right carousel-control', + 'data-slide' => 'next', + ]); + } elseif ($this->controls === false) { + return ''; + } else { + throw new InvalidConfigException('The "controls" property must be either false or an array of two elements.'); + } + } } diff --git a/Collapse.php b/Collapse.php index 2de06d9..b8fb97c 100644 --- a/Collapse.php +++ b/Collapse.php @@ -41,95 +41,94 @@ use yii\helpers\Html; */ class Collapse extends Widget { - /** - * @var array list of groups in the collapse widget. Each array element represents a single - * group with the following structure: - * - * ```php - * // item key is the actual group header - * 'Collapsible Group Item #1' => [ - * // required, the content (HTML) of the group - * 'content' => 'Anim pariatur cliche...', - * // optional the HTML attributes of the content group - * 'contentOptions' => [], - * // optional the HTML attributes of the group - * 'options' => [], - * ] - * ``` - */ - public $items = []; + /** + * @var array list of groups in the collapse widget. Each array element represents a single + * group with the following structure: + * + * ```php + * // item key is the actual group header + * 'Collapsible Group Item #1' => [ + * // required, the content (HTML) of the group + * 'content' => 'Anim pariatur cliche...', + * // optional the HTML attributes of the content group + * 'contentOptions' => [], + * // optional the HTML attributes of the group + * 'options' => [], + * ] + * ``` + */ + public $items = []; + /** + * Initializes the widget. + */ + public function init() + { + parent::init(); + Html::addCssClass($this->options, 'panel-group'); + } - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - Html::addCssClass($this->options, 'panel-group'); - } + /** + * Renders the widget. + */ + public function run() + { + echo Html::beginTag('div', $this->options) . "\n"; + echo $this->renderItems() . "\n"; + echo Html::endTag('div') . "\n"; + $this->registerPlugin('collapse'); + } - /** - * Renders the widget. - */ - public function run() - { - echo Html::beginTag('div', $this->options) . "\n"; - echo $this->renderItems() . "\n"; - echo Html::endTag('div') . "\n"; - $this->registerPlugin('collapse'); - } + /** + * Renders collapsible items as specified on [[items]]. + * @return string the rendering result + */ + public function renderItems() + { + $items = []; + $index = 0; + foreach ($this->items as $header => $item) { + $options = ArrayHelper::getValue($item, 'options', []); + Html::addCssClass($options, 'panel panel-default'); + $items[] = Html::tag('div', $this->renderItem($header, $item, ++$index), $options); + } - /** - * Renders collapsible items as specified on [[items]]. - * @return string the rendering result - */ - public function renderItems() - { - $items = []; - $index = 0; - foreach ($this->items as $header => $item) { - $options = ArrayHelper::getValue($item, 'options', []); - Html::addCssClass($options, 'panel panel-default'); - $items[] = Html::tag('div', $this->renderItem($header, $item, ++$index), $options); - } + return implode("\n", $items); + } - return implode("\n", $items); - } + /** + * Renders a single collapsible item group + * @param string $header a label of the item group [[items]] + * @param array $item a single item from [[items]] + * @param integer $index the item index as each item group content must have an id + * @return string the rendering result + * @throws InvalidConfigException + */ + public function renderItem($header, $item, $index) + { + if (isset($item['content'])) { + $id = $this->options['id'] . '-collapse' . $index; + $options = ArrayHelper::getValue($item, 'contentOptions', []); + $options['id'] = $id; + Html::addCssClass($options, 'panel-collapse collapse'); - /** - * Renders a single collapsible item group - * @param string $header a label of the item group [[items]] - * @param array $item a single item from [[items]] - * @param integer $index the item index as each item group content must have an id - * @return string the rendering result - * @throws InvalidConfigException - */ - public function renderItem($header, $item, $index) - { - if (isset($item['content'])) { - $id = $this->options['id'] . '-collapse' . $index; - $options = ArrayHelper::getValue($item, 'contentOptions', []); - $options['id'] = $id; - Html::addCssClass($options, 'panel-collapse collapse'); + $headerToggle = Html::a($header, '#' . $id, [ + 'class' => 'collapse-toggle', + 'data-toggle' => 'collapse', + 'data-parent' => '#' . $this->options['id'] + ]) . "\n"; - $headerToggle = Html::a($header, '#' . $id, [ - 'class' => 'collapse-toggle', - 'data-toggle' => 'collapse', - 'data-parent' => '#' . $this->options['id'] - ]) . "\n"; + $header = Html::tag('h4', $headerToggle, ['class' => 'panel-title']); - $header = Html::tag('h4', $headerToggle, ['class' => 'panel-title']); + $content = Html::tag('div', $item['content'], ['class' => 'panel-body']) . "\n"; + } else { + throw new InvalidConfigException('The "content" option is required.'); + } + $group = []; - $content = Html::tag('div', $item['content'], ['class' => 'panel-body']) . "\n"; - } else { - throw new InvalidConfigException('The "content" option is required.'); - } - $group = []; + $group[] = Html::tag('div', $header, ['class' => 'panel-heading']); + $group[] = Html::tag('div', $content, $options); - $group[] = Html::tag('div', $header, ['class' => 'panel-heading']); - $group[] = Html::tag('div', $content, $options); - - return implode("\n", $group); - } + return implode("\n", $group); + } } diff --git a/Dropdown.php b/Dropdown.php index 85136b8..8109add 100644 --- a/Dropdown.php +++ b/Dropdown.php @@ -20,79 +20,79 @@ use yii\helpers\Html; */ class Dropdown extends Widget { - /** - * @var array list of menu items in the dropdown. Each array element can be either an HTML string, - * or an array representing a single menu with the following structure: - * - * - label: string, required, the label of the item link - * - url: string, optional, the url of the item link. Defaults to "#". - * - visible: boolean, optional, whether this menu item is visible. Defaults to true. - * - linkOptions: array, optional, the HTML attributes of the item link. - * - options: array, optional, the HTML attributes of the item. - * - items: array, optional, the submenu items. The structure is the same as this property. - * Note that Bootstrap doesn't support dropdown submenu. You have to add your own CSS styles to support it. - * - * To insert divider use ``. - */ - public $items = []; - /** - * @var boolean whether the labels for header items should be HTML-encoded. - */ - public $encodeLabels = true; + /** + * @var array list of menu items in the dropdown. Each array element can be either an HTML string, + * or an array representing a single menu with the following structure: + * + * - label: string, required, the label of the item link + * - url: string, optional, the url of the item link. Defaults to "#". + * - visible: boolean, optional, whether this menu item is visible. Defaults to true. + * - linkOptions: array, optional, the HTML attributes of the item link. + * - options: array, optional, the HTML attributes of the item. + * - items: array, optional, the submenu items. The structure is the same as this property. + * Note that Bootstrap doesn't support dropdown submenu. You have to add your own CSS styles to support it. + * + * To insert divider use ``. + */ + public $items = []; + /** + * @var boolean whether the labels for header items should be HTML-encoded. + */ + public $encodeLabels = true; - /** - * Initializes the widget. - * If you override this method, make sure you call the parent implementation first. - */ - public function init() - { - parent::init(); - Html::addCssClass($this->options, 'dropdown-menu'); - } + /** + * Initializes the widget. + * If you override this method, make sure you call the parent implementation first. + */ + public function init() + { + parent::init(); + Html::addCssClass($this->options, 'dropdown-menu'); + } - /** - * Renders the widget. - */ - public function run() - { - echo $this->renderItems($this->items); - $this->registerPlugin('dropdown'); - } + /** + * Renders the widget. + */ + public function run() + { + echo $this->renderItems($this->items); + $this->registerPlugin('dropdown'); + } - /** - * Renders menu items. - * @param array $items the menu items to be rendered - * @return string the rendering result. - * @throws InvalidConfigException if the label option is not specified in one of the items. - */ - protected function renderItems($items) - { - $lines = []; - foreach ($items as $i => $item) { - if (isset($item['visible']) && !$item['visible']) { - unset($items[$i]); - continue; - } - if (is_string($item)) { - $lines[] = $item; - continue; - } - if (!isset($item['label'])) { - throw new InvalidConfigException("The 'label' option is required."); - } - $label = $this->encodeLabels ? Html::encode($item['label']) : $item['label']; - $options = ArrayHelper::getValue($item, 'options', []); - $linkOptions = ArrayHelper::getValue($item, 'linkOptions', []); - $linkOptions['tabindex'] = '-1'; - $content = Html::a($label, ArrayHelper::getValue($item, 'url', '#'), $linkOptions); - if (!empty($item['items'])) { - $content .= $this->renderItems($item['items']); - Html::addCssClass($options, 'dropdown-submenu'); - } - $lines[] = Html::tag('li', $content, $options); - } + /** + * Renders menu items. + * @param array $items the menu items to be rendered + * @return string the rendering result. + * @throws InvalidConfigException if the label option is not specified in one of the items. + */ + protected function renderItems($items) + { + $lines = []; + foreach ($items as $i => $item) { + if (isset($item['visible']) && !$item['visible']) { + unset($items[$i]); + continue; + } + if (is_string($item)) { + $lines[] = $item; + continue; + } + if (!isset($item['label'])) { + throw new InvalidConfigException("The 'label' option is required."); + } + $label = $this->encodeLabels ? Html::encode($item['label']) : $item['label']; + $options = ArrayHelper::getValue($item, 'options', []); + $linkOptions = ArrayHelper::getValue($item, 'linkOptions', []); + $linkOptions['tabindex'] = '-1'; + $content = Html::a($label, ArrayHelper::getValue($item, 'url', '#'), $linkOptions); + if (!empty($item['items'])) { + $content .= $this->renderItems($item['items']); + Html::addCssClass($options, 'dropdown-submenu'); + } + $lines[] = Html::tag('li', $content, $options); + } - return Html::tag('ul', implode("\n", $lines), $this->options); - } + return Html::tag('ul', implode("\n", $lines), $this->options); + } } diff --git a/Modal.php b/Modal.php index e498f49..6235278 100644 --- a/Modal.php +++ b/Modal.php @@ -35,201 +35,202 @@ use yii\helpers\Html; */ class Modal extends Widget { - const SIZE_LARGE = "modal-lg"; - const SIZE_SMALL = "modal-sm"; - const SIZE_DEFAULT = ""; - - /** - * @var string the header content in the modal window. - */ - public $header; - /** - * @var string the footer content in the modal window. - */ - public $footer; - /** - * @var string the modal size. Can be MODAL_LG or MODAL_SM, or empty for default. - */ - public $size; - /** - * @var array the options for rendering the close button tag. - * The close button is displayed in the header of the modal window. Clicking - * on the button will hide the modal window. If this is null, no close button will be rendered. - * - * The following special options are supported: - * - * - tag: string, the tag name of the button. Defaults to 'button'. - * - label: string, the label of the button. Defaults to '×'. - * - * The rest of the options will be rendered as the HTML attributes of the button tag. - * Please refer to the [Modal plugin help](http://getbootstrap.com/javascript/#modals) - * for the supported HTML attributes. - */ - public $closeButton = []; - /** - * @var array the options for rendering the toggle button tag. - * The toggle button is used to toggle the visibility of the modal window. - * If this property is null, no toggle button will be rendered. - * - * The following special options are supported: - * - * - tag: string, the tag name of the button. Defaults to 'button'. - * - label: string, the label of the button. Defaults to 'Show'. - * - * The rest of the options will be rendered as the HTML attributes of the button tag. - * Please refer to the [Modal plugin help](http://getbootstrap.com/javascript/#modals) - * for the supported HTML attributes. - */ - public $toggleButton; - - - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - - $this->initOptions(); - - echo $this->renderToggleButton() . "\n"; - echo Html::beginTag('div', $this->options) . "\n"; - echo Html::beginTag('div', ['class' => 'modal-dialog ' . $this->size]) . "\n"; - echo Html::beginTag('div', ['class' => 'modal-content']) . "\n"; - echo $this->renderHeader() . "\n"; - echo $this->renderBodyBegin() . "\n"; - } - - /** - * Renders the widget. - */ - public function run() - { - echo "\n" . $this->renderBodyEnd(); - echo "\n" . $this->renderFooter(); - echo "\n" . Html::endTag('div'); // modal-content - echo "\n" . Html::endTag('div'); // modal-dialog - echo "\n" . Html::endTag('div'); - - $this->registerPlugin('modal'); - } - - /** - * Renders the header HTML markup of the modal - * @return string the rendering result - */ - protected function renderHeader() - { - $button = $this->renderCloseButton(); - if ($button !== null) { - $this->header = $button . "\n" . $this->header; - } - if ($this->header !== null) { - return Html::tag('div', "\n" . $this->header . "\n", ['class' => 'modal-header']); - } else { - return null; - } - } - - /** - * Renders the opening tag of the modal body. - * @return string the rendering result - */ - protected function renderBodyBegin() - { - return Html::beginTag('div', ['class' => 'modal-body']); - } - - /** - * Renders the closing tag of the modal body. - * @return string the rendering result - */ - protected function renderBodyEnd() - { - return Html::endTag('div'); - } - - /** - * Renders the HTML markup for the footer of the modal - * @return string the rendering result - */ - protected function renderFooter() - { - if ($this->footer !== null) { - return Html::tag('div', "\n" . $this->footer . "\n", ['class' => 'modal-footer']); - } else { - return null; - } - } - - /** - * Renders the toggle button. - * @return string the rendering result - */ - protected function renderToggleButton() - { - if ($this->toggleButton !== null) { - $tag = ArrayHelper::remove($this->toggleButton, 'tag', 'button'); - $label = ArrayHelper::remove($this->toggleButton, 'label', 'Show'); - if ($tag === 'button' && !isset($this->toggleButton['type'])) { - $this->toggleButton['type'] = 'button'; - } - return Html::tag($tag, $label, $this->toggleButton); - } else { - return null; - } - } - - /** - * Renders the close button. - * @return string the rendering result - */ - protected function renderCloseButton() - { - if ($this->closeButton !== null) { - $tag = ArrayHelper::remove($this->closeButton, 'tag', 'button'); - $label = ArrayHelper::remove($this->closeButton, 'label', '×'); - if ($tag === 'button' && !isset($this->closeButton['type'])) { - $this->closeButton['type'] = 'button'; - } - return Html::tag($tag, $label, $this->closeButton); - } else { - return null; - } - } - - /** - * Initializes the widget options. - * This method sets the default values for various options. - */ - protected function initOptions() - { - $this->options = array_merge([ - 'class' => 'fade', - 'role' => 'dialog', - 'tabindex' => -1, - ], $this->options); - Html::addCssClass($this->options, 'modal'); - - if ($this->clientOptions !== false) { - $this->clientOptions = array_merge(['show' => false], $this->clientOptions); - } - - if ($this->closeButton !== null) { - $this->closeButton = array_merge([ - 'data-dismiss' => 'modal', - 'aria-hidden' => 'true', - 'class' => 'close', - ], $this->closeButton); - } - - if ($this->toggleButton !== null) { - $this->toggleButton = array_merge([ - 'data-toggle' => 'modal', - ], $this->toggleButton); - if (!isset($this->toggleButton['data-target']) && !isset($this->toggleButton['href'])) { - $this->toggleButton['data-target'] = '#' . $this->options['id']; - } - } - } + const SIZE_LARGE = "modal-lg"; + const SIZE_SMALL = "modal-sm"; + const SIZE_DEFAULT = ""; + + /** + * @var string the header content in the modal window. + */ + public $header; + /** + * @var string the footer content in the modal window. + */ + public $footer; + /** + * @var string the modal size. Can be MODAL_LG or MODAL_SM, or empty for default. + */ + public $size; + /** + * @var array the options for rendering the close button tag. + * The close button is displayed in the header of the modal window. Clicking + * on the button will hide the modal window. If this is null, no close button will be rendered. + * + * The following special options are supported: + * + * - tag: string, the tag name of the button. Defaults to 'button'. + * - label: string, the label of the button. Defaults to '×'. + * + * The rest of the options will be rendered as the HTML attributes of the button tag. + * Please refer to the [Modal plugin help](http://getbootstrap.com/javascript/#modals) + * for the supported HTML attributes. + */ + public $closeButton = []; + /** + * @var array the options for rendering the toggle button tag. + * The toggle button is used to toggle the visibility of the modal window. + * If this property is null, no toggle button will be rendered. + * + * The following special options are supported: + * + * - tag: string, the tag name of the button. Defaults to 'button'. + * - label: string, the label of the button. Defaults to 'Show'. + * + * The rest of the options will be rendered as the HTML attributes of the button tag. + * Please refer to the [Modal plugin help](http://getbootstrap.com/javascript/#modals) + * for the supported HTML attributes. + */ + public $toggleButton; + + /** + * Initializes the widget. + */ + public function init() + { + parent::init(); + + $this->initOptions(); + + echo $this->renderToggleButton() . "\n"; + echo Html::beginTag('div', $this->options) . "\n"; + echo Html::beginTag('div', ['class' => 'modal-dialog ' . $this->size]) . "\n"; + echo Html::beginTag('div', ['class' => 'modal-content']) . "\n"; + echo $this->renderHeader() . "\n"; + echo $this->renderBodyBegin() . "\n"; + } + + /** + * Renders the widget. + */ + public function run() + { + echo "\n" . $this->renderBodyEnd(); + echo "\n" . $this->renderFooter(); + echo "\n" . Html::endTag('div'); // modal-content + echo "\n" . Html::endTag('div'); // modal-dialog + echo "\n" . Html::endTag('div'); + + $this->registerPlugin('modal'); + } + + /** + * Renders the header HTML markup of the modal + * @return string the rendering result + */ + protected function renderHeader() + { + $button = $this->renderCloseButton(); + if ($button !== null) { + $this->header = $button . "\n" . $this->header; + } + if ($this->header !== null) { + return Html::tag('div', "\n" . $this->header . "\n", ['class' => 'modal-header']); + } else { + return null; + } + } + + /** + * Renders the opening tag of the modal body. + * @return string the rendering result + */ + protected function renderBodyBegin() + { + return Html::beginTag('div', ['class' => 'modal-body']); + } + + /** + * Renders the closing tag of the modal body. + * @return string the rendering result + */ + protected function renderBodyEnd() + { + return Html::endTag('div'); + } + + /** + * Renders the HTML markup for the footer of the modal + * @return string the rendering result + */ + protected function renderFooter() + { + if ($this->footer !== null) { + return Html::tag('div', "\n" . $this->footer . "\n", ['class' => 'modal-footer']); + } else { + return null; + } + } + + /** + * Renders the toggle button. + * @return string the rendering result + */ + protected function renderToggleButton() + { + if ($this->toggleButton !== null) { + $tag = ArrayHelper::remove($this->toggleButton, 'tag', 'button'); + $label = ArrayHelper::remove($this->toggleButton, 'label', 'Show'); + if ($tag === 'button' && !isset($this->toggleButton['type'])) { + $this->toggleButton['type'] = 'button'; + } + + return Html::tag($tag, $label, $this->toggleButton); + } else { + return null; + } + } + + /** + * Renders the close button. + * @return string the rendering result + */ + protected function renderCloseButton() + { + if ($this->closeButton !== null) { + $tag = ArrayHelper::remove($this->closeButton, 'tag', 'button'); + $label = ArrayHelper::remove($this->closeButton, 'label', '×'); + if ($tag === 'button' && !isset($this->closeButton['type'])) { + $this->closeButton['type'] = 'button'; + } + + return Html::tag($tag, $label, $this->closeButton); + } else { + return null; + } + } + + /** + * Initializes the widget options. + * This method sets the default values for various options. + */ + protected function initOptions() + { + $this->options = array_merge([ + 'class' => 'fade', + 'role' => 'dialog', + 'tabindex' => -1, + ], $this->options); + Html::addCssClass($this->options, 'modal'); + + if ($this->clientOptions !== false) { + $this->clientOptions = array_merge(['show' => false], $this->clientOptions); + } + + if ($this->closeButton !== null) { + $this->closeButton = array_merge([ + 'data-dismiss' => 'modal', + 'aria-hidden' => 'true', + 'class' => 'close', + ], $this->closeButton); + } + + if ($this->toggleButton !== null) { + $this->toggleButton = array_merge([ + 'data-toggle' => 'modal', + ], $this->toggleButton); + if (!isset($this->toggleButton['data-target']) && !isset($this->toggleButton['href'])) { + $this->toggleButton['data-target'] = '#' . $this->options['id']; + } + } + } } diff --git a/Nav.php b/Nav.php index 9d4afc0..191578c 100644 --- a/Nav.php +++ b/Nav.php @@ -48,168 +48,169 @@ use yii\helpers\Html; */ class Nav extends Widget { - /** - * @var array list of items in the nav widget. Each array element represents a single - * menu item which can be either a string or an array with the following structure: - * - * - label: string, required, the nav item label. - * - url: optional, the item's URL. Defaults to "#". - * - visible: boolean, optional, whether this menu item is visible. Defaults to true. - * - linkOptions: array, optional, the HTML attributes of the item's link. - * - options: array, optional, the HTML attributes of the item container (LI). - * - active: boolean, optional, whether the item should be on active state or not. - * - items: array|string, optional, the configuration array for creating a [[Dropdown]] widget, - * or a string representing the dropdown menu. Note that Bootstrap does not support sub-dropdown menus. - * - * If a menu item is a string, it will be rendered directly without HTML encoding. - */ - public $items = []; - /** - * @var boolean whether the nav items labels should be HTML-encoded. - */ - public $encodeLabels = true; - /** - * @var boolean whether to automatically activate items according to whether their route setting - * matches the currently requested route. - * @see isItemActive - */ - public $activateItems = true; - /** - * @var string the route used to determine if a menu item is active or not. - * If not set, it will use the route of the current request. - * @see params - * @see isItemActive - */ - public $route; - /** - * @var array the parameters used to determine if a menu item is active or not. - * If not set, it will use `$_GET`. - * @see route - * @see isItemActive - */ - public $params; - - - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - if ($this->route === null && Yii::$app->controller !== null) { - $this->route = Yii::$app->controller->getRoute(); - } - if ($this->params === null) { - $this->params = Yii::$app->request->getQueryParams(); - } - Html::addCssClass($this->options, 'nav'); - } - - /** - * Renders the widget. - */ - public function run() - { - echo $this->renderItems(); - BootstrapAsset::register($this->getView()); - } - - /** - * Renders widget items. - */ - public function renderItems() - { - $items = []; - foreach ($this->items as $i => $item) { - if (isset($item['visible']) && !$item['visible']) { - unset($items[$i]); - continue; - } - $items[] = $this->renderItem($item); - } - - return Html::tag('ul', implode("\n", $items), $this->options); - } - - /** - * Renders a widget's item. - * @param string|array $item the item to render. - * @return string the rendering result. - * @throws InvalidConfigException - */ - public function renderItem($item) - { - if (is_string($item)) { - return $item; - } - if (!isset($item['label'])) { - throw new InvalidConfigException("The 'label' option is required."); - } - $label = $this->encodeLabels ? Html::encode($item['label']) : $item['label']; - $options = ArrayHelper::getValue($item, 'options', []); - $items = ArrayHelper::getValue($item, 'items'); - $url = ArrayHelper::getValue($item, 'url', '#'); - $linkOptions = ArrayHelper::getValue($item, 'linkOptions', []); - - if (isset($item['active'])) { - $active = ArrayHelper::remove($item, 'active', false); - } else { - $active = $this->isItemActive($item); - } - - if ($active) { - Html::addCssClass($options, 'active'); - } - - if ($items !== null) { - $linkOptions['data-toggle'] = 'dropdown'; - Html::addCssClass($options, 'dropdown'); - Html::addCssClass($linkOptions, 'dropdown-toggle'); - $label .= ' ' . Html::tag('b', '', ['class' => 'caret']); - if (is_array($items)) { - $items = Dropdown::widget([ - 'items' => $items, - 'encodeLabels' => $this->encodeLabels, - 'clientOptions' => false, - 'view' => $this->getView(), - ]); - } - } - - return Html::tag('li', Html::a($label, $url, $linkOptions) . $items, $options); - } - - - /** - * Checks whether a menu item is active. - * This is done by checking if [[route]] and [[params]] match that specified in the `url` option of the menu item. - * When the `url` option of a menu item is specified in terms of an array, its first element is treated - * as the route for the item and the rest of the elements are the associated parameters. - * Only when its route and parameters match [[route]] and [[params]], respectively, will a menu item - * be considered active. - * @param array $item the menu item to be checked - * @return boolean whether the menu item is active - */ - protected function isItemActive($item) - { - if (isset($item['url']) && is_array($item['url']) && isset($item['url'][0])) { - $route = $item['url'][0]; - if ($route[0] !== '/' && Yii::$app->controller) { - $route = Yii::$app->controller->module->getUniqueId() . '/' . $route; - } - if (ltrim($route, '/') !== $this->route) { - return false; - } - unset($item['url']['#']); - if (count($item['url']) > 1) { - foreach (array_splice($item['url'], 1) as $name => $value) { - if ($value !== null && (!isset($this->params[$name]) || $this->params[$name] != $value)) { - return false; - } - } - } - return true; - } - return false; - } + /** + * @var array list of items in the nav widget. Each array element represents a single + * menu item which can be either a string or an array with the following structure: + * + * - label: string, required, the nav item label. + * - url: optional, the item's URL. Defaults to "#". + * - visible: boolean, optional, whether this menu item is visible. Defaults to true. + * - linkOptions: array, optional, the HTML attributes of the item's link. + * - options: array, optional, the HTML attributes of the item container (LI). + * - active: boolean, optional, whether the item should be on active state or not. + * - items: array|string, optional, the configuration array for creating a [[Dropdown]] widget, + * or a string representing the dropdown menu. Note that Bootstrap does not support sub-dropdown menus. + * + * If a menu item is a string, it will be rendered directly without HTML encoding. + */ + public $items = []; + /** + * @var boolean whether the nav items labels should be HTML-encoded. + */ + public $encodeLabels = true; + /** + * @var boolean whether to automatically activate items according to whether their route setting + * matches the currently requested route. + * @see isItemActive + */ + public $activateItems = true; + /** + * @var string the route used to determine if a menu item is active or not. + * If not set, it will use the route of the current request. + * @see params + * @see isItemActive + */ + public $route; + /** + * @var array the parameters used to determine if a menu item is active or not. + * If not set, it will use `$_GET`. + * @see route + * @see isItemActive + */ + public $params; + + /** + * Initializes the widget. + */ + public function init() + { + parent::init(); + if ($this->route === null && Yii::$app->controller !== null) { + $this->route = Yii::$app->controller->getRoute(); + } + if ($this->params === null) { + $this->params = Yii::$app->request->getQueryParams(); + } + Html::addCssClass($this->options, 'nav'); + } + + /** + * Renders the widget. + */ + public function run() + { + echo $this->renderItems(); + BootstrapAsset::register($this->getView()); + } + + /** + * Renders widget items. + */ + public function renderItems() + { + $items = []; + foreach ($this->items as $i => $item) { + if (isset($item['visible']) && !$item['visible']) { + unset($items[$i]); + continue; + } + $items[] = $this->renderItem($item); + } + + return Html::tag('ul', implode("\n", $items), $this->options); + } + + /** + * Renders a widget's item. + * @param string|array $item the item to render. + * @return string the rendering result. + * @throws InvalidConfigException + */ + public function renderItem($item) + { + if (is_string($item)) { + return $item; + } + if (!isset($item['label'])) { + throw new InvalidConfigException("The 'label' option is required."); + } + $label = $this->encodeLabels ? Html::encode($item['label']) : $item['label']; + $options = ArrayHelper::getValue($item, 'options', []); + $items = ArrayHelper::getValue($item, 'items'); + $url = ArrayHelper::getValue($item, 'url', '#'); + $linkOptions = ArrayHelper::getValue($item, 'linkOptions', []); + + if (isset($item['active'])) { + $active = ArrayHelper::remove($item, 'active', false); + } else { + $active = $this->isItemActive($item); + } + + if ($active) { + Html::addCssClass($options, 'active'); + } + + if ($items !== null) { + $linkOptions['data-toggle'] = 'dropdown'; + Html::addCssClass($options, 'dropdown'); + Html::addCssClass($linkOptions, 'dropdown-toggle'); + $label .= ' ' . Html::tag('b', '', ['class' => 'caret']); + if (is_array($items)) { + $items = Dropdown::widget([ + 'items' => $items, + 'encodeLabels' => $this->encodeLabels, + 'clientOptions' => false, + 'view' => $this->getView(), + ]); + } + } + + return Html::tag('li', Html::a($label, $url, $linkOptions) . $items, $options); + } + + + /** + * Checks whether a menu item is active. + * This is done by checking if [[route]] and [[params]] match that specified in the `url` option of the menu item. + * When the `url` option of a menu item is specified in terms of an array, its first element is treated + * as the route for the item and the rest of the elements are the associated parameters. + * Only when its route and parameters match [[route]] and [[params]], respectively, will a menu item + * be considered active. + * @param array $item the menu item to be checked + * @return boolean whether the menu item is active + */ + protected function isItemActive($item) + { + if (isset($item['url']) && is_array($item['url']) && isset($item['url'][0])) { + $route = $item['url'][0]; + if ($route[0] !== '/' && Yii::$app->controller) { + $route = Yii::$app->controller->module->getUniqueId() . '/' . $route; + } + if (ltrim($route, '/') !== $this->route) { + return false; + } + unset($item['url']['#']); + if (count($item['url']) > 1) { + foreach (array_splice($item['url'], 1) as $name => $value) { + if ($value !== null && (!isset($this->params[$name]) || $this->params[$name] != $value)) { + return false; + } + } + } + + return true; + } + + return false; + } } diff --git a/NavBar.php b/NavBar.php index d1396a2..ab681d1 100644 --- a/NavBar.php +++ b/NavBar.php @@ -39,120 +39,121 @@ use yii\helpers\Html; */ class NavBar extends Widget { - /** - * @var array the HTML attributes for the widget container tag. The following special options are recognized: - * - * - tag: string, defaults to "nav", the name of the container tag. - * - * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. - */ - public $options = []; - /** - * @var array the HTML attributes for the container tag. The following special options are recognized: - * - * - tag: string, defaults to "div", the name of the container tag. - * - * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. - */ - public $containerOptions = []; - /** - * @var string the text of the brand. Note that this is not HTML-encoded. - * @see http://getbootstrap.com/components/#navbar - */ - public $brandLabel; - /** - * @param array|string $url the URL for the brand's hyperlink tag. This parameter will be processed by [[Url::to()]] - * and will be used for the "href" attribute of the brand link. If not set, [[\yii\web\Application::homeUrl]] will be used. - */ - public $brandUrl; - /** - * @var array the HTML attributes of the brand link. - * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. - */ - public $brandOptions = []; - /** - * @var string text to show for screen readers for the button to toggle the navbar. - */ - public $screenReaderToggleText = 'Toggle navigation'; - /** - * @var boolean whether the navbar content should be included in an inner div container which by default - * adds left and right padding. Set this to false for a 100% width navbar. - */ - public $renderInnerContainer = true; - /** - * @var array the HTML attributes of the inner container. - * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. - */ - public $innerContainerOptions = []; + /** + * @var array the HTML attributes for the widget container tag. The following special options are recognized: + * + * - tag: string, defaults to "nav", the name of the container tag. + * + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. + */ + public $options = []; + /** + * @var array the HTML attributes for the container tag. The following special options are recognized: + * + * - tag: string, defaults to "div", the name of the container tag. + * + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. + */ + public $containerOptions = []; + /** + * @var string the text of the brand. Note that this is not HTML-encoded. + * @see http://getbootstrap.com/components/#navbar + */ + public $brandLabel; + /** + * @param array|string $url the URL for the brand's hyperlink tag. This parameter will be processed by [[Url::to()]] + * and will be used for the "href" attribute of the brand link. If not set, [[\yii\web\Application::homeUrl]] will be used. + */ + public $brandUrl; + /** + * @var array the HTML attributes of the brand link. + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. + */ + public $brandOptions = []; + /** + * @var string text to show for screen readers for the button to toggle the navbar. + */ + public $screenReaderToggleText = 'Toggle navigation'; + /** + * @var boolean whether the navbar content should be included in an inner div container which by default + * adds left and right padding. Set this to false for a 100% width navbar. + */ + public $renderInnerContainer = true; + /** + * @var array the HTML attributes of the inner container. + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. + */ + public $innerContainerOptions = []; - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - $this->clientOptions = false; - Html::addCssClass($this->options, 'navbar'); - if ($this->options['class'] === 'navbar') { - Html::addCssClass($this->options, 'navbar-default'); - } - Html::addCssClass($this->brandOptions, 'navbar-brand'); - if (empty($this->options['role'])) { - $this->options['role'] = 'navigation'; - } - $options = $this->options; - $tag = ArrayHelper::remove($options, 'tag', 'nav'); - echo Html::beginTag($tag, $options); - if ($this->renderInnerContainer) { - if (!isset($this->innerContainerOptions['class'])) { - Html::addCssClass($this->innerContainerOptions, 'container'); - } - echo Html::beginTag('div', $this->innerContainerOptions); - } - echo Html::beginTag('div', ['class' => 'navbar-header']); - if (!isset($this->containerOptions['id'])) { - $this->containerOptions['id'] = "{$this->options['id']}-collapse"; - } - echo $this->renderToggleButton(); - if ($this->brandLabel !== null) { - Html::addCssClass($this->brandOptions, 'navbar-brand'); - echo Html::a($this->brandLabel, $this->brandUrl === null ? Yii::$app->homeUrl : $this->brandUrl, $this->brandOptions); - } - echo Html::endTag('div'); - Html::addCssClass($this->containerOptions, 'collapse'); - Html::addCssClass($this->containerOptions, 'navbar-collapse'); - $options = $this->containerOptions; - $tag = ArrayHelper::remove($options, 'tag', 'div'); - echo Html::beginTag($tag, $options); - } + /** + * Initializes the widget. + */ + public function init() + { + parent::init(); + $this->clientOptions = false; + Html::addCssClass($this->options, 'navbar'); + if ($this->options['class'] === 'navbar') { + Html::addCssClass($this->options, 'navbar-default'); + } + Html::addCssClass($this->brandOptions, 'navbar-brand'); + if (empty($this->options['role'])) { + $this->options['role'] = 'navigation'; + } + $options = $this->options; + $tag = ArrayHelper::remove($options, 'tag', 'nav'); + echo Html::beginTag($tag, $options); + if ($this->renderInnerContainer) { + if (!isset($this->innerContainerOptions['class'])) { + Html::addCssClass($this->innerContainerOptions, 'container'); + } + echo Html::beginTag('div', $this->innerContainerOptions); + } + echo Html::beginTag('div', ['class' => 'navbar-header']); + if (!isset($this->containerOptions['id'])) { + $this->containerOptions['id'] = "{$this->options['id']}-collapse"; + } + echo $this->renderToggleButton(); + if ($this->brandLabel !== null) { + Html::addCssClass($this->brandOptions, 'navbar-brand'); + echo Html::a($this->brandLabel, $this->brandUrl === null ? Yii::$app->homeUrl : $this->brandUrl, $this->brandOptions); + } + echo Html::endTag('div'); + Html::addCssClass($this->containerOptions, 'collapse'); + Html::addCssClass($this->containerOptions, 'navbar-collapse'); + $options = $this->containerOptions; + $tag = ArrayHelper::remove($options, 'tag', 'div'); + echo Html::beginTag($tag, $options); + } - /** - * Renders the widget. - */ - public function run() - { - $tag = ArrayHelper::remove($this->containerOptions, 'tag', 'div'); - echo Html::endTag($tag); - if ($this->renderInnerContainer) { - echo Html::endTag('div'); - } - $tag = ArrayHelper::remove($this->options, 'tag', 'nav'); - echo Html::endTag($tag, $this->options); - BootstrapPluginAsset::register($this->getView()); - } + /** + * Renders the widget. + */ + public function run() + { + $tag = ArrayHelper::remove($this->containerOptions, 'tag', 'div'); + echo Html::endTag($tag); + if ($this->renderInnerContainer) { + echo Html::endTag('div'); + } + $tag = ArrayHelper::remove($this->options, 'tag', 'nav'); + echo Html::endTag($tag, $this->options); + BootstrapPluginAsset::register($this->getView()); + } - /** - * Renders collapsible toggle button. - * @return string the rendering toggle button. - */ - protected function renderToggleButton() - { - $bar = Html::tag('span', '', ['class' => 'icon-bar']); - $screenReader = "{$this->screenReaderToggleText}"; - return Html::button("{$screenReader}\n{$bar}\n{$bar}\n{$bar}", [ - 'class' => 'navbar-toggle', - 'data-toggle' => 'collapse', - 'data-target' => "#{$this->containerOptions['id']}", - ]); - } + /** + * Renders collapsible toggle button. + * @return string the rendering toggle button. + */ + protected function renderToggleButton() + { + $bar = Html::tag('span', '', ['class' => 'icon-bar']); + $screenReader = "{$this->screenReaderToggleText}"; + + return Html::button("{$screenReader}\n{$bar}\n{$bar}\n{$bar}", [ + 'class' => 'navbar-toggle', + 'data-toggle' => 'collapse', + 'data-target' => "#{$this->containerOptions['id']}", + ]); + } } diff --git a/Progress.php b/Progress.php index 33b7bb1..ec0827a 100644 --- a/Progress.php +++ b/Progress.php @@ -59,105 +59,106 @@ use yii\helpers\Html; */ class Progress extends Widget { - /** - * @var string the button label. - */ - public $label; - /** - * @var integer the amount of progress as a percentage. - */ - public $percent = 0; - /** - * @var array the HTML attributes of the bar. - * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. - */ - public $barOptions = []; - /** - * @var array a set of bars that are stacked together to form a single progress bar. - * Each bar is an array of the following structure: - * - * ```php - * [ - * // required, the amount of progress as a percentage. - * 'percent' => 30, - * // optional, the label to be displayed on the bar - * 'label' => '30%', - * // optional, array, additional HTML attributes for the bar tag - * 'options' => [], - * ] - * ``` - */ - public $bars; + /** + * @var string the button label. + */ + public $label; + /** + * @var integer the amount of progress as a percentage. + */ + public $percent = 0; + /** + * @var array the HTML attributes of the bar. + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. + */ + public $barOptions = []; + /** + * @var array a set of bars that are stacked together to form a single progress bar. + * Each bar is an array of the following structure: + * + * ```php + * [ + * // required, the amount of progress as a percentage. + * 'percent' => 30, + * // optional, the label to be displayed on the bar + * 'label' => '30%', + * // optional, array, additional HTML attributes for the bar tag + * 'options' => [], + * ] + * ``` + */ + public $bars; + /** + * Initializes the widget. + * If you override this method, make sure you call the parent implementation first. + */ + public function init() + { + parent::init(); + Html::addCssClass($this->options, 'progress'); + } - /** - * Initializes the widget. - * If you override this method, make sure you call the parent implementation first. - */ - public function init() - { - parent::init(); - Html::addCssClass($this->options, 'progress'); - } + /** + * Renders the widget. + */ + public function run() + { + echo Html::beginTag('div', $this->options) . "\n"; + echo $this->renderProgress() . "\n"; + echo Html::endTag('div') . "\n"; + BootstrapAsset::register($this->getView()); + } - /** - * Renders the widget. - */ - public function run() - { - echo Html::beginTag('div', $this->options) . "\n"; - echo $this->renderProgress() . "\n"; - echo Html::endTag('div') . "\n"; - BootstrapAsset::register($this->getView()); - } + /** + * Renders the progress. + * @return string the rendering result. + * @throws InvalidConfigException if the "percent" option is not set in a stacked progress bar. + */ + protected function renderProgress() + { + if (empty($this->bars)) { + return $this->renderBar($this->percent, $this->label, $this->barOptions); + } + $bars = []; + foreach ($this->bars as $bar) { + $label = ArrayHelper::getValue($bar, 'label', ''); + if (!isset($bar['percent'])) { + throw new InvalidConfigException("The 'percent' option is required."); + } + $options = ArrayHelper::getValue($bar, 'options', []); + $bars[] = $this->renderBar($bar['percent'], $label, $options); + } - /** - * Renders the progress. - * @return string the rendering result. - * @throws InvalidConfigException if the "percent" option is not set in a stacked progress bar. - */ - protected function renderProgress() - { - if (empty($this->bars)) { - return $this->renderBar($this->percent, $this->label, $this->barOptions); - } - $bars = []; - foreach ($this->bars as $bar) { - $label = ArrayHelper::getValue($bar, 'label', ''); - if (!isset($bar['percent'])) { - throw new InvalidConfigException("The 'percent' option is required."); - } - $options = ArrayHelper::getValue($bar, 'options', []); - $bars[] = $this->renderBar($bar['percent'], $label, $options); - } - return implode("\n", $bars); - } + return implode("\n", $bars); + } - /** - * Generates a bar - * @param integer $percent the percentage of the bar - * @param string $label, optional, the label to display at the bar - * @param array $options the HTML attributes of the bar - * @return string the rendering result. - */ - protected function renderBar($percent, $label = '', $options = []) - { - $defaultOptions = [ - 'role' => 'progressbar', - 'aria-valuenow' => $percent, - 'aria-valuemin' => 0, - 'aria-valuemax' => 100, - 'style' => "width:{$percent}%", - ]; - $options = array_merge($defaultOptions, $options); - Html::addCssClass($options, 'progress-bar'); + /** + * Generates a bar + * @param integer $percent the percentage of the bar + * @param string $label, optional, the label to display at the bar + * @param array $options the HTML attributes of the bar + * @return string the rendering result. + */ + protected function renderBar($percent, $label = '', $options = []) + { + $defaultOptions = [ + 'role' => 'progressbar', + 'aria-valuenow' => $percent, + 'aria-valuemin' => 0, + 'aria-valuemax' => 100, + 'style' => "width:{$percent}%", + ]; + $options = array_merge($defaultOptions, $options); + Html::addCssClass($options, 'progress-bar'); - $out = Html::beginTag('div', $options); - $out .= $label; - $out .= Html::tag('span', \Yii::t('yii', '{percent}% Complete', ['percent' => $percent]), [ - 'class' => 'sr-only' - ]); - $out .= Html::endTag('div'); - return $out; - } + $out = Html::beginTag('div', $options); + $out .= $label; + $out .= Html::tag('span', \Yii::t('yii', '{percent}% Complete', ['percent' => $percent]), [ + 'class' => 'sr-only' + ]); + $out .= Html::endTag('div'); + + return $out; + } } diff --git a/Tabs.php b/Tabs.php index 6c7fd21..7c7274a 100644 --- a/Tabs.php +++ b/Tabs.php @@ -53,179 +53,180 @@ use yii\helpers\Html; */ class Tabs extends Widget { - /** - * @var array list of tabs in the tabs widget. Each array element represents a single - * tab with the following structure: - * - * - label: string, required, the tab header label. - * - headerOptions: array, optional, the HTML attributes of the tab header. - * - linkOptions: array, optional, the HTML attributes of the tab header link tags. - * - content: array, required if `items` is not set. The content (HTML) of the tab pane. - * - options: array, optional, the HTML attributes of the tab pane container. - * - active: boolean, optional, whether the item tab header and pane should be visible or not. - * - items: array, optional, if not set then `content` will be required. The `items` specify a dropdown items - * configuration array. Each item can hold two extra keys, besides the above ones: - * * active: boolean, optional, whether the item tab header and pane should be visible or not. - * * content: string, required if `items` is not set. The content (HTML) of the tab pane. - * * contentOptions: optional, array, the HTML attributes of the tab content container. - */ - public $items = []; - /** - * @var array list of HTML attributes for the item container tags. This will be overwritten - * by the "options" set in individual [[items]]. The following special options are recognized: - * - * - tag: string, defaults to "div", the tag name of the item container tags. - * - * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. - */ - public $itemOptions = []; - /** - * @var array list of HTML attributes for the header container tags. This will be overwritten - * by the "headerOptions" set in individual [[items]]. - * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. - */ - public $headerOptions = []; - /** - * @var array list of HTML attributes for the tab header link tags. This will be overwritten - * by the "linkOptions" set in individual [[items]]. - * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. - */ - public $linkOptions = []; - /** - * @var boolean whether the labels for header items should be HTML-encoded. - */ - public $encodeLabels = true; - /** - * @var string specifies the Bootstrap tab styling. - */ - public $navType = 'nav-tabs'; - - - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - Html::addCssClass($this->options, 'nav ' . $this->navType); - } - - /** - * Renders the widget. - */ - public function run() - { - echo $this->renderItems(); - $this->registerPlugin('tab'); - } - - /** - * Renders tab items as specified on [[items]]. - * @return string the rendering result. - * @throws InvalidConfigException. - */ - protected function renderItems() - { - $headers = []; - $panes = []; - - if (!$this->hasActiveTab() && !empty($this->items)) { - $this->items[0]['active'] = true; - } - - foreach ($this->items as $n => $item) { - if (!isset($item['label'])) { - throw new InvalidConfigException("The 'label' option is required."); - } - $label = $this->encodeLabels ? Html::encode($item['label']) : $item['label']; - $headerOptions = array_merge($this->headerOptions, ArrayHelper::getValue($item, 'headerOptions', [])); - $linkOptions = array_merge($this->linkOptions, ArrayHelper::getValue($item, 'linkOptions', [])); - - if (isset($item['items'])) { - $label .= ' '; - Html::addCssClass($headerOptions, 'dropdown'); - - if ($this->renderDropdown($item['items'], $panes)) { - Html::addCssClass($headerOptions, 'active'); - } - - Html::addCssClass($linkOptions, 'dropdown-toggle'); - $linkOptions['data-toggle'] = 'dropdown'; - $header = Html::a($label, "#", $linkOptions) . "\n" - . Dropdown::widget(['items' => $item['items'], 'clientOptions' => false, 'view' => $this->getView()]); - } elseif (isset($item['content'])) { - $options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', [])); - $options['id'] = ArrayHelper::getValue($options, 'id', $this->options['id'] . '-tab' . $n); - - Html::addCssClass($options, 'tab-pane'); - if (ArrayHelper::remove($item, 'active')) { - Html::addCssClass($options, 'active'); - Html::addCssClass($headerOptions, 'active'); - } - $linkOptions['data-toggle'] = 'tab'; - $header = Html::a($label, '#' . $options['id'], $linkOptions); - $panes[] = Html::tag('div', $item['content'], $options); - } else { - throw new InvalidConfigException("Either the 'content' or 'items' option must be set."); - } - - $headers[] = Html::tag('li', $header, $headerOptions); - } - - return Html::tag('ul', implode("\n", $headers), $this->options) . "\n" - . Html::tag('div', implode("\n", $panes), ['class' => 'tab-content']); - } - - /** - * @return boolean if there's active tab defined - */ - protected function hasActiveTab() - { - foreach ($this->items as $item) { - if (isset($item['active']) && $item['active']===true) { - return true; - } - } - return false; - } - - /** - * Normalizes dropdown item options by removing tab specific keys `content` and `contentOptions`, and also - * configure `panes` accordingly. - * @param array $items the dropdown items configuration. - * @param array $panes the panes reference array. - * @return boolean whether any of the dropdown items is `active` or not. - * @throws InvalidConfigException - */ - protected function renderDropdown(&$items, &$panes) - { - $itemActive = false; - - foreach ($items as $n => &$item) { - if (is_string($item)) { - continue; - } - if (!isset($item['content'])) { - throw new InvalidConfigException("The 'content' option is required."); - } - - $content = ArrayHelper::remove($item, 'content'); - $options = ArrayHelper::remove($item, 'contentOptions', []); - Html::addCssClass($options, 'tab-pane'); - if (ArrayHelper::remove($item, 'active')) { - Html::addCssClass($options, 'active'); - Html::addCssClass($item['options'], 'active'); - $itemActive = true; - } - - $options['id'] = ArrayHelper::getValue($options, 'id', $this->options['id'] . '-dd-tab' . $n); - $item['url'] = '#' . $options['id']; - $item['linkOptions']['data-toggle'] = 'tab'; - - $panes[] = Html::tag('div', $content, $options); - - unset($item); - } - return $itemActive; - } + /** + * @var array list of tabs in the tabs widget. Each array element represents a single + * tab with the following structure: + * + * - label: string, required, the tab header label. + * - headerOptions: array, optional, the HTML attributes of the tab header. + * - linkOptions: array, optional, the HTML attributes of the tab header link tags. + * - content: array, required if `items` is not set. The content (HTML) of the tab pane. + * - options: array, optional, the HTML attributes of the tab pane container. + * - active: boolean, optional, whether the item tab header and pane should be visible or not. + * - items: array, optional, if not set then `content` will be required. The `items` specify a dropdown items + * configuration array. Each item can hold two extra keys, besides the above ones: + * * active: boolean, optional, whether the item tab header and pane should be visible or not. + * * content: string, required if `items` is not set. The content (HTML) of the tab pane. + * * contentOptions: optional, array, the HTML attributes of the tab content container. + */ + public $items = []; + /** + * @var array list of HTML attributes for the item container tags. This will be overwritten + * by the "options" set in individual [[items]]. The following special options are recognized: + * + * - tag: string, defaults to "div", the tag name of the item container tags. + * + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. + */ + public $itemOptions = []; + /** + * @var array list of HTML attributes for the header container tags. This will be overwritten + * by the "headerOptions" set in individual [[items]]. + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. + */ + public $headerOptions = []; + /** + * @var array list of HTML attributes for the tab header link tags. This will be overwritten + * by the "linkOptions" set in individual [[items]]. + * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. + */ + public $linkOptions = []; + /** + * @var boolean whether the labels for header items should be HTML-encoded. + */ + public $encodeLabels = true; + /** + * @var string specifies the Bootstrap tab styling. + */ + public $navType = 'nav-tabs'; + + /** + * Initializes the widget. + */ + public function init() + { + parent::init(); + Html::addCssClass($this->options, 'nav ' . $this->navType); + } + + /** + * Renders the widget. + */ + public function run() + { + echo $this->renderItems(); + $this->registerPlugin('tab'); + } + + /** + * Renders tab items as specified on [[items]]. + * @return string the rendering result. + * @throws InvalidConfigException. + */ + protected function renderItems() + { + $headers = []; + $panes = []; + + if (!$this->hasActiveTab() && !empty($this->items)) { + $this->items[0]['active'] = true; + } + + foreach ($this->items as $n => $item) { + if (!isset($item['label'])) { + throw new InvalidConfigException("The 'label' option is required."); + } + $label = $this->encodeLabels ? Html::encode($item['label']) : $item['label']; + $headerOptions = array_merge($this->headerOptions, ArrayHelper::getValue($item, 'headerOptions', [])); + $linkOptions = array_merge($this->linkOptions, ArrayHelper::getValue($item, 'linkOptions', [])); + + if (isset($item['items'])) { + $label .= ' '; + Html::addCssClass($headerOptions, 'dropdown'); + + if ($this->renderDropdown($item['items'], $panes)) { + Html::addCssClass($headerOptions, 'active'); + } + + Html::addCssClass($linkOptions, 'dropdown-toggle'); + $linkOptions['data-toggle'] = 'dropdown'; + $header = Html::a($label, "#", $linkOptions) . "\n" + . Dropdown::widget(['items' => $item['items'], 'clientOptions' => false, 'view' => $this->getView()]); + } elseif (isset($item['content'])) { + $options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', [])); + $options['id'] = ArrayHelper::getValue($options, 'id', $this->options['id'] . '-tab' . $n); + + Html::addCssClass($options, 'tab-pane'); + if (ArrayHelper::remove($item, 'active')) { + Html::addCssClass($options, 'active'); + Html::addCssClass($headerOptions, 'active'); + } + $linkOptions['data-toggle'] = 'tab'; + $header = Html::a($label, '#' . $options['id'], $linkOptions); + $panes[] = Html::tag('div', $item['content'], $options); + } else { + throw new InvalidConfigException("Either the 'content' or 'items' option must be set."); + } + + $headers[] = Html::tag('li', $header, $headerOptions); + } + + return Html::tag('ul', implode("\n", $headers), $this->options) . "\n" + . Html::tag('div', implode("\n", $panes), ['class' => 'tab-content']); + } + + /** + * @return boolean if there's active tab defined + */ + protected function hasActiveTab() + { + foreach ($this->items as $item) { + if (isset($item['active']) && $item['active']===true) { + return true; + } + } + + return false; + } + + /** + * Normalizes dropdown item options by removing tab specific keys `content` and `contentOptions`, and also + * configure `panes` accordingly. + * @param array $items the dropdown items configuration. + * @param array $panes the panes reference array. + * @return boolean whether any of the dropdown items is `active` or not. + * @throws InvalidConfigException + */ + protected function renderDropdown(&$items, &$panes) + { + $itemActive = false; + + foreach ($items as $n => &$item) { + if (is_string($item)) { + continue; + } + if (!isset($item['content'])) { + throw new InvalidConfigException("The 'content' option is required."); + } + + $content = ArrayHelper::remove($item, 'content'); + $options = ArrayHelper::remove($item, 'contentOptions', []); + Html::addCssClass($options, 'tab-pane'); + if (ArrayHelper::remove($item, 'active')) { + Html::addCssClass($options, 'active'); + Html::addCssClass($item['options'], 'active'); + $itemActive = true; + } + + $options['id'] = ArrayHelper::getValue($options, 'id', $this->options['id'] . '-dd-tab' . $n); + $item['url'] = '#' . $options['id']; + $item['linkOptions']['data-toggle'] = 'tab'; + + $panes[] = Html::tag('div', $content, $options); + + unset($item); + } + + return $itemActive; + } } diff --git a/Widget.php b/Widget.php index e135737..2984e7a 100644 --- a/Widget.php +++ b/Widget.php @@ -19,64 +19,63 @@ use yii\helpers\Json; */ class Widget extends \yii\base\Widget { - /** - * @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 = []; + /** + * @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(); + } + } - /** - * 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(); - /** - * 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); - BootstrapPluginAsset::register($view); + $id = $this->options['id']; - $id = $this->options['id']; + if ($this->clientOptions !== false) { + $options = empty($this->clientOptions) ? '' : Json::encode($this->clientOptions); + $js = "jQuery('#$id').$name($options);"; + $view->registerJs($js); + } - if ($this->clientOptions !== false) { - $options = empty($this->clientOptions) ? '' : Json::encode($this->clientOptions); - $js = "jQuery('#$id').$name($options);"; - $view->registerJs($js); - } - - if (!empty($this->clientEvents)) { - $js = []; - foreach ($this->clientEvents as $event => $handler) { - $js[] = "jQuery('#$id').on('$event', $handler);"; - } - $view->registerJs(implode("\n", $js)); - } - } + if (!empty($this->clientEvents)) { + $js = []; + foreach ($this->clientEvents as $event => $handler) { + $js[] = "jQuery('#$id').on('$event', $handler);"; + } + $view->registerJs(implode("\n", $js)); + } + } }