added offcanvas navigation feature

This commit is contained in:
Simon Karlen 2021-08-05 10:01:02 +02:00
parent 0a1ff00cc0
commit 91e31dd164
No known key found for this signature in database
GPG Key ID: 0630C27D666EBCC3
2 changed files with 99 additions and 13 deletions

View File

@ -49,13 +49,19 @@ class NavBar extends Widget
*/ */
public $options = []; public $options = [];
/** /**
* @var array the HTML attributes for the container tag. The following special options are recognized: * @var array|bool the HTML attributes for the collapse container tag. The following special options are recognized:
* *
* - tag: string, defaults to "div", the name of the container tag. * - tag: string, defaults to "div", the name of the container tag.
* *
* @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
*/ */
public $collapseOptions = []; public $collapseOptions = [];
/**
* @var array|bool the HTML attributes for the offcanvas container tag.
*
* @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
*/
public $offcanvasOptions = false;
/** /**
* @var string|bool the text of the brand or false if it's not used. Note that this is not HTML-encoded. * @var string|bool the text of the brand or false if it's not used. Note that this is not HTML-encoded.
* @see https://getbootstrap.com/docs/5.1/components/navbar/ * @see https://getbootstrap.com/docs/5.1/components/navbar/
@ -130,8 +136,10 @@ class NavBar extends Widget
if (!isset($this->innerContainerOptions['class'])) { if (!isset($this->innerContainerOptions['class'])) {
Html::addCssClass($this->innerContainerOptions, ['panel' => 'container']); Html::addCssClass($this->innerContainerOptions, ['panel' => 'container']);
} }
if (!isset($this->collapseOptions['id'])) { if ($this->collapseOptions !== false && !isset($this->collapseOptions['id'])) {
$this->collapseOptions['id'] = "{$this->options['id']}-collapse"; $this->collapseOptions['id'] = "{$this->options['id']}-collapse";
} elseif ($this->offcanvasOptions !== false && !isset($this->offcanvasOptions['id'])) {
$this->offcanvasOptions['id'] = "{$this->options['id']}-offcanvas";
} }
if ($this->brandImage !== false) { if ($this->brandImage !== false) {
$this->brandLabel = Html::img($this->brandImage); $this->brandLabel = Html::img($this->brandImage);
@ -148,9 +156,6 @@ class NavBar extends Widget
); );
} }
} }
Html::addCssClass($this->collapseOptions, ['collapse' => 'collapse', 'widget' => 'navbar-collapse']);
$collapseOptions = $this->collapseOptions;
$collapseTag = ArrayHelper::remove($collapseOptions, 'tag', 'div');
echo Html::beginTag($navTag, $navOptions) . "\n"; echo Html::beginTag($navTag, $navOptions) . "\n";
if ($this->renderInnerContainer) { if ($this->renderInnerContainer) {
@ -158,7 +163,14 @@ class NavBar extends Widget
} }
echo $brand . "\n"; echo $brand . "\n";
echo $this->renderToggleButton() . "\n"; echo $this->renderToggleButton() . "\n";
echo Html::beginTag($collapseTag, $collapseOptions) . "\n"; if ($this->collapseOptions !== false) {
Html::addCssClass($this->collapseOptions, ['collapse' => 'collapse', 'widget' => 'navbar-collapse']);
$collapseOptions = $this->collapseOptions;
$collapseTag = ArrayHelper::remove($collapseOptions, 'tag', 'div');
echo Html::beginTag($collapseTag, $collapseOptions) . "\n";
} elseif ($this->offcanvasOptions !== false) {
Offcanvas::begin($this->offcanvasOptions);
}
} }
/** /**
@ -166,8 +178,12 @@ class NavBar extends Widget
*/ */
public function run() public function run()
{ {
$tag = ArrayHelper::remove($this->collapseOptions, 'tag', 'div'); if ($this->collapseOptions !== false) {
echo Html::endTag($tag) . "\n"; $tag = ArrayHelper::remove($this->collapseOptions, 'tag', 'div');
echo Html::endTag($tag) . "\n";
} elseif ($this->offcanvasOptions !== false) {
Offcanvas::end();
}
if ($this->renderInnerContainer) { if ($this->renderInnerContainer) {
echo Html::endTag('div') . "\n"; echo Html::endTag('div') . "\n";
} }
@ -194,17 +210,22 @@ class NavBar extends Widget
{ {
$options = $this->togglerOptions; $options = $this->togglerOptions;
Html::addCssClass($options, ['widget' => 'navbar-toggler']); Html::addCssClass($options, ['widget' => 'navbar-toggler']);
if ($this->offcanvasOptions !== false) {
$bsData = ['bs-toggle' => 'offcanvas', 'bs-target' => '#' . $this->offcanvasOptions['id']];
$aria = $this->offcanvasOptions['id'];
} else {
$bsData = ['bs-toggle' => 'collapse', 'bs-target' => '#' . $this->collapseOptions['id']];
$aria = $this->collapseOptions['id'];
}
return Html::button( return Html::button(
$this->togglerContent, $this->togglerContent,
ArrayHelper::merge($options, [ ArrayHelper::merge($options, [
'type' => 'button', 'type' => 'button',
'data' => [ 'data' => $bsData,
'bs-toggle' => 'collapse',
'bs-target' => '#' . $this->collapseOptions['id'],
],
'aria' => [ 'aria' => [
'controls' => $this->collapseOptions['id'], 'controls' => $aria,
'expanded' => 'false', 'expanded' => 'false',
'label' => $this->screenReaderToggleText, 'label' => $this->screenReaderToggleText,
] ]

View File

@ -4,6 +4,7 @@ namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Nav; use yii\bootstrap5\Nav;
use yii\bootstrap5\NavBar; use yii\bootstrap5\NavBar;
use yii\bootstrap5\Offcanvas;
/** /**
* Tests for NavBar widget * Tests for NavBar widget
@ -127,4 +128,68 @@ EXPECTED;
$this->assertEqualsWithoutLE($expected, $out); $this->assertEqualsWithoutLE($expected, $out);
} }
public function testOffcanvasNavigation()
{
NavBar::$counter = 0;
ob_start();
NavBar::begin([
'brandLabel' => 'Offcanvas navbar',
'brandUrl' => ['/'],
'options' => [
'class' => ['navbar', 'navbar-light', 'bg-light', 'fixed-top']
],
'innerContainerOptions' => [
'class' => ['container-fluid']
],
'collapseOptions' => false,
'offcanvasOptions' => [
'title' => 'Offcanvas',
'placement' => Offcanvas::PLACEMENT_END
]
]);
echo Nav::widget([
'options' => [
'class' => ['navbar-nav']
],
'items' => [
['label' => 'Home', 'url' => '#'],
['label' => 'Link', 'url' => '#'],
['label' => 'Dropdown', 'items' => [
['label' => 'Action', 'url' => '#'],
['label' => 'Another action', 'url' => '#'],
'-',
['label' => 'Something else here', 'url' => '#'],
]]
]
]);
NavBar::end();
$out = ob_get_clean();
$expected = <<<HTML
<nav id="w0" class="navbar navbar-light bg-light fixed-top">
<div class="container-fluid">
<a class="navbar-brand" href="/index.php?r=">Offcanvas navbar</a>
<button type="button" class="navbar-toggler" data-bs-toggle="offcanvas" data-bs-target="#w0-offcanvas" aria-controls="w0-offcanvas" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
<div id="w0-offcanvas" class="offcanvas offcanvas-end" tabindex="-1" data-bs-backdrop="true" data-bs-scroll="false" aria-labelledby="w0-offcanvas-label">
<div class="offcanvas-header">
<h5 id="w0-offcanvas-label" class="offcanvas-title">Offcanvas</h5>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<ul id="w1" class="navbar-nav nav"><li class="nav-item"><a class="nav-link" href="#">Home</a></li>
<li class="nav-item"><a class="nav-link" href="#">Link</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-bs-toggle="dropdown" role="button" aria-expanded="false">Dropdown</a><div id="w2" class="dropdown-menu"><a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<hr class="dropdown-divider">
<a class="dropdown-item" href="#">Something else here</a></div></li></ul>
</div>
</div></div>
</nav>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
} }