Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 157
0.00% covered (danger)
0.00%
0 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
PFTextAreaInput
0.00% covered (danger)
0.00%
0 / 157
0.00% covered (danger)
0.00%
0 / 11
3192
0.00% covered (danger)
0.00%
0 / 1
 getName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultCargoTypes
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultCargoTypeLists
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 __construct
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
240
 getDefaultPropTypes
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getOtherPropTypesHandled
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getOtherPropTypeListsHandled
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getParameters
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
2
 getResourceModuleNames
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 getTextAreaAttributes
0.00% covered (danger)
0.00%
0 / 53
0.00% covered (danger)
0.00%
0 / 1
342
 getHtmlText
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
156
1<?php
2
3/**
4 * @file
5 * @ingroup PF
6 */
7
8/**
9 * @ingroup PFFormInput
10 */
11class PFTextAreaInput extends PFFormInput {
12
13    protected $mEditor = null;
14
15    public static function getName(): string {
16        return 'textarea';
17    }
18
19    public static function getDefaultCargoTypes() {
20        return [
21            'Text' => [],
22            'Searchtext' => []
23        ];
24    }
25
26    public static function getDefaultCargoTypeLists() {
27        return [
28            'Text' => [ 'field_type' => 'text', 'is_list' => 'true' ],
29            'Searchtext' => [ 'field_type' => 'text', 'is_list' => 'true' ]
30        ];
31    }
32
33    /**
34     * @param string $input_number The number of the input in the form. For a simple HTML input
35     *  element this should end up in the id attribute in the format 'input_<number>'.
36     * @param string $cur_value The current value of the input field. For a simple HTML input
37     *  element this should end up in the value attribute.
38     * @param string $input_name The name of the input. For a simple HTML input element this should
39     *  end up in the name attribute.
40     * @param bool $disabled Is this input disabled?
41     * @param array $other_args An associative array of other parameters that were present in the
42     *  input definition.
43     */
44    public function __construct( $input_number, $cur_value, $input_name, $disabled, array $other_args ) {
45        global $wgOut;
46
47        parent::__construct( $input_number, $cur_value, $input_name, $disabled, $other_args );
48
49        $newClasses = null;
50
51        // WikiEditor
52        if (
53            array_key_exists( 'editor', $this->mOtherArgs ) &&
54            $this->mOtherArgs['editor'] == 'wikieditor' &&
55            in_array( 'ext.wikiEditor', $wgOut->getResourceLoader()->getModuleNames() )
56        ) {
57            $this->mEditor = 'wikieditor';
58            $this->addJsInitFunctionData( 'window.ext.wikieditor.init' );
59        }
60
61        // VisualEditor (plus VEForAll)
62        if (
63            array_key_exists( 'editor', $this->mOtherArgs ) &&
64            $this->mOtherArgs['editor'] == 'visualeditor' &&
65            ExtensionRegistry::getInstance()->isLoaded( 'VisualEditor' )
66        ) {
67            $this->mEditor = 'visualeditor';
68            if ( $input_name != 'pf_free_text' && !array_key_exists( 'isSection', $this->mOtherArgs ) ) {
69                $newClasses = 'vePartOfTemplate';
70            }
71        }
72
73        // TinyMCE
74        if (
75            array_key_exists( 'editor', $this->mOtherArgs ) &&
76            $this->mOtherArgs['editor'] == 'tinymce'
77        ) {
78            $this->mEditor = 'tinymce';
79            global $wgTinyMCEEnabled;
80            $wgTinyMCEEnabled = true;
81            $newClasses = 'mceMinimizeOnBlur';
82            if ( $input_name != 'pf_free_text' && !array_key_exists( 'isSection', $this->mOtherArgs ) ) {
83                $newClasses .= ' mcePartOfTemplate';
84            }
85        }
86
87        if ( $newClasses == null ) {
88            // Do nothing.
89        } elseif ( array_key_exists( 'class', $this->mOtherArgs ) ) {
90            $this->mOtherArgs['class'] .= ' ' . $newClasses;
91        } else {
92            $this->mOtherArgs['class'] = $newClasses;
93        }
94    }
95
96    public static function getDefaultPropTypes() {
97        return [ '_cod' => [] ];
98    }
99
100    public static function getOtherPropTypesHandled() {
101        return [ '_txt', '_wpg' ];
102    }
103
104    public static function getOtherPropTypeListsHandled() {
105        return [ '_txt', '_wpg' ];
106    }
107
108    public static function getParameters() {
109        $params = parent::getParameters();
110
111        $params['preload'] = [
112            'name' => 'preload',
113            'type' => 'string',
114            'description' => wfMessage( 'pf_forminputs_preload' )->text()
115        ];
116        $params['rows'] = [
117            'name' => 'rows',
118            'type' => 'int',
119            'description' => wfMessage( 'pf_forminputs_rows' )->text()
120        ];
121        $params['cols'] = [
122            'name' => 'cols',
123            'type' => 'int',
124            'description' => wfMessage( 'pf_forminputs_cols' )->text()
125        ];
126        $params['maxlength'] = [
127            'name' => 'maxlength',
128            'type' => 'int',
129            'description' => wfMessage( 'pf_forminputs_maxlength' )->text()
130        ];
131        $params['placeholder'] = [
132            'name' => 'placeholder',
133            'type' => 'string',
134            'description' => wfMessage( 'pf_forminputs_placeholder' )->text()
135        ];
136        $params['autogrow'] = [
137            'name' => 'autogrow',
138            'type' => 'boolean',
139            'description' => wfMessage( 'pf_forminputs_autogrow' )->text()
140        ];
141        return $params;
142    }
143
144    /**
145     * Returns the names of the resource modules this input type uses.
146     *
147     * Returns the names of the modules as an array or - if there is only one
148     * module - as a string.
149     *
150     * @return null|string|array
151     */
152    public function getResourceModuleNames() {
153        if ( $this->mEditor == 'wikieditor' ) {
154            return 'ext.pageforms.wikieditor';
155        } elseif ( $this->mEditor == 'visualeditor' ) {
156            return 'ext.veforall.main';
157        } elseif ( $this->mEditor == 'tinymce' ) {
158            return 'ext.tinymce';
159        } else {
160            return null;
161        }
162    }
163
164    protected function getTextAreaAttributes() {
165        global $wgPageFormsTabIndex, $wgPageFormsFieldNum;
166
167        // Use a special ID for the free text field -
168        // this was originally done for FCKeditor, but maybe it's
169        // useful for other stuff too.
170        $input_id = $this->mInputName == 'pf_free_text' ? 'pf_free_text' : "input_$wgPageFormsFieldNum";
171
172        if ( $this->mEditor == 'wikieditor' ) {
173            global $wgOut;
174            $wgOut->addModuleStyles( 'ext.wikiEditor.styles' );
175            $wgOut->addModules( 'ext.wikiEditor' );
176            $className = 'wikieditor ';
177        } elseif ( $this->mEditor == 'visualeditor' ) {
178            $className = 'visualeditor ';
179        } elseif ( $this->mEditor == 'tinymce' ) {
180            $className = 'tinymce ';
181        } else {
182            $className = '';
183        }
184
185        $className .= ( $this->mIsMandatory ) ? 'mandatoryField' : 'createboxInput';
186        if ( array_key_exists( 'unique', $this->mOtherArgs ) ) {
187            $className .= ' uniqueField';
188        }
189
190        if ( array_key_exists( 'class', $this->mOtherArgs ) ) {
191            $className .= ' ' . $this->mOtherArgs['class'];
192        }
193
194        if ( array_key_exists( 'autogrow', $this->mOtherArgs ) ) {
195            $className .= ' autoGrow';
196        }
197
198        if ( array_key_exists( 'rows', $this->mOtherArgs ) ) {
199            $rows = $this->mOtherArgs['rows'];
200        } else {
201            $rows = 5;
202        }
203
204        $textarea_attrs = [
205            'tabindex' => $wgPageFormsTabIndex,
206            'name' => $this->mInputName,
207            'id' => $input_id,
208            'class' => $className,
209            'rows' => $rows,
210        ];
211
212        if ( array_key_exists( 'cols', $this->mOtherArgs ) ) {
213            $textarea_attrs['cols'] = $this->mOtherArgs['cols'];
214            // Needed to prevent CSS from overriding the manually-
215            // set width.
216            $textarea_attrs['style'] = 'width: auto';
217        } elseif ( array_key_exists( 'autogrow', $this->mOtherArgs ) ) {
218            // If 'autogrow' has been set, automatically set
219            // the number of columns - otherwise, the Javascript
220            // won't be able to know how many characters there
221            // are per line, and thus won't work.
222            $textarea_attrs['cols'] = 90;
223            $textarea_attrs['style'] = 'width: auto';
224        } else {
225            $textarea_attrs['cols'] = 90;
226            $textarea_attrs['style'] = 'width: 100%';
227        }
228
229        if ( $this->mIsDisabled ) {
230            $textarea_attrs['disabled'] = 'disabled';
231        }
232
233        if ( array_key_exists( 'maxlength', $this->mOtherArgs ) ) {
234            $maxlength = $this->mOtherArgs['maxlength'];
235            // For every actual character pressed (i.e., excluding
236            // things like the Shift key), reduce the string to its
237            // allowed length if it's exceeded that.
238            // This JS code is complicated so that it'll work
239            // correctly in IE - IE moves the cursor to the end
240            // whenever this.value is reset, so we'll make sure to
241            // do that only when we need to.
242            $maxLengthJSCheck = "if (window.event && window.event.keyCode < 48 && window.event.keyCode != 13) return; if (this.value.length > $maxlength) { this.value = this.value.substring(0, $maxlength); }";
243            $textarea_attrs['onKeyDown'] = $maxLengthJSCheck;
244            $textarea_attrs['onKeyUp'] = $maxLengthJSCheck;
245        }
246
247        if ( array_key_exists( 'placeholder', $this->mOtherArgs ) ) {
248            $textarea_attrs['placeholder'] = $this->mOtherArgs['placeholder'];
249        }
250        if ( array_key_exists( 'autocapitalize', $this->mOtherArgs ) ) {
251            $textarea_attrs['autocapitalize'] = $this->mOtherArgs['autocapitalize'];
252        }
253        if ( array_key_exists( 'feeds to map', $this->mOtherArgs ) ) {
254            global $wgPageFormsMapsWithFeeders;
255            $targetMapName = $this->mOtherArgs['feeds to map'];
256            if ( array_key_exists( 'part_of_multiple', $this->mOtherArgs ) ) {
257                $targetMapName = str_replace( '[', '[num][', $targetMapName );
258            }
259            $wgPageFormsMapsWithFeeders[$targetMapName] = true;
260            $textarea_attrs['data-feeds-to-map'] = $targetMapName;
261        }
262
263        return $textarea_attrs;
264    }
265
266    /**
267     * Returns the HTML code to be included in the output page for this input.
268     * @return string
269     */
270    public function getHtmlText(): string {
271        $textarea_attrs = $this->getTextAreaAttributes();
272
273        $text = Html::element( 'textarea', $textarea_attrs, $this->mCurrentValue );
274        $spanClass = 'inputSpan';
275        if ( $this->mInputName == 'pf_free_text' ) {
276            $spanClass .= ' freeText';
277        }
278        if ( array_key_exists( 'isSection', $this->mOtherArgs ) ) {
279            $spanClass .= ' pageSection';
280        }
281        if ( $this->mIsMandatory ) {
282            $spanClass .= ' mandatoryFieldSpan';
283        }
284        if ( array_key_exists( 'unique', $this->mOtherArgs ) ) {
285            $spanClass .= ' uniqueFieldSpan';
286        }
287        if ( $this->mEditor == 'visualeditor' && !$this->mIsDisabled ) {
288            $spanClass .= ' ve-area-wrapper';
289        }
290        $spanAttrs = [ 'class' => $spanClass ];
291        if ( $this->mEditor == 'visualeditor' ) {
292            // VisualEditor, by default, autogrows with no limit -
293            // which is fine in a regular edit page, but not good
294            // in a form. So we add a "max height" value, which in
295            // turn gets processed by VEForAll into true CSS.
296            $maxHeightNumOnly = true;
297            if ( array_key_exists( 'max height', $this->mOtherArgs ) ) {
298                $maxHeightStr = $this->mOtherArgs['max height'];
299                if ( substr( $maxHeightStr, -2 ) == 'em' || substr( $maxHeightStr, -2 ) == 'vh' ) {
300                    $maxHeightNumOnly = false;
301                    $maxHeight = $maxHeightStr;
302                } else {
303                    $maxHeight = (int)$maxHeightStr;
304                }
305            } else {
306                $config = RequestContext::getMain()->getConfig();
307                $maxHeight = $config->get( 'PageFormsVisualEditorMaxHeight' );
308            }
309            if ( $maxHeightNumOnly ) {
310                $spanAttrs['data-max-height'] = $maxHeight . 'px';
311            } else {
312                $spanAttrs['data-max-height'] = $maxHeight;
313            }
314        }
315
316        $text = Html::rawElement( 'span', $spanAttrs, $text );
317
318        return $text;
319    }
320
321}