e9c3ba412f94db7c24b32030b5d1fea72cd5227c
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / Element / TextElement.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\Html\RteHtmlParser;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20 use TYPO3\CMS\Core\Utility\MathUtility;
21
22 /**
23 * Generation of TCEform elements of the type "text"
24 */
25 class TextElement extends AbstractFormElement {
26
27 /**
28 * This will render a <textarea> OR RTE area form field,
29 * possibly with various control/validation features
30 *
31 * @param string $table The table name of the record
32 * @param string $field The field name which this element is supposed to edit
33 * @param array $row The record data array where the value(s) for the field can be found
34 * @param array $additionalInformation An array with additional configuration options.
35 * @return string The HTML code for the TCEform field
36 */
37 public function render($table, $field, $row, &$additionalInformation) {
38 $config = $additionalInformation['fieldConf']['config'];
39
40 // Setting columns number
41 $cols = MathUtility::forceIntegerInRange($config['cols'] ?: 30, 5, $this->formEngine->maxTextareaWidth);
42
43 // Setting number of rows
44 $rows = MathUtility::forceIntegerInRange($config['rows'] ?: 5, 1, 20);
45 $originalRows = $rows;
46
47 $itemFormElementValueLength = strlen($additionalInformation['itemFormElValue']);
48 if ($itemFormElementValueLength > $this->formEngine->charsPerRow * 2) {
49 $cols = $this->formEngine->maxTextareaWidth;
50 $rows = MathUtility::forceIntegerInRange(
51 round($itemFormElementValueLength / $this->formEngine->charsPerRow),
52 count(explode(LF, $additionalInformation['itemFormElValue'])),
53 20
54 );
55 if ($rows < $originalRows) {
56 $rows = $originalRows;
57 }
58 }
59
60 // must be called after the cols and rows calculation, so the parameters are applied
61 // to read-only fields as well.
62 if ($this->isRenderReadonly() || $config['readOnly']) {
63 $config['cols'] = $cols;
64 $config['rows'] = $rows;
65 return $this->formEngine->getSingleField_typeNone_render($config, $additionalInformation['itemFormElValue']);
66 }
67
68 $evalList = GeneralUtility::trimExplode(',', $config['eval'], TRUE);
69 if (in_array('required', $evalList, TRUE)) {
70 $this->formEngine->requiredFields[$table . '_' . $row['uid'] . '_' . $field] = $additionalInformation['itemFormElName'];
71 }
72 // Init RTE vars
73 // Set TRUE, if the RTE is loaded; If not a normal textarea is shown.
74 $rteWasLoaded = FALSE;
75 // Set TRUE, if the RTE would have been loaded if it wasn't for the disable-RTE flag in the bottom of the page...
76 $rteWouldHaveBeenLoaded = FALSE;
77 // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist. Traditionally, this is where RTE configuration has been found.
78 $specialConfiguration = BackendUtility::getSpecConfParts($additionalInformation['extra'], $additionalInformation['fieldConf']['defaultExtras']);
79 // Setting up the altItem form field, which is a hidden field containing the value
80 $altItem = '<input type="hidden" name="' . htmlspecialchars($additionalInformation['itemFormElName']) . '" value="' . htmlspecialchars($additionalInformation['itemFormElValue']) . '" />';
81 $item = '';
82 // If RTE is generally enabled (TYPO3_CONF_VARS and user settings)
83 if ($this->formEngine->RTEenabled) {
84 $parameters = BackendUtility::getSpecConfParametersFromArray($specialConfiguration['rte_transform']['parameters']);
85 // If the field is configured for RTE and if any flag-field is not set to disable it.
86 if (isset($specialConfiguration['richtext']) && (!$parameters['flag'] || !$row[$parameters['flag']])) {
87 BackendUtility::fixVersioningPid($table, $row);
88 list($recordPid, $tsConfigPid) = BackendUtility::getTSCpidCached($table, $row['uid'], $row['pid']);
89 // If the pid-value is not negative (that is, a pid could NOT be fetched)
90 if ($tsConfigPid >= 0) {
91 $rteSetup = $this->getBackendUserAuthentication()->getTSConfig('RTE', BackendUtility::getPagesTSconfig($recordPid));
92 $rteTcaTypeValue = BackendUtility::getTCAtypeValue($table, $row);
93 $rteSetupConfiguration = BackendUtility::RTEsetup($rteSetup['properties'], $table, $field, $rteTcaTypeValue);
94 if (!$rteSetupConfiguration['disabled']) {
95 if (!$this->formEngine->disableRTE) {
96 $this->formEngine->RTEcounter++;
97 // Get RTE object, draw form and set flag:
98 $rteObject = BackendUtility::RTEgetObj();
99 $item = $rteObject->drawRTE(
100 $this->formEngine,
101 $table,
102 $field,
103 $row,
104 $additionalInformation,
105 $specialConfiguration,
106 $rteSetupConfiguration,
107 $rteTcaTypeValue,
108 '',
109 $tsConfigPid
110 );
111
112 // Wizard
113 $item = $this->formEngine->renderWizards(
114 array($item, $altItem),
115 $config['wizards'],
116 $table,
117 $row,
118 $field,
119 $additionalInformation,
120 $additionalInformation['itemFormElName'],
121 $specialConfiguration,
122 TRUE
123 );
124 $rteWasLoaded = TRUE;
125 } else {
126 $rteWouldHaveBeenLoaded = TRUE;
127 $this->formEngine->commentMessages[] = $additionalInformation['itemFormElName'] . ': RTE is disabled by the on-page RTE-flag (probably you can enable it by the check-box in the bottom of this page!)';
128 }
129 } else {
130 $this->formEngine->commentMessages[] = $additionalInformation['itemFormElName'] . ': RTE is disabled by the Page TSconfig, "RTE"-key (eg. by RTE.default.disabled=0 or such)';
131 }
132 } else {
133 $this->formEngine->commentMessages[] = $additionalInformation['itemFormElName'] . ': PID value could NOT be fetched. Rare error, normally with new records.';
134 }
135 } else {
136 if (!isset($specialConfiguration['richtext'])) {
137 $this->formEngine->commentMessages[] = $additionalInformation['itemFormElName'] . ': RTE was not configured for this field in TCA-types';
138 }
139 if (!(!$parameters['flag'] || !$row[$parameters['flag']])) {
140 $this->formEngine->commentMessages[] = $additionalInformation['itemFormElName'] . ': Field-flag (' . $additionalInformation['flag'] . ') has been set to disable RTE!';
141 }
142 }
143 }
144 // Display ordinary field if RTE was not loaded.
145 if (!$rteWasLoaded) {
146 // Show message, if no RTE (field can only be edited with RTE!)
147 if ($specialConfiguration['rte_only']) {
148 $item = '<p><em>' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.noRTEfound')) . '</em></p>';
149 } else {
150 if ($specialConfiguration['nowrap']) {
151 $wrap = 'off';
152 } else {
153 $wrap = $config['wrap'] ?: 'virtual';
154 }
155 $classes = array();
156 if ($specialConfiguration['fixed-font']) {
157 $classes[] = 'fixed-font';
158 }
159 if ($specialConfiguration['enable-tab']) {
160 $classes[] = 'enable-tab';
161 }
162 $formWidthText = $this->formWidthText($cols, $wrap);
163 // add the max-height from the users' preference to it
164 $maximumHeight = (int)$this->getBackendUserAuthentication()->uc['resizeTextareas_MaxHeight'];
165 if ($maximumHeight > 0) {
166 $formWidthText = str_replace('style="', 'style="max-height: ' . $maximumHeight . 'px; ', $formWidthText);
167 }
168
169 // Extract class attributes from $formWidthText (otherwise it would be added twice to the output)
170 $res = array();
171 if (preg_match('/ class="(.+?)"/', $formWidthText, $res)) {
172 $formWidthText = str_replace(' class="' . $res[1] . '"', '', $formWidthText);
173 $classes = array_merge($classes, explode(' ', $res[1]));
174 }
175
176 if (!empty($classes)) {
177 $class = ' class="tceforms-textarea t3js-formengine-textarea ' . implode(' ', $classes) . '"';
178 } else {
179 $class = ' class="tceforms-textarea t3js-formengine-textarea"';
180 }
181
182 foreach ($evalList as $func) {
183 if ($func === 'required') {
184 $this->formEngine->registerRequiredProperty('field', $table . '_' . $row['uid'] . '_' . $field, $additionalInformation['itemFormElName']);
185 } else {
186 // Pair hook to the one in \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_input_Eval()
187 // and \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_text_Eval()
188 $evalObj = GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func] . ':&' . $func);
189 if (is_object($evalObj) && method_exists($evalObj, 'deevaluateFieldValue')) {
190 $_params = array(
191 'value' => $additionalInformation['itemFormElValue']
192 );
193 $additionalInformation['itemFormElValue'] = $evalObj->deevaluateFieldValue($_params);
194 }
195 }
196 }
197 $textOnChange = implode('', $additionalInformation['fieldChangeFunc']);
198 $additionalAttributes = '';
199 if (isset($config['max']) && (int)$config['max'] > 0) {
200 $additionalAttributes = ' maxlength="' . (int)$config['max'] . '"';
201 }
202 $item .= '
203 <textarea ' . 'id="' . str_replace('.', '', uniqid('tceforms-textarea-', TRUE)) . '" ' . 'name="' . $additionalInformation['itemFormElName']
204 . '"' . $formWidthText . $class . ' ' . 'rows="' . $rows . '" ' . 'wrap="' . $wrap . '" ' . 'onchange="'
205 . htmlspecialchars($textOnChange) . '"' . $this->formEngine->getPlaceholderAttribute($table, $field, $config, $row)
206 . $additionalInformation['onFocus'] . $additionalAttributes . '>' . GeneralUtility::formatForTextarea($additionalInformation['itemFormElValue']) . '</textarea>';
207 $item = $this->formEngine->renderWizards(
208 array($item, $altItem),
209 $config['wizards'],
210 $table,
211 $row,
212 $field,
213 $additionalInformation,
214 $additionalInformation['itemFormElName'],
215 $specialConfiguration,
216 $rteWouldHaveBeenLoaded
217 );
218 }
219 }
220 return $item;
221 }
222
223 /**
224 * Returns parameters to set with for a textarea field
225 *
226 * @param int $size The abstract width (1-48)
227 * @param string $wrap Empty or "off" (text wrapping in the field or not)
228 * @return string The "cols" attribute string (or style from formWidth())
229 * @see formWidth()
230 */
231 protected function formWidthText($size = 48, $wrap = '') {
232 $wTags = $this->formEngine->formWidth($size, TRUE);
233 // Netscape 6+ seems to have this ODD problem where there WILL ALWAYS be wrapping
234 // with the cols-attribute set and NEVER without the col-attribute...
235 if (strtolower(trim($wrap)) != 'off' && $GLOBALS['CLIENT']['BROWSER'] == 'net' && $GLOBALS['CLIENT']['VERSION'] >= 5) {
236 $wTags .= ' cols="' . $size . '"';
237 }
238 return $wTags;
239 }
240
241 }