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