1<?php 2 3/* 4 * This file is part of the TYPO3 CMS project. 5 * 6 * It is free software; you can redistribute it and/or modify it under 7 * the terms of the GNU General Public License, either version 2 8 * of the License, or any later version. 9 * 10 * For the full copyright and license information, please read the 11 * LICENSE.txt file that was distributed with this source code. 12 * 13 * The TYPO3 project - inspiring people to share! 14 */ 15 16namespace TYPO3\CMS\Backend\Form\Element; 17 18use TYPO3\CMS\Core\Localization\LanguageService; 19use TYPO3\CMS\Core\Utility\GeneralUtility; 20use TYPO3\CMS\Core\Utility\MathUtility; 21use TYPO3\CMS\Core\Utility\StringUtility; 22 23/** 24 * Render an input field with a color picker 25 */ 26class InputColorPickerElement extends AbstractFormElement 27{ 28 /** 29 * Default field information enabled for this element. 30 * 31 * @var array 32 */ 33 protected $defaultFieldInformation = [ 34 'tcaDescription' => [ 35 'renderType' => 'tcaDescription', 36 ], 37 ]; 38 39 /** 40 * Default field wizards enabled for this element. 41 * 42 * @var array 43 */ 44 protected $defaultFieldWizard = [ 45 'localizationStateSelector' => [ 46 'renderType' => 'localizationStateSelector', 47 ], 48 'otherLanguageContent' => [ 49 'renderType' => 'otherLanguageContent', 50 'after' => [ 51 'localizationStateSelector' 52 ], 53 ], 54 'defaultLanguageDifferences' => [ 55 'renderType' => 'defaultLanguageDifferences', 56 'after' => [ 57 'otherLanguageContent', 58 ], 59 ], 60 ]; 61 62 /** 63 * This will render a single-line input form field, possibly with various control/validation features 64 * 65 * @return array As defined in initializeResultArray() of AbstractNode 66 */ 67 public function render() 68 { 69 $evalData = ''; 70 $languageService = $this->getLanguageService(); 71 72 $table = $this->data['tableName']; 73 $fieldName = $this->data['fieldName']; 74 $row = $this->data['databaseRow']; 75 $parameterArray = $this->data['parameterArray']; 76 $resultArray = $this->initializeResultArray(); 77 78 $itemValue = $parameterArray['itemFormElValue']; 79 $config = $parameterArray['fieldConf']['config']; 80 $size = MathUtility::forceIntegerInRange($config['size'] ?: $this->defaultInputWidth, $this->minimumInputWidth, $this->maxInputWidth); 81 $evalList = GeneralUtility::trimExplode(',', $config['eval'], true); 82 $width = (int)$this->formMaxWidth($size); 83 $nullControlNameEscaped = htmlspecialchars('control[active][' . $table . '][' . $row['uid'] . '][' . $fieldName . ']'); 84 85 $fieldInformationResult = $this->renderFieldInformation(); 86 $fieldInformationHtml = $fieldInformationResult['html']; 87 $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false); 88 89 if ($config['readOnly']) { 90 $html = []; 91 $html[] = '<div class="formengine-field-item t3js-formengine-field-item">'; 92 $html[] = $fieldInformationHtml; 93 $html[] = '<div class="form-wizards-wrap">'; 94 $html[] = '<div class="form-wizards-element">'; 95 $html[] = '<div class="form-control-wrap" style="max-width: ' . $width . 'px">'; 96 $html[] = '<input class="form-control" value="' . htmlspecialchars($itemValue) . '" type="text" disabled>'; 97 $html[] = '</div>'; 98 $html[] = '</div>'; 99 $html[] = '</div>'; 100 $html[] = '</div>'; 101 $resultArray['html'] = implode(LF, $html); 102 return $resultArray; 103 } 104 105 // @todo: The whole eval handling is a mess and needs refactoring 106 foreach ($evalList as $func) { 107 // @todo: This is ugly: The code should find out on it's own whether an eval definition is a 108 // @todo: keyword like "date", or a class reference. The global registration could be dropped then 109 // Pair hook to the one in \TYPO3\CMS\Core\DataHandling\DataHandler::checkValue_input_Eval() 110 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][$func])) { 111 if (class_exists($func)) { 112 $evalObj = GeneralUtility::makeInstance($func); 113 if (method_exists($evalObj, 'deevaluateFieldValue')) { 114 $_params = [ 115 'value' => $itemValue 116 ]; 117 $itemValue = $evalObj->deevaluateFieldValue($_params); 118 } 119 if (method_exists($evalObj, 'returnFieldJS')) { 120 // @todo: variable $evalData must be replaced with $func 121 $resultArray['additionalJavaScriptPost'][] = 'TBE_EDITOR.customEvalFunctions[' . GeneralUtility::quoteJSvalue($evalData) . '] = function(value) {' . $evalObj->returnFieldJS() . '};'; 122 } 123 } 124 } 125 } 126 127 // Load needed js library 128 $resultArray['requireJsModules'][] = [ 129 'TYPO3/CMS/Backend/ColorPicker' => 'function(ColorPicker){ColorPicker.initialize()}' 130 ]; 131 132 $attributes = [ 133 'value' => $itemValue, 134 'id' => StringUtility::getUniqueId('formengine-input-'), 135 'class' => implode(' ', [ 136 'form-control', 137 'hasDefaultValue', 138 't3js-clearable', 139 't3js-color-picker', 140 'formengine-colorpickerelement', 141 ]), 142 'data-formengine-validation-rules' => $this->getValidationDataAsJsonString($config), 143 'data-formengine-input-params' => (string)json_encode([ 144 'field' => $parameterArray['itemFormElName'], 145 'evalList' => implode(',', $evalList), 146 'is_in' => trim($config['is_in']), 147 ]), 148 'data-formengine-input-name' => $parameterArray['itemFormElName'], 149 ]; 150 151 if (isset($config['max']) && (int)$config['max'] > 0) { 152 $attributes['maxlength'] = (string)(int)$config['max']; 153 } 154 if (!empty($config['placeholder'])) { 155 $attributes['placeholder'] = trim($config['placeholder']); 156 } 157 if (isset($config['autocomplete'])) { 158 $attributes['autocomplete'] = empty($config['autocomplete']) ? 'new-' . $fieldName : 'on'; 159 } 160 161 $valuePickerHtml = []; 162 if (isset($config['valuePicker']['items']) && is_array($config['valuePicker']['items'])) { 163 $valuePickerHtml[] = '<select class="t3js-colorpicker-value-trigger form-control tceforms-select tceforms-wizardselect">'; 164 $valuePickerHtml[] = '<option></option>'; 165 foreach ($config['valuePicker']['items'] as $item) { 166 $valuePickerHtml[] = '<option value="' . htmlspecialchars($item[1]) . '">' . htmlspecialchars($languageService->sL($item[0])) . '</option>'; 167 } 168 $valuePickerHtml[] = '</select>'; 169 } 170 171 $fieldWizardResult = $this->renderFieldWizard(); 172 $fieldWizardHtml = $fieldWizardResult['html']; 173 $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false); 174 175 $fieldControlResult = $this->renderFieldControl(); 176 $fieldControlHtml = $fieldControlResult['html']; 177 $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false); 178 179 $mainFieldHtml = []; 180 $mainFieldHtml[] = '<div class="form-control-wrap" style="max-width: ' . $width . 'px">'; 181 $mainFieldHtml[] = '<div class="form-wizards-wrap">'; 182 $mainFieldHtml[] = '<div class="form-wizards-element">'; 183 $mainFieldHtml[] = '<input type="text" ' . GeneralUtility::implodeAttributes($attributes, true) . ' />'; 184 $mainFieldHtml[] = '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '" value="' . htmlspecialchars($itemValue) . '" />'; 185 $mainFieldHtml[] = '</div>'; 186 $mainFieldHtml[] = '<div class="form-wizards-items-aside">'; 187 $mainFieldHtml[] = '<div class="btn-group">'; 188 $mainFieldHtml[] = $fieldControlHtml; 189 $mainFieldHtml[] = implode(LF, $valuePickerHtml); 190 $mainFieldHtml[] = '</div>'; 191 $mainFieldHtml[] = '</div>'; 192 if (!empty($fieldWizardHtml)) { 193 $mainFieldHtml[] = '<div class="form-wizards-items-bottom">'; 194 $mainFieldHtml[] = $fieldWizardHtml; 195 $mainFieldHtml[] = '</div>'; 196 } 197 $mainFieldHtml[] = '</div>'; 198 $mainFieldHtml[] = '</div>'; 199 $mainFieldHtml = implode(LF, $mainFieldHtml); 200 201 $fullElement = $mainFieldHtml; 202 if ($this->hasNullCheckboxButNoPlaceholder()) { 203 $checked = $itemValue !== null ? ' checked="checked"' : ''; 204 $fullElement = []; 205 $fullElement[] = '<div class="t3-form-field-disable"></div>'; 206 $fullElement[] = '<div class="checkbox t3-form-field-eval-null-checkbox">'; 207 $fullElement[] = '<label for="' . $nullControlNameEscaped . '">'; 208 $fullElement[] = '<input type="hidden" name="' . $nullControlNameEscaped . '" value="0" />'; 209 $fullElement[] = '<input type="checkbox" name="' . $nullControlNameEscaped . '" id="' . $nullControlNameEscaped . '" value="1"' . $checked . ' />'; 210 $fullElement[] = $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.nullCheckbox'); 211 $fullElement[] = '</label>'; 212 $fullElement[] = '</div>'; 213 $fullElement[] = $mainFieldHtml; 214 $fullElement = implode(LF, $fullElement); 215 } elseif ($this->hasNullCheckboxWithPlaceholder()) { 216 $checked = $itemValue !== null ? ' checked="checked"' : ''; 217 $placeholder = $shortenedPlaceholder = $config['placeholder'] ?? ''; 218 $disabled = ''; 219 $fallbackValue = 0; 220 if (strlen($placeholder) > 0) { 221 $shortenedPlaceholder = GeneralUtility::fixed_lgd_cs($placeholder, 20); 222 if ($placeholder !== $shortenedPlaceholder) { 223 $overrideLabel = sprintf( 224 $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.placeholder.override'), 225 '<span title="' . htmlspecialchars($placeholder) . '">' . htmlspecialchars($shortenedPlaceholder) . '</span>' 226 ); 227 } else { 228 $overrideLabel = sprintf( 229 $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.placeholder.override'), 230 htmlspecialchars($placeholder) 231 ); 232 } 233 } else { 234 $overrideLabel = $languageService->sL( 235 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.placeholder.override_not_available' 236 ); 237 } 238 $fullElement = []; 239 $fullElement[] = '<div class="checkbox t3js-form-field-eval-null-placeholder-checkbox">'; 240 $fullElement[] = '<label for="' . $nullControlNameEscaped . '">'; 241 $fullElement[] = '<input type="hidden" name="' . $nullControlNameEscaped . '" value="' . $fallbackValue . '" />'; 242 $fullElement[] = '<input type="checkbox" name="' . $nullControlNameEscaped . '" id="' . $nullControlNameEscaped . '" value="1"' . $checked . $disabled . ' />'; 243 $fullElement[] = $overrideLabel; 244 $fullElement[] = '</label>'; 245 $fullElement[] = '</div>'; 246 $fullElement[] = '<div class="t3js-formengine-placeholder-placeholder">'; 247 $fullElement[] = '<div class="form-control-wrap" style="max-width:' . $width . 'px">'; 248 $fullElement[] = '<input type="text" class="form-control" disabled="disabled" value="' . htmlspecialchars($shortenedPlaceholder) . '" />'; 249 $fullElement[] = '</div>'; 250 $fullElement[] = '</div>'; 251 $fullElement[] = '<div class="t3js-formengine-placeholder-formfield">'; 252 $fullElement[] = $mainFieldHtml; 253 $fullElement[] = '</div>'; 254 $fullElement = implode(LF, $fullElement); 255 } 256 257 $resultArray['html'] = '<div class="formengine-field-item t3js-formengine-field-item">' . $fieldInformationHtml . $fullElement . '</div>'; 258 return $resultArray; 259 } 260 261 /** 262 * @return LanguageService 263 */ 264 protected function getLanguageService() 265 { 266 return $GLOBALS['LANG']; 267 } 268} 269