Completed
Push — master ( 92c51b...1c2d7c )
by Wilmer
02:09 queued 02:09
created

Offcanvas::titleOptions()   A

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 Widget
11
{
12
    public const PLACEMENT_TOP = 'offcanvas-top';
13
    public const PLACEMENT_END = 'offcanvas-end';
14
    public const PLACEMENT_BOTTOM = 'offcanvas-bottom';
15
    public const PLACEMENT_START = 'offcanvas-start';
16
17
    private array $options = [];
18
    private array $headerOptions = [];
19
    private array $titleOptions = [];
20
    private array $bodyOptions = [];
21
    private array $closeButtonOptions = [];
22
    private ?string $title = null;
23
    private string $placement = self::PLACEMENT_START;
24
    private bool $scroll = false;
25
    private bool $backdrop = true;
26
27 11
    public function getId(?string $suffix = '-offcanvas'): ?string
28
    {
29 11
        return $this->options['id'] ?? parent::getId($suffix);
30
    }
31
32
    /**
33
     * Enable/disable body scroll when offcanvas show
34
     *
35
     * @return self
36
     *
37
     * @link https://getbootstrap.com/docs/5.1/components/offcanvas/#backdrop
38
     */
39 1
    public function scroll(bool $scroll): self
40
    {
41 1
        $new = clone $this;
42 1
        $new->scroll = $scroll;
43
44 1
        return $new;
45
    }
46
47
    /**
48
     * Enable/disable offcanvas
49
     *
50
     * @return self
51
     *
52
     * @link https://getbootstrap.com/docs/5.1/components/offcanvas/#backdrop
53
     */
54 1
    public function backdrop(bool $backdrop): self
55
    {
56 1
        $new = clone $this;
57 1
        $new->backdrop = $backdrop;
58
59 1
        return $new;
60
    }
61
62
    /**
63
     * Set placement for opened offcanvas
64
     *
65
     * @param string $placement
66
     *
67
     * @return self
68
     *
69
     * @link https://getbootstrap.com/docs/5.1/components/offcanvas/#placement
70
     */
71 1
    public function placement(string $placement): self
72
    {
73 1
        $new = clone $this;
74 1
        $new->placement = $placement;
75
76 1
        return $new;
77
    }
78
79
    /**
80
     * The HTML attributes for the widget container tag. The following special options are recognized.
81
     *
82
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
83
     *
84
     * @param array $options
85
     *
86
     * @return self
87
     */
88 2
    public function options(array $options): self
89
    {
90 2
        $new = clone $this;
91 2
        $new->options = $options;
92
93 2
        return $new;
94
    }
95
96
    /**
97
     * The HTML attributes for the widget header tag. The following special options are recognized.
98
     *
99
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
100
     *
101
     * @param array $options
102
     *
103
     * @return self
104
     */
105 1
    public function headerOptions(array $options): self
106
    {
107 1
        $new = clone $this;
108 1
        $new->headerOptions = $options;
109
110 1
        return $new;
111
    }
112
113
    /**
114
     * Set/remove offcanvas title
115
     *
116
     * @param string|null $title
117
     *
118
     * @return self
119
     */
120 10
    public function title(?string $title): self
121
    {
122 10
        $new = clone $this;
123 10
        $new->title = $title;
124
125 10
        return $new;
126
    }
127
128
    /**
129
     * The HTML attributes for the widget title tag. The following special options are recognized.
130
     *
131
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
132
     *
133
     * @param array $options
134
     *
135
     * @return self
136
     */
137 1
    public function titleOptions(array $options): self
138
    {
139 1
        $new = clone $this;
140 1
        $new->titleOptions = $options;
141
142 1
        return $new;
143
    }
144
145
    /**
146
     * The HTML attributes for the widget body tag. The following special options are recognized.
147
     *
148
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
149
     *
150
     * @param array $options
151
     *
152
     * @return self
153
     */
154 1
    public function bodyOptions(array $options): self
155
    {
156 1
        $new = clone $this;
157 1
        $new->bodyOptions = $options;
158
159 1
        return $new;
160
    }
161
162
    /**
163
     * The HTML attributes for the widget close button tag. The following special options are recognized.
164
     *
165
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
166
     *
167
     * @param array $options
168
     *
169
     * @return self
170
     */
171
    public function closeButtonOptions(array $options): self
172
    {
173
        $new = clone $this;
174
        $new->closeButtonOptions = $options;
175
176
        return $new;
177
    }
178
179 11
    public function begin(): string
180
    {
181 11
        parent::begin();
182
183 11
        $options = $this->options;
184 11
        $bodyOptions = $this->bodyOptions;
185 11
        $tag = ArrayHelper::remove($options, 'tag', 'div');
186 11
        $bodyTag = ArrayHelper::remove($bodyOptions, 'tag', 'div');
187
188 11
        Html::addCssClass($options, ['widget' => 'offcanvas', 'placement' => $this->placement]);
189 11
        Html::addCssClass($bodyOptions, ['widget' => 'offcanvas-body']);
190
191 11
        $options['id'] = $this->getId();
192 11
        $options['tabindex'] = -1;
193
194 11
        if (!empty($this->title)) {
195 9
            if (isset($this->titleOptions['id'])) {
196
                $options['aria-labelledby'] = $this->titleOptions['id'];
197 9
            } elseif ($options['id']) {
198 9
                $options['aria-labelledby'] = $options['id'] . '-title';
199
            }
200
        }
201
202 11
        if ($this->scroll) {
203 1
            $options['data-bs-scroll'] = 'true';
204
        }
205
206 11
        if (!$this->backdrop) {
207 1
            $options['data-bs-backdrop'] = 'false';
208
        }
209
210 11
        $html = Html::openTag($tag, $options);
211 11
        $html .= $this->renderHeader();
212 11
        $html .= Html::openTag($bodyTag, $bodyOptions);
213
214 11
        return $html;
215
    }
216
217 11
    protected function run(): string
218
    {
219 11
        $tag = ArrayHelper::getValue($this->options, 'tag', 'div');
220 11
        $bodyTag = ArrayHelper::getValue($this->bodyOptions, 'tag', 'div');
221
222 11
        return Html::closeTag($bodyTag) . Html::closeTag($tag);
223
    }
224
225
    /**
226
     * Renders offcanvas header.
227
     *
228
     * @return string the rendering header.
229
     */
230 11
    private function renderHeader(): string
231
    {
232 11
        $options = $this->headerOptions;
233 11
        $tag = ArrayHelper::remove($options, 'tag', 'header');
234
235 11
        Html::addCssClass($options, ['widget' => 'offcanvas-header']);
236
237 11
        $title = (string) $this->renderTitle();
238 11
        $closeButton = $this->renderCloseButton();
239
240 11
        return Html::tag($tag, $title . $closeButton, $options)->encode(false)->render();
241
    }
242
243
    /**
244
     * Renders offcanvas title.
245
     *
246
     * @return string|null the rendering header.
247
     */
248 11
    private function renderTitle(): ?string
249
    {
250 11
        if ($this->title === null) {
251 2
            return null;
252
        }
253
254 10
        $options = $this->titleOptions;
255 10
        $tag = ArrayHelper::remove($options, 'tag', 'h5');
256 10
        $encode = ArrayHelper::remove($options, 'encode');
257
258 10
        Html::addCssClass($options, ['offcanvas-title']);
259
260 10
        if (!isset($options['id']) && $id = $this->getId()) {
261 10
            $options['id'] = $id . '-title';
262
        }
263
264 10
        return Html::tag($tag, $this->title, $options)->encode($encode)->render();
265
    }
266
267
    /**
268
     * Renders offcanvas close button.
269
     *
270
     * @return string the rendering close button.
271
     */
272 11
    private function renderCloseButton(): string
273
    {
274 11
        $options = $this->closeButtonOptions;
275 11
        $label = ArrayHelper::remove($options, 'label');
276 11
        $encode = ArrayHelper::remove($options, 'encode');
277
278 11
        if ($label === null) {
279 11
            Html::addCssClass($options, ['btn-close']);
280
        }
281
282 11
        $options['type'] = 'button';
283 11
        $options['aria-label'] = 'Close';
284 11
        $options['data-bs-dismiss'] = 'offcanvas';
285
286 11
        return Html::tag('button', $label, $options)->encode($encode)->render();
287
    }
288
}
289