Passed
Push — master ( d5c6a7...b7d446 )
by Alexander
02:56
created

NavBar::options()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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