Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
49.72% covered (danger)
49.72%
89 / 179
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
HTMLFeatureField
49.72% covered (danger)
49.72%
89 / 179
0.00% covered (danger)
0.00%
0 / 6
190.71
0.00% covered (danger)
0.00%
0 / 1
 getCheckboxHTML
89.29% covered (warning)
89.29%
25 / 28
0.00% covered (danger)
0.00%
0 / 1
5.03
 getHeaderHTML
94.74% covered (success)
94.74%
36 / 38
0.00% covered (danger)
0.00%
0 / 1
7.01
 getMainHTML
17.35% covered (danger)
17.35%
17 / 98
0.00% covered (danger)
0.00%
0 / 1
222.84
 getInputHTML
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
2.00
 getInputOOUI
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFieldLayoutOOUI
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * This file is part of the MediaWiki extension BetaFeatures.
4 *
5 * BetaFeatures 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 * BetaFeatures 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
16 * along with BetaFeatures.  If not, see <http://www.gnu.org/licenses/>.
17 *
18 * HTML feature field
19 *
20 * @file
21 * @ingroup Extensions
22 * @copyright 2013 Mark Holmquist and others; see AUTHORS
23 * @license GPL-2.0-or-later
24 */
25
26namespace MediaWiki\Extension\BetaFeatures;
27
28use HTMLCheckField;
29use HTMLFormFieldLayout;
30use MediaWiki\Html\Html;
31use OOUI\CheckboxInputWidget;
32use OOUI\IconWidget;
33
34class HTMLFeatureField extends HTMLCheckField {
35    /**
36     * @param string $value
37     * @return string
38     */
39    protected function getCheckboxHTML( $value ) {
40        if ( !empty( $this->mParams['invert'] ) ) {
41            $value = !$value;
42        }
43
44        $out = $this->mParent->getOutput();
45        $out->addModules( 'ext.betaFeatures' );
46        $out->addModuleStyles( 'ext.betaFeatures.styles' );
47        $out->enableOOUI();
48
49        // TODO: Support $this->getTooltipAndAccessKey?
50
51        $extraParams = [];
52        // Only support disable here, it shouldn't be hide partially
53        if ( isset( $this->mParams['disable-if'] ) ) {
54            $extraParams['classes'] = [ 'mw-htmlform-disable-if' ];
55            $extraParams['condState']['disable'] = $this->parseCondState( $this->mParams['disable-if'] );
56        }
57        return Html::openElement( 'div', [ 'class' => 'mw-ui-feature-checkbox' ] ) .
58            new HTMLFormFieldLayout(
59                new CheckboxInputWidget( [
60                    'infusable' => true,
61                    'name' => $this->mName,
62                    'selected' => $value,
63                    'value' => 1,
64                    'classes' => $this->mClass ? [ $this->mClass ] : [],
65                    'disabled' => isset( $this->mParams['disabled'] ) &&
66                        $this->mParams['disabled'] === true,
67                ] ),
68                [
69                    'infusable' => true,
70                    'align' => 'inline',
71                    'label' => $this->mLabel,
72                ] + $extraParams
73            ) .
74            Html::closeElement( 'div' );
75    }
76
77    /**
78     * @param string $value
79     * @return string HTML
80     */
81    private function getHeaderHTML( $value ) {
82        $html = Html::openElement( 'div', [ 'class' => 'mw-ui-feature-header' ] );
83
84        $html .= Html::rawElement(
85            'div',
86            [ 'class' => 'mw-ui-feature-title-contain' ],
87            $this->getCheckboxHTML( $value )
88        );
89
90        if ( isset( $this->mParams['info-message'] ) ) {
91            $infoLink = $this->mParent->msg( $this->mParams['info-message'] )->text();
92        } else {
93            $infoLink = $this->mParams['info-link'];
94        }
95
96        if ( isset( $this->mParams['discussion-message'] ) ) {
97            $discussionLink = $this->mParent->msg( $this->mParams['discussion-message'] )->text();
98        } else {
99            $discussionLink = $this->mParams['discussion-link'];
100        }
101
102        $infoLinkClasses = [ 'mw-ui-feature-info-links' ];
103
104        if ( $infoLink !== null || $discussionLink !== null ) {
105            $infoLinkClasses[] = 'filled';
106        }
107
108        $html .= Html::openElement( 'div', [ 'class' => $infoLinkClasses ] );
109
110        $out = $this->mParent->getOutput();
111
112        if ( $infoLink !== null ) {
113            $out->addModuleStyles( 'oojs-ui.styles.icons-content' );
114            $html .= Html::rawElement( 'a', [
115                    'href' => $infoLink,
116                    'class' => 'mw-ui-feature-info-link',
117                ],
118                new IconWidget( [ 'icon' => 'article' ] ) .
119                $this->mParent->msg( 'mw-ui-feature-info' )->escaped()
120            );
121            $html .= ' ';
122        }
123
124        if ( $discussionLink !== null ) {
125            $out->addModuleStyles( 'oojs-ui.styles.icons-alerts' );
126            $html .= Html::rawElement( 'a', [
127                    'href' => $discussionLink,
128                    'class' => 'mw-ui-feature-discussion-link',
129                ],
130                new IconWidget( [ 'icon' => 'speechBubbles' ] ) .
131                $this->mParent->msg( 'mw-ui-feature-discuss' )->escaped()
132            );
133        }
134
135        // Close mw-ui-feature-info-links and then -header
136        $html .= Html::closeElement( 'div' ) . Html::closeElement( 'div' );
137
138        return $html;
139    }
140
141    /**
142     * @param string $value
143     * @return string HTML
144     */
145    private function getMainHTML( $value ) {
146        $parent = $this->mParent;
147
148        $html = Html::openElement( 'div', [ 'class' => 'mw-ui-feature-main' ] );
149
150        $html .= Html::openElement( 'div', [ 'class' => 'mw-ui-feature-meta' ] );
151
152        if ( isset( $this->mParams['user-count'] ) ) {
153            $userCountMsg = 'mw-ui-feature-user-count';
154
155            if ( isset( $this->mParams['user-count-msg'] ) ) {
156                $userCountMsg = $this->mParams['user-count-msg'];
157            }
158
159            $html .= Html::rawElement(
160                'p',
161                [ 'class' => 'mw-ui-feature-user-count' ],
162                $parent->msg( $userCountMsg )->numParams( $this->mParams['user-count'] )->escaped()
163            );
164        }
165
166        if ( isset( $this->mParams['desc-message'] ) ) {
167            $html .= Html::rawElement(
168                'p',
169                [ 'class' => 'mw-ui-feature-description' ],
170                $parent->msg( $this->mParams['desc-message'] )->parse() );
171        }
172
173        $html .= Html::openElement( 'ul', [ 'class' => 'mw-ui-feature-requirements-list' ] );
174
175        if ( isset( $this->mParams['requirements'] ) ) {
176            if (
177                isset( $this->mParams['requirements']['javascript'] ) &&
178                $this->mParams['requirements']['javascript']
179            ) {
180                $html .= Html::rawElement(
181                    'li',
182                    [ 'class' => 'mw-ui-feature-requirements-javascript' ],
183                    $parent->msg( 'mw-ui-feature-requirements-javascript' )->escaped()
184                );
185            }
186
187            $unsupportedList = $this->mParams['requirements']['unsupportedList'] ?? false;
188            if ( $unsupportedList ) {
189                $html .= Html::openElement(
190                    'li',
191                    [ 'class' => 'mw-ui-feature-requirements-browser' ]
192                );
193                $browserCount = count( $unsupportedList );
194                $html .= $parent->msg( 'mw-ui-feature-requirements-browser', $browserCount )->escaped();
195                $html .= Html::openElement( 'ul' );
196                foreach ( $unsupportedList as $browser => $versions ) {
197                    $browserString = $browser;
198                    if ( $versions ) {
199                        foreach ( $versions as $version ) {
200                            $browserString .= ' ' . implode( ' ', $version );
201                        }
202                    }
203                    $html .= Html::element(
204                        'li',
205                        [],
206                        $browserString
207                    );
208                }
209                $html .= Html::closeElement( 'ul' );
210                $html .= Html::closeElement( 'li' );
211            }
212
213            if (
214                isset( $this->mParams['requirements']['skin-not-supported'] ) &&
215                $this->mParams['requirements']['skin-not-supported'] === true
216            ) {
217                $html .= Html::openElement(
218                    'li',
219                    [ 'class' => 'mw-ui-feature-requirements-skins' ]
220                );
221                $skinCount = count( $this->mParams['requirements']['skins'] );
222                $html .= $parent->msg( 'mw-ui-feature-requirements-skins', $skinCount )->escaped();
223                $html .= Html::openElement( 'ul' );
224                foreach ( $this->mParams['requirements']['skins'] as $skin ) {
225                    $html .= Html::element(
226                        'li',
227                        [],
228                        $parent->msg( "skinname-$skin" )->text()
229                    );
230                }
231                $html .= Html::closeElement( 'ul' );
232                $html .= Html::closeElement( 'li' );
233            }
234
235            if ( isset( $this->mParams['requirements']['betafeatures-messages'] ) ) {
236                $html .= Html::openElement(
237                    'li',
238                    [ 'class' => 'mw-ui-feature-requirements-betafeatures' ]
239                );
240                $featureCount = count( $this->mParams['requirements']['betafeatures-messages'] );
241                $html .= $parent->msg( 'mw-ui-feature-requirements-betafeatures', $featureCount )->escaped();
242                $html .= Html::openElement( 'ul' );
243                foreach ( $this->mParams['requirements']['betafeatures-messages'] as $message ) {
244                    $html .= Html::rawElement(
245                        'li',
246                        [],
247                        $parent->msg( $message )->escaped()
248                    );
249                }
250                $html .= Html::closeElement( 'ul' );
251                $html .= Html::closeElement( 'li' );
252            }
253        }
254
255        // mw-ui-feature-requirements-list
256        $html .= Html::closeElement( 'ul' );
257
258        // Close -meta
259        $html .= Html::closeElement( 'div' );
260
261        $html .= Html::openElement( 'div', [ 'class' => 'mw-ui-feature-screenshot-contain' ] );
262
263        if ( isset( $this->mParams['screenshot'] ) ) {
264            $screenshot = $this->mParams['screenshot'];
265
266            // The screenshot parameter is either a string with a filename
267            // or an array that specifies a screenshot for each language,
268            // and default screenshots for rtl and ltr languages
269            if ( is_array( $screenshot ) ) {
270                $language = $this->mParent->getLanguage();
271                $langCode = $language->getCode();
272
273                if ( array_key_exists( $langCode, $screenshot ) ) {
274                    $screenshot = $screenshot[$langCode];
275                } else {
276                    $screenshot = $screenshot[$language->getDir()];
277                }
278            }
279
280            $html .= Html::element( 'img', [
281                'src' => $screenshot,
282                'class' => 'mw-ui-feature-screenshot',
283                'alt' => '',
284            ] );
285        }
286
287        // Close -screenshot-contain and then -main
288        $html .= Html::closeElement( 'div' ) . Html::closeElement( 'div' );
289
290        return $html;
291    }
292
293    /** @inheritDoc */
294    public function getInputHTML( $value ) {
295        $divClasses = [ 'mw-ui-feature-field' ];
296
297        // Use 'cssclass' to populate this. Separate from 'class', of course.
298        if ( $this->mClass !== '' ) {
299            $divClasses[] = $this->mClass;
300        }
301
302        return Html::rawElement(
303            'div',
304            [ 'class' => $divClasses ],
305            Html::rawElement(
306                'div',
307                [ 'class' => 'mw-ui-feature-contain' ],
308                $this->getHeaderHTML( $value ) . $this->getMainHTML( $value )
309            )
310        );
311    }
312
313    /** @inheritDoc */
314    public function getInputOOUI( $value ) {
315        // Use the same output as for the HTML version, otherwise OOUIHTMLForm would use
316        // a plain checkbox, inherited from HTMLCheckField. This isn't actually a widget
317        // (just a HTML string) but that's okay, HTMLFormField::getOOUI() will handle it.
318        // @phan-suppress-next-line PhanTypeMismatchReturn
319        return $this->getInputHTML( $value );
320    }
321
322    /** @inheritDoc */
323    protected function getFieldLayoutOOUI( $inputField, $config ) {
324        // Label is already included in the field's HTML, do not duplicate it
325        unset( $config['label'] );
326        return parent::getFieldLayoutOOUI( $inputField, $config );
327    }
328}