Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
65.62% covered (warning)
65.62%
21 / 32
60.00% covered (warning)
60.00%
6 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
XmlSelect
65.62% covered (warning)
65.62%
21 / 32
60.00% covered (warning)
60.00%
6 / 10
36.25
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 setDefault
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setTagName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setAttribute
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAttribute
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addOption
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 addOptions
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 formatOptions
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
4.25
 getHTML
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 parseOptionsMessage
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2/**
3 * Class for generating HTML <select> elements.
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
23use MediaWiki\Html\Html;
24
25/**
26 * Class for generating HTML <select> or <datalist> elements.
27 */
28class XmlSelect {
29    protected $options = [];
30    protected $default = false;
31    protected $tagName = 'select';
32    protected $attributes = [];
33
34    public function __construct( $name = false, $id = false, $default = false ) {
35        if ( $name ) {
36            $this->setAttribute( 'name', $name );
37        }
38
39        if ( $id ) {
40            $this->setAttribute( 'id', $id );
41        }
42
43        if ( $default !== false ) {
44            $this->default = $default;
45        }
46    }
47
48    /**
49     * @param string|array $default
50     */
51    public function setDefault( $default ) {
52        $this->default = $default;
53    }
54
55    /**
56     * @param string|array $tagName
57     */
58    public function setTagName( $tagName ) {
59        $this->tagName = $tagName;
60    }
61
62    /**
63     * @param string $name
64     * @param string|int $value
65     */
66    public function setAttribute( $name, $value ) {
67        $this->attributes[$name] = $value;
68    }
69
70    /**
71     * @param string $name
72     * @return string|int|null
73     */
74    public function getAttribute( $name ) {
75        return $this->attributes[$name] ?? null;
76    }
77
78    /**
79     * @param string $label
80     * @param string|int|float|false $value If not given, assumed equal to $label
81     */
82    public function addOption( $label, $value = false ) {
83        $value = $value !== false ? $value : $label;
84        $this->options[] = [ $label => $value ];
85    }
86
87    /**
88     * This accepts an array of form
89     * label => value
90     * label => ( label => value, label => value )
91     *
92     * @param array $options
93     */
94    public function addOptions( $options ) {
95        $this->options[] = $options;
96    }
97
98    /**
99     * This accepts an array of form:
100     * label => value
101     * label => ( label => value, label => value )
102     *
103     * @param array $options
104     * @param string|array|false $default
105     * @return string
106     */
107    public static function formatOptions( $options, $default = false ) {
108        $data = '';
109
110        foreach ( $options as $label => $value ) {
111            if ( is_array( $value ) ) {
112                $contents = self::formatOptions( $value, $default );
113                $data .= Html::rawElement( 'optgroup', [ 'label' => $label ], $contents ) . "\n";
114            } else {
115                // If $default is an array, then the <select> probably has the multiple attribute,
116                // so we should check if each $value is in $default, rather than checking if
117                // $value is equal to $default.
118                $selected = is_array( $default ) ? in_array( $value, $default ) : $value === $default;
119                $data .= Xml::option( $label, $value, $selected ) . "\n";
120            }
121        }
122
123        return $data;
124    }
125
126    /**
127     * @return string
128     */
129    public function getHTML() {
130        $contents = '';
131
132        foreach ( $this->options as $options ) {
133            $contents .= self::formatOptions( $options, $this->default );
134        }
135
136        return Html::rawElement( $this->tagName, $this->attributes, rtrim( $contents ) );
137    }
138
139    /**
140     * Parse labels and values out of a comma- and colon-separated list of options, such as is used for
141     * expiry and duration lists. Documentation of the format is on translatewiki.net.
142     * @since 1.35
143     * @link https://translatewiki.net/wiki/Template:Doc-mediawiki-options-list
144     * @param string $msg The message to parse.
145     * @return string[] The options array, where keys are option labels (i.e. translations)
146     * and values are option values (i.e. untranslated).
147     */
148    public static function parseOptionsMessage( string $msg ): array {
149        $options = [];
150        foreach ( explode( ',', $msg ) as $option ) {
151            // Normalize options that only have one part.
152            if ( strpos( $option, ':' ) === false ) {
153                $option = "$option:$option";
154            }
155            // Extract the two parts.
156            [ $label, $value ] = explode( ':', $option );
157            $options[ trim( $label ) ] = trim( $value );
158        }
159        return $options;
160    }
161}