Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 153 |
|
0.00% |
0 / 11 |
CRAP | |
0.00% |
0 / 1 |
OOUIHTMLForm | |
0.00% |
0 / 152 |
|
0.00% |
0 / 11 |
2256 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
loadInputFromParameters | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
getButtons | |
0.00% |
0 / 51 |
|
0.00% |
0 / 1 |
210 | |||
wrapFieldSetSection | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
2 | |||
formatField | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
formatSection | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
getErrorsOrWarnings | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
182 | |||
getHeaderHtml | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
formatFormHeader | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
56 | |||
getBody | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
wrapForm | |
0.00% |
0 / 24 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | |
3 | namespace MediaWiki\HTMLForm; |
4 | |
5 | /** |
6 | * HTML form generation and submission handling, OOUI style. |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. |
12 | * |
13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU General Public License along |
19 | * with this program; if not, write to the Free Software Foundation, Inc., |
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
21 | * http://www.gnu.org/copyleft/gpl.html |
22 | * |
23 | * @file |
24 | */ |
25 | |
26 | use DomainException; |
27 | use MediaWiki\Html\Html; |
28 | use MediaWiki\Linker\Linker; |
29 | use MediaWiki\Parser\Sanitizer; |
30 | use MediaWiki\Status\Status; |
31 | |
32 | /** |
33 | * Compact stacked vertical format for forms, implemented using OOUI widgets. |
34 | * |
35 | * @stable to extend |
36 | */ |
37 | class OOUIHTMLForm extends HTMLForm { |
38 | /** @var array */ |
39 | private $oouiErrors; |
40 | /** @var array */ |
41 | private $oouiWarnings; |
42 | |
43 | /** |
44 | * @stable to call |
45 | * @inheritDoc |
46 | */ |
47 | public function __construct( $descriptor, $context = null, $messagePrefix = '' ) { |
48 | parent::__construct( $descriptor, $context, $messagePrefix ); |
49 | $this->getOutput()->enableOOUI(); |
50 | $this->getOutput()->addModuleStyles( 'mediawiki.htmlform.ooui.styles' ); |
51 | } |
52 | |
53 | /** @inheritDoc */ |
54 | protected $displayFormat = 'ooui'; |
55 | |
56 | public static function loadInputFromParameters( $fieldname, $descriptor, |
57 | ?HTMLForm $parent = null |
58 | ) { |
59 | $field = parent::loadInputFromParameters( $fieldname, $descriptor, $parent ); |
60 | $field->setShowEmptyLabel( false ); |
61 | return $field; |
62 | } |
63 | |
64 | public function getButtons() { |
65 | $buttons = ''; |
66 | |
67 | if ( $this->mShowSubmit ) { |
68 | $attribs = [ |
69 | 'infusable' => true, |
70 | 'classes' => [ 'mw-htmlform-submit' ], |
71 | 'type' => 'submit', |
72 | 'label' => $this->getSubmitText(), |
73 | 'value' => $this->getSubmitText(), |
74 | 'flags' => $this->mSubmitFlags, |
75 | ]; |
76 | |
77 | if ( $this->mSubmitID !== null ) { |
78 | $attribs['id'] = $this->mSubmitID; |
79 | } |
80 | |
81 | if ( $this->mSubmitName !== null ) { |
82 | $attribs['name'] = $this->mSubmitName; |
83 | } |
84 | |
85 | if ( $this->mSubmitTooltip !== null ) { |
86 | $attribs += [ |
87 | 'title' => Linker::titleAttrib( $this->mSubmitTooltip ), |
88 | 'accessKey' => Linker::accesskey( $this->mSubmitTooltip ), |
89 | ]; |
90 | } |
91 | |
92 | $buttons .= new \OOUI\ButtonInputWidget( $attribs ); |
93 | } |
94 | |
95 | if ( $this->mShowCancel ) { |
96 | $buttons .= new \OOUI\ButtonWidget( [ |
97 | 'label' => $this->msg( 'cancel' )->text(), |
98 | 'href' => $this->getCancelTargetURL(), |
99 | ] ); |
100 | } |
101 | |
102 | foreach ( $this->mButtons as $button ) { |
103 | $attrs = []; |
104 | |
105 | // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset Always set in HTMLForm::addButton |
106 | if ( $button['attribs'] ) { |
107 | // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset Always set in HTMLForm::addButton |
108 | $attrs += $button['attribs']; |
109 | } |
110 | |
111 | if ( isset( $button['id'] ) ) { |
112 | $attrs['id'] = $button['id']; |
113 | } |
114 | |
115 | if ( isset( $button['label-message'] ) ) { |
116 | $label = new \OOUI\HtmlSnippet( $this->getMessage( $button['label-message'] )->parse() ); |
117 | } elseif ( isset( $button['label'] ) ) { |
118 | $label = $button['label']; |
119 | } elseif ( isset( $button['label-raw'] ) ) { |
120 | $label = new \OOUI\HtmlSnippet( $button['label-raw'] ); |
121 | } else { |
122 | $label = $button['value']; |
123 | } |
124 | |
125 | $attrs['classes'] = isset( $attrs['class'] ) ? (array)$attrs['class'] : []; |
126 | |
127 | $buttons .= new \OOUI\ButtonInputWidget( [ |
128 | 'type' => 'submit', |
129 | 'name' => $button['name'], |
130 | 'value' => $button['value'], |
131 | 'label' => $label, |
132 | // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset Always set in HTMLForm::addButton |
133 | 'flags' => $button['flags'], |
134 | // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset Always set in HTMLForm::addButton |
135 | 'framed' => $button['framed'], |
136 | ] + $attrs ); |
137 | } |
138 | |
139 | if ( !$buttons ) { |
140 | return ''; |
141 | } |
142 | |
143 | return Html::rawElement( 'div', |
144 | [ 'class' => 'mw-htmlform-submit-buttons' ], "\n$buttons" ) . "\n"; |
145 | } |
146 | |
147 | /** |
148 | * @inheritDoc |
149 | * @return \OOUI\PanelLayout |
150 | */ |
151 | protected function wrapFieldSetSection( $legend, $section, $attributes, $isRoot ) { |
152 | // to get a user visible effect, wrap the fieldset into a framed panel layout |
153 | $layout = new \OOUI\PanelLayout( [ |
154 | 'expanded' => false, |
155 | 'padded' => true, |
156 | 'framed' => true, |
157 | ] ); |
158 | |
159 | $layout->appendContent( |
160 | new \OOUI\FieldsetLayout( [ |
161 | 'label' => $legend, |
162 | 'items' => [ |
163 | new \OOUI\Widget( [ |
164 | 'content' => new \OOUI\HtmlSnippet( $section ) |
165 | ] ), |
166 | ], |
167 | ] + $attributes ) |
168 | ); |
169 | return $layout; |
170 | } |
171 | |
172 | /** |
173 | * @inheritDoc |
174 | * @return \OOUI\FieldLayout HTML |
175 | */ |
176 | protected function formatField( HTMLFormField $field, $value ) { |
177 | return $field->getOOUI( $value ); |
178 | } |
179 | |
180 | /** |
181 | * Put a form section together from the individual fields' HTML, merging it and wrapping. |
182 | * @param \OOUI\FieldLayout[] $fieldsHtml Array of outputs from formatField() |
183 | * @param string $sectionName |
184 | * @param bool $anyFieldHasLabel Unused |
185 | * @return string HTML |
186 | */ |
187 | protected function formatSection( array $fieldsHtml, $sectionName, $anyFieldHasLabel ) { |
188 | if ( !$fieldsHtml ) { |
189 | // Do not generate any wrappers for empty sections. Sections may be empty if they only have |
190 | // subsections, but no fields. A legend will still be added in wrapFieldSetSection(). |
191 | return ''; |
192 | } |
193 | |
194 | $html = implode( '', $fieldsHtml ); |
195 | |
196 | if ( $sectionName ) { |
197 | return Html::rawElement( |
198 | 'div', |
199 | [ 'id' => Sanitizer::escapeIdForAttribute( $sectionName ) ], |
200 | $html |
201 | ); |
202 | } |
203 | return $html; |
204 | } |
205 | |
206 | /** |
207 | * @param string|array|Status $elements |
208 | * @param string $elementsType |
209 | * @return string |
210 | */ |
211 | public function getErrorsOrWarnings( $elements, $elementsType ) { |
212 | if ( $elements === '' ) { |
213 | return ''; |
214 | } |
215 | |
216 | if ( !in_array( $elementsType, [ 'error', 'warning' ], true ) ) { |
217 | throw new DomainException( $elementsType . ' is not a valid type.' ); |
218 | } |
219 | $errors = []; |
220 | if ( $elements instanceof Status ) { |
221 | if ( !$elements->isGood() ) { |
222 | foreach ( $elements->getMessages( $elementsType ) as $msg ) { |
223 | $errors[] = $this->getMessage( $msg )->parse(); |
224 | } |
225 | } |
226 | } elseif ( $elementsType === 'error' ) { |
227 | if ( is_array( $elements ) ) { |
228 | foreach ( $elements as $error ) { |
229 | $errors[] = $this->getMessage( $error )->parse(); |
230 | } |
231 | } elseif ( $elements && $elements !== true ) { |
232 | $errors[] = (string)$elements; |
233 | } |
234 | } |
235 | |
236 | foreach ( $errors as &$error ) { |
237 | $error = new \OOUI\HtmlSnippet( $error ); |
238 | } |
239 | |
240 | // Used in formatFormHeader() |
241 | if ( $elementsType === 'error' ) { |
242 | $this->oouiErrors = $errors; |
243 | } else { |
244 | $this->oouiWarnings = $errors; |
245 | } |
246 | return ''; |
247 | } |
248 | |
249 | public function getHeaderHtml( $section = null ) { |
250 | if ( $section === null ) { |
251 | // We handle $this->mHeader elsewhere, in getBody() |
252 | return ''; |
253 | } else { |
254 | return parent::getHeaderHtml( $section ); |
255 | } |
256 | } |
257 | |
258 | protected function formatFormHeader() { |
259 | if ( !( $this->mHeader || $this->oouiErrors || $this->oouiWarnings ) ) { |
260 | return ''; |
261 | } |
262 | $classes = [ |
263 | 'mw-htmlform-ooui-header', |
264 | ...$this->oouiErrors ? [ 'mw-htmlform-ooui-header-errors' ] : [], |
265 | ...$this->oouiWarnings ? [ 'mw-htmlform-ooui-header-warnings' ] : [], |
266 | ]; |
267 | // if there's no header, don't create an (empty) LabelWidget, simply use a placeholder |
268 | if ( $this->mHeader ) { |
269 | $element = new \OOUI\LabelWidget( [ 'label' => new \OOUI\HtmlSnippet( $this->mHeader ) ] ); |
270 | } else { |
271 | $element = new \OOUI\Widget( [] ); |
272 | } |
273 | return new \OOUI\FieldLayout( |
274 | $element, |
275 | [ |
276 | 'align' => 'top', |
277 | 'errors' => $this->oouiErrors, |
278 | 'notices' => $this->oouiWarnings, |
279 | 'classes' => $classes, |
280 | ] |
281 | ); |
282 | } |
283 | |
284 | public function getBody() { |
285 | return $this->formatFormHeader() . parent::getBody(); |
286 | } |
287 | |
288 | public function wrapForm( $html ) { |
289 | if ( is_string( $this->mWrapperLegend ) ) { |
290 | $phpClass = $this->mCollapsible ? CollapsibleFieldsetLayout::class : \OOUI\FieldsetLayout::class; |
291 | $content = new $phpClass( [ |
292 | 'label' => $this->mWrapperLegend, |
293 | 'collapsed' => $this->mCollapsed, |
294 | 'items' => [ |
295 | new \OOUI\Widget( [ |
296 | 'content' => new \OOUI\HtmlSnippet( $html ) |
297 | ] ), |
298 | ], |
299 | ] + \OOUI\Element::configFromHtmlAttributes( $this->mWrapperAttributes ) ); |
300 | } else { |
301 | $content = new \OOUI\HtmlSnippet( $html ); |
302 | } |
303 | |
304 | $form = new \OOUI\FormLayout( $this->getFormAttributes() + [ |
305 | 'classes' => [ 'mw-htmlform', 'mw-htmlform-ooui' ], |
306 | 'content' => $content, |
307 | ] ); |
308 | |
309 | // Include a wrapper for style, if requested. |
310 | $form = new \OOUI\PanelLayout( [ |
311 | 'classes' => [ 'mw-htmlform-ooui-wrapper' ], |
312 | 'expanded' => false, |
313 | 'padded' => $this->mWrapperLegend !== false, |
314 | 'framed' => $this->mWrapperLegend !== false, |
315 | 'content' => $form, |
316 | ] ); |
317 | |
318 | return $form; |
319 | } |
320 | } |
321 | |
322 | /** @deprecated class alias since 1.42 */ |
323 | class_alias( OOUIHTMLForm::class, 'OOUIHTMLForm' ); |