Passed
Push — master ( 8617c9...9932bf )
by Alexander
03:51 queued 01:34
created

ModalCard::toggleButtonSize()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.0932

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 11
ccs 5
cts 7
cp 0.7143
crap 2.0932
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\Html\Html;
10
11
/**
12
 * ModalCard renders a modal window that can be toggled by clicking on a button.
13
 *
14
 * The following example will show the content enclosed between the {@see begin()} and {@see end()} calls within the
15
 * modal window:
16
 *
17
 * ```php
18
 * echo ModalCard::widget()
19
 *     ->title('Modal title')
20
 *     ->footer(
21
 *         Html::button('Cancel', ['class' => 'button'])
22
 *     )
23
 *     ->begin();
24
 *
25
 * echo 'Say hello...';
26
 *
27
 * echo ModalCard::end();
28
 * ```
29
 *
30
 * @link https://bulma.io/documentation/components/modal/
31
 */
32
final class ModalCard extends Widget
33
{
34
    public const SIZE_SMALL = 'is-small';
35
    public const SIZE_MEDIUM = 'is-medium';
36
    public const SIZE_LARGE = 'is-large';
37
    private const SIZE_ALL = [
38
        self::SIZE_SMALL,
39
        self::SIZE_MEDIUM,
40
        self::SIZE_LARGE,
41
    ];
42
43
    public const COLOR_PRIMARY = 'is-primary';
44
    public const COLOR_LINK = 'is-link';
45
    public const COLOR_INFO = 'is-info';
46
    public const COLOR_SUCCESS = 'is-success';
47
    public const COLOR_WARNING = 'is-warning';
48
    public const COLOR_DANGER = 'is-danger';
49
    private const COLOR_ALL = [
50
        self::COLOR_PRIMARY,
51
        self::COLOR_LINK,
52
        self::COLOR_INFO,
53
        self::COLOR_SUCCESS,
54
        self::COLOR_WARNING,
55
        self::COLOR_DANGER,
56
    ];
57
58
    private array $options = [];
59
    private array $contentOptions = [];
60
    private array $closeButtonOptions = [];
61
    private string $closeButtonSize = '';
62
    private bool $closeButtonEnabled = true;
63
    private string $toggleButtonLabel = 'Toggle button';
64
    private string $toggleButtonSize = '';
65
    private string $toggleButtonColor = '';
66
    private array $toggleButtonOptions = [];
67
    private bool $toggleButtonEnabled = true;
68
    private string $title = '';
69
    private string $footer = '';
70
    private array $titleOptions = [];
71
    private array $headerOptions = [];
72
    private array $bodyOptions = [];
73
    private array $footerOptions = [];
74
75 16
    public function begin(): ?string
76
    {
77 16
        parent::begin();
78
79 16
        $this->buildOptions();
80
81 16
        $html = '';
82 16
        $html .= $this->renderToggleButton() . "\n";
83 16
        $html .= Html::beginTag('div', $this->options) . "\n"; // .modal
84 16
        $html .= $this->renderBackgroundTransparentOverlay() . "\n"; // .modal-background
85 16
        $html .= Html::beginTag('div', $this->contentOptions) . "\n"; // .modal-card
86 16
        $html .= $this->renderHeader();
87 16
        $html .= $this->renderBodyBegin() . "\n";
88
89 16
        return $html;
90
    }
91
92 16
    protected function run(): string
93
    {
94 16
        $html = '';
95 16
        $html .= $this->renderBodyEnd() . "\n";
96 16
        $html .= $this->renderFooter() . "\n";
97 16
        $html .= Html::endTag('div') . "\n"; // .modal-card
98 16
        $html .= Html::endTag('div'); // .modal
99
100 16
        return $html;
101
    }
102
103 16
    private function buildOptions(): void
104
    {
105 16
        $this->options['id'] ??= "{$this->getId()}-modal";
106 16
        $this->options = $this->addOptions($this->options, 'modal');
107
108 16
        $this->closeButtonOptions = $this->addOptions($this->closeButtonOptions, 'delete');
109 16
        $this->closeButtonOptions['aria-label'] = 'close';
110
111 16
        if ($this->closeButtonSize !== '') {
112 1
            Html::addCssClass($this->closeButtonOptions, $this->closeButtonSize);
113
        }
114
115 16
        $this->toggleButtonOptions = $this->addOptions($this->toggleButtonOptions, 'button');
116 16
        $this->toggleButtonOptions['data-target'] = '#' . $this->options['id'];
117 16
        $this->toggleButtonOptions['aria-haspopup'] = 'true';
118
119 16
        if ($this->toggleButtonSize !== '') {
120 1
            Html::addCssClass($this->toggleButtonOptions, $this->toggleButtonSize);
121
        }
122
123 16
        if ($this->toggleButtonColor !== '') {
124 1
            Html::addCssClass($this->toggleButtonOptions, $this->toggleButtonColor);
125
        }
126
127 16
        $this->contentOptions = $this->addOptions($this->contentOptions, 'modal-card');
128 16
        $this->headerOptions = $this->addOptions($this->headerOptions, 'modal-card-head');
129 16
        $this->titleOptions = $this->addOptions($this->titleOptions, 'modal-card-title');
130 16
        $this->bodyOptions = $this->addOptions($this->bodyOptions, 'modal-card-body');
131 16
        $this->footerOptions = $this->addOptions($this->footerOptions, 'modal-card-foot');
132 16
    }
133
134
    /**
135
     * Main container options.
136
     *
137
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
138
     *
139
     * @param array $value
140
     *
141
     * @return self
142
     */
143
    public function options(array $value): self
144
    {
145
        $new = clone $this;
146
        $new->options = $value;
147
148
        return $new;
149
    }
150
151
    /**
152
     * Main content container options.
153
     *
154
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
155
     *
156
     * @param array $value
157
     *
158
     * @return self
159
     */
160 1
    public function contentOptions(array $value): self
161
    {
162 1
        $new = clone $this;
163 1
        $new->contentOptions = $value;
164
165 1
        return $new;
166
    }
167
168
    /**
169
     * Toggle button label.
170
     *
171
     * @param string $value
172
     *
173
     * @return self
174
     */
175 1
    public function toggleButtonLabel(string $value): self
176
    {
177 1
        $new = clone $this;
178 1
        $new->toggleButtonLabel = $value;
179
180 1
        return $new;
181
    }
182
183
    /**
184
     * Toggle button options.
185
     *
186
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
187
     *
188
     * @param array $value
189
     *
190
     * @return self
191
     */
192 1
    public function toggleButtonOptions(array $value): self
193
    {
194 1
        $new = clone $this;
195 1
        $new->toggleButtonOptions = $value;
196
197 1
        return $new;
198
    }
199
200
    /**
201
     * Toggle button size.
202
     *
203
     * @param string $value
204
     *
205
     * @return self
206
     */
207 1
    public function toggleButtonSize(string $value): self
208
    {
209 1
        if (!in_array($value, self::SIZE_ALL)) {
210
            $values = implode('", "', self::SIZE_ALL);
211
            throw new InvalidArgumentException("Invalid size. Valid values are: \"$values\".");
212
        }
213
214 1
        $new = clone $this;
215 1
        $new->toggleButtonSize = $value;
216
217 1
        return $new;
218
    }
219
220
    /**
221
     * Toggle button color.
222
     *
223
     * @param string $value
224
     *
225
     * @return self
226
     */
227 1
    public function toggleButtonColor(string $value): self
228
    {
229 1
        if (!in_array($value, self::COLOR_ALL)) {
230
            $values = implode('", "', self::COLOR_ALL);
231
            throw new InvalidArgumentException("Invalid color. Valid values are: \"$values\".");
232
        }
233
234 1
        $new = clone $this;
235 1
        $new->toggleButtonColor = $value;
236
237 1
        return $new;
238
    }
239
240
    /**
241
     * Enable/Disable toggle button.
242
     *
243
     * @param bool $value
244
     *
245
     * @return self
246
     */
247 1
    public function toggleButtonEnabled(bool $value): self
248
    {
249 1
        $new = clone $this;
250 1
        $new->toggleButtonEnabled = $value;
251
252 1
        return $new;
253
    }
254
255
    /**
256
     * Renders the toggle button.
257
     *
258
     * @throws JsonException
259
     *
260
     * @return string
261
     */
262 16
    private function renderToggleButton(): string
263
    {
264 16
        if ($this->toggleButtonEnabled) {
265 15
            return Html::button($this->toggleButtonLabel, $this->toggleButtonOptions);
266
        }
267
268 1
        return '';
269
    }
270
271
    /**
272
     * Close button size.
273
     *
274
     * @param string $value
275
     *
276
     * @return self
277
     */
278 1
    public function closeButtonSize(string $value): self
279
    {
280 1
        if (!in_array($value, self::SIZE_ALL)) {
281
            $values = implode('"', self::SIZE_ALL);
282
            throw new InvalidArgumentException("Invalid size. Valid values are: \"$values\".");
283
        }
284
285 1
        $new = clone $this;
286 1
        $new->closeButtonSize = $value;
287
288 1
        return $new;
289
    }
290
291
    /**
292
     * Close button options
293
     *
294
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
295
     *
296
     * @param array $value
297
     *
298
     * @return self
299
     */
300 1
    public function closeButtonOptions(array $value): self
301
    {
302 1
        $new = clone $this;
303 1
        $new->closeButtonOptions = $value;
304
305 1
        return $new;
306
    }
307
308
    /**
309
     * Enable/Disable close button.
310
     *
311
     * @param bool $value
312
     *
313
     * @return self
314
     */
315 1
    public function closeButtonEnabled(bool $value): self
316
    {
317 1
        $new = clone $this;
318 1
        $new->closeButtonEnabled = $value;
319
320 1
        return $new;
321
    }
322
323
    /**
324
     * Renders the close button.
325
     *
326
     * @throws JsonException
327
     *
328
     * @return string
329
     */
330 16
    private function renderCloseButton(): string
331
    {
332 16
        if ($this->closeButtonEnabled) {
333 15
            return Html::button('', $this->closeButtonOptions);
334
        }
335
336 1
        return '';
337
    }
338
339
    /**
340
     * Header options.
341
     *
342
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
343
     *
344
     * @param array $value
345
     *
346
     * @return self
347
     */
348 1
    public function headerOptions(array $value): self
349
    {
350 1
        $new = clone $this;
351 1
        $new->headerOptions = $value;
352
353 1
        return $new;
354
    }
355
356
    /**
357
     * Renders header.
358
     *
359
     * @throws JsonException
360
     *
361
     * @return string
362
     */
363 16
    private function renderHeader(): string
364
    {
365 16
        $html = '';
366 16
        $html .= Html::beginTag('header', $this->headerOptions) . "\n";
367 16
        $html .= Html::tag('p', $this->title, $this->titleOptions) . "\n";
368 16
        $html .= $this->renderCloseButton() . "\n";
369 16
        $html .= Html::endTag('header') . "\n";
370
371 16
        return $html;
372
    }
373
374
    /**
375
     * Body options.
376
     *
377
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
378
     *
379
     * @param array $value
380
     *
381
     * @return self
382
     */
383 1
    public function bodyOptions(array $value): self
384
    {
385 1
        $new = clone $this;
386 1
        $new->bodyOptions = $value;
387
388 1
        return $new;
389
    }
390
391
    /**
392
     * Renders begin body tag.
393
     *
394
     * @throws JsonException
395
     *
396
     * @return string
397
     */
398 16
    private function renderBodyBegin(): string
399
    {
400 16
        return Html::beginTag('section', $this->bodyOptions);
401
    }
402
403
    /**
404
     * Renders end body tag.
405
     *
406
     * @throws JsonException
407
     *
408
     * @return string
409
     */
410 16
    private function renderBodyEnd(): string
411
    {
412 16
        return Html::endTag('section');
413
    }
414
415
    /**
416
     * Footer options
417
     *
418
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
419
     *
420
     * @param array $value
421
     *
422
     * @return self
423
     */
424 1
    public function footerOptions(array $value): self
425
    {
426 1
        $new = clone $this;
427 1
        $new->footerOptions = $value;
428
429 1
        return $new;
430
    }
431
432
    /**
433
     * The footer content in the modal window.
434
     *
435
     * @param string $value
436
     *
437
     * @return self
438
     */
439 1
    public function footer(string $value): self
440
    {
441 1
        $new = clone $this;
442 1
        $new->footer = $value;
443
444 1
        return $new;
445
    }
446
447
    /**
448
     * Title options.
449
     *
450
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
451
     *
452
     * @param array $value
453
     *
454
     * @return self
455
     */
456 1
    public function titleOptions(array $value): self
457
    {
458 1
        $new = clone $this;
459 1
        $new->titleOptions = $value;
460
461 1
        return $new;
462
    }
463
464
    /**
465
     * The title content in the modal window.
466
     *
467
     * @param string $value
468
     *
469
     * @return self
470
     */
471 1
    public function title(string $value): self
472
    {
473 1
        $new = clone $this;
474 1
        $new->title = $value;
475
476 1
        return $new;
477
    }
478
479
    /**
480
     * Renders the footer.
481
     *
482
     * @throws JsonException
483
     *
484
     * @return string
485
     */
486 16
    private function renderFooter(): string
487
    {
488 16
        return Html::tag('footer', $this->footer, $this->footerOptions);
489
    }
490
491
    /**
492
     * Renders the background transparent overlay.
493
     *
494
     * @throws JsonException
495
     *
496
     * @return string
497
     */
498 16
    private function renderBackgroundTransparentOverlay(): string
499
    {
500 16
        return Html::tag('div', '', ['class' => 'modal-background']);
501
    }
502
}
503