Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 132
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
CodexHTMLForm
0.00% covered (danger)
0.00%
0 / 131
0.00% covered (danger)
0.00%
0 / 9
756
0.00% covered (danger)
0.00%
0 / 1
 loadInputFromParameters
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getHTML
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 formatField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFormAttributes
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 wrapForm
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 wrapFieldSetSection
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getLegend
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
42
 formatSection
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 getButtons
0.00% covered (danger)
0.00%
0 / 69
0.00% covered (danger)
0.00%
0 / 1
156
1<?php
2
3/**
4 * HTML form generation using Codex components.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 * @file
22 */
23
24namespace MediaWiki\HTMLForm;
25
26use MediaWiki\Html\Html;
27use MediaWiki\HTMLForm\Field\HTMLButtonField;
28use MediaWiki\Linker\Linker;
29use MediaWiki\Parser\Sanitizer;
30
31/**
32 * Codex based HTML form
33 *
34 * @since 1.41
35 */
36class CodexHTMLForm extends HTMLForm {
37
38    protected $displayFormat = 'codex';
39
40    public static function loadInputFromParameters( $fieldname, $descriptor,
41        HTMLForm $parent = null
42    ) {
43        $field = parent::loadInputFromParameters( $fieldname, $descriptor, $parent );
44        $field->setShowEmptyLabel( false );
45        return $field;
46    }
47
48    public function getHTML( $submitResult ) {
49        $this->getOutput()->addModuleStyles( [
50            'codex-styles',
51            'mediawiki.htmlform.codex.styles',
52        ] );
53
54        return parent::getHTML( $submitResult );
55    }
56
57    /**
58     * @inheritDoc
59     */
60    protected function formatField( HTMLFormField $field, $value ) {
61        return $field->getCodex( $value );
62    }
63
64    protected function getFormAttributes() {
65        $attribs = parent::getFormAttributes();
66        $attribs['class'] = [ 'mw-htmlform', 'mw-htmlform-codex' ];
67        return $attribs;
68    }
69
70    public function wrapForm( $html ) {
71        return Html::rawElement( 'form', $this->getFormAttributes(), $html );
72    }
73
74    protected function wrapFieldSetSection( $legend, $section, $attributes, $isRoot ) {
75        $attributes['class'] = 'cdx-field';
76        $legendElement = Html::rawElement( 'legend', [ 'class' => [ 'cdx-label' ] ], $legend );
77        return Html::rawElement( 'fieldset', $attributes, "$legendElement\n$section" ) . "\n";
78    }
79
80    /**
81     * Note that this method returns HTML, while the parent method specifies that it should return
82     * a plain string. This method is only used to get the `$legend` argument of the
83     * wrapFieldSetSection() call, so we can be reasonably sure that returning HTML here is okay.
84     *
85     * @inheritDoc
86     */
87    public function getLegend( $key ) {
88        $legendText = $this->msg(
89            $this->mMessagePrefix ? "{$this->mMessagePrefix}-$key" : $key
90        )->text();
91        $legendTextMarkup = Html::element(
92            'span',
93            [ 'class' => [ 'cdx-label__label__text' ] ],
94            $legendText
95        );
96
97        $isOptional = $this->mSections[$key]['optional'] ?? false;
98        $optionalFlagMarkup = '';
99        if ( $isOptional ) {
100            $optionalFlagMarkup = Html::element(
101                'span',
102                [ 'class' => [ 'cdx-label__label__optional-flag' ] ],
103                $this->msg( 'word-separator' )->text() . $this->msg( 'htmlform-optional-flag' )->text()
104            );
105        }
106
107        $descriptionMarkup = '';
108        if ( isset( $this->mSections[$key]['description-message'] ) ) {
109            $needsParse = $this->mSections[ $key ][ 'description-message-parse' ] ?? false;
110            $descriptionMessage = $this->msg( $this->mSections[ $key ][ 'description-message' ] );
111            $descriptionMarkup = Html::rawElement(
112                'span',
113                [ 'class' => [ 'cdx-label__description' ] ],
114                $needsParse ? $descriptionMessage->parse() : $descriptionMessage->escaped()
115            );
116        } elseif ( isset( $this->mSections[$key]['description'] ) ) {
117            $descriptionMarkup = Html::element(
118                'span',
119                [ 'class' => [ 'cdx-label__description' ] ],
120                $this->mSections[ $key ][ 'description' ]
121            );
122        }
123
124        return Html::rawElement(
125            'span',
126            [ 'class' => [ 'cdx-label__label' ] ],
127            $legendTextMarkup . $optionalFlagMarkup
128        ) . $descriptionMarkup;
129    }
130
131    protected function formatSection( array $fieldsHtml, $sectionName, $anyFieldHasLabel ) {
132        if ( !$fieldsHtml ) {
133            // Do not generate any wrappers for empty sections. Sections may be empty if they only
134            // have subsections, but no fields. A legend will still be added in
135            // wrapFieldSetSection().
136            return '';
137        }
138
139        $html = implode( '', $fieldsHtml );
140
141        if ( $sectionName ) {
142            $attribs = [
143                'id' => Sanitizer::escapeIdForAttribute( $sectionName ),
144                'class' => [ 'cdx-field__control' ]
145            ];
146
147            return Html::rawElement( 'div', $attribs, $html );
148        }
149
150        return $html;
151    }
152
153    /**
154     * Get the submit and cancel buttons.
155     * @stable to override
156     * @return string HTML.
157     */
158    public function getButtons() {
159        $buttons = [];
160
161        if ( $this->mShowSubmit ) {
162            $value = $this->getSubmitText();
163            // Define flag classes for the submit button
164            $submitFlags = $this->mSubmitFlags;
165            $submitClasses = [ 'mw-htmlform-submit', 'cdx-button' ];
166            $submitButtonLabel = $this->getSubmitText();
167            $submitID = $this->mSubmitID;
168            $submitName = $this->mSubmitName;
169            $submitTooltip = [];
170
171            if ( isset( $this->mSubmitTooltip ) ) {
172                $submitTooltip += Linker::tooltipAndAccesskeyAttribs( $this->mSubmitTooltip );
173            }
174
175            $buttonAttribs = [
176                'value' => $value,
177                'type' => 'submit',
178                'name' => $submitName,
179                'id' => $submitID,
180                'class' => $submitClasses,
181                'formnovalidate' => false,
182            ] + $submitTooltip;
183
184            $button = HTMLButtonField::buildCodexComponent(
185                $submitFlags,
186                $submitButtonLabel,
187                $buttonAttribs
188            );
189            $buttons[] = $button;
190        }
191
192        // The reset button is unused and will be removed from HTMLForm (T361032).
193
194        if ( $this->mShowCancel ) {
195            $target = $this->getCancelTargetURL();
196            $buttonClasses = [
197                'cdx-button',
198                'cdx-button--fake-button',
199                'cdx-button--fake-button--enabled',
200            ];
201            $attr = [
202                'href' => $target,
203                'class' => $buttonClasses,
204                'role' => 'button',
205            ];
206            $cancelButton = Html::element(
207                'a', $attr, $this->msg( 'cancel' )->text()
208            );
209            $buttons[] = $cancelButton;
210        }
211
212        foreach ( $this->mButtons as $button ) {
213            $attrs = [
214                'type' => 'submit',
215                'name' => $button['name'],
216                'value' => $button['value']
217            ];
218
219            if ( isset( $button['label-message'] ) ) {
220                $label = $this->getMessage( $button['label-message'] )->parse();
221            } elseif ( isset( $button['label'] ) ) {
222                $label = htmlspecialchars( $button['label'] );
223            } elseif ( isset( $button['label-raw'] ) ) {
224                $label = $button['label-raw'];
225            } else {
226                $label = htmlspecialchars( $button['value'] );
227            }
228
229            // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset Always set in self::addButton
230            if ( $button['attribs'] ) {
231                // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset Always set in self::addButton
232                $attrs += $button['attribs'];
233            }
234
235            if ( isset( $button['id'] ) ) {
236                $attrs['id'] = $button['id'];
237            }
238
239            if ( isset( $attrs['class'] ) ) {
240                // Ensure $attrs['class'] is always treated as an array whether it's initially set
241                // as an array or a string.
242                $attrs['class'] = (array)( $attrs['class'] ?? [] );
243            }
244
245            $attrs['class'][] = 'cdx-button';
246
247            $buttons[] = Html::rawElement( 'button', $attrs, $label ) . "\n";
248        }
249
250        if ( !$buttons ) {
251            return '';
252        }
253
254        return Html::rawElement(
255            'div',
256            [ 'class' => 'mw-htmlform-submit-buttons' ],
257            implode( "\n", $buttons )
258        ) . "\n";
259    }
260}
261
262/** @deprecated class alias since 1.42 */
263class_alias( CodexHTMLForm::class, 'CodexHTMLForm' );