Passed
Push — master ( d3891b...901043 )
by Alexander
02:19
created

NavBar::run()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4.0466

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 7
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 11
ccs 6
cts 7
cp 0.8571
crap 4.0466
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Bulma;
6
7
use JsonException;
8
use Yiisoft\Arrays\ArrayHelper;
9
use Yiisoft\Html\Html;
10
11
use function strpos;
12
13
/**
14
 * The navbar component is a responsive and versatile horizontal navigation bar.
15
 *
16
 * @link https://bulma.io/documentation/components/navbar/
17
 */
18
final class NavBar extends Widget
19
{
20
    private string $brand = '';
21
    private string $brandLabel = '';
22
    private string $brandImage = '';
23
    private string $brandUrl = '/';
24
    private string $toggleIcon = '';
25
    private array $options = [];
26
    private array $brandOptions = [];
27
    private array $brandLabelOptions = [];
28
    private array $brandImageOptions = [];
29
    private array $itemsOptions = [];
30
    private array $menuOptions = [];
31
    private array $toggleOptions = [
32
        'aria-expanded' => 'false',
33
        'aria-label' => 'menu',
34
        'class' => 'navbar-burger',
35
        'role' => 'button'
36
    ];
37
38 14
    public function start(): string
39
    {
40 14
        $this->buildOptions();
41 14
        $this->renderBrand();
42
43 14
        $navOptions = $this->options;
44 14
        $navTag = ArrayHelper::remove($navOptions, 'tag', 'nav');
45 14
        if (!is_string($navTag) && !is_bool($navTag) && $navTag !== null) {
46
            throw new \InvalidArgumentException('Tag should be either string, bool or null.');
47
        }
48
49
        return
50 14
            Html::beginTag($navTag, $navOptions) . "\n" .
51 14
            $this->brand . "\n" .
52 14
            Html::beginTag('div', $this->menuOptions) .
53 14
            Html::beginTag('div', $this->itemsOptions);
54
    }
55
56 14
    protected function run(): string
57
    {
58 14
        $tag = ArrayHelper::remove($this->options, 'tag', 'nav');
59 14
        if (!is_string($tag) && !is_bool($tag) && $tag !== null) {
60
            throw new \InvalidArgumentException('Tag should be either string, bool or null.');
61
        }
62
63
        return
64 14
            Html::endTag('div') . "\n" .
65 14
            Html::endTag('div') . "\n" .
66 14
            Html::endTag($tag);
67
    }
68
69
    /**
70
     * Set render brand custom, {@see brandLabel} and {@see brandImage} are not generated.
71
     *
72
     * @param string $value
73
     *
74
     * @return self
75
     */
76 1
    public function brand(string $value): self
77
    {
78 1
        $new = clone $this;
79 1
        $new->brand = $value;
80 1
        return $new;
81
    }
82
83
    /**
84
     * The text of the brand label or empty if it's not used. Note that this is not HTML-encoded.
85
     *
86
     * @param string $value
87
     *
88
     * @return self
89
     */
90 13
    public function brandLabel(string $value): self
91
    {
92 13
        $new = clone $this;
93 13
        $new->brandLabel = $value;
94 13
        return $new;
95
    }
96
97
    /**
98
     * The image of the brand or empty if it's not used.
99
     *
100
     * @param string $value
101
     *
102
     * @return self
103
     */
104 12
    public function brandImage(string $value): self
105
    {
106 12
        $new = clone $this;
107 12
        $new->brandImage = $value;
108 12
        return $new;
109
    }
110
111
    /**
112
     * The URL for the brand's hyperlink tag and will be used for the "href" attribute of the brand link. Default value
113
     * is '/' will be used. You may set it to `null` if you want to have no link at all.
114
     *
115
     * @param string $value
116
     *
117
     * @return self
118
     */
119 11
    public function brandUrl(string $value): self
120
    {
121 11
        $new = clone $this;
122 11
        $new->brandUrl = $value;
123 11
        return $new;
124
    }
125
126
    /**
127
     * Set toggle icon.
128
     *
129
     * @param string $value.
130
     *
131
     * @return self
132
     */
133 1
    public function toggleIcon(string $value): self
134
    {
135 1
        $new = clone $this;
136 1
        $new->toggleIcon = $value;
137 1
        return $new;
138
    }
139
140
    /**
141
     * Options HTML attributes for the tag nav.
142
     *
143
     * @param array $value
144
     *
145
     * @return self
146
     *
147
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
148
     */
149 2
    public function options(array $value): self
150
    {
151 2
        $new = clone $this;
152 2
        $new->options = $value;
153 2
        return $new;
154
    }
155
156
    /**
157
     * Options HTML attributes of the tag div brand.
158
     *
159
     * @param array $value default value `navbar-item`.
160
     *
161
     * @return self
162
     *
163
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
164
     */
165 1
    public function brandOptions(array $value): self
166
    {
167 1
        $new = clone $this;
168 1
        $new->brandOptions = $value;
169 1
        return $new;
170
    }
171
172
    /**
173
     * Options HTML attributes of the tag div brand label.
174
     *
175
     * @param array $value default value `navbar-item`.
176
     *
177
     * @return self
178
     *
179
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
180
     */
181 1
    public function brandLabelOptions(array $value): self
182
    {
183 1
        $new = clone $this;
184 1
        $new->brandLabelOptions = $value;
185 1
        return $new;
186
    }
187
188
    /**
189
     * Options HTML attributes of the tag div brand link.
190
     *
191
     * @param array $value default value `navbar-item`.
192
     *
193
     * @return self
194
     *
195
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
196
     */
197 1
    public function brandImageOptions(array $value): self
198
    {
199 1
        $new = clone $this;
200 1
        $new->brandImageOptions = $value;
201 1
        return $new;
202
    }
203
204
    /**
205
     * Options HTML attributes of the tag div items nav, values `navbar-start`, `navbar-end`.
206
     *
207
     * @param array $value default value `navbar-start`.
208
     *
209
     * @return self
210
     *
211
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
212
     */
213 2
    public function itemsOptions(array $value): self
214
    {
215 2
        $new = clone $this;
216 2
        $new->itemsOptions = $value;
217 2
        return $new;
218
    }
219
220
    /**
221
     * Options HTML attributes of the tag div nav menu.
222
     *
223
     * @param array $value default value `navbar-menu`.
224
     *
225
     * @return self
226
     *
227
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
228
     */
229 1
    public function menuOptions(array $value): self
230
    {
231 1
        $new = clone $this;
232 1
        $new->menuOptions = $value;
233 1
        return $new;
234
    }
235
236
    /**
237
     * The HTML attributes of the navbar toggler button.
238
     *
239
     * @param array $value
240
     *
241
     * @return self
242
     *
243
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
244
     */
245 1
    public function toggleOptions(array $value): self
246
    {
247 1
        $new = clone $this;
248 1
        $new->toggleOptions = $value;
249 1
        return $new;
250
    }
251
252 14
    private function buildOptions(): void
253
    {
254 14
        $id = '';
255
256 14
        if (!isset($this->options['id'])) {
257 14
            $id = $this->getId();
258 14
            $this->options['id'] = "{$id}-navbar";
259
        }
260
261 14
        $this->options = $this->addOptions($this->options, 'navbar');
262 14
        $this->brandOptions = $this->addOptions($this->brandOptions, 'navbar-brand');
263 14
        $this->brandLabelOptions = $this->addOptions($this->brandLabelOptions, 'navbar-item');
264 14
        $this->brandImageOptions = $this->addOptions($this->brandImageOptions, 'navbar-item');
265 14
        $this->menuOptions = $this->addOptions($this->menuOptions, 'navbar-menu');
266
267 14
        $this->menuOptions['id'] = "{$id}-navbar-Menu";
268
269 14
        $this->initItemsOptions();
270 14
    }
271
272 14
    private function initItemsOptions(): void
273
    {
274 14
        $itemsClass = '';
275
276 14
        if (isset($this->itemsOptions['class'])) {
277 2
            $itemsClass = $this->itemsOptions['class'];
278 2
            unset($this->itemsOptions['class']);
279 2
            if (is_array($itemsClass)) {
280
                $itemsClass = implode(' ', $itemsClass);
281
            }
282
        }
283
284
        /** @var string $itemsClass */
285 14
        if (strpos($itemsClass, 'navbar-end') === false) {
286 13
            Html::addCssClass($this->itemsOptions, 'navbar-start');
287
        }
288
289 14
        if (!empty($itemsClass)) {
290 2
            Html::addCssClass($this->itemsOptions, $itemsClass);
291
        }
292 14
    }
293
294 14
    private function renderBrand(): void
295
    {
296 14
        if ($this->brand === '') {
297 13
            $this->brand = Html::beginTag('div', $this->brandOptions);
298
299 13
            if ($this->brandImage !== '' && $this->brandLabel !== '') {
300 11
                $this->brand .= Html::tag('span', Html::img($this->brandImage), $this->brandImageOptions);
301
            }
302
303 13
            if ($this->brandImage !== '' && $this->brandLabel === '') {
304 1
                $this->brand .= Html::a(Html::img($this->brandImage), $this->brandUrl, $this->brandImageOptions);
305
            }
306
307 13
            if ($this->brandLabel !== '') {
308 12
                $this->brand .= Html::a($this->brandLabel, $this->brandUrl, $this->brandLabelOptions);
309
            }
310
311 13
            $this->brand .= $this->renderToggleButton();
312 13
            $this->brand .= Html::endTag('div');
313
        }
314 14
    }
315
316
    /**
317
     * Renders collapsible toggle button.
318
     *
319
     * @throws JsonException
320
     *
321
     * @return string the rendering toggle button.
322
     */
323 13
    private function renderToggleButton(): string
324
    {
325
        return
326 13
            Html::beginTag('a', $this->toggleOptions) .
327 13
                $this->renderToggleIcon() .
328
329 13
            Html::endTag('a');
330
    }
331
332
    /**
333
     * Render icon toggle.
334
     *
335
     * @throws JsonException
336
     *
337
     * @return string
338
     */
339 13
    private function renderToggleIcon(): string
340
    {
341 13
        if ($this->toggleIcon === '') {
342 12
            $this->toggleIcon = Html::tag('span', '', ['aria-hidden' => 'true']) .
343 12
                Html::tag('span', '', ['aria-hidden' => 'true']) .
344 12
                Html::tag('span', '', ['aria-hidden' => 'true']);
345
        }
346
347 13
        return $this->toggleIcon;
348
    }
349
}
350