MediaWiki 1.44.0
Xml.php
Go to the documentation of this file.
1<?php
23namespace MediaWiki\Xml;
24
32use UtfNormal\Validator;
33
37class Xml {
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
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
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
119 public static function openElement( $element, $attribs = null ) {
120 return '<' . $element . self::expandAttributes( $attribs ) . '>';
121 }
122
128 public static function closeElement( $element ) {
129 return "</$element>";
130 }
131
145 public static function tags( $element, $attribs, $contents ) {
146 return self::openElement( $element, $attribs ) . $contents . "</$element>";
147 }
148
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
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
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()
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
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
277 public static function span( $text, $class, $attribs = [] ) {
278 wfDeprecated( __METHOD__, '1.42' );
279
280 return self::element( 'span', [ 'class' => $class ] + $attribs, $text );
281 }
282
294 public static function wrapClass( $text, $class, $tag = 'span', $attribs = [] ) {
295 wfDeprecated( __METHOD__, '1.42' );
296 return self::tags( $tag, [ 'class' => $class ] + $attribs, $text );
297 }
298
309 public static function input( $name, $size = false, $value = false, $attribs = [] ) {
310 wfDeprecated( __METHOD__, '1.42' );
311
312 $attributes = [ 'name' => $name ];
313
314 if ( $size ) {
315 $attributes['size'] = $size;
316 }
317
318 if ( $value !== false ) { // maybe 0
319 $attributes['value'] = $value;
320 }
321
322 return self::element( 'input', $attributes + $attribs );
323 }
324
335 public static function password( $name, $size = false, $value = false,
336 $attribs = []
337 ) {
338 wfDeprecated( __METHOD__, '1.42' );
339
340 return self::input( $name, $size, $value,
341 array_merge( $attribs, [ 'type' => 'password' ] ) );
342 }
343
354 public static function attrib( $name, $present = true ) {
355 return $present ? [ $name => $name ] : [];
356 }
357
367 public static function check( $name, $checked = false, $attribs = [] ) {
368 wfDeprecated( __METHOD__, '1.42' );
369
370 return self::element( 'input', array_merge(
371 [
372 'name' => $name,
373 'type' => 'checkbox',
374 'value' => 1 ],
375 self::attrib( 'checked', $checked ),
376 $attribs ) );
377 }
378
389 public static function radio( $name, $value, $checked = false, $attribs = [] ) {
390 wfDeprecated( __METHOD__, '1.42' );
391
392 return self::element( 'input', [
393 'name' => $name,
394 'type' => 'radio',
395 'value' => $value ] + self::attrib( 'checked', $checked ) + $attribs );
396 }
397
410 public static function label( $label, $id, $attribs = [] ) {
411 $a = [ 'for' => $id ];
412
413 foreach ( [ 'class', 'title' ] as $attr ) {
414 if ( isset( $attribs[$attr] ) ) {
415 $a[$attr] = $attribs[$attr];
416 }
417 }
418
419 return self::element( 'label', $a, $label );
420 }
421
434 public static function inputLabel( $label, $name, $id, $size = false,
435 $value = false, $attribs = []
436 ) {
437 wfDeprecated( __METHOD__, '1.42' );
438
439 [ $label, $input ] = self::inputLabelSep( $label, $name, $id, $size, $value, $attribs );
440 return $label . "\u{00A0}" . $input;
441 }
442
456 public static function inputLabelSep( $label, $name, $id, $size = false,
457 $value = false, $attribs = []
458 ) {
459 wfDeprecated( __METHOD__, '1.42' );
460
461 return [
462 self::label( $label, $id, $attribs ),
463 self::input( $name, $size, $value, [ 'id' => $id ] + $attribs )
464 ];
465 }
466
479 public static function checkLabel( $label, $name, $id, $checked = false, $attribs = [] ) {
480 wfDeprecated( __METHOD__, '1.42' );
481
482 return self::check( $name, $checked, [ 'id' => $id ] + $attribs ) .
483 "\u{00A0}" .
484 self::label( $label, $id, $attribs );
485 }
486
500 public static function radioLabel( $label, $name, $value, $id,
501 $checked = false, $attribs = []
502 ) {
503 wfDeprecated( __METHOD__, '1.42' );
504
505 return self::radio( $name, $value, $checked, [ 'id' => $id ] + $attribs ) .
506 "\u{00A0}" .
507 self::label( $label, $id, $attribs );
508 }
509
519 public static function submitButton( $value, $attribs = [] ) {
520 wfDeprecated( __METHOD__, '1.42' );
521
522 $attribs += [
523 'type' => 'submit',
524 'value' => $value,
525 ];
526 return Html::element( 'input', $attribs );
527 }
528
539 public static function option( $text, $value = null, $selected = false,
540 $attribs = [] ) {
541 if ( $value !== null ) {
542 $attribs['value'] = $value;
543 }
544 if ( $selected ) {
545 $attribs['selected'] = 'selected';
546 }
547 return Html::element( 'option', $attribs, $text );
548 }
549
565 public static function listDropdown( $name = '', $list = '', $other = '',
566 $selected = '', $class = '', $tabindex = null
567 ) {
568 $options = self::listDropdownOptions( $list, [ 'other' => $other ] );
569
570 $xmlSelect = new XmlSelect( $name, $name, $selected );
571 $xmlSelect->addOptions( $options );
572
573 if ( $class ) {
574 $xmlSelect->setAttribute( 'class', $class );
575 }
576 if ( $tabindex ) {
577 $xmlSelect->setAttribute( 'tabindex', $tabindex );
578 }
579
580 return $xmlSelect->getHTML();
581 }
582
598 public static function listDropdownOptions( $list, $params = [] ) {
599 $options = [];
600
601 if ( isset( $params['other'] ) ) {
602 $options[ $params['other'] ] = 'other';
603 }
604
605 $optgroup = false;
606 foreach ( explode( "\n", $list ) as $option ) {
607 $value = trim( $option );
608 if ( $value == '' ) {
609 continue;
610 }
611 if ( substr( $value, 0, 1 ) == '*' && substr( $value, 1, 1 ) != '*' ) {
612 # A new group is starting...
613 $value = trim( substr( $value, 1 ) );
614 if ( $value !== '' &&
615 // Do not use the value for 'other' as option group - T251351
616 ( !isset( $params['other'] ) || $value !== $params['other'] )
617 ) {
618 $optgroup = $value;
619 } else {
620 $optgroup = false;
621 }
622 } elseif ( substr( $value, 0, 2 ) == '**' ) {
623 # groupmember
624 $opt = trim( substr( $value, 2 ) );
625 if ( $optgroup === false ) {
626 $options[$opt] = $opt;
627 } else {
628 $options[$optgroup][$opt] = $opt;
629 }
630 } else {
631 # groupless reason list
632 $optgroup = false;
633 $options[$option] = $option;
634 }
635 }
636
637 return $options;
638 }
639
650 public static function listDropdownOptionsOoui( $options ) {
651 $optionsOoui = [];
652
653 foreach ( $options as $text => $value ) {
654 if ( is_array( $value ) ) {
655 $optionsOoui[] = [ 'optgroup' => (string)$text ];
656 foreach ( $value as $text2 => $value2 ) {
657 $optionsOoui[] = [ 'data' => (string)$value2, 'label' => (string)$text2 ];
658 }
659 } else {
660 $optionsOoui[] = [ 'data' => (string)$value, 'label' => (string)$text ];
661 }
662 }
663
664 return $optionsOoui;
665 }
666
679 public static function fieldset( $legend = false, $content = false, $attribs = [] ) {
680 $s = self::openElement( 'fieldset', $attribs ) . "\n";
681
682 if ( $legend ) {
683 $s .= self::element( 'legend', null, $legend ) . "\n";
684 }
685
686 if ( $content !== false ) {
687 $s .= $content . "\n";
688 $s .= self::closeElement( 'fieldset' ) . "\n";
689 }
690
691 return $s;
692 }
693
706 public static function textarea( $name, $content, $cols = 40, $rows = 5, $attribs = [] ) {
707 wfDeprecated( __METHOD__, '1.42' );
708
709 return self::element( 'textarea',
710 [
711 'name' => $name,
712 'id' => $name,
713 'cols' => $cols,
714 'rows' => $rows
715 ] + $attribs,
716 $content, false );
717 }
718
734 public static function encodeJsVar( $value, $pretty = false ) {
735 wfDeprecated( __METHOD__, '1.41' );
736
737 return Html::encodeJsVar( $value, $pretty );
738 }
739
756 public static function encodeJsCall( $name, $args, $pretty = false ) {
757 wfDeprecated( __METHOD__, '1.41' );
758
759 return Html::encodeJsCall( $name, $args, $pretty );
760 }
761
773 private static function isWellFormed( $text ) {
774 $parser = xml_parser_create( "UTF-8" );
775
776 # case folding violates XML standard, turn it off
777 xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, 0 );
778
779 if ( !xml_parse( $parser, $text, true ) ) {
780 // $err = xml_error_string( xml_get_error_code( $parser ) );
781 // $position = xml_get_current_byte_index( $parser );
782 // $fragment = $this->extractFragment( $html, $position );
783 // $this->mXmlError = "$err at byte $position:\n$fragment";
784 xml_parser_free( $parser );
785 return false;
786 }
787
788 xml_parser_free( $parser );
789
790 return true;
791 }
792
801 public static function isWellFormedXmlFragment( $text ) {
802 $html =
803 Sanitizer::hackDocType() .
804 '<html>' .
805 $text .
806 '</html>';
807
808 return self::isWellFormed( $html );
809 }
810
818 public static function escapeTagsOnly( $in ) {
819 return str_replace(
820 [ '"', '>', '<' ],
821 [ '&quot;', '&gt;', '&lt;' ],
822 $in );
823 }
824
838 public static function buildForm( $fields, $submitLabel = null, $submitAttribs = [] ) {
839 $form = '';
840 $form .= "<table><tbody>";
841
842 foreach ( $fields as $labelmsg => $input ) {
843 $id = "mw-$labelmsg";
844 $form .= self::openElement( 'tr', [ 'id' => $id ] );
845
846 // TODO use a <label> here for accessibility purposes - will need
847 // to either not use a table to build the form, or find the ID of
848 // the input somehow.
849
850 $form .= self::tags( 'td', [ 'class' => 'mw-label' ], wfMessage( $labelmsg )->parse() );
851 $form .= self::openElement( 'td', [ 'class' => 'mw-input' ] )
852 . $input . self::closeElement( 'td' );
853 $form .= self::closeElement( 'tr' );
854 }
855
856 if ( $submitLabel ) {
857 $form .= self::openElement( 'tr' );
858 $form .= self::tags( 'td', [], '' );
859 $form .= self::openElement( 'td', [ 'class' => 'mw-submit' ] )
861 'input',
862 $submitAttribs + [
863 'type' => 'submit',
864 'value' => wfMessage( $submitLabel )->text(),
865 ]
866 )
867 . self::closeElement( 'td' );
868 $form .= self::closeElement( 'tr' );
869 }
870
871 $form .= "</tbody></table>";
872
873 return $form;
874 }
875
884 public static function buildTable( $rows, $attribs = [], $headers = null ) {
885 wfDeprecated( __METHOD__, '1.42' );
886
887 $s = self::openElement( 'table', $attribs );
888
889 if ( is_array( $headers ) ) {
890 $s .= self::openElement( 'thead', $attribs );
891
892 foreach ( $headers as $id => $header ) {
893 $attribs = [];
894
895 if ( is_string( $id ) ) {
896 $attribs['id'] = $id;
897 }
898
899 $s .= self::element( 'th', $attribs, $header );
900 }
901 $s .= self::closeElement( 'thead' );
902 }
903
904 foreach ( $rows as $id => $row ) {
905 $attribs = [];
906
907 if ( is_string( $id ) ) {
908 $attribs['id'] = $id;
909 }
910
911 $s .= self::buildTableRow( $attribs, $row );
912 }
913
914 $s .= self::closeElement( 'table' );
915
916 return $s;
917 }
918
927 public static function buildTableRow( $attribs, $cells ) {
928 wfDeprecated( __METHOD__, '1.42' );
929
930 $s = self::openElement( 'tr', $attribs );
931
932 foreach ( $cells as $id => $cell ) {
933 $attribs = [];
934
935 if ( is_string( $id ) ) {
936 $attribs['id'] = $id;
937 }
938
939 $s .= self::element( 'td', $attribs, $cell );
940 }
941
942 $s .= self::closeElement( 'tr' );
943
944 return $s;
945 }
946}
948class_alias( Xml::class, 'Xml' );
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
if(!defined( 'MW_NO_SESSION') &&MW_ENTRY_POINT !=='cli' $wgLang
Definition Setup.php:565
This class is a collection of static functions that serve two purposes:
Definition Html.php:57
A service that provides utilities to do with language names and codes.
A class containing constants representing the names of configuration variables.
const LanguageCode
Name constant for the LanguageCode setting, for use with Config::get()
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition Message.php:157
HTML sanitizer for MediaWiki.
Definition Sanitizer.php:46
Library for creating and parsing MW-style timestamps.
Class for generating HTML <select> or <datalist> elements.
Definition XmlSelect.php:30
Module of static functions for generating XML.
Definition Xml.php:37
static escapeTagsOnly( $in)
Replace " > and < with their respective HTML entities ( ", >, <)
Definition Xml.php:818
static textarea( $name, $content, $cols=40, $rows=5, $attribs=[])
Shortcut for creating textareas.
Definition Xml.php:706
static checkLabel( $label, $name, $id, $checked=false, $attribs=[])
Convenience function to build an HTML checkbox with a label.
Definition Xml.php:479
static elementClean( $element, $attribs=[], $contents='')
Format an XML element as with self::element(), but run text through the content language's normalize(...
Definition Xml.php:101
static inputLabel( $label, $name, $id, $size=false, $value=false, $attribs=[])
Convenience function to build an HTML text input field with a label.
Definition Xml.php:434
static attrib( $name, $present=true)
Internal function for use in checkboxes and radio buttons and such.
Definition Xml.php:354
static isWellFormedXmlFragment( $text)
Check if a string is a well-formed XML fragment.
Definition Xml.php:801
static span( $text, $class, $attribs=[])
Shortcut to make a span element.
Definition Xml.php:277
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition Xml.php:54
static radio( $name, $value, $checked=false, $attribs=[])
Convenience function to build an HTML radio button.
Definition Xml.php:389
static monthSelector( $selected='', $allmonths=null, $id='month')
Create a date selector.
Definition Xml.php:160
static label( $label, $id, $attribs=[])
Convenience function to build an HTML form label.
Definition Xml.php:410
static tags( $element, $attribs, $contents)
Same as Xml::element(), but does not escape contents.
Definition Xml.php:145
static check( $name, $checked=false, $attribs=[])
Convenience function to build an HTML checkbox.
Definition Xml.php:367
static expandAttributes(?array $attribs)
Given an array of ('attributename' => 'value'), it generates the code to set the XML attributes : att...
Definition Xml.php:79
static buildForm( $fields, $submitLabel=null, $submitAttribs=[])
Generate a form (without the opening form element).
Definition Xml.php:838
static radioLabel( $label, $name, $value, $id, $checked=false, $attribs=[])
Convenience function to build an HTML radio button with a label.
Definition Xml.php:500
static buildTable( $rows, $attribs=[], $headers=null)
Definition Xml.php:884
static inputLabelSep( $label, $name, $id, $size=false, $value=false, $attribs=[])
Same as Xml::inputLabel() but return input and label in an array.
Definition Xml.php:456
static encodeJsCall( $name, $args, $pretty=false)
Create a call to a JavaScript function.
Definition Xml.php:756
static openElement( $element, $attribs=null)
This opens an XML element.
Definition Xml.php:119
static option( $text, $value=null, $selected=false, $attribs=[])
Convenience function to build an HTML drop-down list item.
Definition Xml.php:539
static languageSelector( $selected, $customisedOnly=true, $inLanguage=null, $overrideAttrs=[], ?Message $msg=null)
Construct a language selector appropriate for use in a form or preferences.
Definition Xml.php:227
static listDropdown( $name='', $list='', $other='', $selected='', $class='', $tabindex=null)
Build a drop-down box from a textual list.
Definition Xml.php:565
static listDropdownOptionsOoui( $options)
Convert options for a drop-down box into a format accepted by OOUI\DropdownInputWidget etc.
Definition Xml.php:650
static dateMenu( $year, $month)
Definition Xml.php:187
static closeElement( $element)
Shortcut to close an XML element.
Definition Xml.php:128
static input( $name, $size=false, $value=false, $attribs=[])
Convenience function to build an HTML text input field.
Definition Xml.php:309
static fieldset( $legend=false, $content=false, $attribs=[])
Shortcut for creating fieldsets.
Definition Xml.php:679
static password( $name, $size=false, $value=false, $attribs=[])
Convenience function to build an HTML password input field.
Definition Xml.php:335
static listDropdownOptions( $list, $params=[])
Build options for a drop-down box from a textual list.
Definition Xml.php:598
static submitButton( $value, $attribs=[])
Convenience function to build an HTML submit button.
Definition Xml.php:519
static encodeJsVar( $value, $pretty=false)
Encode a variable of arbitrary type to JavaScript.
Definition Xml.php:734
static buildTableRow( $attribs, $cells)
Build a row for a table.
Definition Xml.php:927
static wrapClass( $text, $class, $tag='span', $attribs=[])
Shortcut to make a specific element with a class attribute.
Definition Xml.php:294
element(SerializerNode $parent, SerializerNode $node, $contents)
$header