1 | <?php |
||||
2 | |||||
3 | declare(strict_types=1); |
||||
4 | |||||
5 | namespace Yiisoft\Yii\Bootstrap4; |
||||
6 | |||||
7 | use Yiisoft\Arrays\ArrayHelper; |
||||
8 | use Yiisoft\Factory\Exceptions\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 | 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 string $dropdownClass = Dropdown::class; |
||||
59 | private bool $renderContainer = true; |
||||
60 | |||||
61 | 3 | protected function run(): string |
|||
62 | { |
||||
63 | /** Set options id to button options id to ensure correct css selector in plugin initialisation */ |
||||
64 | 3 | if (empty($this->options['id'])) { |
|||
65 | 3 | $id = $this->getId(); |
|||
66 | |||||
67 | 3 | $this->options['id'] = "{$id}-button-dropdown"; |
|||
68 | 3 | $this->buttonOptions['id'] = "{$id}-button"; |
|||
69 | } |
||||
70 | |||||
71 | 3 | $html = $this->renderButton() . "\n" . $this->renderDropdown(); |
|||
72 | |||||
73 | 3 | if ($this->renderContainer) { |
|||
74 | 3 | Html::addCssClass($this->options, ['widget' => 'drop' . $this->direction, 'btn-group']); |
|||
75 | |||||
76 | 3 | $options = $this->options; |
|||
77 | 3 | $tag = ArrayHelper::remove($options, 'tag', 'div'); |
|||
78 | 3 | $html = Html::tag($tag, $html, $options); |
|||
79 | } |
||||
80 | |||||
81 | 3 | $this->registerPlugin('dropdown', $this->options); |
|||
82 | |||||
83 | 3 | return $html; |
|||
84 | } |
||||
85 | |||||
86 | /** |
||||
87 | * Generates the button dropdown. |
||||
88 | * |
||||
89 | * @throws InvalidConfigException |
||||
90 | * |
||||
91 | * @return string the rendering result. |
||||
92 | */ |
||||
93 | 3 | protected function renderButton(): string |
|||
94 | { |
||||
95 | 3 | Html::addCssClass($this->buttonOptions, ['widget' => 'btn']); |
|||
96 | |||||
97 | 3 | $label = $this->label; |
|||
98 | |||||
99 | 3 | if ($this->encodeLabels) { |
|||
100 | 3 | $label = Html::encode($label); |
|||
101 | } |
||||
102 | |||||
103 | 3 | if ($this->split) { |
|||
104 | 1 | $buttonOptions = $this->buttonOptions; |
|||
105 | |||||
106 | 1 | $this->buttonOptions['data-toggle'] = 'dropdown'; |
|||
107 | 1 | $this->buttonOptions['aria-haspopup'] = 'true'; |
|||
108 | 1 | $this->buttonOptions['aria-expanded'] = 'false'; |
|||
109 | |||||
110 | 1 | Html::addCssClass($this->buttonOptions, ['toggle' => 'dropdown-toggle dropdown-toggle-split']); |
|||
111 | |||||
112 | 1 | unset($buttonOptions['id']); |
|||
113 | |||||
114 | 1 | $splitButton = Button::widget() |
|||
115 | 1 | ->label('<span class="sr-only">Toggle Dropdown</span>') |
|||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
116 | 1 | ->encodeLabels(false) |
|||
117 | 1 | ->options($this->buttonOptions) |
|||
118 | 1 | ->render(); |
|||
119 | } else { |
||||
120 | 2 | $buttonOptions = $this->buttonOptions; |
|||
121 | |||||
122 | 2 | Html::addCssClass($buttonOptions, ['toggle' => 'dropdown-toggle']); |
|||
123 | |||||
124 | 2 | $buttonOptions['data-toggle'] = 'dropdown'; |
|||
125 | 2 | $buttonOptions['aria-haspopup'] = 'true'; |
|||
126 | 2 | $buttonOptions['aria-expanded'] = 'false'; |
|||
127 | 2 | $splitButton = ''; |
|||
128 | } |
||||
129 | |||||
130 | 3 | if (!isset($buttonOptions['href']) && ($this->tagName === 'a')) { |
|||
131 | $buttonOptions['href'] = '#'; |
||||
132 | $buttonOptions['role'] = 'button'; |
||||
133 | } |
||||
134 | |||||
135 | 3 | return Button::widget() |
|||
136 | 3 | ->tagName($this->tagName) |
|||
0 ignored issues
–
show
The method
tagName() does not exist on Yiisoft\Widget\Widget . It seems like you code against a sub-type of Yiisoft\Widget\Widget such as Yiisoft\Yii\Bootstrap4\Button or Yiisoft\Yii\Bootstrap4\ButtonDropdown .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
137 | 3 | ->label($label) |
|||
138 | 3 | ->options($buttonOptions) |
|||
139 | 3 | ->encodeLabels(false) |
|||
140 | 3 | ->render() |
|||
141 | 3 | . "\n" . $splitButton; |
|||
142 | } |
||||
143 | |||||
144 | /** |
||||
145 | * Generates the dropdown menu. |
||||
146 | * |
||||
147 | * @return string the rendering result. |
||||
148 | */ |
||||
149 | 3 | protected function renderDropdown(): string |
|||
150 | { |
||||
151 | 3 | $dropdownClass = $this->dropdownClass; |
|||
152 | |||||
153 | 3 | return $dropdownClass::widget() |
|||
154 | 3 | ->items($this->dropdown['items']) |
|||
155 | 3 | ->render(); |
|||
156 | } |
||||
157 | |||||
158 | /** |
||||
159 | * The HTML attributes of the button. |
||||
160 | * |
||||
161 | * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered. |
||||
162 | * |
||||
163 | * @param array $value |
||||
164 | * |
||||
165 | * @return $this |
||||
166 | */ |
||||
167 | public function buttonOptions(array $value): self |
||||
168 | { |
||||
169 | $this->buttonOptions = $value; |
||||
170 | |||||
171 | return $this; |
||||
172 | } |
||||
173 | |||||
174 | /** |
||||
175 | * The drop-direction of the widget. |
||||
176 | * |
||||
177 | * Possible values are 'left', 'right', 'up', or 'down' (default) |
||||
178 | * |
||||
179 | * @param string $value |
||||
180 | * |
||||
181 | * @return $this |
||||
182 | */ |
||||
183 | 3 | public function direction(string $value): self |
|||
184 | { |
||||
185 | 3 | $this->direction = $value; |
|||
186 | |||||
187 | 3 | return $this; |
|||
188 | } |
||||
189 | |||||
190 | /** |
||||
191 | * The configuration array for example: |
||||
192 | * |
||||
193 | * ```php |
||||
194 | * [ |
||||
195 | * 'items' => [ |
||||
196 | * ['label' => 'DropdownA', 'url' => '/'], |
||||
197 | * ['label' => 'DropdownB', 'url' => '#'], |
||||
198 | * ], |
||||
199 | * ] |
||||
200 | * ``` |
||||
201 | * |
||||
202 | * {@see Dropdown} |
||||
203 | * |
||||
204 | * @param array $value |
||||
205 | * |
||||
206 | * @return $this |
||||
207 | */ |
||||
208 | 3 | public function dropdown(array $value): self |
|||
209 | { |
||||
210 | 3 | $this->dropdown = $value; |
|||
211 | |||||
212 | 3 | return $this; |
|||
213 | } |
||||
214 | |||||
215 | /** |
||||
216 | * Name of a class to use for rendering dropdowns withing this widget. Defaults to {@see Dropdown}. |
||||
217 | * |
||||
218 | * @param string $value |
||||
219 | * |
||||
220 | * @return $this |
||||
221 | */ |
||||
222 | public function dropdownClass(string $value): self |
||||
223 | { |
||||
224 | $this->dropdownClass = $value; |
||||
225 | |||||
226 | return $this; |
||||
227 | } |
||||
228 | |||||
229 | /** |
||||
230 | * Whether the label should be HTML-encoded. |
||||
231 | * |
||||
232 | * @param bool $value |
||||
233 | * |
||||
234 | * @return $this |
||||
235 | */ |
||||
236 | public function encodeLabels(bool $value): self |
||||
237 | { |
||||
238 | $this->encodeLabels = $value; |
||||
239 | |||||
240 | return $this; |
||||
241 | } |
||||
242 | |||||
243 | /** |
||||
244 | * The button label. |
||||
245 | * |
||||
246 | * @param string $value |
||||
247 | * |
||||
248 | * @return $this |
||||
249 | */ |
||||
250 | 3 | public function label(string $value): self |
|||
251 | { |
||||
252 | 3 | $this->label = $value; |
|||
253 | |||||
254 | 3 | return $this; |
|||
255 | } |
||||
256 | |||||
257 | /** |
||||
258 | * The HTML attributes for the container tag. The following special options are recognized. |
||||
259 | * |
||||
260 | * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered. |
||||
261 | * |
||||
262 | * @param array $value |
||||
263 | * |
||||
264 | * @return $this |
||||
265 | */ |
||||
266 | 1 | public function options(array $value): self |
|||
267 | { |
||||
268 | 1 | $this->options = $value; |
|||
269 | |||||
270 | 1 | return $this; |
|||
271 | } |
||||
272 | |||||
273 | /** |
||||
274 | * Whether to render the container using the {@see options} as HTML attributes. If set to `false`, the container |
||||
275 | * element enclosing the button and dropdown will NOT be rendered. |
||||
276 | * |
||||
277 | * @param bool $value |
||||
278 | * |
||||
279 | * @return $this |
||||
280 | */ |
||||
281 | public function renderContainer(bool $value): self |
||||
282 | { |
||||
283 | $this->renderContainer = $value; |
||||
284 | |||||
285 | return $this; |
||||
286 | } |
||||
287 | |||||
288 | /** |
||||
289 | * Whether to display a group of split-styled button group. |
||||
290 | * |
||||
291 | * @param bool $value |
||||
292 | * |
||||
293 | * @return $this |
||||
294 | */ |
||||
295 | 1 | public function split(bool $value): self |
|||
296 | { |
||||
297 | 1 | $this->split = $value; |
|||
298 | |||||
299 | 1 | return $this; |
|||
300 | } |
||||
301 | |||||
302 | /** |
||||
303 | * The tag to use to render the button. |
||||
304 | * |
||||
305 | * @param string $value |
||||
306 | * |
||||
307 | * @return $this |
||||
308 | */ |
||||
309 | public function tagName(string $value): self |
||||
310 | { |
||||
311 | $this->tagName = $value; |
||||
312 | |||||
313 | return $this; |
||||
314 | } |
||||
315 | } |
||||
316 |