a626a66cf245e88156672db29fb1aa74791fda8e
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / Element / InputElement.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\Backend\Utility\IconUtility;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20 use TYPO3\CMS\Core\Utility\MathUtility;
21
22 /**
23 * Generation of TCEform elements of the type "input"
24 */
25 class InputElement extends AbstractFormElement {
26
27 /**
28 * This will render a single-line input form field, possibly with various control/validation features
29 *
30 * @return array As defined in initializeResultArray() of AbstractNode
31 */
32 public function render() {
33 $languageService = $this->getLanguageService();
34
35 $table = $this->globalOptions['table'];
36 $fieldName = $this->globalOptions['fieldName'];
37 $row = $this->globalOptions['databaseRow'];
38 $parameterArray = $this->globalOptions['parameterArray'];
39 $resultArray = $this->initializeResultArray();
40 $isDateField = FALSE;
41
42 $config = $parameterArray['fieldConf']['config'];
43 $specConf = BackendUtility::getSpecConfParts($parameterArray['extra'], $parameterArray['fieldConf']['defaultExtras']);
44 $size = MathUtility::forceIntegerInRange($config['size'] ?: $this->defaultInputWidth, $this->minimumInputWidth, $this->maxInputWidth);
45 $evalList = GeneralUtility::trimExplode(',', $config['eval'], TRUE);
46 $classes = array();
47 $attributes = array();
48
49 if (!isset($config['checkbox'])) {
50 $config['checkbox'] = '0';
51 $checkboxIsset = FALSE;
52 } else {
53 $checkboxIsset = TRUE;
54 }
55
56 // set all date times available
57 $dateFormats = array(
58 'date' => '%d-%m-%Y',
59 'year' => '%Y',
60 'time' => '%H:%M',
61 'timesec' => '%H:%M:%S'
62 );
63 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat']) {
64 $dateFormats['date'] = '%m-%d-%Y';
65 }
66 $dateFormats['datetime'] = $dateFormats['time'] . ' ' . $dateFormats['date'];
67 $dateFormats['datetimesec'] = $dateFormats['timesec'] . ' ' . $dateFormats['date'];
68
69 // readonly
70 if ($this->isGlobalReadonly() || $config['readOnly']) {
71 $itemFormElValue = $parameterArray['itemFormElValue'];
72 if (in_array('date', $evalList)) {
73 $config['format'] = 'date';
74 } elseif (in_array('datetime', $evalList)) {
75 $config['format'] = 'datetime';
76 } elseif (in_array('time', $evalList)) {
77 $config['format'] = 'time';
78 }
79 if (in_array('password', $evalList)) {
80 $itemFormElValue = $itemFormElValue ? '*********' : '';
81 }
82 /** @var NoneElement $noneElement */
83 $noneElement = GeneralUtility::makeInstance(NoneElement::class);
84 $noneElementOptions = $this->globalOptions;
85 $noneElementOptions['parameterArray'] = array(
86 'fieldConf' => array(
87 'config' => $config,
88 ),
89 'itemFormElValue' => $itemFormElValue,
90 );
91 return $noneElement->setGlobalOptions($noneElementOptions)->render();
92 }
93
94 if (in_array('datetime', $evalList, TRUE)
95 || in_array('date', $evalList)) {
96
97 $classes[] = 't3js-datetimepicker';
98 $isDateField = TRUE;
99 if (in_array('datetime', $evalList)) {
100 $attributes['data-date-type'] = 'datetime';
101 $dateFormat = $dateFormats['datetime'];
102 } elseif (in_array('date', $evalList)) {
103 $attributes['data-date-type'] = 'date';
104 $dateFormat = $dateFormats['date'];
105 }
106 if ($parameterArray['itemFormElValue'] > 0) {
107 $parameterArray['itemFormElValue'] += date('Z', $parameterArray['itemFormElValue']);
108 }
109 if (isset($config['range']['lower'])) {
110 $attributes['data-date-minDate'] = (int)$config['range']['lower'];
111 }
112 if (isset($config['range']['upper'])) {
113 $attributes['data-date-maxDate'] = (int)$config['range']['upper'];
114 }
115 } elseif (in_array('time', $evalList)) {
116 $dateFormat = $dateFormats['time'];
117 $isDateField = TRUE;
118 $classes[] = 't3js-datetimepicker';
119 $attributes['data-date-type'] = 'time';
120 } elseif (in_array('timesec', $evalList)) {
121 $dateFormat = $dateFormats['timesec'];
122 $isDateField = TRUE;
123 $classes[] = 't3js-datetimepicker';
124 $attributes['data-date-type'] = 'timesec';
125 } else {
126 if ($checkboxIsset === FALSE) {
127 $config['checkbox'] = '';
128 }
129 }
130
131 foreach ($evalList as $func) {
132 switch ($func) {
133 case 'required':
134 $resultArray['requiredFields'][$table . '_' . $row['uid'] . '_' . $fieldName] = $parameterArray['itemFormElName'];
135 $tabAndInlineStack = $this->globalOptions['tabAndInlineStack'];
136 if (!empty($tabAndInlineStack) && preg_match('/^(.+\\])\\[(\\w+)\\]$/', $parameterArray['itemFormElName'], $match)) {
137 array_shift($match);
138 $resultArray['requiredNested'][$parameterArray['itemFormElName']] = array(
139 'parts' => $match,
140 'level' => $tabAndInlineStack,
141 );
142 }
143 // Mark this field for date/time disposal:
144 if (array_intersect($evalList, array('date', 'datetime', 'time', 'timesec'))) {
145 $resultArray['requiredAdditional'][$parameterArray['itemFormElName']] = array(
146 'isPositiveNumber' => TRUE,
147 );
148 }
149 break;
150 default:
151 // Pair hook to the one in \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_input_Eval()
152 $evalObj = GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func] . ':&' . $func);
153 if (is_object($evalObj) && method_exists($evalObj, 'deevaluateFieldValue')) {
154 $_params = array(
155 'value' => $parameterArray['itemFormElValue']
156 );
157 $parameterArray['itemFormElValue'] = $evalObj->deevaluateFieldValue($_params);
158 }
159 }
160 }
161 $paramsList = GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . ',' . GeneralUtility::quoteJSvalue(implode(',', $evalList)) . ',' . GeneralUtility::quoteJSvalue(trim($config['is_in'])) . ',' . ($config['checkbox'] ? 1 : 0) . ',' . GeneralUtility::quoteJSvalue($config['checkbox']);
162 $parameterArray['fieldChangeFunc'] = array_merge(array('typo3form.fieldGet' => 'typo3form.fieldGet(' . $paramsList . ');'), $parameterArray['fieldChangeFunc']);
163
164 // set classes
165 $classes[] = 'form-control';
166 $classes[] = 't3js-clearable';
167 $classes[] = 'hasDefaultValue';
168
169 // calculate attributes
170 $attributes['id'] = str_replace('.', '', uniqid('formengine-input-', TRUE));
171 $attributes['name'] = $parameterArray['itemFormElName'] . '_hr';
172 $attributes['value'] = '';
173 $attributes['maxlength'] = $config['max'] ?: 256;
174 $attributes['onchange'] = implode('', $parameterArray['fieldChangeFunc']);
175
176 if (!empty($styles)) {
177 $attributes['style'] = implode(' ', $styles);
178 }
179 if (!empty($classes)) {
180 $attributes['class'] = implode(' ', $classes);
181 }
182 if (isset($config['max']) && (int)$config['max'] > 0) {
183 $attributes['maxlength'] = (int)$config['max'];
184 }
185
186 // Build the attribute string
187 $attributeString = '';
188 foreach ($attributes as $attributeName => $attributeValue) {
189 $attributeString .= ' ' . $attributeName . '="' . htmlspecialchars($attributeValue) . '"';
190 }
191
192 // This is the EDITABLE form field.
193 $placeholderValue = $this->getPlaceholderValue($table, $config, $row);
194 $placeholderAttribute = '';
195 if (!empty($placeholderValue)) {
196 $placeholderAttribute = ' placeholder="' . htmlspecialchars(trim($languageService->sL($placeholderValue))) . '" ';
197 }
198
199 $html = '
200 <input type="text"'
201 . $attributeString
202 . $placeholderAttribute
203 . $parameterArray['onFocus'] . ' />';
204
205 // 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.
206 $html .= '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '" value="' . htmlspecialchars($parameterArray['itemFormElValue']) . '" />';
207
208 $resultArray['extJSCODE'] = 'typo3form.fieldSet(' . $paramsList . ');';
209 // Going through all custom evaluations configured for this field
210 foreach ($evalList as $evalData) {
211 $evalObj = GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$evalData] . ':&' . $evalData);
212 if (is_object($evalObj) && method_exists($evalObj, 'returnFieldJS')) {
213 $resultArray['extJSCODE'] .= LF . 'TBE_EDITOR.customEvalFunctions[\'' . $evalData . '\'] = function(value) {' . $evalObj->returnFieldJS() . '}';
214 }
215 }
216
217 // add HTML wrapper
218 if ($isDateField) {
219 $html = '
220 <div class="input-group">
221 ' . $html . '
222 <span class="input-group-btn">
223 <label class="btn btn-default" for="' . $attributes['id'] . '">
224 ' . IconUtility::getSpriteIcon('actions-edit-pick-date') . '
225 </label>
226 </span>
227 </div>';
228 }
229
230 // Creating an alternative item without the JavaScript handlers.
231 $altItem = '
232 <input type="hidden" name="' . $parameterArray['itemFormElName'] . '_hr" value="" />
233 <input type="hidden" name="' . $parameterArray['itemFormElName'] . '" value="' . htmlspecialchars($parameterArray['itemFormElValue']) . '" />';
234
235 // Wrap a wizard around the item?
236 $html = $this->renderWizards(
237 array($html, $altItem),
238 $config['wizards'],
239 $table,
240 $row,
241 $fieldName,
242 $parameterArray,
243 $parameterArray['itemFormElName'] . '_hr', $specConf
244 );
245
246 // Add a wrapper to remain maximum width
247 $width = (int)$this->formMaxWidth($size);
248 $html = '<div class="form-control-wrap"' . ($width ? ' style="max-width: ' . $width . 'px"' : '') . '>' . $html . '</div>';
249 $resultArray['html'] = $html;
250 return $resultArray;
251 }
252
253 }