Passed
Push — master ( 566566...d0f53d )
by Alexander
02:18
created

Toast::encodeTags()   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 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Bootstrap5;
6
7
use JsonException;
8
use Yiisoft\Arrays\ArrayHelper;
9
use Yiisoft\Html\Html;
10
11
use function array_merge;
12
13
/**
14
 * Toasts renders a toast bootstrap widget.
15
 *
16
 * For example,
17
 *
18
 * ```php
19
  * echo Toast::widget()
20
 *     ->title('Hello world!')
21
 *     ->dateTime('a minute ago')
22
 *     ->body('Say hello...')
23
 *     ->begin();
24
 * ```
25
 *
26
 * The following example will show the content enclosed between the {@see begin()}
27
 * and {@see end()} calls within the toast box:
28
 *
29
 * ```php
30
 * echo Toast::widget()
31
 *     ->title('Hello world!')
32
 *     ->dateTime('a minute ago')
33
 *     ->begin();
34
 *
35
 * echo 'Say hello...';
36
 *
37
 * echo Toast::end();
38
 * ```
39
 *
40
 * @see https://getbootstrap.com/docs/5.0/components/toasts/
41
 */
42
final class Toast extends Widget
43
{
44
    private string $body = '';
45
    private string $title = '';
46
    private string $dateTime = '';
47
    private array $closeButton = [];
48
    private array $titleOptions = [];
49
    private array $dateTimeOptions = [];
50
    private array $headerOptions = [];
51
    private array $bodyOptions = [];
52
    private array $options = [];
53
    private bool $encodeTags = false;
54
55 8
    public function begin(): string
56
    {
57 8
        parent::begin();
58
59 8
        if (!isset($this->options['id'])) {
60 8
            $this->options['id'] = "{$this->getId()}-toast";
61
        }
62
63 8
        $this->initOptions();
64
65
        return
66 8
            Html::beginTag('div', $this->options) . "\n" .
67 8
            $this->renderHeader() . "\n" .
68 8
            $this->renderBodyBegin();
69
    }
70
71 8
    protected function run(): string
72
    {
73 8
        return $this->renderBodyEnd() . Html::endTag('div');
74
    }
75
76
    /**
77
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
78
     *
79
     * @param array $value Body options.
80
     *
81
     * @return self
82
     */
83 1
    public function bodyOptions(array $value): self
84
    {
85 1
        $new = clone $this;
86 1
        $new->bodyOptions = $value;
87
88 1
        return $new;
89
    }
90
91
    /**
92
     * The options for rendering the close button tag.
93
     *
94
     * The close button is displayed in the header of the toast window. Clicking on the button will hide the toast
95
     * window. If {@see closeButtonEnabled} is false, no close button will be rendered.
96
     *
97
     * The following special options are supported:
98
     *
99
     * - tag: string, the tag name of the button. Defaults to 'button'.
100
     * - label: string, the label of the button. Defaults to '&times;'.
101
     *
102
     * The rest of the options will be rendered as the HTML attributes of the button tag. Please refer to the
103
     * [Toast plugin help](https://getbootstrap.com/docs/5.0/components/toasts/) for the supported HTML attributes.
104
     *
105
     * @param array $value
106
     *
107
     * @return $this
108
     */
109 1
    public function closeButton(array $value): self
110
    {
111 1
        $new = clone $this;
112 1
        $new->closeButton = $value;
113
114 1
        return $new;
115
    }
116
117
    /**
118
     * The date/time content in the toast window.
119
     *
120
     * @param string $value
121
     *
122
     * @return $this
123
     */
124 2
    public function dateTime(string $value): self
125
    {
126 2
        $new = clone $this;
127 2
        $new->dateTime = $value;
128
129 2
        return $new;
130
    }
131
132
    /**
133
     * Additional DateTime options.
134
     *
135
     * @param array $value
136
     *
137
     * @return $this
138
     *
139
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
140
     */
141 1
    public function dateTimeOptions(array $value): self
142
    {
143 1
        $new = clone $this;
144 1
        $new->dateTimeOptions = $value;
145
146 1
        return $new;
147
    }
148
149
    /**
150
     * Additional header options.
151
     *
152
     * @param array $value
153
     *
154
     * @return $this
155
     *
156
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
157
     */
158 2
    public function headerOptions(array $value): self
159
    {
160 2
        $new = clone $this;
161 2
        $new->headerOptions = $value;
162
163 2
        return $new;
164
    }
165
166
    /**
167
     * @param array $value the HTML attributes for the widget container tag. The following special options are
168
     * recognized.
169
     *
170
     * @return $this
171
     *
172
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
173
     */
174 1
    public function options(array $value): self
175
    {
176 1
        $new = clone $this;
177 1
        $new->options = $value;
178
179 1
        return $new;
180
    }
181
182
    /**
183
     * The title content in the toast window.
184
     *
185
     * @param string $value
186
     *
187
     * @return $this
188
     */
189 7
    public function title(string $value): self
190
    {
191 7
        $new = clone $this;
192 7
        $new->title = $value;
193
194 7
        return $new;
195
    }
196
197
    /**
198
     * Additional title options.
199
     *
200
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
201
     *
202
     * @param array $value
203
     *
204
     * @return $this
205
     */
206 4
    public function titleOptions(array $value): self
207
    {
208 4
        $new = clone $this;
209 4
        $new->titleOptions = $value;
210
211 4
        return $new;
212
    }
213
214
    /**
215
     * Allows you to enable the encoding tags html.
216
     *
217
     * @return self
218
     */
219 1
    public function encodeTags(): self
220
    {
221 1
        $new = clone $this;
222 1
        $new->encodeTags = true;
223
224 1
        return $new;
225
    }
226
227
    /**
228
     * Renders the header HTML markup of the toast.
229
     *
230
     * @throws JsonException
231
     *
232
     * @return string the rendering result
233
     */
234 8
    private function renderHeader(): string
235
    {
236 8
        $button = $this->renderCloseButton();
237 8
        $tag = ArrayHelper::remove($this->titleOptions, 'tag', 'strong');
238 8
        Html::addCssClass($this->titleOptions, ['widget' => 'me-auto']);
239 8
        $title = Html::tag($tag, $this->title, $this->titleOptions);
240
241 8
        if ($this->dateTime !== '') {
242 2
            $tag = ArrayHelper::remove($this->dateTimeOptions, 'tag', 'small');
243 2
            $title .= "\n" . Html::tag($tag, $this->dateTime, $this->dateTimeOptions);
244
        }
245
246 8
        $title .= "\n" . $button;
247
248 8
        Html::addCssClass($this->headerOptions, ['widget' => 'toast-header']);
249 8
        return Html::div("\n" . $title . "\n", $this->headerOptions);
250
    }
251
252
    /**
253
     * Renders the opening tag of the toast body.
254
     *
255
     * @throws JsonException
256
     *
257
     * @return string the rendering result
258
     */
259 8
    private function renderBodyBegin(): string
260
    {
261 8
        Html::addCssClass($this->bodyOptions, ['widget' => 'toast-body']);
262 8
        return Html::beginTag('div', $this->bodyOptions);
263
    }
264
265
    /**
266
     * Renders the closing tag of the toast body.
267
     *
268
     * @return string the rendering result
269
     */
270 8
    private function renderBodyEnd(): string
271
    {
272 8
        return $this->body . "\n" . Html::endTag('div');
273
    }
274
275
    /**
276
     * Renders the close button.
277
     *
278
     * @throws JsonException
279
     *
280
     * @return string the rendering result
281
     */
282 8
    private function renderCloseButton(): string
283
    {
284 8
        $tag = ArrayHelper::remove($this->closeButton, 'tag', 'button');
285 8
        $label = ArrayHelper::remove(
286 8
            $this->closeButton,
287 8
            'label',
288 8
            Html::tag('span', '&times;', ['aria-hidden' => 'true', 'encode' => false])
289
        );
290
291 8
        return Html::tag($tag, "\n" . $label . "\n", $this->closeButton);
292
    }
293
294
    /**
295
     * Initializes the widget options.
296
     *
297
     * This method sets the default values for various options.
298
     */
299 8
    private function initOptions(): void
300
    {
301 8
        if ($this->encodeTags === false) {
302 7
            $this->bodyOptions['encode'] = false;
303 7
            $this->closeButton['encode'] = false;
304 7
            $this->dateTimeOptions['encode'] = false;
305 7
            $this->headerOptions['encode'] = false;
306 7
            $this->options['encode'] = false;
307 7
            $this->titleOptions['encode'] = false;
308
        }
309
310 8
        Html::addCssClass($this->options, ['widget' => 'toast']);
311
312 8
        $this->closeButton = array_merge([
313 8
            'aria' => ['label' => 'Close'],
314
            'data' => ['bs-dismiss' => 'toast'],
315
            'class' => ['widget' => 'btn-close'],
316
            'type' => 'button',
317 8
        ], $this->closeButton);
318
319 8
        if (!isset($this->options['role'])) {
320 8
            $this->options['role'] = 'alert';
321
        }
322
323 8
        if (!isset($this->options['aria']) && !isset($this->options['aria-live'])) {
324 8
            $this->options['aria'] = [
325
                'live' => 'assertive',
326
                'atomic' => 'true',
327
            ];
328
        }
329 8
    }
330
}
331