From 534aa4f93c89e3bb20a0554b7dbb7b2bb0c42b61 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 12 Aug 2013 07:17:43 -0400 Subject: [PATCH] Support auto-activation of Nav. --- apps/basic/views/layouts/main.php | 8 ++--- framework/yii/bootstrap/Nav.php | 67 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/apps/basic/views/layouts/main.php b/apps/basic/views/layouts/main.php index 709ad78..67b74af 100644 --- a/apps/basic/views/layouts/main.php +++ b/apps/basic/views/layouts/main.php @@ -1,7 +1,7 @@ 'navbar-inverse navbar-fixed-top', ), )); - echo Menu::widget(array( - 'options' => array('class' => 'nav navbar-nav pull-right'), + echo Nav::widget(array( + 'options' => array('class' => 'navbar-nav pull-right'), 'items' => array( array('label' => 'Home', 'url' => array('/site/index')), array('label' => 'About', 'url' => array('/site/about')), diff --git a/framework/yii/bootstrap/Nav.php b/framework/yii/bootstrap/Nav.php index 5b5d40b..38451d1 100644 --- a/framework/yii/bootstrap/Nav.php +++ b/framework/yii/bootstrap/Nav.php @@ -7,6 +7,7 @@ namespace yii\bootstrap; +use Yii; use yii\base\InvalidConfigException; use yii\helpers\ArrayHelper; use yii\helpers\Html; @@ -21,9 +22,8 @@ use yii\helpers\Html; * 'items' => array( * array( * 'label' => 'Home', - * 'url' => '/', + * 'url' => array('site/index'), * 'linkOptions' => array(...), - * 'active' => true, * ), * array( * 'label' => 'Dropdown', @@ -63,7 +63,7 @@ class Nav extends Widget * - 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. - * - dropdown: array|string, optional, the configuration array for creating a [[Dropdown]] widget, + * - 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. */ public $items = array(); @@ -71,6 +71,26 @@ class Nav extends Widget * @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; /** @@ -79,6 +99,12 @@ class Nav extends 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 = $_GET; + } Html::addCssClass($this->options, 'nav'); } @@ -124,7 +150,13 @@ class Nav extends Widget $url = Html::url(ArrayHelper::getValue($item, 'url', '#')); $linkOptions = ArrayHelper::getValue($item, 'linkOptions', array()); - if (ArrayHelper::getValue($item, 'active')) { + if (isset($item['active'])) { + $active = ArrayHelper::remove($item, 'active', false); + } else { + $active = $this->isItemActive($item); + } + + if ($active) { Html::addCssClass($options, 'active'); } @@ -144,4 +176,31 @@ class Nav extends Widget 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']) && trim($item['url'][0], '/') === $this->route) { + unset($item['url']['#']); + if (count($item['url']) > 1) { + foreach (array_splice($item['url'], 1) as $name => $value) { + if (!isset($this->params[$name]) || $this->params[$name] != $value) { + return false; + } + } + } + return true; + } + return false; + } }