[TASK] Use single quotes instead of double quotes
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / FormResultCompiler.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form;
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\Authentication\BackendUserAuthentication;
19 use TYPO3\CMS\Core\Page\PageRenderer;
20 use TYPO3\CMS\Core\Utility\ArrayUtility;
21 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Lang\LanguageService;
24
25 /**
26 * This is form engine - Class for creating the backend editing forms.
27 *
28 * @internal This class and its exposed method and method signatures will change
29 */
30 class FormResultCompiler
31 {
32 /**
33 * @var string
34 */
35 protected $extJSCODE = '';
36
37 /**
38 * @var array HTML of additional hidden fields rendered by sub containers
39 */
40 protected $hiddenFieldAccum = array();
41
42 /**
43 * Can be set to point to a field name in the form which will be set to '1' when the form
44 * is submitted with a *save* button. This way the recipient script can determine that
45 * the form was submitted for save and not "close" for example.
46 *
47 * @var string
48 */
49 protected $doSaveFieldName = '';
50
51 /**
52 * @var array Data array from IRRE pushed to frontend as json array
53 */
54 protected $inlineData = array();
55
56 /**
57 * List of additional style sheet files to load
58 *
59 * @var array
60 */
61 protected $stylesheetFiles = [];
62
63 /**
64 * Additional JavaScript printed after the form
65 *
66 * @var array
67 */
68 protected $additionalJS_post = array();
69
70 /**
71 * Additional JavaScript executed on submit; If you set "OK" variable it will raise an error
72 * about RTEs not being loaded and offer to block further submission.
73 *
74 * @var array
75 */
76 protected $additionalJS_submit = array();
77
78 /**
79 * Array with requireJS modules, use module name as key, the value could be callback code.
80 * Use NULL as value if no callback is used.
81 *
82 * @var array
83 */
84 protected $requireJsModules = array();
85
86 /**
87 * @var PageRenderer
88 */
89 protected $pageRenderer = null;
90
91 /**
92 * Merge existing data with the given result array
93 *
94 * @param array $resultArray Array returned by child
95 * @return void
96 * @internal Temporary method to use FormEngine class as final data merger
97 */
98 public function mergeResult(array $resultArray)
99 {
100 $this->doSaveFieldName = $resultArray['doSaveFieldName'];
101 foreach ($resultArray['additionalJavaScriptPost'] as $element) {
102 $this->additionalJS_post[] = $element;
103 }
104 foreach ($resultArray['additionalJavaScriptSubmit'] as $element) {
105 $this->additionalJS_submit[] = $element;
106 }
107 if (!empty($resultArray['requireJsModules'])) {
108 foreach ($resultArray['requireJsModules'] as $module) {
109 $moduleName = null;
110 $callback = null;
111 if (is_string($module)) {
112 // if $module is a string, no callback
113 $moduleName = $module;
114 $callback = null;
115 } elseif (is_array($module)) {
116 // if $module is an array, callback is possible
117 foreach ($module as $key => $value) {
118 $moduleName = $key;
119 $callback = $value;
120 break;
121 }
122 }
123 if ($moduleName !== null) {
124 if (!empty($this->requireJsModules[$moduleName]) && $callback !== null) {
125 $existingValue = $this->requireJsModules[$moduleName];
126 if (!is_array($existingValue)) {
127 $existingValue = array($existingValue);
128 }
129 $existingValue[] = $callback;
130 $this->requireJsModules[$moduleName] = $existingValue;
131 } else {
132 $this->requireJsModules[$moduleName] = $callback;
133 }
134 }
135 }
136 }
137 $this->extJSCODE = $this->extJSCODE . LF . $resultArray['extJSCODE'];
138 $this->inlineData = $resultArray['inlineData'];
139 foreach ($resultArray['additionalHiddenFields'] as $element) {
140 $this->hiddenFieldAccum[] = $element;
141 }
142 foreach ($resultArray['stylesheetFiles'] as $stylesheetFile) {
143 if (!in_array($stylesheetFile, $this->stylesheetFiles)) {
144 $this->stylesheetFiles[] = $stylesheetFile;
145 }
146 }
147
148 if (!empty($resultArray['inlineData'])) {
149 $resultArrayInlineData = $this->inlineData;
150 $resultInlineData = $resultArray['inlineData'];
151 ArrayUtility::mergeRecursiveWithOverrule($resultArrayInlineData, $resultInlineData);
152 $this->inlineData = $resultArrayInlineData;
153 }
154 }
155
156 /**
157 * JavaScript code added BEFORE the form is drawn:
158 *
159 * @return string A <script></script> section with JavaScript.
160 */
161 public function JStop()
162 {
163 $stylesheetHtml = [];
164 foreach ($this->stylesheetFiles as $stylesheetFile) {
165 $stylesheetHtml[] = '<link rel="stylesheet" type="text/css" href="' . $stylesheetFile . '" />';
166 }
167 return implode(LF, $stylesheetHtml);
168 }
169
170 /**
171 * Prints necessary JavaScript for TCEforms (after the form HTML).
172 * currently this is used to transform page-specific options in the TYPO3.Settings array for JS
173 * so the JS module can access these values
174 *
175 * @return string
176 */
177 public function printNeededJSFunctions()
178 {
179 // set variables to be accessible for JS
180 $pageRenderer = $this->getPageRenderer();
181 $pageRenderer->addInlineSetting('FormEngine', 'formName', 'editform');
182 $pageRenderer->addInlineSetting('FormEngine', 'backPath', '');
183
184 return $this->JSbottom('editform');
185 }
186
187 /**
188 * JavaScript bottom code
189 *
190 * @param string $formname The identification of the form on the page.
191 * @return string A section with JavaScript - if $update is FALSE, embedded in <script></script>
192 */
193 protected function JSbottom($formname = 'forms[0]')
194 {
195 $languageService = $this->getLanguageService();
196 $jsFile = array();
197
198 // @todo: this is messy here - "additional hidden fields" should be handled elsewhere
199 $html = implode(LF, $this->hiddenFieldAccum);
200
201 $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/md5.js');
202 // load the main module for FormEngine with all important JS functions
203 $this->requireJsModules['TYPO3/CMS/Backend/FormEngine'] = 'function(FormEngine) {
204 FormEngine.setBrowserUrl(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('wizard_element_browser')) . ');
205 }';
206 $this->requireJsModules['TYPO3/CMS/Backend/FormEngineValidation'] = 'function(FormEngineValidation) {
207 FormEngineValidation.setUsMode(' . ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? '1' : '0') . ');
208 FormEngineValidation.registerReady();
209 }';
210
211 $pageRenderer = $this->getPageRenderer();
212 foreach ($this->requireJsModules as $moduleName => $callbacks) {
213 if (!is_array($callbacks)) {
214 $callbacks = array($callbacks);
215 }
216 foreach ($callbacks as $callback) {
217 $pageRenderer->loadRequireJsModule($moduleName, $callback);
218 }
219 }
220 $pageRenderer->loadJquery();
221 $pageRenderer->loadExtJS();
222 // Load tree stuff here
223 $pageRenderer->addJsFile('sysext/backend/Resources/Public/JavaScript/tree.js');
224 $pageRenderer->addInlineLanguageLabelFile(ExtensionManagementUtility::extPath('lang') . 'locallang_csh_corebe.xlf', 'tcatree');
225 $pageRenderer->addJsFile('sysext/backend/Resources/Public/JavaScript/notifications.js');
226 if (ExtensionManagementUtility::isLoaded('rtehtmlarea')) {
227 // This js addition is hackish ... it will always load this file even if not RTE
228 // is added here. But this simplifies RTE initialization a lot and is thus kept for now.
229 $pageRenderer->addJsFile('sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/NameSpace/NameSpace.js');
230 }
231
232 $beUserAuth = $this->getBackendUserAuthentication();
233 // Make textareas resizable and flexible ("autogrow" in height)
234 $textareaSettings = array(
235 'autosize' => (bool)$beUserAuth->uc['resizeTextareas_Flexible']
236 );
237 $pageRenderer->addInlineSettingArray('Textarea', $textareaSettings);
238
239 $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.tbe_editor.js');
240 $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ValueSlider');
241 // Needed for FormEngine manipulation (date picker)
242 $dateFormat = ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? array('MM-DD-YYYY', 'HH:mm MM-DD-YYYY') : array('DD-MM-YYYY', 'HH:mm DD-MM-YYYY'));
243 $pageRenderer->addInlineSetting('DateTimePicker', 'DateFormat', $dateFormat);
244
245 // support placeholders for IE9 and lower
246 $clientInfo = GeneralUtility::clientInfo();
247 if ($clientInfo['BROWSER'] == 'msie' && $clientInfo['VERSION'] <= 9) {
248 $this->loadJavascriptLib('sysext/core/Resources/Public/JavaScript/Contrib/placeholders.jquery.min.js');
249 }
250
251 $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileListLocalisation');
252
253 $pageRenderer->addInlineLanguagelabelFile(
254 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('lang') . 'locallang_core.xlf',
255 'file_upload'
256 );
257 // Load codemirror for T3Editor
258 if (ExtensionManagementUtility::isLoaded('t3editor')) {
259 $this->loadJavascriptLib('sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/codemirror.js');
260 }
261 // We want to load jQuery-ui inside our js. Enable this using requirejs.
262 $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.inline.js');
263 $out = '
264 inline.setNoTitleString("' . addslashes(BackendUtility::getNoRecordTitle(true)) . '");
265 ';
266
267 $out .= '
268 TBE_EDITOR.formname = "' . $formname . '";
269 TBE_EDITOR.formnameUENC = "' . rawurlencode($formname) . '";
270 TBE_EDITOR.backPath = "";
271 TBE_EDITOR.isPalettedoc = null;
272 TBE_EDITOR.doSaveFieldName = "' . ($this->doSaveFieldName ? addslashes($this->doSaveFieldName) : '') . '";
273 TBE_EDITOR.labels.fieldsChanged = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.fieldsChanged')) . ';
274 TBE_EDITOR.labels.fieldsMissing = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.fieldsMissing')) . ';
275 TBE_EDITOR.labels.maxItemsAllowed = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.maxItemsAllowed')) . ';
276 TBE_EDITOR.labels.refresh_login = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login')) . ';
277 TBE_EDITOR.labels.refreshRequired = {};
278 TBE_EDITOR.labels.refreshRequired.title = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:mess.refreshRequired.title')) . ';
279 TBE_EDITOR.labels.refreshRequired.content = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:mess.refreshRequired.content')) . ';
280 TBE_EDITOR.labels.remainingCharacters = ' . GeneralUtility::quoteJSvalue($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.remainingCharacters')) . ';
281 TBE_EDITOR.customEvalFunctions = {};
282 ';
283
284 // Add JS required for inline fields
285 if (!empty($this->inlineData)) {
286 $out .= '
287 inline.addToDataArray(' . json_encode($this->inlineData) . ');
288 ';
289 }
290 // $this->additionalJS_submit:
291 if ($this->additionalJS_submit) {
292 $additionalJS_submit = implode('', $this->additionalJS_submit);
293 $additionalJS_submit = str_replace(array(CR, LF), '', $additionalJS_submit);
294 $out .= '
295 TBE_EDITOR.addActionChecks("submit", "' . addslashes($additionalJS_submit) . '");
296 ';
297 }
298 $out .= LF . implode(LF, $this->additionalJS_post) . LF . $this->extJSCODE;
299
300 $spacer = LF . TAB;
301 $out = $html . $spacer . implode($spacer, $jsFile) . GeneralUtility::wrapJS($out);
302
303 return $out;
304 }
305
306 /**
307 * Includes a javascript library that exists in the core /typo3/ directory. The
308 * backpath is automatically applied.
309 *
310 * @param string $lib Library name. Call it with the full path like "sysext/core/Resources/Public/JavaScript/QueryGenerator.js" to load it
311 * @return void
312 */
313 protected function loadJavascriptLib($lib)
314 {
315 $pageRenderer = $this->getPageRenderer();
316 $pageRenderer->addJsFile($lib);
317 }
318
319 /**
320 * @return BackendUserAuthentication
321 */
322 protected function getBackendUserAuthentication()
323 {
324 return $GLOBALS['BE_USER'];
325 }
326
327 /**
328 * @return LanguageService
329 */
330 protected function getLanguageService()
331 {
332 return $GLOBALS['LANG'];
333 }
334
335 /**
336 * Wrapper for access to the current page renderer object
337 *
338 * @return \TYPO3\CMS\Core\Page\PageRenderer
339 */
340 protected function getPageRenderer()
341 {
342 if ($this->pageRenderer === null) {
343 $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
344 }
345 return $this->pageRenderer;
346 }
347 }