1<?php 2declare(strict_types = 1); 3namespace TYPO3\CMS\T3editor\Form\Element; 4 5/* 6 * This file is part of the TYPO3 CMS project. 7 * 8 * It is free software; you can redistribute it and/or modify it under 9 * the terms of the GNU General Public License, either version 2 10 * of the License, or any later version. 11 * 12 * For the full copyright and license information, please read the 13 * LICENSE.txt file that was distributed with this source code. 14 * 15 * The TYPO3 project - inspiring people to share! 16 */ 17 18use TYPO3\CMS\Backend\Form\Element\AbstractFormElement; 19use TYPO3\CMS\Core\Utility\GeneralUtility; 20use TYPO3\CMS\Core\Utility\MathUtility; 21use TYPO3\CMS\T3editor\Exception\InvalidModeException; 22use TYPO3\CMS\T3editor\Mode; 23use TYPO3\CMS\T3editor\Registry\AddonRegistry; 24use TYPO3\CMS\T3editor\Registry\ModeRegistry; 25use TYPO3\CMS\T3editor\T3editor; 26 27/** 28 * t3editor FormEngine widget 29 * @internal 30 */ 31class T3editorElement extends AbstractFormElement 32{ 33 /** 34 * @var array 35 */ 36 protected $resultArray; 37 38 /** 39 * @var string 40 */ 41 protected $mode = ''; 42 43 /** 44 * Default field information enabled for this element. 45 * 46 * @var array 47 */ 48 protected $defaultFieldInformation = [ 49 'tcaDescription' => [ 50 'renderType' => 'tcaDescription', 51 ], 52 ]; 53 54 /** 55 * Default field wizards enabled for this element. 56 * 57 * @var array 58 */ 59 protected $defaultFieldWizard = [ 60 'localizationStateSelector' => [ 61 'renderType' => 'localizationStateSelector', 62 ], 63 'otherLanguageContent' => [ 64 'renderType' => 'otherLanguageContent', 65 'after' => [ 66 'localizationStateSelector', 67 ], 68 ], 69 'defaultLanguageDifferences' => [ 70 'renderType' => 'defaultLanguageDifferences', 71 'after' => [ 72 'otherLanguageContent', 73 ], 74 ], 75 ]; 76 77 /** 78 * Render t3editor element 79 * 80 * @return array As defined in initializeResultArray() of AbstractNode 81 * @throws \TYPO3\CMS\T3editor\Exception\InvalidModeException 82 * @throws \InvalidArgumentException 83 * @throws \BadFunctionCallException 84 */ 85 public function render(): array 86 { 87 $this->resultArray = $this->initializeResultArray(); 88 $this->resultArray['stylesheetFiles'][] = 'EXT:t3editor/Resources/Public/JavaScript/Contrib/cm/lib/codemirror.css'; 89 $this->resultArray['stylesheetFiles'][] = 'EXT:t3editor/Resources/Public/Css/t3editor.css'; 90 $this->resultArray['requireJsModules'][] = [ 91 'TYPO3/CMS/T3editor/T3editor' => 'function(T3editor) {T3editor.observeEditorCandidates()}' 92 ]; 93 94 // Compile and register t3editor configuration 95 GeneralUtility::makeInstance(T3editor::class)->registerConfiguration(); 96 97 $registeredAddons = AddonRegistry::getInstance()->getForMode($this->getMode()->getFormatCode()); 98 foreach ($registeredAddons as $addon) { 99 foreach ($addon->getCssFiles() as $cssFile) { 100 $this->resultArray['stylesheetFiles'][] = $cssFile; 101 } 102 } 103 104 $parameterArray = $this->data['parameterArray']; 105 106 $attributes = []; 107 if (isset($parameterArray['fieldConf']['config']['rows']) && MathUtility::canBeInterpretedAsInteger($parameterArray['fieldConf']['config']['rows'])) { 108 $attributes['rows'] = $parameterArray['fieldConf']['config']['rows']; 109 } 110 111 $attributes['wrap'] = 'off'; 112 $attributes['style'] = 'width:100%;'; 113 $attributes['onchange'] = GeneralUtility::quoteJSvalue($parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged']); 114 115 $attributeString = GeneralUtility::implodeAttributes($attributes, true); 116 117 $editorHtml = $this->getHTMLCodeForEditor( 118 $parameterArray['itemFormElName'], 119 'text-monospace enable-tab', 120 $parameterArray['itemFormElValue'], 121 $attributeString, 122 $this->data['tableName'] . ' > ' . $this->data['fieldName'], 123 [ 124 'target' => 0, 125 'effectivePid' => $this->data['effectivePid'] 126 ] 127 ); 128 129 $fieldInformationResult = $this->renderFieldInformation(); 130 $fieldInformationHtml = $fieldInformationResult['html']; 131 $this->resultArray = $this->mergeChildReturnIntoExistingResult($this->resultArray, $fieldInformationResult, false); 132 133 $fieldControlResult = $this->renderFieldControl(); 134 $fieldControlHtml = $fieldControlResult['html']; 135 $this->resultArray = $this->mergeChildReturnIntoExistingResult($this->resultArray, $fieldControlResult, false); 136 137 $fieldWizardResult = $this->renderFieldWizard(); 138 $fieldWizardHtml = $fieldWizardResult['html']; 139 $this->resultArray = $this->mergeChildReturnIntoExistingResult($this->resultArray, $fieldWizardResult, false); 140 141 $html = []; 142 $html[] = '<div class="formengine-field-item t3js-formengine-field-item">'; 143 $html[] = $fieldInformationHtml; 144 $html[] = '<div class="form-control-wrap">'; 145 $html[] = '<div class="form-wizards-wrap">'; 146 $html[] = '<div class="form-wizards-element">'; 147 $html[] = '<div class="t3editor-wrapper">'; 148 $html[] = $editorHtml; 149 $html[] = '</div>'; 150 $html[] = '</div>'; 151 if (!empty($fieldControlHtml)) { 152 $html[] = '<div class="form-wizards-items-aside">'; 153 $html[] = '<div class="btn-group">'; 154 $html[] = $fieldControlHtml; 155 $html[] = '</div>'; 156 $html[] = '</div>'; 157 } 158 if (!empty($fieldWizardHtml)) { 159 $html[] = '<div class="form-wizards-items-bottom">'; 160 $html[] = $fieldWizardHtml; 161 $html[] = '</div>'; 162 } 163 $html[] = '</div>'; 164 $html[] = '</div>'; 165 $html[] = '</div>'; 166 167 $this->resultArray['html'] = implode(LF, $html); 168 169 return $this->resultArray; 170 } 171 172 /** 173 * Generates HTML with code editor 174 * 175 * @param string $name Name attribute of HTML tag 176 * @param string $class Class attribute of HTML tag 177 * @param string $content Content of the editor 178 * @param string $additionalParams Any additional editor parameters 179 * @param string $alt Alt attribute 180 * @param array $hiddenfields 181 * 182 * @return string Generated HTML code for editor 183 * @throws \TYPO3\CMS\T3editor\Exception\InvalidModeException 184 */ 185 protected function getHTMLCodeForEditor( 186 string $name, 187 string $class = '', 188 string $content = '', 189 string $additionalParams = '', 190 string $alt = '', 191 array $hiddenfields = [] 192 ): string { 193 $code = []; 194 $attributes = []; 195 $mode = $this->getMode(); 196 $registeredAddons = AddonRegistry::getInstance()->getForMode($mode->getFormatCode()); 197 198 $attributes['class'] = $class . ' t3editor'; 199 $attributes['alt'] = $alt; 200 $attributes['id'] = 't3editor_' . md5($name); 201 $attributes['name'] = $name; 202 203 $settings = AddonRegistry::getInstance()->compileSettings($registeredAddons); 204 $addons = []; 205 foreach ($registeredAddons as $addon) { 206 $addons[] = $addon->getIdentifier(); 207 } 208 209 $attributes['data-codemirror-config'] = json_encode([ 210 'mode' => $mode->getIdentifier(), 211 'addons' => json_encode($addons), 212 'options' => json_encode($settings) 213 ]); 214 215 $attributesString = ''; 216 foreach ($attributes as $attribute => $value) { 217 $attributesString .= $attribute . '="' . htmlspecialchars((string)$value) . '" '; 218 } 219 $attributesString .= $additionalParams; 220 221 $code[] = '<textarea ' . $attributesString . '>' . htmlspecialchars($content) . '</textarea>'; 222 223 if (!empty($hiddenfields)) { 224 foreach ($hiddenfields as $attributeName => $value) { 225 $code[] = '<input type="hidden" name="' . htmlspecialchars($attributeName) . '" value="' . htmlspecialchars((string)$value) . '" />'; 226 } 227 } 228 return implode(LF, $code); 229 } 230 231 /** 232 * @return Mode 233 * @throws InvalidModeException 234 */ 235 protected function getMode(): Mode 236 { 237 $config = $this->data['parameterArray']['fieldConf']['config']; 238 239 if (!isset($config['format'])) { 240 return ModeRegistry::getInstance()->getDefaultMode(); 241 } 242 243 $identifier = $config['format']; 244 if (strpos($config['format'], '/') !== false) { 245 $parts = explode('/', $config['format']); 246 $identifier = end($parts); 247 } 248 249 return ModeRegistry::getInstance()->getByFormatCode($identifier); 250 } 251} 252