Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
36.99% covered (danger)
36.99%
27 / 73
36.36% covered (danger)
36.36%
4 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
Licenses
36.99% covered (danger)
36.99%
27 / 73
36.36% covered (danger)
36.36%
4 / 11
209.40
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getMessageFromParams
28.57% covered (danger)
28.57%
2 / 7
0.00% covered (danger)
0.00%
0 / 1
6.28
 buildLine
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 makeLines
86.67% covered (warning)
86.67%
13 / 15
0.00% covered (danger)
0.00%
0 / 1
7.12
 trimStars
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 stackItem
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 makeHtml
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
12
 outputOption
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 getLines
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getLicenses
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getInputHTML
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * License selector for use on Special:Upload.
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 * @ingroup SpecialPage
22 * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
23 * @copyright Copyright © 2005, Ævar Arnfjörð Bjarmason
24 */
25
26use MediaWiki\Html\Html;
27use MediaWiki\HTMLForm\HTMLFormField;
28use MediaWiki\MediaWikiServices;
29
30/**
31 * A License class for use on Special:Upload
32 */
33class Licenses extends HTMLFormField {
34    /** @var string */
35    protected $msg;
36
37    /** @var array */
38    protected $lines = [];
39
40    /** @var string */
41    protected $html;
42
43    /** @var string|null */
44    protected $selected;
45
46    /**
47     * @param array $params
48     */
49    public function __construct( $params ) {
50        parent::__construct( $params );
51
52        $this->msg = static::getMessageFromParams( $params );
53        $this->selected = null;
54
55        $this->makeLines();
56    }
57
58    /**
59     * @param array $params
60     * @return string
61     */
62    protected static function getMessageFromParams( $params ) {
63        if ( !empty( $params['licenses'] ) ) {
64            return $params['licenses'];
65        }
66
67        // If the licenses page is in $wgForceUIMsgAsContentMsg (which is the case
68        // on Commons), translations will be in the database, in subpages of this
69        // message (e.g. MediaWiki:Licenses/<lang>)
70        // If there is no such translation, the result will be '-' (the empty default
71        // in the i18n files), so we'll need to force it to look up the actual licenses
72        // in the default site language (= get the translation from MediaWiki:Licenses)
73        // Also see https://phabricator.wikimedia.org/T3495
74        $defaultMsg = wfMessage( 'licenses' )->inContentLanguage();
75        if ( $defaultMsg->isDisabled() ) {
76            $defaultMsg = wfMessage( 'licenses' )->inLanguage(
77                MediaWikiServices::getInstance()->getContentLanguage() );
78        }
79
80        return $defaultMsg->plain();
81    }
82
83    /**
84     * @param string $line
85     * @return License
86     */
87    protected function buildLine( $line ) {
88        return new License( $line );
89    }
90
91    /**
92     * @internal
93     */
94    protected function makeLines() {
95        $levels = [];
96        $lines = explode( "\n", $this->msg );
97
98        foreach ( $lines as $line ) {
99            if ( !str_starts_with( $line, '*' ) ) {
100                continue;
101            }
102            [ $level, $line ] = $this->trimStars( $line );
103
104            if ( str_contains( $line, '|' ) ) {
105                $obj = $this->buildLine( $line );
106                $this->stackItem( $this->lines, $levels, $obj );
107            } else {
108                if ( $level < count( $levels ) ) {
109                    $levels = array_slice( $levels, 0, $level );
110                }
111                if ( $level == count( $levels ) ) {
112                    $levels[$level - 1] = $line;
113                } elseif ( $level > count( $levels ) ) {
114                    $levels[] = $line;
115                }
116            }
117        }
118    }
119
120    /**
121     * @param string $str
122     * @return array
123     */
124    protected function trimStars( $str ) {
125        $numStars = strspn( $str, '*' );
126        return [ $numStars, ltrim( substr( $str, $numStars ), ' ' ) ];
127    }
128
129    /**
130     * @param array &$list
131     * @param array $path
132     * @param mixed $item
133     */
134    protected function stackItem( &$list, $path, $item ) {
135        $position =& $list;
136        if ( $path ) {
137            foreach ( $path as $key ) {
138                $position =& $position[$key];
139            }
140        }
141        $position[] = $item;
142    }
143
144    /**
145     * @param array $tagset
146     * @param int $depth
147     * @return string
148     */
149    protected function makeHtml( $tagset, $depth = 0 ) {
150        $html = '';
151
152        foreach ( $tagset as $key => $val ) {
153            if ( is_array( $val ) ) {
154                $html .= $this->outputOption(
155                    $key, '',
156                    [
157                        'disabled' => 'disabled'
158                    ],
159                    $depth
160                );
161                $html .= $this->makeHtml( $val, $depth + 1 );
162            } else {
163                $html .= $this->outputOption(
164                    $val->text, $val->template,
165                    [ 'title' => '{{' . $val->template . '}}' ],
166                    $depth
167                );
168            }
169        }
170
171        return $html;
172    }
173
174    /**
175     * @param string $message
176     * @param string $value
177     * @param null|array $attribs
178     * @param int $depth
179     * @return string
180     */
181    protected function outputOption( $message, $value, $attribs = null, $depth = 0 ) {
182        $msgObj = $this->msg( $message );
183        $text = $msgObj->exists() ? $msgObj->text() : $message;
184        $attribs['value'] = $value;
185        if ( $value === $this->selected && !isset( $attribs['disabled'] ) ) {
186            $attribs['selected'] = 'selected';
187        }
188
189        $val = str_repeat( /* &nbsp */ "\u{00A0}", $depth * 2 ) . $text;
190        return str_repeat( "\t", $depth ) . Html::element( 'option', $attribs, $val ) . "\n";
191    }
192
193    /**
194     * Accessor for $this->lines
195     *
196     * @return array
197     */
198    public function getLines() {
199        return $this->lines;
200    }
201
202    /**
203     * Accessor for $this->lines
204     *
205     * @return array
206     *
207     * @deprecated since 1.31 Use getLines() instead
208     */
209    public function getLicenses() {
210        return $this->getLines();
211    }
212
213    /**
214     * @inheritDoc
215     */
216    public function getInputHTML( $value ) {
217        $this->selected = $value;
218
219        // add a default "no license selected" option
220        $default = $this->buildLine( '|nolicense' );
221        array_unshift( $this->lines, $default );
222
223        $html = $this->makeHtml( $this->getLines() );
224
225        $attribs = [
226            'name' => $this->mName,
227            'id' => $this->mID
228        ];
229        if ( !empty( $this->mParams['disabled'] ) ) {
230            $attribs['disabled'] = 'disabled';
231        }
232
233        $html = Html::rawElement( 'select', $attribs, $html );
234
235        // remove default "no license selected" from lines again
236        array_shift( $this->lines );
237
238        return $html;
239    }
240}