Passed
Pull Request — master (#79)
by Wilmer
02:24
created

Modal::render()   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\Bulma;
6
7
use InvalidArgumentException;
8
use Yiisoft\Html\Html;
9
use Yiisoft\Html\Tag\Div;
10
use Yiisoft\Html\Tag\Button;
11
use Yiisoft\Widget\Widget;
12
13
use function array_key_exists;
14
use function implode;
15
use function in_array;
16
17
/**
18
 * Modal renders a modal window that can be toggled by clicking on a button.
19
 *
20
 * The following example will show the content enclosed between the {@see Widget::begin()} and {@see Widget::end()}
21
 * calls within the modal window:
22
 *
23
 * ```php
24
 * echo Modal::widget()->begin();
25
 *
26
 * echo 'Say hello...';
27
 *
28
 * echo Modal::end();
29
 * ```
30
 *
31
 * @link https://bulma.io/documentation/components/modal/
32
 */
33
final class Modal extends Widget
34
{
35
    public const SIZE_SMALL = 'is-small';
36
    public const SIZE_MEDIUM = 'is-medium';
37
    public const SIZE_LARGE = 'is-large';
38
    private const SIZE_ALL = [
39
        self::SIZE_SMALL,
40
        self::SIZE_MEDIUM,
41
        self::SIZE_LARGE,
42
    ];
43
44
    public const COLOR_PRIMARY = 'is-primary';
45
    public const COLOR_LINK = 'is-link';
46
    public const COLOR_INFO = 'is-info';
47
    public const COLOR_SUCCESS = 'is-success';
48
    public const COLOR_WARNING = 'is-warning';
49
    public const COLOR_DANGER = 'is-danger';
50
    public const COLOR_DARK = 'is-dark';
51
    private const COLOR_ALL = [
52
        self::COLOR_PRIMARY,
53
        self::COLOR_LINK,
54
        self::COLOR_INFO,
55
        self::COLOR_SUCCESS,
56
        self::COLOR_WARNING,
57
        self::COLOR_DANGER,
58
        self::COLOR_DARK,
59
    ];
60
    private array $attributes = [];
61
    private string $autoIdPrefix = 'w';
62
    private string $backgroundClass = 'modal-background';
63
    private string $buttonClass = 'button modal-button';
64
    private array $closeButtonAttributes = [];
65
    private string $closeButtonClass = 'modal-close';
66
    private string $closeButtonSize = '';
67
    private array $contentAttributes = [];
68
    private string $contentClass = 'modal-content';
69
    private string $modalClass = 'modal';
70
    private array $toggleButtonAttributes = [];
71
    private string $toggleButtonLabel = 'Toggle button';
72
    private string $toggleButtonSize = '';
73
    private string $toggleButtonColor = '';
74
    private bool $withoutCloseButton = false;
75
    private bool $withoutToggleButton = false;
76
77
    /**
78
     * Returns a new instance with the specified HTML attributes for widget.
79
     *
80
     * @param array $values Attribute values indexed by attribute names.
81
     *
82
     * @return self
83
     *
84
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} For details on how attributes are being rendered.
85
     */
86 2
    public function attributes(array $values): self
87
    {
88 2
        $new = clone $this;
89 2
        $new->attributes = $values;
90 2
        return $new;
91
    }
92
93
    /**
94
     * Returns a new instance with the specified prefix to the automatically generated widget IDs.
95
     *
96
     * @param string $value The prefix to the automatically generated widget IDs.
97
     *
98
     * @return self
99
     */
100 1
    public function autoIdPrefix(string $value): self
101
    {
102 1
        $new = clone $this;
103 1
        $new->autoIdPrefix = $value;
104 1
        return $new;
105
    }
106
107
    /**
108
     * Returns a new instance with the specified close button options.
109
     *
110
     * @param array $value The close button options.
111
     *
112
     * {@see Html::renderTagAttributes()} For details on how attributes are being rendered.
113
     *
114
     * @return self
115
     */
116 2
    public function closeButtonAttributes(array $value): self
117
    {
118 2
        $new = clone $this;
119 2
        $new->closeButtonAttributes = $value;
120 2
        return $new;
121
    }
122
123
    /**
124
     * Returns a new instance with the specified close button size.
125
     *
126
     * @param string $value The close button size. Default setting empty normal.
127
     * Possible values: Modal::SIZE_SMALL, Modal::SIZE_MEDIUM, Model::SIZE_LARGE.
128
     *
129
     * @return self
130
     */
131 3
    public function closeButtonSize(string $value): self
132
    {
133 3
        if (!in_array($value, self::SIZE_ALL, true)) {
134 1
            $values = implode('", "', self::SIZE_ALL);
135 1
            throw new InvalidArgumentException("Invalid size. Valid values are: \"$values\".");
136
        }
137
138 2
        $new = clone $this;
139 2
        $new->closeButtonSize = $value;
140 2
        return $new;
141
    }
142
143
    /**
144
     * Returns a new instance with the specified content options.
145
     *
146
     * @param array $value The content options.
147
     *
148
     * {@see Html::renderTagAttributes()} For details on how attributes are being rendered.
149
     *
150
     * @return self
151
     */
152 2
    public function contentAttributes(array $value): self
153
    {
154 2
        $new = clone $this;
155 2
        $new->contentAttributes = $value;
156
157 2
        return $new;
158
    }
159
160
    /**
161
     * Returns a new instance with the specified ID of the widget.
162
     *
163
     * @param string $value The ID of the widget.
164
     *
165
     * @return self
166
     */
167 1
    public function id(string $value): self
168
    {
169 1
        $new = clone $this;
170 1
        $new->attributes['id'] = $value;
171 1
        return $new;
172
    }
173
174
    /**
175
     * Returns a new instance with the specified modal background class.
176
     *
177
     * @param string $value The modal background class.
178
     *
179
     * @return self
180
     */
181 2
    public function backgroundClass(string $value): self
182
    {
183 2
        $new = clone $this;
184 2
        $new->backgroundClass = $value;
185 2
        return $new;
186
    }
187
188
    /**
189
     * Returns a new instance with the specified modal button class.
190
     *
191
     * @param string $value The modal button class.
192
     *
193
     * @return self
194
     */
195 2
    public function buttonClass(string $value): self
196
    {
197 2
        $new = clone $this;
198 2
        $new->buttonClass = $value;
199 2
        return $new;
200
    }
201
202
    /**
203
     * Returns a new instance with the specified modal class.
204
     *
205
     * @param string $value The modal class.
206
     *
207
     * @return self
208
     */
209 2
    public function modalClass(string $value): self
210
    {
211 2
        $new = clone $this;
212 2
        $new->modalClass = $value;
213 2
        return $new;
214
    }
215
216
    /**
217
     * Returns a new instance with the specified modal content class.
218
     *
219
     * @param string $value The modal content class.
220
     *
221
     * @return self
222
     */
223 2
    public function contentClass(string $value): self
224
    {
225 2
        $new = clone $this;
226 2
        $new->contentClass = $value;
227 2
        return $new;
228
    }
229
230
    /**
231
     * Returns a new instance with the specified toggle button options.
232
     *
233
     * @param array $values Attribute values indexed by attribute names.
234
     *
235
     * {@see Html::renderTagAttributes()} For details on how attributes are being rendered.
236
     *
237
     * @return self
238
     */
239 2
    public function toggleButtonAttributes(array $values): self
240
    {
241 2
        $new = clone $this;
242 2
        $new->toggleButtonAttributes = $values;
243 2
        return $new;
244
    }
245
246
    /**
247
     * Returns a new instance with the specified toggle button color.
248
     *
249
     * @param string $value The toggle button color. Default setting is empty without color.
250
     * Possible values: Modal::COLOR_PRIMARY, Modal::COLOR_LINK, Modal::COLOR_INFO, Modal::COLOR_SUCCESS,
251
     * Modal::COLOR_WARNING, Modal::COLOR_DANGER, Modal::COLOR_DARK.
252
     *
253
     * @return self
254
     */
255 3
    public function toggleButtonColor(string $value): self
256
    {
257 3
        if (!in_array($value, self::COLOR_ALL, true)) {
258 1
            $values = implode('", "', self::COLOR_ALL);
259 1
            throw new InvalidArgumentException("Invalid color. Valid values are: \"$values\".");
260
        }
261
262 2
        $new = clone $this;
263 2
        $new->toggleButtonColor = $value;
264 2
        return $new;
265
    }
266
267
    /**
268
     * Returns a new instance with the specified toggle button label.
269
     *
270
     * @param string $value The toggle button label.
271
     *
272
     * @return self
273
     */
274 2
    public function toggleButtonLabel(string $value): self
275
    {
276 2
        $new = clone $this;
277 2
        $new->toggleButtonLabel = $value;
278 2
        return $new;
279
    }
280
281
    /**
282
     * Returns a new instance with the specified toggle button size.
283
     *
284
     * @param string $value The toggle button size. Default setting empty normal.
285
     * Possible values: Modal::SIZE_SMALL, Modal::SIZE_MEDIUM, Model::SIZE_LARGE.
286
     *
287
     * @return self
288
     */
289 3
    public function toggleButtonSize(string $value): self
290
    {
291 3
        if (!in_array($value, self::SIZE_ALL, true)) {
292 1
            $values = implode('", "', self::SIZE_ALL);
293 1
            throw new InvalidArgumentException("Invalid size. Valid values are: \"$values\".");
294
        }
295
296 2
        $new = clone $this;
297 2
        $new->toggleButtonSize = $value;
298 2
        return $new;
299
    }
300
301
    /**
302
     * Returns a new instance with the specified options for rendering the close button tag.
303
     *
304
     * @param bool $value Whether the close button is disabled.
305
     *
306
     * @return self
307
     */
308 2
    public function withoutCloseButton(bool $value): self
309
    {
310 2
        $new = clone $this;
311 2
        $new->withoutCloseButton = $value;
312 2
        return $new;
313
    }
314
315
    /**
316
     * Returns a new instance with the disabled toggle button.
317
     *
318
     * @param bool $value Whether the toggle button is disabled.
319
     *
320
     * @return self
321
     */
322 2
    public function withoutToggleButton(bool $value): self
323
    {
324 2
        $new = clone $this;
325 2
        $new->withoutToggleButton = $value;
326 2
        return $new;
327
    }
328
329 15
    public function begin(): ?string
330
    {
331 15
        parent::begin();
332
333 15
        $attributes = $this->attributes;
334 15
        $contentAttributes = $this->contentAttributes;
335 15
        $html = '';
336
337 15
        if (!array_key_exists('id', $attributes)) {
338 15
            $attributes['id'] = Html::generateId($this->autoIdPrefix) . '-modal';
339
        }
340
341
        /** @var string */
342 15
        $id = $attributes['id'];
343
344 15
        Html::addCssClass($attributes, $this->modalClass);
345 15
        Html::addCssClass($contentAttributes, $this->contentClass);
346
347 15
        if ($this->withoutToggleButton === false) {
348 14
            $html = $this->renderToggleButton($id) . PHP_EOL;
349
        }
350
351 15
        $html .= Html::openTag('div', $attributes) . PHP_EOL; // .modal
352 15
        $html .= Div::tag()->class($this->backgroundClass) . PHP_EOL;
353
354 15
        if ($this->withoutCloseButton === false) {
355 14
            $html .= $this->renderCloseButton() . PHP_EOL;
356
        }
357
358 15
        $html .= Html::openTag('div', $contentAttributes) . PHP_EOL; // .modal-content
359
360 15
        return $html;
361
    }
362
363 15
    public function render(): string
364
    {
365 15
        $html = Html::closeTag('div') . PHP_EOL; // .modal-content
366 15
        $html .= Html::closeTag('div'); // .modal
367
368 15
        return $html;
369
    }
370
371
    /**
372
     * Renders the toggle button.
373
     *
374
     * @param string $id
375
     *
376
     * @return string
377
     */
378 14
    private function renderToggleButton(string $id): string
379
    {
380 14
        $toggleButtonAttributes = $this->toggleButtonAttributes;
381
382 14
        $toggleButtonAttributes['data-target'] = '#' . $id;
383 14
        $toggleButtonAttributes['aria-haspopup'] = 'true';
384
385 14
        if ($this->toggleButtonSize !== '') {
386 1
            Html::addCssClass($toggleButtonAttributes, $this->toggleButtonSize);
387
        }
388
389 14
        if ($this->toggleButtonColor !== '') {
390 1
            Html::addCssClass($toggleButtonAttributes, $this->toggleButtonColor);
391
        }
392
393 14
        Html::addCssClass($toggleButtonAttributes, $this->buttonClass);
394
395 14
        return Button::tag()
396 14
            ->attributes($toggleButtonAttributes)
397 14
            ->content($this->toggleButtonLabel)
398 14
            ->render();
399
    }
400
401
    /**
402
     * Renders the close button.
403
     *
404
     * @return string
405
     */
406 14
    private function renderCloseButton(): string
407
    {
408 14
        $closeButtonAttributes = $this->closeButtonAttributes;
409 14
        $closeButtonAttributes['aria-label'] = 'close';
410
411 14
        if ($this->closeButtonSize !== '') {
412 1
            Html::addCssClass($closeButtonAttributes, $this->closeButtonSize);
413
        }
414
415 14
        Html::addCssClass($closeButtonAttributes, $this->closeButtonClass);
416
417 14
        return Button::tag()
418 14
            ->attributes($closeButtonAttributes)
419 14
            ->render();
420
    }
421
}
422