diff --git a/framework/yii/bootstrap/Alert.php b/framework/yii/bootstrap/Alert.php
index f84a70b..d57bcbe 100644
--- a/framework/yii/bootstrap/Alert.php
+++ b/framework/yii/bootstrap/Alert.php
@@ -140,7 +140,7 @@ class Alert extends Widget
'class' => 'fade in',
), $this->options);
- $this->addCssClass($this->options, 'alert');
+ Html::addCssClass($this->options, 'alert');
if ($this->closeButton !== null) {
$this->closeButton = array_merge(array(
diff --git a/framework/yii/bootstrap/Button.php b/framework/yii/bootstrap/Button.php
index 856c420..c351ea0 100644
--- a/framework/yii/bootstrap/Button.php
+++ b/framework/yii/bootstrap/Button.php
@@ -48,7 +48,7 @@ class Button extends Widget
{
parent::init();
$this->clientOptions = false;
- $this->addCssClass($this->options, 'btn');
+ Html::addCssClass($this->options, 'btn');
}
/**
diff --git a/framework/yii/bootstrap/ButtonDropdown.php b/framework/yii/bootstrap/ButtonDropdown.php
index fec042e..5d94bdc 100644
--- a/framework/yii/bootstrap/ButtonDropdown.php
+++ b/framework/yii/bootstrap/ButtonDropdown.php
@@ -64,7 +64,7 @@ class ButtonDropdown extends Widget
public function init()
{
parent::init();
- $this->addCssClass($this->options, 'btn-group');
+ Html::addCssClass($this->options, 'btn-group');
}
/**
@@ -85,12 +85,12 @@ class ButtonDropdown extends Widget
*/
protected function renderButton()
{
- $this->addCssClass($this->buttonOptions, 'btn');
+ Html::addCssClass($this->buttonOptions, 'btn');
if ($this->split) {
$tag = 'button';
$options = $this->buttonOptions;
$this->buttonOptions['data-toggle'] = 'dropdown';
- $this->addCssClass($this->buttonOptions, 'dropdown-toggle');
+ Html::addCssClass($this->buttonOptions, 'dropdown-toggle');
$splitButton = Button::widget(array(
'label' => '',
'encodeLabel' => false,
@@ -103,7 +103,7 @@ class ButtonDropdown extends Widget
if (!isset($options['href'])) {
$options['href'] = '#';
}
- $this->addCssClass($options, 'dropdown-toggle');
+ Html::addCssClass($options, 'dropdown-toggle');
$options['data-toggle'] = 'dropdown';
$splitButton = '';
}
diff --git a/framework/yii/bootstrap/ButtonGroup.php b/framework/yii/bootstrap/ButtonGroup.php
index e5bf4e9..3606241 100644
--- a/framework/yii/bootstrap/ButtonGroup.php
+++ b/framework/yii/bootstrap/ButtonGroup.php
@@ -61,7 +61,7 @@ class ButtonGroup extends Widget
{
parent::init();
$this->clientOptions = false;
- $this->addCssClass($this->options, 'btn-group');
+ Html::addCssClass($this->options, 'btn-group');
}
/**
diff --git a/framework/yii/bootstrap/Carousel.php b/framework/yii/bootstrap/Carousel.php
index f8904fa..c2c68a7 100644
--- a/framework/yii/bootstrap/Carousel.php
+++ b/framework/yii/bootstrap/Carousel.php
@@ -70,7 +70,7 @@ class Carousel extends Widget
public function init()
{
parent::init();
- $this->addCssClass($this->options, 'carousel');
+ Html::addCssClass($this->options, 'carousel');
}
/**
@@ -96,7 +96,7 @@ class Carousel extends Widget
for ($i = 0, $count = count($this->items); $i < $count; $i++) {
$options = array('data-target' => '#' . $this->options['id'], 'data-slide-to' => $i);
if ($i === 0) {
- $this->addCssClass($options, 'active');
+ Html::addCssClass($options, 'active');
}
$indicators[] = Html::tag('li', '', $options);
}
@@ -140,9 +140,9 @@ class Carousel extends Widget
throw new InvalidConfigException('The "content" option is required.');
}
- $this->addCssClass($options, 'item');
+ Html::addCssClass($options, 'item');
if ($index === 0) {
- $this->addCssClass($options, 'active');
+ Html::addCssClass($options, 'active');
}
return Html::tag('div', $content . "\n" . $caption, $options);
diff --git a/framework/yii/bootstrap/Collapse.php b/framework/yii/bootstrap/Collapse.php
index fdcaae1..8aed0b1 100644
--- a/framework/yii/bootstrap/Collapse.php
+++ b/framework/yii/bootstrap/Collapse.php
@@ -66,7 +66,7 @@ class Collapse extends Widget
public function init()
{
parent::init();
- $this->addCssClass($this->options, 'accordion');
+ Html::addCssClass($this->options, 'accordion');
}
/**
@@ -90,7 +90,7 @@ class Collapse extends Widget
$index = 0;
foreach ($this->items as $header => $item) {
$options = ArrayHelper::getValue($item, 'options', array());
- $this->addCssClass($options, 'accordion-group');
+ Html::addCssClass($options, 'accordion-group');
$items[] = Html::tag('div', $this->renderItem($header, $item, ++$index), $options);
}
@@ -111,7 +111,7 @@ class Collapse extends Widget
$id = $this->options['id'] . '-collapse' . $index;
$options = ArrayHelper::getValue($item, 'contentOptions', array());
$options['id'] = $id;
- $this->addCssClass($options, 'accordion-body collapse');
+ Html::addCssClass($options, 'accordion-body collapse');
$header = Html::a($header, '#' . $id, array(
'class' => 'accordion-toggle',
diff --git a/framework/yii/bootstrap/Dropdown.php b/framework/yii/bootstrap/Dropdown.php
index 827e6cc..0568fe4 100644
--- a/framework/yii/bootstrap/Dropdown.php
+++ b/framework/yii/bootstrap/Dropdown.php
@@ -46,7 +46,7 @@ class Dropdown extends Widget
public function init()
{
parent::init();
- $this->addCssClass($this->options, 'dropdown-menu');
+ Html::addCssClass($this->options, 'dropdown-menu');
}
/**
@@ -81,7 +81,7 @@ class Dropdown extends Widget
$linkOptions['tabindex'] = '-1';
if (isset($item['items'])) {
- $this->addCssClass($options, 'dropdown-submenu');
+ Html::addCssClass($options, 'dropdown-submenu');
$content = Html::a($label, '#', $linkOptions) . $this->renderItems($item['items']);
} else {
$content = Html::a($label, ArrayHelper::getValue($item, 'url', '#'), $linkOptions);
diff --git a/framework/yii/bootstrap/Modal.php b/framework/yii/bootstrap/Modal.php
index 0608fbe..f676273 100644
--- a/framework/yii/bootstrap/Modal.php
+++ b/framework/yii/bootstrap/Modal.php
@@ -197,7 +197,7 @@ class Modal extends Widget
$this->options = array_merge(array(
'class' => 'modal hide',
), $this->options);
- $this->addCssClass($this->options, 'modal');
+ Html::addCssClass($this->options, 'modal');
$this->clientOptions = array_merge(array(
'show' => false,
diff --git a/framework/yii/bootstrap/Nav.php b/framework/yii/bootstrap/Nav.php
index 8069699..7b003f4 100644
--- a/framework/yii/bootstrap/Nav.php
+++ b/framework/yii/bootstrap/Nav.php
@@ -79,7 +79,7 @@ class Nav extends Widget
public function init()
{
parent::init();
- $this->addCssClass($this->options, 'nav');
+ Html::addCssClass($this->options, 'nav');
}
/**
@@ -125,13 +125,13 @@ class Nav extends Widget
$linkOptions = ArrayHelper::getValue($item, 'linkOptions', array());
if (ArrayHelper::getValue($item, 'active')) {
- $this->addCssClass($options, 'active');
+ Html::addCssClass($options, 'active');
}
if ($items !== null) {
$linkOptions['data-toggle'] = 'dropdown';
- $this->addCssClass($options, 'dropdown');
- $this->addCssClass($urlOptions, 'dropdown-toggle');
+ Html::addCssClass($options, 'dropdown');
+ Html::addCssClass($urlOptions, 'dropdown-toggle');
$label .= ' ' . Html::tag('b', '', array('class' => 'caret'));
if (is_array($items)) {
$items = Dropdown::widget(array(
diff --git a/framework/yii/bootstrap/NavBar.php b/framework/yii/bootstrap/NavBar.php
index 17a938c..337e449 100644
--- a/framework/yii/bootstrap/NavBar.php
+++ b/framework/yii/bootstrap/NavBar.php
@@ -107,8 +107,8 @@ class NavBar extends Widget
{
parent::init();
$this->clientOptions = false;
- $this->addCssClass($this->options, 'navbar');
- $this->addCssClass($this->brandOptions, 'brand');
+ Html::addCssClass($this->options, 'navbar');
+ Html::addCssClass($this->brandOptions, 'brand');
}
/**
diff --git a/framework/yii/bootstrap/Progress.php b/framework/yii/bootstrap/Progress.php
index 7c0473e..ae44619 100644
--- a/framework/yii/bootstrap/Progress.php
+++ b/framework/yii/bootstrap/Progress.php
@@ -94,7 +94,7 @@ class Progress extends Widget
public function init()
{
parent::init();
- $this->addCssClass($this->options, 'progress');
+ Html::addCssClass($this->options, 'progress');
}
/**
@@ -139,7 +139,7 @@ class Progress extends Widget
*/
protected function renderBar($percent, $label = '', $options = array())
{
- $this->addCssClass($options, 'bar');
+ Html::addCssClass($options, 'bar');
$options['style'] = "width:{$percent}%";
return Html::tag('div', $label, $options);
}
diff --git a/framework/yii/bootstrap/Tabs.php b/framework/yii/bootstrap/Tabs.php
index 4a85b9a..90c9794 100644
--- a/framework/yii/bootstrap/Tabs.php
+++ b/framework/yii/bootstrap/Tabs.php
@@ -93,7 +93,7 @@ class Tabs extends Widget
public function init()
{
parent::init();
- $this->addCssClass($this->options, 'nav nav-tabs');
+ Html::addCssClass($this->options, 'nav nav-tabs');
}
/**
@@ -123,10 +123,10 @@ class Tabs extends Widget
if (isset($item['items'])) {
$label .= ' ';
- $this->addCssClass($headerOptions, 'dropdown');
+ Html::addCssClass($headerOptions, 'dropdown');
if ($this->renderDropdown($item['items'], $panes)) {
- $this->addCssClass($headerOptions, 'active');
+ Html::addCssClass($headerOptions, 'active');
}
$header = Html::a($label, "#", array('class' => 'dropdown-toggle', 'data-toggle' => 'dropdown')) . "\n"
@@ -135,10 +135,10 @@ class Tabs extends Widget
$options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', array()));
$options['id'] = ArrayHelper::getValue($options, 'id', $this->options['id'] . '-tab' . $n);
- $this->addCssClass($options, 'tab-pane');
+ Html::addCssClass($options, 'tab-pane');
if (ArrayHelper::remove($item, 'active')) {
- $this->addCssClass($options, 'active');
- $this->addCssClass($headerOptions, 'active');
+ Html::addCssClass($options, 'active');
+ Html::addCssClass($headerOptions, 'active');
}
$header = Html::a($label, '#' . $options['id'], array('data-toggle' => 'tab', 'tabindex' => '-1'));
$panes[] = Html::tag('div', $item['content'], $options);
@@ -175,10 +175,10 @@ class Tabs extends Widget
$content = ArrayHelper::remove($item, 'content');
$options = ArrayHelper::remove($item, 'contentOptions', array());
- $this->addCssClass($options, 'tab-pane');
+ Html::addCssClass($options, 'tab-pane');
if (ArrayHelper::remove($item, 'active')) {
- $this->addCssClass($options, 'active');
- $this->addCssClass($item['options'], 'active');
+ Html::addCssClass($options, 'active');
+ Html::addCssClass($item['options'], 'active');
$itemActive = true;
}
diff --git a/framework/yii/bootstrap/Widget.php b/framework/yii/bootstrap/Widget.php
index 48b0331..004f040 100644
--- a/framework/yii/bootstrap/Widget.php
+++ b/framework/yii/bootstrap/Widget.php
@@ -82,20 +82,4 @@ class Widget extends \yii\base\Widget
$view->registerJs(implode("\n", $js));
}
}
-
- /**
- * Adds a CSS class to the specified options.
- * This method will ensure that the CSS class is unique and the "class" option is properly formatted.
- * @param array $options the options to be modified.
- * @param string $class the CSS class to be added
- */
- protected function addCssClass(&$options, $class)
- {
- if (isset($options['class'])) {
- $classes = preg_split('/\s+/', $options['class'] . ' ' . $class, -1, PREG_SPLIT_NO_EMPTY);
- $options['class'] = implode(' ', array_unique($classes));
- } else {
- $options['class'] = $class;
- }
- }
}
diff --git a/framework/yii/helpers/base/Html.php b/framework/yii/helpers/base/Html.php
index 47385e2..ba9a889 100644
--- a/framework/yii/helpers/base/Html.php
+++ b/framework/yii/helpers/base/Html.php
@@ -1373,6 +1373,44 @@ class Html
}
/**
+ * Adds a CSS class to the specified options.
+ * If the CSS class is already in the options, it will not be added again.
+ * @param array $options the options to be modified.
+ * @param string $class the CSS class to be added
+ */
+ public static function addCssClass(&$options, $class)
+ {
+ if (isset($options['class'])) {
+ $classes = ' ' . $options['class'] . ' ';
+ if (($pos = strpos($classes, ' ' . $class . ' ')) === false) {
+ $options['class'] .= ' ' . $class;
+ }
+ } else {
+ $options['class'] = $class;
+ }
+ }
+
+ /**
+ * Removes a CSS class from the specified options.
+ * @param array $options the options to be modified.
+ * @param string $class the CSS class to be removed
+ */
+ public static function removeCssClass(&$options, $class)
+ {
+ if (isset($options['class'])) {
+ $classes = array_unique(preg_split('/\s+/', $options['class'] . ' ' . $class, -1, PREG_SPLIT_NO_EMPTY));
+ if (($index = array_search($class, $classes)) !== false) {
+ unset($classes[$index]);
+ }
+ if (empty($classes)) {
+ unset($options['class']);
+ } else {
+ $options['class'] = implode(' ', $classes);
+ }
+ }
+ }
+
+ /**
* Returns the real attribute name from the given attribute expression.
*
* An attribute expression is an attribute name prefixed and/or suffixed with array indexes.
diff --git a/tests/unit/framework/helpers/HtmlTest.php b/tests/unit/framework/helpers/HtmlTest.php
index 2311321..0399a4e 100644
--- a/tests/unit/framework/helpers/HtmlTest.php
+++ b/tests/unit/framework/helpers/HtmlTest.php
@@ -434,6 +434,38 @@ EOD;
Html::$showBooleanAttributeValues = true;
}
+ public function testAddCssClass()
+ {
+ $options = array();
+ Html::addCssClass($options, 'test');
+ $this->assertEquals(array('class' => 'test'), $options);
+ Html::addCssClass($options, 'test');
+ $this->assertEquals(array('class' => 'test'), $options);
+ Html::addCssClass($options, 'test2');
+ $this->assertEquals(array('class' => 'test test2'), $options);
+ Html::addCssClass($options, 'test');
+ $this->assertEquals(array('class' => 'test test2'), $options);
+ Html::addCssClass($options, 'test2');
+ $this->assertEquals(array('class' => 'test test2'), $options);
+ Html::addCssClass($options, 'test3');
+ $this->assertEquals(array('class' => 'test test2 test3'), $options);
+ Html::addCssClass($options, 'test2');
+ $this->assertEquals(array('class' => 'test test2 test3'), $options);
+ }
+
+ public function testRemoveCssClass()
+ {
+ $options = array('class' => 'test test2 test3');
+ Html::removeCssClass($options, 'test2');
+ $this->assertEquals(array('class' => 'test test3'), $options);
+ Html::removeCssClass($options, 'test2');
+ $this->assertEquals(array('class' => 'test test3'), $options);
+ Html::removeCssClass($options, 'test');
+ $this->assertEquals(array('class' => 'test3'), $options);
+ Html::removeCssClass($options, 'test3');
+ $this->assertEquals(array(), $options);
+ }
+
protected function getDataItems()
{
return array(