Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
65.69% |
157 / 239 |
|
41.67% |
15 / 36 |
CRAP | |
0.00% |
0 / 1 |
Xml | |
65.97% |
157 / 238 |
|
41.67% |
15 / 36 |
401.25 | |
0.00% |
0 / 1 |
element | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
5 | |||
expandAttributes | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
elementClean | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
openElement | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
closeElement | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
tags | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
monthSelector | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
3 | |||
dateMenu | |
100.00% |
19 / 19 |
|
100.00% |
1 / 1 |
6 | |||
languageSelector | |
90.48% |
19 / 21 |
|
0.00% |
0 / 1 |
5.02 | |||
span | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
wrapClass | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
input | |
83.33% |
5 / 6 |
|
0.00% |
0 / 1 |
3.04 | |||
password | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
attrib | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
check | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
radio | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
label | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
inputLabel | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
inputLabelSep | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
checkLabel | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
radioLabel | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
submitButton | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
option | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
listDropdown | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
3 | |||
listDropdownOptions | |
86.36% |
19 / 22 |
|
0.00% |
0 / 1 |
11.31 | |||
listDropdownOptionsOoui | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
4 | |||
fieldset | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
3 | |||
textarea | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 | |||
encodeJsVar | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
encodeJsCall | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isWellFormed | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
isWellFormedXmlFragment | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
escapeTagsOnly | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
buildForm | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
12 | |||
buildTable | |
87.50% |
14 / 16 |
|
0.00% |
0 / 1 |
6.07 | |||
buildTableRow | |
87.50% |
7 / 8 |
|
0.00% |
0 / 1 |
3.02 |
1 | <?php |
2 | /** |
3 | * Methods to generate XML. |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License along |
16 | * with this program; if not, write to the Free Software Foundation, Inc., |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | * http://www.gnu.org/copyleft/gpl.html |
19 | * |
20 | * @file |
21 | */ |
22 | |
23 | namespace MediaWiki\Xml; |
24 | |
25 | use MediaWiki\Html\Html; |
26 | use MediaWiki\Languages\LanguageNameUtils; |
27 | use MediaWiki\MainConfigNames; |
28 | use MediaWiki\MediaWikiServices; |
29 | use MediaWiki\Message\Message; |
30 | use MediaWiki\Parser\Sanitizer; |
31 | use MediaWiki\Utils\MWTimestamp; |
32 | use UtfNormal\Validator; |
33 | |
34 | /** |
35 | * Module of static functions for generating XML |
36 | */ |
37 | class Xml { |
38 | /** |
39 | * Format an XML element with given attributes and, optionally, text content. |
40 | * Element and attribute names are assumed to be ready for literal inclusion. |
41 | * Strings are assumed to not contain XML-illegal characters; special |
42 | * characters (<, >, &) are escaped but illegals are not touched. |
43 | * |
44 | * @param string $element Element name |
45 | * @param-taint $element tainted |
46 | * @param array|null $attribs Name=>value pairs. Values will be escaped. |
47 | * @param-taint $attribs escapes_html |
48 | * @param string|null $contents Null to make an open tag only; '' for a contentless closed tag (default) |
49 | * @param-taint $contents escapes_html |
50 | * @param bool $allowShortTag Whether '' in $contents will result in a contentless closed tag |
51 | * @return string |
52 | * @return-taint escaped |
53 | */ |
54 | public static function element( $element, $attribs = null, $contents = '', |
55 | $allowShortTag = true |
56 | ) { |
57 | $out = '<' . $element; |
58 | if ( $attribs !== null ) { |
59 | $out .= self::expandAttributes( $attribs ); |
60 | } |
61 | if ( $contents === null ) { |
62 | $out .= '>'; |
63 | } elseif ( $allowShortTag && $contents === '' ) { |
64 | $out .= ' />'; |
65 | } else { |
66 | $out .= '>' . htmlspecialchars( $contents, ENT_NOQUOTES ) . "</$element>"; |
67 | } |
68 | return $out; |
69 | } |
70 | |
71 | /** |
72 | * Given an array of ('attributename' => 'value'), it generates the code |
73 | * to set the XML attributes : attributename="value". |
74 | * The values are passed to Sanitizer::encodeAttribute. |
75 | * Returns null or empty string if no attributes given. |
76 | * @param array|null $attribs Array of attributes for an XML element |
77 | * @return null|string |
78 | */ |
79 | public static function expandAttributes( ?array $attribs ) { |
80 | if ( $attribs === null ) { |
81 | return null; |
82 | } |
83 | $out = ''; |
84 | foreach ( $attribs as $name => $val ) { |
85 | $out .= " {$name}=\"" . Sanitizer::encodeAttribute( $val ) . '"'; |
86 | } |
87 | return $out; |
88 | } |
89 | |
90 | /** |
91 | * Format an XML element as with self::element(), but run text through the content language's |
92 | * normalize() validator first to ensure that no invalid UTF-8 is passed. |
93 | * |
94 | * @param string $element |
95 | * @param array|null $attribs Name=>value pairs. Values will be escaped. |
96 | * @param string|null $contents Null to make an open tag only; '' for a contentless closed tag (default) |
97 | * @return string |
98 | * @param-taint $attribs escapes_html |
99 | * @param-taint $contents escapes_html |
100 | */ |
101 | public static function elementClean( $element, $attribs = [], $contents = '' ) { |
102 | if ( $attribs ) { |
103 | $attribs = array_map( [ Validator::class, 'cleanUp' ], $attribs ); |
104 | } |
105 | if ( $contents ) { |
106 | $contents = |
107 | MediaWikiServices::getInstance()->getContentLanguage()->normalize( $contents ); |
108 | } |
109 | return self::element( $element, $attribs, $contents ); |
110 | } |
111 | |
112 | /** |
113 | * This opens an XML element |
114 | * |
115 | * @param string $element Name of the element |
116 | * @param array|null $attribs Array of attributes, see Xml::expandAttributes() |
117 | * @return string |
118 | */ |
119 | public static function openElement( $element, $attribs = null ) { |
120 | return '<' . $element . self::expandAttributes( $attribs ) . '>'; |
121 | } |
122 | |
123 | /** |
124 | * Shortcut to close an XML element |
125 | * @param string $element Element name |
126 | * @return string |
127 | */ |
128 | public static function closeElement( $element ) { |
129 | return "</$element>"; |
130 | } |
131 | |
132 | /** |
133 | * Same as Xml::element(), but does not escape contents. Handy when the |
134 | * content you have is already valid xml. |
135 | * |
136 | * @param string $element Element name |
137 | * @param-taint $element tainted |
138 | * @param array|null $attribs Array of attributes |
139 | * @param-taint $attribs escapes_html |
140 | * @param string $contents Content of the element |
141 | * @param-taint $contents tainted |
142 | * @return string |
143 | * @return-taint escaped |
144 | */ |
145 | public static function tags( $element, $attribs, $contents ) { |
146 | return self::openElement( $element, $attribs ) . $contents . "</$element>"; |
147 | } |
148 | |
149 | /** |
150 | * Create a date selector |
151 | * |
152 | * @param string|null $selected The month which should be selected, default ''. |
153 | * @param string|null $allmonths Value of a special item denoting all month. |
154 | * Null to not include (default). |
155 | * @param string $id Element identifier |
156 | * @return string Html string containing the month selector |
157 | * |
158 | * @deprecated since 1.42 |
159 | */ |
160 | public static function monthSelector( $selected = '', $allmonths = null, $id = 'month' ) { |
161 | wfDeprecated( __METHOD__, '1.42' ); |
162 | |
163 | global $wgLang; |
164 | $options = []; |
165 | |
166 | $data = new XmlSelect( 'month', $id, $selected ?? '' ); |
167 | |
168 | if ( $allmonths !== null ) { |
169 | $options[wfMessage( 'monthsall' )->text()] = $allmonths; |
170 | } |
171 | for ( $i = 1; $i < 13; $i++ ) { |
172 | $options[$wgLang->getMonthName( $i )] = $i; |
173 | } |
174 | $data->addOptions( $options ); |
175 | $data->setAttribute( 'class', 'mw-month-selector' ); |
176 | return $data->getHTML(); |
177 | } |
178 | |
179 | /** |
180 | * @param int|string $year Use '' or 0 to start with no year preselected. |
181 | * @param int|string $month A month in the 1..12 range. Use '', 0 or -1 to start with no month |
182 | * preselected. |
183 | * @return string Formatted HTML |
184 | * |
185 | * @deprecated since 1.42 |
186 | */ |
187 | public static function dateMenu( $year, $month ) { |
188 | wfDeprecated( __METHOD__, '1.42' ); |
189 | # Offset overrides year/month selection |
190 | if ( $month && $month !== -1 ) { |
191 | $encMonth = intval( $month ); |
192 | } else { |
193 | $encMonth = ''; |
194 | } |
195 | if ( $year ) { |
196 | $encYear = intval( $year ); |
197 | } elseif ( $encMonth ) { |
198 | $timestamp = MWTimestamp::getInstance(); |
199 | $thisMonth = intval( $timestamp->format( 'n' ) ); |
200 | $thisYear = intval( $timestamp->format( 'Y' ) ); |
201 | if ( $encMonth > $thisMonth ) { |
202 | $thisYear--; |
203 | } |
204 | $encYear = $thisYear; |
205 | } else { |
206 | $encYear = ''; |
207 | } |
208 | $inputAttribs = [ 'id' => 'year', 'maxlength' => 4, 'size' => 7 ]; |
209 | return self::label( wfMessage( 'year' )->text(), 'year' ) . ' ' . |
210 | Html::input( 'year', $encYear, 'number', $inputAttribs ) . ' ' . |
211 | self::label( wfMessage( 'month' )->text(), 'month' ) . ' ' . |
212 | self::monthSelector( $encMonth, '-1' ); |
213 | } |
214 | |
215 | /** |
216 | * Construct a language selector appropriate for use in a form or preferences |
217 | * |
218 | * @param string $selected The language code of the selected language |
219 | * @param bool $customisedOnly If true only languages which have some content are listed |
220 | * @param string|null $inLanguage The ISO code of the language to display the select list in |
221 | * @param array $overrideAttrs Override the attributes of the select tag (since 1.20) |
222 | * @param Message|null $msg Label message key (since 1.20) |
223 | * @return array Array containing 2 items: label HTML and select list HTML |
224 | * |
225 | * @deprecated since 1.42 |
226 | */ |
227 | public static function languageSelector( $selected, $customisedOnly = true, |
228 | $inLanguage = null, $overrideAttrs = [], ?Message $msg = null |
229 | ) { |
230 | wfDeprecated( __METHOD__, '1.42' ); |
231 | $languageCode = MediaWikiServices::getInstance()->getMainConfig() |
232 | ->get( MainConfigNames::LanguageCode ); |
233 | |
234 | $include = $customisedOnly ? LanguageNameUtils::SUPPORTED : LanguageNameUtils::DEFINED; |
235 | $languages = MediaWikiServices::getInstance() |
236 | ->getLanguageNameUtils() |
237 | ->getLanguageNames( $inLanguage, $include ); |
238 | |
239 | // Make sure the site language is in the list; |
240 | // a custom language code might not have a defined name... |
241 | if ( !array_key_exists( $languageCode, $languages ) ) { |
242 | $languages[$languageCode] = $languageCode; |
243 | // Sort the array again |
244 | ksort( $languages ); |
245 | } |
246 | |
247 | /** |
248 | * If a bogus value is set, default to the content language. |
249 | * Otherwise, no default is selected and the user ends up |
250 | * with Afrikaans since it's first in the list. |
251 | */ |
252 | $selected = isset( $languages[$selected] ) ? $selected : $languageCode; |
253 | $options = "\n"; |
254 | foreach ( $languages as $code => $name ) { |
255 | $options .= self::option( "$code - $name", $code, $code == $selected ) . "\n"; |
256 | } |
257 | |
258 | $attrs = [ 'id' => 'wpUserLanguage', 'name' => 'wpUserLanguage' ]; |
259 | $attrs = array_merge( $attrs, $overrideAttrs ); |
260 | |
261 | $msg ??= wfMessage( 'yourlanguage' ); |
262 | return [ |
263 | self::label( $msg->text(), $attrs['id'] ), |
264 | self::tags( 'select', $attrs, $options ) |
265 | ]; |
266 | } |
267 | |
268 | /** |
269 | * Shortcut to make a span element |
270 | * @param string $text Content of the element, will be escaped |
271 | * @param string $class Class name of the span element |
272 | * @param array $attribs Other attributes |
273 | * @return string |
274 | * |
275 | * @deprecated since 1.42, use {@see Html::element} instead |
276 | */ |
277 | public static function span( $text, $class, $attribs = [] ) { |
278 | return self::element( 'span', [ 'class' => $class ] + $attribs, $text ); |
279 | } |
280 | |
281 | /** |
282 | * Shortcut to make a specific element with a class attribute |
283 | * |
284 | * @param string $text Content of the element, will be escaped |
285 | * @param string $class Class name of the span element |
286 | * @param string $tag Element name |
287 | * @param array $attribs Other attributes |
288 | * @return string |
289 | * |
290 | * @deprecated since 1.42, use {@see Xml::tags} instead |
291 | */ |
292 | public static function wrapClass( $text, $class, $tag = 'span', $attribs = [] ) { |
293 | wfDeprecated( __METHOD__, '1.42' ); |
294 | return self::tags( $tag, [ 'class' => $class ] + $attribs, $text ); |
295 | } |
296 | |
297 | /** |
298 | * Convenience function to build an HTML text input field |
299 | * @param string $name Value of the name attribute |
300 | * @param int|false $size Value of the size attribute |
301 | * @param string|false $value Value of the value attribute |
302 | * @param array $attribs Other attributes |
303 | * @return string HTML |
304 | * |
305 | * @deprecated since 1.42, use {@see Html::input} instead |
306 | */ |
307 | public static function input( $name, $size = false, $value = false, $attribs = [] ) { |
308 | $attributes = [ 'name' => $name ]; |
309 | |
310 | if ( $size ) { |
311 | $attributes['size'] = $size; |
312 | } |
313 | |
314 | if ( $value !== false ) { // maybe 0 |
315 | $attributes['value'] = $value; |
316 | } |
317 | |
318 | return self::element( 'input', $attributes + $attribs ); |
319 | } |
320 | |
321 | /** |
322 | * Convenience function to build an HTML password input field |
323 | * @param string $name Value of the name attribute |
324 | * @param int|false $size Value of the size attribute |
325 | * @param string|false $value Value of the value attribute |
326 | * @param array $attribs Other attributes |
327 | * @return string HTML |
328 | * |
329 | * @deprecated since 1.42, use {@see Html::input} instead |
330 | */ |
331 | public static function password( $name, $size = false, $value = false, |
332 | $attribs = [] |
333 | ) { |
334 | return self::input( $name, $size, $value, |
335 | array_merge( $attribs, [ 'type' => 'password' ] ) ); |
336 | } |
337 | |
338 | /** |
339 | * Internal function for use in checkboxes and radio buttons and such. |
340 | * |
341 | * @param string $name |
342 | * @param bool $present |
343 | * |
344 | * @return array |
345 | * |
346 | * @deprecated since 1.42; only for use in methods being deprecated |
347 | */ |
348 | public static function attrib( $name, $present = true ) { |
349 | return $present ? [ $name => $name ] : []; |
350 | } |
351 | |
352 | /** |
353 | * Convenience function to build an HTML checkbox |
354 | * @param string $name Value of the name attribute |
355 | * @param bool $checked Whether the checkbox is checked or not |
356 | * @param array $attribs Array other attributes |
357 | * @return string HTML |
358 | * |
359 | * @deprecated since 1.42, use {@see Html::check} instead |
360 | */ |
361 | public static function check( $name, $checked = false, $attribs = [] ) { |
362 | return self::element( 'input', array_merge( |
363 | [ |
364 | 'name' => $name, |
365 | 'type' => 'checkbox', |
366 | 'value' => 1 ], |
367 | self::attrib( 'checked', $checked ), |
368 | $attribs ) ); |
369 | } |
370 | |
371 | /** |
372 | * Convenience function to build an HTML radio button |
373 | * @param string $name Value of the name attribute |
374 | * @param string $value Value of the value attribute |
375 | * @param bool $checked Whether the checkbox is checked or not |
376 | * @param array $attribs Other attributes |
377 | * @return string HTML |
378 | * |
379 | * @deprecated since 1.42, use {@see Html::radio} instead |
380 | */ |
381 | public static function radio( $name, $value, $checked = false, $attribs = [] ) { |
382 | return self::element( 'input', [ |
383 | 'name' => $name, |
384 | 'type' => 'radio', |
385 | 'value' => $value ] + self::attrib( 'checked', $checked ) + $attribs ); |
386 | } |
387 | |
388 | /** |
389 | * Convenience function to build an HTML form label |
390 | * @param string $label Text of the label |
391 | * @param string $id |
392 | * @param array $attribs An attribute array. This will usually be |
393 | * the same array as is passed to the corresponding input element, |
394 | * so this function will cherry-pick appropriate attributes to |
395 | * apply to the label as well; only class and title are applied. |
396 | * @return string HTML |
397 | * |
398 | * @deprecated since 1.42, use {@see Html::label} instead |
399 | */ |
400 | public static function label( $label, $id, $attribs = [] ) { |
401 | $a = [ 'for' => $id ]; |
402 | |
403 | foreach ( [ 'class', 'title' ] as $attr ) { |
404 | if ( isset( $attribs[$attr] ) ) { |
405 | $a[$attr] = $attribs[$attr]; |
406 | } |
407 | } |
408 | |
409 | return self::element( 'label', $a, $label ); |
410 | } |
411 | |
412 | /** |
413 | * Convenience function to build an HTML text input field with a label |
414 | * @param string $label Text of the label |
415 | * @param string $name Value of the name attribute |
416 | * @param string $id Id of the input |
417 | * @param int|false $size Value of the size attribute |
418 | * @param string|false $value Value of the value attribute |
419 | * @param array $attribs Other attributes |
420 | * @return string HTML |
421 | * |
422 | * @deprecated since 1.42, use {@see Html::input} and {@see Html::label} instead |
423 | */ |
424 | public static function inputLabel( $label, $name, $id, $size = false, |
425 | $value = false, $attribs = [] |
426 | ) { |
427 | [ $label, $input ] = self::inputLabelSep( $label, $name, $id, $size, $value, $attribs ); |
428 | return $label . "\u{00A0}" . $input; |
429 | } |
430 | |
431 | /** |
432 | * Same as Xml::inputLabel() but return input and label in an array |
433 | * |
434 | * @param string $label |
435 | * @param string $name |
436 | * @param string $id |
437 | * @param int|false $size |
438 | * @param string|false $value |
439 | * @param array $attribs |
440 | * @return array |
441 | * |
442 | * @deprecated since 1.42, use {@see Html::input} and {@see Html::label} instead |
443 | */ |
444 | public static function inputLabelSep( $label, $name, $id, $size = false, |
445 | $value = false, $attribs = [] |
446 | ) { |
447 | return [ |
448 | self::label( $label, $id, $attribs ), |
449 | self::input( $name, $size, $value, [ 'id' => $id ] + $attribs ) |
450 | ]; |
451 | } |
452 | |
453 | /** |
454 | * Convenience function to build an HTML checkbox with a label |
455 | * |
456 | * @param string $label |
457 | * @param string $name |
458 | * @param string $id |
459 | * @param bool $checked |
460 | * @param array $attribs |
461 | * @return string HTML |
462 | * |
463 | * @deprecated since 1.42, use {@see Html::check} and {@see Html::label} instead |
464 | */ |
465 | public static function checkLabel( $label, $name, $id, $checked = false, $attribs = [] ) { |
466 | return self::check( $name, $checked, [ 'id' => $id ] + $attribs ) . |
467 | "\u{00A0}" . |
468 | self::label( $label, $id, $attribs ); |
469 | } |
470 | |
471 | /** |
472 | * Convenience function to build an HTML radio button with a label |
473 | * |
474 | * @param string $label |
475 | * @param string $name |
476 | * @param string $value |
477 | * @param string $id |
478 | * @param bool $checked |
479 | * @param array $attribs |
480 | * @return string HTML |
481 | * |
482 | * @deprecated since 1.42, use {@see Html::radio} and {@see Html::label} instead |
483 | */ |
484 | public static function radioLabel( $label, $name, $value, $id, |
485 | $checked = false, $attribs = [] |
486 | ) { |
487 | return self::radio( $name, $value, $checked, [ 'id' => $id ] + $attribs ) . |
488 | "\u{00A0}" . |
489 | self::label( $label, $id, $attribs ); |
490 | } |
491 | |
492 | /** |
493 | * Convenience function to build an HTML submit button. |
494 | * |
495 | * @param string $value Label text for the button (unescaped) |
496 | * @param array $attribs Optional custom attributes |
497 | * @return string HTML |
498 | * |
499 | * @deprecated since 1.42, use {@see Html::submitButton} instead |
500 | */ |
501 | public static function submitButton( $value, $attribs = [] ) { |
502 | $attribs += [ |
503 | 'type' => 'submit', |
504 | 'value' => $value, |
505 | ]; |
506 | return Html::element( 'input', $attribs ); |
507 | } |
508 | |
509 | /** |
510 | * Convenience function to build an HTML drop-down list item. |
511 | * @param string $text Text for this item. Will be HTML escaped |
512 | * @param string|null $value Form submission value; if empty, use text |
513 | * @param bool $selected If true, will be the default selected item |
514 | * @param array $attribs Optional additional HTML attributes |
515 | * @return string HTML |
516 | * |
517 | * @deprecated since 1.42, use {@see Html::element} instead |
518 | */ |
519 | public static function option( $text, $value = null, $selected = false, |
520 | $attribs = [] ) { |
521 | if ( $value !== null ) { |
522 | $attribs['value'] = $value; |
523 | } |
524 | if ( $selected ) { |
525 | $attribs['selected'] = 'selected'; |
526 | } |
527 | return Html::element( 'option', $attribs, $text ); |
528 | } |
529 | |
530 | /** |
531 | * Build a drop-down box from a textual list. This is a wrapper |
532 | * for Xml::listDropdownOptions() plus the XmlSelect class. |
533 | * |
534 | * @param string $name Name and id for the drop-down |
535 | * @param string $list Correctly formatted text (newline delimited) to be |
536 | * used to generate the options. |
537 | * @param string $other Text for the "Other reasons" option |
538 | * @param string $selected Option which should be pre-selected |
539 | * @param string $class CSS classes for the drop-down |
540 | * @param int|null $tabindex Value of the tabindex attribute |
541 | * @return string |
542 | * |
543 | * @deprecated since 1.42; use the equivalent methods in Html without a wrapper |
544 | */ |
545 | public static function listDropdown( $name = '', $list = '', $other = '', |
546 | $selected = '', $class = '', $tabindex = null |
547 | ) { |
548 | $options = self::listDropdownOptions( $list, [ 'other' => $other ] ); |
549 | |
550 | $xmlSelect = new XmlSelect( $name, $name, $selected ); |
551 | $xmlSelect->addOptions( $options ); |
552 | |
553 | if ( $class ) { |
554 | $xmlSelect->setAttribute( 'class', $class ); |
555 | } |
556 | if ( $tabindex ) { |
557 | $xmlSelect->setAttribute( 'tabindex', $tabindex ); |
558 | } |
559 | |
560 | return $xmlSelect->getHTML(); |
561 | } |
562 | |
563 | /** |
564 | * Build options for a drop-down box from a textual list. |
565 | * |
566 | * The result of this function can be passed to XmlSelect::addOptions() |
567 | * (to render a plain `<select>` dropdown box) or to Xml::listDropdownOptionsOoui() |
568 | * and then OOUI\DropdownInputWidget() (to render a pretty one). |
569 | * |
570 | * @param string $list Correctly formatted text (newline delimited) to be |
571 | * used to generate the options. |
572 | * @param array $params Extra parameters: |
573 | * - string $params['other'] If set, add an option with this as text and a value of 'other' |
574 | * @return array Array keys are textual labels, values are internal values |
575 | * |
576 | * @deprecated since 1.42; use the equivalent method in Html |
577 | */ |
578 | public static function listDropdownOptions( $list, $params = [] ) { |
579 | $options = []; |
580 | |
581 | if ( isset( $params['other'] ) ) { |
582 | $options[ $params['other'] ] = 'other'; |
583 | } |
584 | |
585 | $optgroup = false; |
586 | foreach ( explode( "\n", $list ) as $option ) { |
587 | $value = trim( $option ); |
588 | if ( $value == '' ) { |
589 | continue; |
590 | } |
591 | if ( substr( $value, 0, 1 ) == '*' && substr( $value, 1, 1 ) != '*' ) { |
592 | # A new group is starting... |
593 | $value = trim( substr( $value, 1 ) ); |
594 | if ( $value !== '' && |
595 | // Do not use the value for 'other' as option group - T251351 |
596 | ( !isset( $params['other'] ) || $value !== $params['other'] ) |
597 | ) { |
598 | $optgroup = $value; |
599 | } else { |
600 | $optgroup = false; |
601 | } |
602 | } elseif ( substr( $value, 0, 2 ) == '**' ) { |
603 | # groupmember |
604 | $opt = trim( substr( $value, 2 ) ); |
605 | if ( $optgroup === false ) { |
606 | $options[$opt] = $opt; |
607 | } else { |
608 | $options[$optgroup][$opt] = $opt; |
609 | } |
610 | } else { |
611 | # groupless reason list |
612 | $optgroup = false; |
613 | $options[$option] = $option; |
614 | } |
615 | } |
616 | |
617 | return $options; |
618 | } |
619 | |
620 | /** |
621 | * Convert options for a drop-down box into a format accepted by OOUI\DropdownInputWidget etc. |
622 | * |
623 | * TODO Find a better home for this function. |
624 | * |
625 | * @param array $options Options, as returned e.g. by Xml::listDropdownOptions() |
626 | * @return array |
627 | * |
628 | * @deprecated since 1.42; use the equivalent method in Html |
629 | */ |
630 | public static function listDropdownOptionsOoui( $options ) { |
631 | $optionsOoui = []; |
632 | |
633 | foreach ( $options as $text => $value ) { |
634 | if ( is_array( $value ) ) { |
635 | $optionsOoui[] = [ 'optgroup' => (string)$text ]; |
636 | foreach ( $value as $text2 => $value2 ) { |
637 | $optionsOoui[] = [ 'data' => (string)$value2, 'label' => (string)$text2 ]; |
638 | } |
639 | } else { |
640 | $optionsOoui[] = [ 'data' => (string)$value, 'label' => (string)$text ]; |
641 | } |
642 | } |
643 | |
644 | return $optionsOoui; |
645 | } |
646 | |
647 | /** |
648 | * Shortcut for creating fieldsets. |
649 | * |
650 | * @param string|false $legend Legend of the fieldset. If evaluates to false, |
651 | * legend is not added. |
652 | * @param string|false $content Pre-escaped content for the fieldset. If false, |
653 | * only open fieldset is returned. |
654 | * @param array $attribs Any attributes to fieldset-element. |
655 | * @return string |
656 | * |
657 | * @deprecated since 1.42, use {@see Html::element} instead |
658 | */ |
659 | public static function fieldset( $legend = false, $content = false, $attribs = [] ) { |
660 | $s = self::openElement( 'fieldset', $attribs ) . "\n"; |
661 | |
662 | if ( $legend ) { |
663 | $s .= self::element( 'legend', null, $legend ) . "\n"; |
664 | } |
665 | |
666 | if ( $content !== false ) { |
667 | $s .= $content . "\n"; |
668 | $s .= self::closeElement( 'fieldset' ) . "\n"; |
669 | } |
670 | |
671 | return $s; |
672 | } |
673 | |
674 | /** |
675 | * Shortcut for creating textareas. |
676 | * |
677 | * @param string $name The 'name' for the textarea |
678 | * @param string $content Content for the textarea |
679 | * @param int $cols The number of columns for the textarea |
680 | * @param int $rows The number of rows for the textarea |
681 | * @param array $attribs Any other attributes for the textarea |
682 | * @return string |
683 | * |
684 | * @deprecated since 1.42, use {@see Html::textarea} instead |
685 | */ |
686 | public static function textarea( $name, $content, $cols = 40, $rows = 5, $attribs = [] ) { |
687 | return self::element( 'textarea', |
688 | [ |
689 | 'name' => $name, |
690 | 'id' => $name, |
691 | 'cols' => $cols, |
692 | 'rows' => $rows |
693 | ] + $attribs, |
694 | $content, false ); |
695 | } |
696 | |
697 | /** |
698 | * Encode a variable of arbitrary type to JavaScript. |
699 | * If the value is an HtmlJsCode object, pass through the object's value verbatim. |
700 | * |
701 | * @note Only use this function for generating JavaScript code. If generating output |
702 | * for a proper JSON parser, just call FormatJson::encode() directly. |
703 | * |
704 | * @param mixed $value The value being encoded. Can be any type except a resource. |
705 | * @param-taint $value escapes_html |
706 | * @param bool $pretty If true, add non-significant whitespace to improve readability. |
707 | * @return string|false String if successful; false upon failure |
708 | * @return-taint none |
709 | * |
710 | * @deprecated since 1.41, use {@see Html::encodeJsVar} instead |
711 | */ |
712 | public static function encodeJsVar( $value, $pretty = false ) { |
713 | return Html::encodeJsVar( $value, $pretty ); |
714 | } |
715 | |
716 | /** |
717 | * Create a call to a JavaScript function. The supplied arguments will be |
718 | * encoded using Xml::encodeJsVar(). |
719 | * |
720 | * @since 1.17 |
721 | * @param string $name The name of the function to call, or a JavaScript expression |
722 | * which evaluates to a function object which is called. |
723 | * @param-taint $name tainted |
724 | * @param array $args The arguments to pass to the function. |
725 | * @param-taint $args escapes_html |
726 | * @param bool $pretty If true, add non-significant whitespace to improve readability. |
727 | * @return string|false String if successful; false upon failure |
728 | * @return-taint none |
729 | * |
730 | * @deprecated since 1.41, use {@see Html::encodeJsCall} instead |
731 | */ |
732 | public static function encodeJsCall( $name, $args, $pretty = false ) { |
733 | return Html::encodeJsCall( $name, $args, $pretty ); |
734 | } |
735 | |
736 | /** |
737 | * Check if a string is well-formed XML. |
738 | * Must include the surrounding tag. |
739 | * This function is a DoS vector if an attacker can define |
740 | * entities in $text. |
741 | * |
742 | * @param string $text String to test. |
743 | * @return bool |
744 | * |
745 | * @todo Error position reporting return |
746 | */ |
747 | private static function isWellFormed( $text ) { |
748 | $parser = xml_parser_create( "UTF-8" ); |
749 | |
750 | # case folding violates XML standard, turn it off |
751 | xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, 0 ); |
752 | |
753 | if ( !xml_parse( $parser, $text, true ) ) { |
754 | // $err = xml_error_string( xml_get_error_code( $parser ) ); |
755 | // $position = xml_get_current_byte_index( $parser ); |
756 | // $fragment = $this->extractFragment( $html, $position ); |
757 | // $this->mXmlError = "$err at byte $position:\n$fragment"; |
758 | xml_parser_free( $parser ); |
759 | return false; |
760 | } |
761 | |
762 | xml_parser_free( $parser ); |
763 | |
764 | return true; |
765 | } |
766 | |
767 | /** |
768 | * Check if a string is a well-formed XML fragment. |
769 | * Wraps fragment in an \<html\> bit and doctype, so it can be a fragment |
770 | * and can use HTML named entities. |
771 | * |
772 | * @param string $text |
773 | * @return bool |
774 | */ |
775 | public static function isWellFormedXmlFragment( $text ) { |
776 | $html = |
777 | Sanitizer::hackDocType() . |
778 | '<html>' . |
779 | $text . |
780 | '</html>'; |
781 | |
782 | return self::isWellFormed( $html ); |
783 | } |
784 | |
785 | /** |
786 | * Replace " > and < with their respective HTML entities ( ", |
787 | * >, <) |
788 | * |
789 | * @param string $in Text that might contain HTML tags. |
790 | * @return string Escaped string |
791 | */ |
792 | public static function escapeTagsOnly( $in ) { |
793 | return str_replace( |
794 | [ '"', '>', '<' ], |
795 | [ '"', '>', '<' ], |
796 | $in ); |
797 | } |
798 | |
799 | /** |
800 | * Generate a form (without the opening form element). |
801 | * Output optionally includes a submit button. |
802 | * @param array $fields Associative array, key is the name of a message that |
803 | * contains a description for the field, value is an HTML string |
804 | * containing the appropriate input. |
805 | * @param string|null $submitLabel The name of a message containing a label for |
806 | * the submit button. |
807 | * @param array $submitAttribs The attributes to add to the submit button |
808 | * @return string HTML form. |
809 | * |
810 | * @deprecated since 1.42, use OOUI or Codex widgets instead |
811 | */ |
812 | public static function buildForm( $fields, $submitLabel = null, $submitAttribs = [] ) { |
813 | $form = ''; |
814 | $form .= "<table><tbody>"; |
815 | |
816 | foreach ( $fields as $labelmsg => $input ) { |
817 | $id = "mw-$labelmsg"; |
818 | $form .= self::openElement( 'tr', [ 'id' => $id ] ); |
819 | |
820 | // TODO use a <label> here for accessibility purposes - will need |
821 | // to either not use a table to build the form, or find the ID of |
822 | // the input somehow. |
823 | |
824 | $form .= self::tags( 'td', [ 'class' => 'mw-label' ], wfMessage( $labelmsg )->parse() ); |
825 | $form .= self::openElement( 'td', [ 'class' => 'mw-input' ] ) |
826 | . $input . self::closeElement( 'td' ); |
827 | $form .= self::closeElement( 'tr' ); |
828 | } |
829 | |
830 | if ( $submitLabel ) { |
831 | $form .= self::openElement( 'tr' ); |
832 | $form .= self::tags( 'td', [], '' ); |
833 | $form .= self::openElement( 'td', [ 'class' => 'mw-submit' ] ) |
834 | . self::submitButton( wfMessage( $submitLabel )->text(), $submitAttribs ) |
835 | . self::closeElement( 'td' ); |
836 | $form .= self::closeElement( 'tr' ); |
837 | } |
838 | |
839 | $form .= "</tbody></table>"; |
840 | |
841 | return $form; |
842 | } |
843 | |
844 | /** |
845 | * @param string[][] $rows |
846 | * @param array|null $attribs An array of attributes to apply to the table tag |
847 | * @param array|null $headers An array of strings to use as table headers |
848 | * @return string |
849 | * |
850 | * @deprecated since 1.42; use OOUI or Codex widgets instead |
851 | */ |
852 | public static function buildTable( $rows, $attribs = [], $headers = null ) { |
853 | $s = self::openElement( 'table', $attribs ); |
854 | |
855 | if ( is_array( $headers ) ) { |
856 | $s .= self::openElement( 'thead', $attribs ); |
857 | |
858 | foreach ( $headers as $id => $header ) { |
859 | $attribs = []; |
860 | |
861 | if ( is_string( $id ) ) { |
862 | $attribs['id'] = $id; |
863 | } |
864 | |
865 | $s .= self::element( 'th', $attribs, $header ); |
866 | } |
867 | $s .= self::closeElement( 'thead' ); |
868 | } |
869 | |
870 | foreach ( $rows as $id => $row ) { |
871 | $attribs = []; |
872 | |
873 | if ( is_string( $id ) ) { |
874 | $attribs['id'] = $id; |
875 | } |
876 | |
877 | $s .= self::buildTableRow( $attribs, $row ); |
878 | } |
879 | |
880 | $s .= self::closeElement( 'table' ); |
881 | |
882 | return $s; |
883 | } |
884 | |
885 | /** |
886 | * Build a row for a table |
887 | * @param array|null $attribs An array of attributes to apply to the tr tag |
888 | * @param string[] $cells An array of strings to put in <td> |
889 | * @return string |
890 | * |
891 | * @deprecated since 1.42; use OOUI or Codex widgets instead |
892 | */ |
893 | public static function buildTableRow( $attribs, $cells ) { |
894 | $s = self::openElement( 'tr', $attribs ); |
895 | |
896 | foreach ( $cells as $id => $cell ) { |
897 | $attribs = []; |
898 | |
899 | if ( is_string( $id ) ) { |
900 | $attribs['id'] = $id; |
901 | } |
902 | |
903 | $s .= self::element( 'td', $attribs, $cell ); |
904 | } |
905 | |
906 | $s .= self::closeElement( 'tr' ); |
907 | |
908 | return $s; |
909 | } |
910 | } |
911 | /** @deprecated class alias since 1.43 */ |
912 | class_alias( Xml::class, 'Xml' ); |