Offcanvas::placement()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
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 6
ccs 4
cts 4
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Bootstrap5;
6
7
use Yiisoft\Arrays\ArrayHelper;
8
use Yiisoft\Html\Html;
9
10
final class Offcanvas extends AbstractToggleWidget
11
{
12
    use CloseButtonTrait;
13
14
    public const PLACEMENT_TOP = 'offcanvas-top';
15
    public const PLACEMENT_END = 'offcanvas-end';
16
    public const PLACEMENT_BOTTOM = 'offcanvas-bottom';
17
    public const PLACEMENT_START = 'offcanvas-start';
18
19
    private array $options = [];
20
    private array $headerOptions = [];
21
    private array $titleOptions = [];
22
    private array $bodyOptions = [];
23
    private ?string $title = null;
24
    private string $placement = self::PLACEMENT_START;
25
    private bool $scroll = false;
26
    private bool $withoutBackdrop = false;
27
    protected bool $renderToggle = false;
28
29 19
    public function getId(?string $suffix = '-offcanvas'): ?string
30
    {
31 19
        return $this->options['id'] ?? parent::getId($suffix);
0 ignored issues
show
Unused Code introduced by
The call to Yiisoft\Yii\Bootstrap5\CloseButtonTrait::getId() has too many arguments starting with $suffix. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

31
        return $this->options['id'] ?? parent::/** @scrutinizer ignore-call */ getId($suffix);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
32
    }
33
34 19
    protected function toggleComponent(): string
35
    {
36 19
        return 'offcanvas';
37
    }
38
39
    /**
40
     * Enable/disable body scroll when offcanvas show
41
     *
42
     * @link https://getbootstrap.com/docs/5.1/components/offcanvas/#backdrop
43
     */
44 1
    public function scroll(bool $scroll = true): self
45
    {
46 1
        $new = clone $this;
47 1
        $new->scroll = $scroll;
48
49 1
        return $new;
50
    }
51
52
    /**
53
     * Enable/disable offcanvas backdrop
54
     *
55
     * @link https://getbootstrap.com/docs/5.1/components/offcanvas/#backdrop
56
     */
57 5
    public function withoutBackdrop(bool $withoutBackdrop = true): self
58
    {
59 5
        $new = clone $this;
60 5
        $new->withoutBackdrop = $withoutBackdrop;
61
62 5
        return $new;
63
    }
64
65
    /**
66
     * Set placement for opened offcanvas
67
     *
68
     * @link https://getbootstrap.com/docs/5.1/components/offcanvas/#placement
69
     */
70 4
    public function placement(string $placement): self
71
    {
72 4
        $new = clone $this;
73 4
        $new->placement = $placement;
74
75 4
        return $new;
76
    }
77
78
    /**
79
     * The HTML attributes for the widget container tag. The following special options are recognized.
80
     *
81
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
82
     */
83 5
    public function options(array $options): self
84
    {
85 5
        $new = clone $this;
86 5
        $new->options = $options;
87
88 5
        return $new;
89
    }
90
91
    /**
92
     * The HTML attributes for the widget header tag. The following special options are recognized.
93
     *
94
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
95
     */
96 1
    public function headerOptions(array $options): self
97
    {
98 1
        $new = clone $this;
99 1
        $new->headerOptions = $options;
100
101 1
        return $new;
102
    }
103
104
    /**
105
     * Set/remove offcanvas title
106
     */
107 14
    public function title(?string $title): self
108
    {
109 14
        $new = clone $this;
110 14
        $new->title = $title;
111
112 14
        return $new;
113
    }
114
115
    /**
116
     * The HTML attributes for the widget title tag. The following special options are recognized.
117
     *
118
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
119
     */
120 1
    public function titleOptions(array $options): self
121
    {
122 1
        $new = clone $this;
123 1
        $new->titleOptions = $options;
124
125 1
        return $new;
126
    }
127
128
    /**
129
     * The HTML attributes for the widget body tag. The following special options are recognized.
130
     *
131
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
132
     */
133 1
    public function bodyOptions(array $options): self
134
    {
135 1
        $new = clone $this;
136 1
        $new->bodyOptions = $options;
137
138 1
        return $new;
139
    }
140
141 18
    public function begin(): string
142
    {
143 18
        parent::begin();
144
145 18
        $options = $this->options;
146 18
        $bodyOptions = $this->bodyOptions;
147 18
        $tag = ArrayHelper::remove($options, 'tag', 'div');
148 18
        $bodyTag = ArrayHelper::remove($bodyOptions, 'tag', 'div');
149
150 18
        Html::addCssClass($options, ['widget' => 'offcanvas', 'placement' => $this->placement]);
151 18
        Html::addCssClass($bodyOptions, ['widget' => 'offcanvas-body']);
152
153 18
        $options['id'] = $this->getId();
154 18
        $options['tabindex'] = -1;
155
156 18
        if (!empty($this->title)) {
157 13
            if (isset($this->titleOptions['id'])) {
158
                $options['aria-labelledby'] = $this->titleOptions['id'];
159 13
            } elseif ($options['id']) {
160 13
                $options['aria-labelledby'] = $options['id'] . '-title';
161
            }
162
        }
163
164 18
        if ($this->scroll) {
165 1
            $options['data-bs-scroll'] = 'true';
166
        }
167
168 18
        if ($this->withoutBackdrop) {
169 5
            $options['data-bs-backdrop'] = 'false';
170
        }
171
172 18
        if ($this->theme) {
173 4
            $options['data-bs-theme'] = $this->theme;
174
        }
175
176 18
        $html = $this->renderToggle ? $this->renderToggle() : '';
177 18
        $html .= Html::openTag($tag, $options);
178 18
        $html .= $this->renderHeader();
179 18
        $html .= Html::openTag($bodyTag, $bodyOptions);
180
181 18
        return $html;
182
    }
183
184 18
    public function render(): string
185
    {
186 18
        $tag = $this->options['tag'] ?? 'div';
187 18
        $bodyTag = $this->bodyOptions['tag'] ?? 'div';
188
189 18
        return Html::closeTag($bodyTag) . Html::closeTag($tag);
190
    }
191
192
    /**
193
     * Renders offcanvas header.
194
     *
195
     * @return string the rendering header.
196
     */
197 18
    private function renderHeader(): string
198
    {
199 18
        $options = $this->headerOptions;
200 18
        $tag = ArrayHelper::remove($options, 'tag', 'header');
201
202 18
        Html::addCssClass($options, ['widget' => 'offcanvas-header']);
203
204 18
        $title = (string) $this->renderTitle();
205 18
        $closeButton = $this->renderCloseButton(true);
206
207 18
        return Html::tag($tag, $title . $closeButton, $options)
208 18
            ->encode(false)
209 18
            ->render();
210
    }
211
212
    /**
213
     * Renders offcanvas title.
214
     *
215
     * @return string|null the rendering header.
216
     */
217 18
    private function renderTitle(): ?string
218
    {
219 18
        if ($this->title === null) {
220 5
            return null;
221
        }
222
223 14
        $options = $this->titleOptions;
224 14
        $tag = ArrayHelper::remove($options, 'tag', 'h5');
225 14
        $encode = ArrayHelper::remove($options, 'encode');
226
227 14
        Html::addCssClass($options, ['offcanvas-title']);
228
229 14
        if (!isset($options['id']) && $id = $this->getId()) {
230 14
            $options['id'] = $id . '-title';
231
        }
232
233 14
        return Html::tag($tag, $this->title, $options)
234 14
            ->encode($encode)
235 14
            ->render();
236
    }
237
}
238