Passed
Pull Request — master (#90)
by
unknown
13:09
created

ButtonDropdown::tagName()   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 1
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 RedCatGirl\YiiBootstrap386;
6
7
use Yiisoft\Arrays\ArrayHelper;
8
use Yiisoft\Definitions\Exception\InvalidConfigException;
9
use Yiisoft\Html\Html;
10
11
/**
12
 * ButtonDropdown renders a group or split button dropdown bootstrap component.
13
 *
14
 * For example,
15
 *
16
 * ```php
17
 * // a button group using Dropdown widget
18
 * echo ButtonDropdown::widget()
19
 *     ->label('Action')
20
 *     ->dropdown'([
21
 *         'items' => [
22
 *             ['label' => 'DropdownA', 'url' => '/'],
23
 *             ['label' => 'DropdownB', 'url' => '#'],
24
 *         ],
25
 *     ]);
26
 * ```
27
 */
28
final class ButtonDropdown extends Widget
29
{
30
    /**
31
     * The css class part of dropdown
32
     */
33
    public const DIRECTION_DOWN = 'down';
34
35
    /**
36
     * The css class part of dropleft
37
     */
38
    public const DIRECTION_LEFT = 'left';
39
40
    /**
41
     * The css class part of dropright
42
     */
43
    public const DIRECTION_RIGHT = 'right';
44
45
    /**
46
     * The css class part of dropup
47
     */
48
    public const DIRECTION_UP = 'up';
49
50
    private string $label = 'Button';
51
    private array $options = [];
52
    private array $buttonOptions = [];
53
    private array $dropdown = [];
54
    private string $direction = self::DIRECTION_DOWN;
55
    private bool $split = false;
56
    private string $tagName = 'button';
57
    private bool $encodeLabels = true;
58
    private bool $encodeTags = false;
59
    private string $dropdownClass = Dropdown::class;
60
    private bool $renderContainer = true;
61
62 10
    protected function run(): string
63
    {
64 10
        if (!isset($this->dropdown['items'])) {
65 1
            return '';
66
        }
67
68
        /** Set options id to button options id to ensure correct css selector in plugin initialisation */
69 9
        if (empty($this->options['id'])) {
70 9
            $id = $this->getId();
71
72 9
            $this->options['id'] = "{$id}-button-dropdown";
73 9
            $this->buttonOptions['id'] = "{$id}-button";
74
        }
75
76 9
        $html = $this->renderButton() . "\n" . $this->renderDropdown();
77
78 9
        if ($this->renderContainer) {
79
            /** @psalm-suppress InvalidArgument */
80 8
            Html::addCssClass($this->options, ['widget' => 'drop' . $this->direction, 'btn-group']);
81
82 8
            $options = $this->options;
83 8
            $tag = ArrayHelper::remove($options, 'tag', 'div');
84 8
            $html = Html::tag($tag, $html, $options)
85 8
                ->encode($this->encodeTags)
86 8
                ->render();
87
        }
88
89 9
        return $html;
90
    }
91
92
    /**
93
     * The HTML attributes of the button.
94
     *
95
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
96
     *
97
     * @param array $value
98
     *
99
     * @return self
100
     */
101 1
    public function buttonOptions(array $value): self
102
    {
103 1
        $new = clone $this;
104 1
        $new->buttonOptions = $value;
105
106 1
        return $new;
107
    }
108
109
    /**
110
     * The drop-direction of the widget.
111
     *
112
     * Possible values are 'left', 'right', 'up', or 'down' (default)
113
     *
114
     * @param string $value
115
     *
116
     * @return self
117
     */
118 2
    public function direction(string $value): self
119
    {
120 2
        $new = clone $this;
121 2
        $new->direction = $value;
122
123 2
        return $new;
124
    }
125
126
    /**
127
     * The configuration array for example:
128
     *
129
     * ```php
130
     *    [
131
     *        'items' => [
132
     *            ['label' => 'DropdownA', 'url' => '/'],
133
     *            ['label' => 'DropdownB', 'url' => '#'],
134
     *        ],
135
     *    ]
136
     * ```
137
     *
138
     * {@see Dropdown}
139
     *
140
     * @param array $value
141
     *
142
     * @return self
143
     */
144 9
    public function dropdown(array $value): self
145
    {
146 9
        $new = clone $this;
147 9
        $new->dropdown = $value;
148
149 9
        return $new;
150
    }
151
152
    /**
153
     * Name of a class to use for rendering dropdowns withing this widget. Defaults to {@see Dropdown}.
154
     *
155
     * @param string $value
156
     *
157
     * @return self
158
     */
159 1
    public function dropdownClass(string $value): self
160
    {
161 1
        $new = clone $this;
162 1
        $new->dropdownClass = $value;
163
164 1
        return $new;
165
    }
166
167
    /**
168
     * When tags Labels HTML should not be encoded.
169
     *
170
     * @return self
171
     */
172 1
    public function withoutEncodeLabels(): self
173
    {
174 1
        $new = clone $this;
175 1
        $new->encodeLabels = false;
176
177 1
        return $new;
178
    }
179
180
    /**
181
     * The button label.
182
     *
183
     * @param string $value
184
     *
185
     * @return self
186
     */
187 2
    public function label(string $value): self
188
    {
189 2
        $new = clone $this;
190 2
        $new->label = $value;
191
192 2
        return $new;
193
    }
194
195
    /**
196
     * The HTML attributes for the container tag. The following special options are recognized.
197
     *
198
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
199
     *
200
     * @param array $value
201
     *
202
     * @return self
203
     */
204 1
    public function options(array $value): self
205
    {
206 1
        $new = clone $this;
207 1
        $new->options = $value;
208
209 1
        return $new;
210
    }
211
212
    /**
213
     * Whether to render the container using the {@see options} as HTML attributes. If set to `false`, the container
214
     * element enclosing the button and dropdown will NOT be rendered.
215
     *
216
     * @return self
217
     */
218 1
    public function withoutRenderContainer(): self
219
    {
220 1
        $new = clone $this;
221 1
        $new->renderContainer = false;
222
223 1
        return $new;
224
    }
225
226
    /**
227
     * Whether to display a group of split-styled button group.
228
     *
229
     * @return self
230
     */
231 1
    public function split(): self
232
    {
233 1
        $new = clone $this;
234 1
        $new->split = true;
235
236 1
        return $new;
237
    }
238
239
    /**
240
     * The tag to use to render the button.
241
     *
242
     * @param string $value
243
     *
244
     * @return self
245
     */
246 1
    public function tagName(string $value): self
247
    {
248 1
        $new = clone $this;
249 1
        $new->tagName = $value;
250
251 1
        return $new;
252
    }
253
254
    /**
255
     * Generates the button dropdown.
256
     *
257
     * @throws InvalidConfigException
258
     *
259
     * @return string the rendering result.
260
     */
261 9
    private function renderButton(): string
262
    {
263 9
        Html::addCssClass($this->buttonOptions, ['buttonOptions' => 'btn']);
264
265 9
        $label = $this->label;
266
267 9
        if ($this->encodeLabels !== false) {
268 9
            $label = Html::encode($label);
269
        }
270
271 9
        if ($this->split) {
272 1
            $buttonOptions = $this->buttonOptions;
273
274 1
            $this->buttonOptions['data-bs-toggle'] = 'dropdown';
275 1
            $this->buttonOptions['aria-haspopup'] = 'true';
276 1
            $this->buttonOptions['aria-expanded'] = 'false';
277
278 1
            Html::addCssClass($this->buttonOptions, ['toggle' => 'dropdown-toggle dropdown-toggle-split']);
279
280 1
            unset($buttonOptions['id']);
281
282 1
            $splitButton = Button::widget()
283 1
                ->label('<span class="sr-only">Toggle Dropdown</span>')
0 ignored issues
show
Bug introduced by
The method label() does not exist on Yiisoft\Widget\Widget. It seems like you code against a sub-type of Yiisoft\Widget\Widget such as RedCatGirl\YiiBootstrap386\Button or RedCatGirl\YiiBootstrap386\Progress or RedCatGirl\YiiBootstrap386\ButtonDropdown. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

283
                ->/** @scrutinizer ignore-call */ label('<span class="sr-only">Toggle Dropdown</span>')
Loading history...
284 1
                ->options($this->buttonOptions)
285 1
                ->withoutEncodeLabels()
286 1
                ->render();
287
        } else {
288 8
            $buttonOptions = $this->buttonOptions;
289
290 8
            Html::addCssClass($buttonOptions, ['toggle' => 'dropdown-toggle']);
291
292 8
            $buttonOptions['data-bs-toggle'] = 'dropdown';
293 8
            $buttonOptions['aria-haspopup'] = 'true';
294 8
            $buttonOptions['aria-expanded'] = 'false';
295 8
            $splitButton = '';
296
        }
297
298 9
        if (!isset($buttonOptions['href']) && ($this->tagName === 'a')) {
299 1
            $buttonOptions['href'] = '#';
300 1
            $buttonOptions['role'] = 'button';
301
        }
302
303 9
        $button = Button::widget()
304 9
            ->label($label)
305 9
            ->options($buttonOptions)
306 9
            ->tagName($this->tagName);
307
308 9
        if ($this->encodeLabels === false) {
309 1
            $button = $button->withoutEncodeLabels();
310
        }
311
312 9
        return $button->render() . "\n" . $splitButton;
313
    }
314
315
    /**
316
     * Generates the dropdown menu.
317
     *
318
     * @return string the rendering result.
319
     */
320 9
    private function renderDropdown(): string
321
    {
322 9
        $dropdownClass = $this->dropdownClass;
323
324 9
        $dropdown = $dropdownClass::widget()->items($this->dropdown['items']);
325
326 9
        if ($this->encodeLabels === false) {
327 1
            $dropdown = $dropdown->withoutEncodeLabels();
328
        }
329
330 9
        return $dropdown->render();
331
    }
332
}
333