Modal   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 349
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 29
eloc 135
c 1
b 0
f 0
dl 0
loc 349
ccs 117
cts 117
cp 1
rs 10

20 Methods

Rating   Name   Duplication   Size   Complexity  
A renderToggleButton() 0 21 3
A contentClass() 0 5 1
A renderCloseButton() 0 14 2
A begin() 0 32 4
A withoutToggleButton() 0 5 1
A backgroundClass() 0 5 1
A withoutCloseButton() 0 5 1
A autoIdPrefix() 0 5 1
A toggleButtonSize() 0 10 2
A buttonClass() 0 5 1
A closeButtonSize() 0 10 2
A modalClass() 0 5 1
A toggleButtonAttributes() 0 5 1
A attributes() 0 5 1
A id() 0 5 1
A toggleButtonColor() 0 10 2
A contentAttributes() 0 6 1
A render() 0 6 1
A toggleButtonLabel() 0 5 1
A closeButtonAttributes() 0 5 1
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
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} For details on how attributes are being rendered.
83
     */
84 2
    public function attributes(array $values): self
85
    {
86 2
        $new = clone $this;
87 2
        $new->attributes = $values;
88 2
        return $new;
89
    }
90
91
    /**
92
     * Returns a new instance with the specified prefix to the automatically generated widget IDs.
93
     *
94
     * @param string $value The prefix to the automatically generated widget IDs.
95
     */
96 1
    public function autoIdPrefix(string $value): self
97
    {
98 1
        $new = clone $this;
99 1
        $new->autoIdPrefix = $value;
100 1
        return $new;
101
    }
102
103
    /**
104
     * Returns a new instance with the specified close button options.
105
     *
106
     * @param array $value The close button options.
107
     *
108
     * {@see Html::renderTagAttributes()} For details on how attributes are being rendered.
109
     */
110 2
    public function closeButtonAttributes(array $value): self
111
    {
112 2
        $new = clone $this;
113 2
        $new->closeButtonAttributes = $value;
114 2
        return $new;
115
    }
116
117
    /**
118
     * Returns a new instance with the specified close button size.
119
     *
120
     * @param string $value The close button size. Default setting empty normal.
121
     * Possible values: Modal::SIZE_SMALL, Modal::SIZE_MEDIUM, Model::SIZE_LARGE.
122
     */
123 3
    public function closeButtonSize(string $value): self
124
    {
125 3
        if (!in_array($value, self::SIZE_ALL, true)) {
126 1
            $values = implode('", "', self::SIZE_ALL);
127 1
            throw new InvalidArgumentException("Invalid size. Valid values are: \"$values\".");
128
        }
129
130 2
        $new = clone $this;
131 2
        $new->closeButtonSize = $value;
132 2
        return $new;
133
    }
134
135
    /**
136
     * Returns a new instance with the specified content options.
137
     *
138
     * @param array $value The content options.
139
     *
140
     * {@see Html::renderTagAttributes()} For details on how attributes are being rendered.
141
     */
142 2
    public function contentAttributes(array $value): self
143
    {
144 2
        $new = clone $this;
145 2
        $new->contentAttributes = $value;
146
147 2
        return $new;
148
    }
149
150
    /**
151
     * Returns a new instance with the specified ID of the widget.
152
     *
153
     * @param string $value The ID of the widget.
154
     */
155 1
    public function id(string $value): self
156
    {
157 1
        $new = clone $this;
158 1
        $new->attributes['id'] = $value;
159 1
        return $new;
160
    }
161
162
    /**
163
     * Returns a new instance with the specified modal background class.
164
     *
165
     * @param string $value The modal background class.
166
     */
167 2
    public function backgroundClass(string $value): self
168
    {
169 2
        $new = clone $this;
170 2
        $new->backgroundClass = $value;
171 2
        return $new;
172
    }
173
174
    /**
175
     * Returns a new instance with the specified modal button class.
176
     *
177
     * @param string $value The modal button class.
178
     */
179 2
    public function buttonClass(string $value): self
180
    {
181 2
        $new = clone $this;
182 2
        $new->buttonClass = $value;
183 2
        return $new;
184
    }
185
186
    /**
187
     * Returns a new instance with the specified modal class.
188
     *
189
     * @param string $value The modal class.
190
     */
191 2
    public function modalClass(string $value): self
192
    {
193 2
        $new = clone $this;
194 2
        $new->modalClass = $value;
195 2
        return $new;
196
    }
197
198
    /**
199
     * Returns a new instance with the specified modal content class.
200
     *
201
     * @param string $value The modal content class.
202
     */
203 2
    public function contentClass(string $value): self
204
    {
205 2
        $new = clone $this;
206 2
        $new->contentClass = $value;
207 2
        return $new;
208
    }
209
210
    /**
211
     * Returns a new instance with the specified toggle button options.
212
     *
213
     * @param array $values Attribute values indexed by attribute names.
214
     *
215
     * {@see Html::renderTagAttributes()} For details on how attributes are being rendered.
216
     */
217 2
    public function toggleButtonAttributes(array $values): self
218
    {
219 2
        $new = clone $this;
220 2
        $new->toggleButtonAttributes = $values;
221 2
        return $new;
222
    }
223
224
    /**
225
     * Returns a new instance with the specified toggle button color.
226
     *
227
     * @param string $value The toggle button color. Default setting is empty without color.
228
     * Possible values: Modal::COLOR_PRIMARY, Modal::COLOR_LINK, Modal::COLOR_INFO, Modal::COLOR_SUCCESS,
229
     * Modal::COLOR_WARNING, Modal::COLOR_DANGER, Modal::COLOR_DARK.
230
     */
231 3
    public function toggleButtonColor(string $value): self
232
    {
233 3
        if (!in_array($value, self::COLOR_ALL, true)) {
234 1
            $values = implode('", "', self::COLOR_ALL);
235 1
            throw new InvalidArgumentException("Invalid color. Valid values are: \"$values\".");
236
        }
237
238 2
        $new = clone $this;
239 2
        $new->toggleButtonColor = $value;
240 2
        return $new;
241
    }
242
243
    /**
244
     * Returns a new instance with the specified toggle button label.
245
     *
246
     * @param string $value The toggle button label.
247
     */
248 2
    public function toggleButtonLabel(string $value): self
249
    {
250 2
        $new = clone $this;
251 2
        $new->toggleButtonLabel = $value;
252 2
        return $new;
253
    }
254
255
    /**
256
     * Returns a new instance with the specified toggle button size.
257
     *
258
     * @param string $value The toggle button size. Default setting empty normal.
259
     * Possible values: Modal::SIZE_SMALL, Modal::SIZE_MEDIUM, Model::SIZE_LARGE.
260
     */
261 3
    public function toggleButtonSize(string $value): self
262
    {
263 3
        if (!in_array($value, self::SIZE_ALL, true)) {
264 1
            $values = implode('", "', self::SIZE_ALL);
265 1
            throw new InvalidArgumentException("Invalid size. Valid values are: \"$values\".");
266
        }
267
268 2
        $new = clone $this;
269 2
        $new->toggleButtonSize = $value;
270 2
        return $new;
271
    }
272
273
    /**
274
     * Returns a new instance with the specified options for rendering the close button tag.
275
     *
276
     * @param bool $value Whether the close button is disabled.
277
     */
278 2
    public function withoutCloseButton(bool $value): self
279
    {
280 2
        $new = clone $this;
281 2
        $new->withoutCloseButton = $value;
282 2
        return $new;
283
    }
284
285
    /**
286
     * Returns a new instance with the disabled toggle button.
287
     *
288
     * @param bool $value Whether the toggle button is disabled.
289
     */
290 2
    public function withoutToggleButton(bool $value): self
291
    {
292 2
        $new = clone $this;
293 2
        $new->withoutToggleButton = $value;
294 2
        return $new;
295
    }
296
297 15
    public function begin(): ?string
298
    {
299 15
        parent::begin();
300
301 15
        $attributes = $this->attributes;
302 15
        $contentAttributes = $this->contentAttributes;
303 15
        $html = '';
304
305 15
        if (!array_key_exists('id', $attributes)) {
306 15
            $attributes['id'] = Html::generateId($this->autoIdPrefix) . '-modal';
307
        }
308
309
        /** @var string */
310 15
        $id = $attributes['id'];
311
312 15
        Html::addCssClass($attributes, $this->modalClass);
313 15
        Html::addCssClass($contentAttributes, $this->contentClass);
314
315 15
        if ($this->withoutToggleButton === false) {
316 14
            $html = $this->renderToggleButton($id) . PHP_EOL;
317
        }
318
319 15
        $html .= Html::openTag('div', $attributes) . PHP_EOL; // .modal
320 15
        $html .= Div::tag()->class($this->backgroundClass) . PHP_EOL;
321
322 15
        if ($this->withoutCloseButton === false) {
323 14
            $html .= $this->renderCloseButton() . PHP_EOL;
324
        }
325
326 15
        $html .= Html::openTag('div', $contentAttributes) . PHP_EOL; // .modal-content
327
328 15
        return $html;
329
    }
330
331 15
    public function render(): string
332
    {
333 15
        $html = Html::closeTag('div') . PHP_EOL; // .modal-content
334 15
        $html .= Html::closeTag('div'); // .modal
335
336 15
        return $html;
337
    }
338
339
    /**
340
     * Renders the toggle button.
341
     */
342 14
    private function renderToggleButton(string $id): string
343
    {
344 14
        $toggleButtonAttributes = $this->toggleButtonAttributes;
345
346 14
        $toggleButtonAttributes['data-target'] = '#' . $id;
347 14
        $toggleButtonAttributes['aria-haspopup'] = 'true';
348
349 14
        if ($this->toggleButtonSize !== '') {
350 1
            Html::addCssClass($toggleButtonAttributes, $this->toggleButtonSize);
351
        }
352
353 14
        if ($this->toggleButtonColor !== '') {
354 1
            Html::addCssClass($toggleButtonAttributes, $this->toggleButtonColor);
355
        }
356
357 14
        Html::addCssClass($toggleButtonAttributes, $this->buttonClass);
358
359 14
        return Button::tag()
360 14
            ->attributes($toggleButtonAttributes)
361 14
            ->content($this->toggleButtonLabel)
362 14
            ->render();
363
    }
364
365
    /**
366
     * Renders the close button.
367
     */
368 14
    private function renderCloseButton(): string
369
    {
370 14
        $closeButtonAttributes = $this->closeButtonAttributes;
371 14
        $closeButtonAttributes['aria-label'] = 'close';
372
373 14
        if ($this->closeButtonSize !== '') {
374 1
            Html::addCssClass($closeButtonAttributes, $this->closeButtonSize);
375
        }
376
377 14
        Html::addCssClass($closeButtonAttributes, $this->closeButtonClass);
378
379 14
        return Button::tag()
380 14
            ->attributes($closeButtonAttributes)
381 14
            ->render();
382
    }
383
}
384