2280ef2b752e7f1acdcf4585999e9bc6b4f48816
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / Element / InputTextElement.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form\Element;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Imaging\Icon;
19 use TYPO3\CMS\Core\Imaging\IconFactory;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Core\Utility\MathUtility;
22 use TYPO3\CMS\Core\Utility\StringUtility;
23
24 /**
25 * Generation of TCEform elements of the type "input type=text"
26 */
27 class InputTextElement extends AbstractFormElement
28 {
29 /**
30 * This will render a single-line input form field, possibly with various control/validation features
31 *
32 * @return array As defined in initializeResultArray() of AbstractNode
33 */
34 public function render()
35 {
36 /** @var IconFactory $iconFactory */
37 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
38 $languageService = $this->getLanguageService();
39
40 $table = $this->data['tableName'];
41 $fieldName = $this->data['fieldName'];
42 $row = $this->data['databaseRow'];
43 $parameterArray = $this->data['parameterArray'];
44 $resultArray = $this->initializeResultArray();
45 $isDateField = false;
46
47 $config = $parameterArray['fieldConf']['config'];
48 $specConf = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
49 $size = MathUtility::forceIntegerInRange($config['size'] ?: $this->defaultInputWidth, $this->minimumInputWidth, $this->maxInputWidth);
50 $evalList = GeneralUtility::trimExplode(',', $config['eval'], true);
51 $classes = array();
52 $attributes = array();
53
54 // set all date times available
55 $dateFormats = array(
56 'date' => '%d-%m-%Y',
57 'year' => '%Y',
58 'time' => '%H:%M',
59 'timesec' => '%H:%M:%S'
60 );
61 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat']) {
62 $dateFormats['date'] = '%m-%d-%Y';
63 }
64 $dateFormats['datetime'] = $dateFormats['time'] . ' ' . $dateFormats['date'];
65 $dateFormats['datetimesec'] = $dateFormats['timesec'] . ' ' . $dateFormats['date'];
66
67 // readonly
68 if ($config['readOnly']) {
69 $itemFormElValue = $parameterArray['itemFormElValue'];
70 if (in_array('date', $evalList)) {
71 $config['format'] = 'date';
72 } elseif (in_array('datetime', $evalList)) {
73 $config['format'] = 'datetime';
74 } elseif (in_array('time', $evalList)) {
75 $config['format'] = 'time';
76 }
77 if (in_array('password', $evalList)) {
78 $itemFormElValue = $itemFormElValue ? '*********' : '';
79 }
80 $options = $this->data;
81 $options['parameterArray'] = array(
82 'fieldConf' => array(
83 'config' => $config,
84 ),
85 'itemFormElValue' => $itemFormElValue,
86 );
87 $options['renderType'] = 'none';
88 return $this->nodeFactory->create($options)->render();
89 }
90
91 if (in_array('datetime', $evalList, true)
92 || in_array('date', $evalList)) {
93 $classes[] = 't3js-datetimepicker';
94 $isDateField = true;
95 if (in_array('datetime', $evalList)) {
96 $attributes['data-date-type'] = 'datetime';
97 $dateFormat = $dateFormats['datetime'];
98 } elseif (in_array('date', $evalList)) {
99 $attributes['data-date-type'] = 'date';
100 $dateFormat = $dateFormats['date'];
101 }
102 if ($parameterArray['itemFormElValue'] > 0) {
103 $parameterArray['itemFormElValue'] += date('Z', $parameterArray['itemFormElValue']);
104 }
105 if (isset($config['range']['lower'])) {
106 $attributes['data-date-minDate'] = (int)$config['range']['lower'];
107 }
108 if (isset($config['range']['upper'])) {
109 $attributes['data-date-maxDate'] = (int)$config['range']['upper'];
110 }
111 } elseif (in_array('time', $evalList)) {
112 $dateFormat = $dateFormats['time'];
113 $isDateField = true;
114 $classes[] = 't3js-datetimepicker';
115 $attributes['data-date-type'] = 'time';
116 } elseif (in_array('timesec', $evalList)) {
117 $dateFormat = $dateFormats['timesec'];
118 $isDateField = true;
119 $classes[] = 't3js-datetimepicker';
120 $attributes['data-date-type'] = 'timesec';
121 }
122
123 // @todo: The whole eval handling is a mess and needs refactoring
124 foreach ($evalList as $func) {
125 switch ($func) {
126 case 'required':
127 $attributes['data-formengine-validation-rules'] = $this->getValidationDataAsJsonString(array('required' => true));
128 break;
129 default:
130 // @todo: This is ugly: The code should find out on it's own whether a eval definition is a
131 // @todo: keyword like "date", or a class reference. The global registration could be dropped then
132 // Pair hook to the one in \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_input_Eval()
133 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func])) {
134 if (class_exists($func)) {
135 $evalObj = GeneralUtility::makeInstance($func);
136 if (method_exists($evalObj, 'deevaluateFieldValue')) {
137 $_params = array(
138 'value' => $parameterArray['itemFormElValue']
139 );
140 $parameterArray['itemFormElValue'] = $evalObj->deevaluateFieldValue($_params);
141 }
142 }
143 }
144 }
145 }
146 $paramsList = array(
147 'field' => $parameterArray['itemFormElName'],
148 'evalList' => implode(',', $evalList),
149 'is_in' => trim($config['is_in']),
150 );
151 // set classes
152 $classes[] = 'form-control';
153 $classes[] = 't3js-clearable';
154 $classes[] = 'hasDefaultValue';
155
156 // calculate attributes
157 $attributes['data-formengine-validation-rules'] = $this->getValidationDataAsJsonString($config);
158 $attributes['data-formengine-input-params'] = json_encode($paramsList);
159 $attributes['data-formengine-input-name'] = htmlspecialchars($parameterArray['itemFormElName']);
160 $attributes['id'] = StringUtility::getUniqueId('formengine-input-');
161 $attributes['value'] = '';
162 if (isset($config['max']) && (int)$config['max'] > 0) {
163 $attributes['maxlength'] = (int)$config['max'];
164 }
165 if (!empty($classes)) {
166 $attributes['class'] = implode(' ', $classes);
167 }
168
169 // This is the EDITABLE form field.
170 if (!empty($config['placeholder'])) {
171 $attributes['placeholder'] = trim($config['placeholder']);
172 }
173
174 if (isset($config['autocomplete'])) {
175 $attributes['autocomplete'] = empty($config['autocomplete']) ? 'off' : 'on';
176 }
177
178 // Build the attribute string
179 $attributeString = '';
180 foreach ($attributes as $attributeName => $attributeValue) {
181 $attributeString .= ' ' . $attributeName . '="' . htmlspecialchars($attributeValue) . '"';
182 }
183
184 $html = '
185 <input type="text"'
186 . $attributeString
187 . $parameterArray['onFocus'] . ' />';
188
189 // This is the ACTUAL form field - values from the EDITABLE field must be transferred to this field which is the one that is written to the database.
190 $html .= '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '" value="' . htmlspecialchars($parameterArray['itemFormElValue']) . '" />';
191
192 // Going through all custom evaluations configured for this field
193 // @todo: Similar to above code!
194 foreach ($evalList as $evalData) {
195 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$evalData])) {
196 if (class_exists($evalData)) {
197 $evalObj = GeneralUtility::makeInstance($evalData);
198 if (method_exists($evalObj, 'returnFieldJS')) {
199 $resultArray['extJSCODE'] .= LF . 'TBE_EDITOR.customEvalFunctions[' . GeneralUtility::quoteJSvalue($evalData) . '] = function(value) {' . $evalObj->returnFieldJS() . '}';
200 }
201 }
202 }
203 }
204
205 // add HTML wrapper
206 if ($isDateField) {
207 $html = '
208 <div class="input-group">
209 ' . $html . '
210 <span class="input-group-btn">
211 <label class="btn btn-default" for="' . $attributes['id'] . '">
212 ' . $iconFactory->getIcon('actions-edit-pick-date', Icon::SIZE_SMALL)->render() . '
213 </label>
214 </span>
215 </div>';
216 }
217
218 // Wrap a wizard around the item?
219 $html = $this->renderWizards(
220 array($html),
221 $config['wizards'],
222 $table,
223 $row,
224 $fieldName,
225 $parameterArray,
226 $parameterArray['itemFormElName'],
227 $specConf
228 );
229
230 // Add a wrapper to remain maximum width
231 $width = (int)$this->formMaxWidth($size);
232 $html = '<div class="form-control-wrap"' . ($width ? ' style="max-width: ' . $width . 'px"' : '') . '>' . $html . '</div>';
233 $resultArray['html'] = $html;
234 return $resultArray;
235 }
236 }