[!!!][FEATURE] FormEngine element level refactoring
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / Classes / Controller / Wizard / RteController.php
1 <?php
2 namespace TYPO3\CMS\Rtehtmlarea\Controller\Wizard;
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 Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Controller\Wizard\AbstractWizardController;
20 use TYPO3\CMS\Backend\Form\FormDataCompiler;
21 use TYPO3\CMS\Backend\Form\FormDataGroup\TcaDatabaseRecord;
22 use TYPO3\CMS\Backend\Form\FormResultCompiler;
23 use TYPO3\CMS\Backend\Form\NodeFactory;
24 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
25 use TYPO3\CMS\Backend\Utility\BackendUtility;
26 use TYPO3\CMS\Core\Database\ConnectionPool;
27 use TYPO3\CMS\Core\Imaging\Icon;
28 use TYPO3\CMS\Core\Imaging\IconFactory;
29 use TYPO3\CMS\Core\Utility\GeneralUtility;
30
31 /**
32 * Script class for rendering the full screen RTE display
33 */
34 class RteController extends AbstractWizardController
35 {
36 /**
37 * Content accumulation for the module.
38 *
39 * @var string
40 */
41 public $content;
42
43 /**
44 * Wizard parameters, coming from FormEngine linking to the wizard.
45 *
46 * @var array
47 */
48 public $P;
49
50 /**
51 * If set, launch a new window with the current records pid.
52 *
53 * @var string
54 */
55 public $popView;
56
57 /**
58 * Set to the URL of this script including variables which is needed to re-display the form. See main()
59 *
60 * @var string
61 */
62 public $R_URI;
63
64 /**
65 * Module configuration
66 *
67 * @var array
68 */
69 public $MCONF = [];
70
71 /**
72 * Constructor
73 */
74 public function __construct()
75 {
76 parent::__construct();
77 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
78 $this->getLanguageService()->includeLLFile('EXT:lang/Resources/Private/Language/locallang_wizards.xlf');
79 $GLOBALS['SOBE'] = $this;
80
81 $this->init();
82 }
83
84 /**
85 * Initialization of the class
86 *
87 * @return void
88 */
89 protected function init()
90 {
91 // Setting GPvars:
92 $this->P = GeneralUtility::_GP('P');
93 $this->popView = GeneralUtility::_GP('popView');
94 $this->R_URI = GeneralUtility::linkThisScript(['popView' => '']);
95 // "Module name":
96 $this->MCONF['name'] = 'wizard_rte';
97 // Need to NOT have the page wrapped in DIV since if we do that we destroy
98 // the feature that the RTE spans the whole height of the page!!!
99 }
100
101 /**
102 * Injects the request object for the current request or subrequest
103 * As this controller goes only through the main() method, it is rather simple for now
104 *
105 * @param ServerRequestInterface $request
106 * @param ResponseInterface $response
107 * @return ResponseInterface
108 */
109 public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
110 {
111 $this->main();
112
113 $response->getBody()->write($this->moduleTemplate->renderContent());
114 return $response;
115 }
116
117 /**
118 * Main function, rendering the document with the iFrame with the RTE in.
119 *
120 * @return void
121 */
122 public function main()
123 {
124 $this->content .= '<form action="'
125 . htmlspecialchars(BackendUtility::getModuleUrl('tce_db'))
126 . '" method="post" enctype="multipart/form-data" id="RteController" name="editform" '
127 . ' onsubmit="return TBE_EDITOR.checkSubmit(1);">';
128 // Translate id to the workspace version:
129 if ($versionedRecord = BackendUtility::getWorkspaceVersionOfRecord(
130 $this->getBackendUserAuthentication()->workspace,
131 $this->P['table'],
132 $this->P['uid'],
133 'uid'
134 )) {
135 $this->P['uid'] = $versionedRecord['uid'];
136 }
137 // If all parameters are available:
138 if ($this->P['table']
139 && $this->P['field']
140 && $this->P['uid']
141 && $this->checkEditAccess($this->P['table'], $this->P['uid'])) {
142 /** @var TcaDatabaseRecord $formDataGroup */
143 $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
144 /** @var FormDataCompiler $formDataCompiler */
145 $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
146 /** @var NodeFactory $nodeFactory */
147 $nodeFactory = GeneralUtility::makeInstance(NodeFactory::class);
148
149 $formDataCompilerInput = [
150 'vanillaUid' => (int)$this->P['uid'],
151 'tableName' => $this->P['table'],
152 'command' => 'edit',
153 'disabledWizards' => true,
154 ];
155
156 $formData = $formDataCompiler->compile($formDataCompilerInput);
157
158 $formData['fieldListToRender'] = $this->P['field'];
159 $formData['renderType'] = 'outerWrapContainer';
160 $formResult = $nodeFactory->create($formData)->render();
161
162 /** @var FormResultCompiler $formResultCompiler */
163 $formResultCompiler = GeneralUtility::makeInstance(FormResultCompiler::class);
164 $formResultCompiler->mergeResult($formResult);
165
166 // override the default jumpToUrl
167 $this->moduleTemplate->addJavaScriptCode(
168 'RteWizardInlineCode',
169 'function jumpToUrl(URL,formEl) {
170 if (document.editform) {
171 if (!TBE_EDITOR.isFormChanged()) {
172 window.location.href = URL;
173 } else if (formEl) {
174 if (formEl.type=="checkbox") formEl.checked = formEl.checked ? 0 : 1;
175 }
176 } else {
177 window.location.href = URL;
178 }
179 }
180 '
181 );
182
183 // Setting JavaScript of the pid value for viewing:
184 if ($this->popView) {
185 $this->moduleTemplate->addJavaScriptCode(
186 'PopupViewInlineJS',
187 BackendUtility::viewOnClick(
188 $formData['databaseRow']['pid'],
189 '',
190 BackendUtility::BEgetRootLine($formData['databaseRow']['pid'])
191 )
192 );
193 }
194
195 $pageTsConfigMerged = $formData['pageTsConfigMerged'];
196 if ((string)$pageTsConfigMerged['TCEFORM.'][$this->P['table'] . '.'][$this->P['field'] . '.']['RTEfullScreenWidth'] !== '') {
197 $width = (string)$pageTsConfigMerged['TCEFORM.'][$this->P['table'] . '.'][$this->P['field'] . '.']['RTEfullScreenWidth'];
198 } else {
199 $width = '100%';
200 }
201 // Get the form field and wrap it in the table with the buttons:
202 $formContent = $formResult['html'];
203 $formContent = '
204 <table border="0" cellpadding="0" cellspacing="0" width="' . $width . '" id="typo3-rtewizard">
205 <tr>
206 <td width="' . $width . '" colspan="2" id="c-formContent">' . $formContent . '</td>
207 <td></td>
208 </tr>
209 </table>';
210
211 // Adding hidden fields:
212 $formContent .= '<input type="hidden" name="redirect" value="' . htmlspecialchars($this->R_URI) . '" />
213 <input type="hidden" name="_serialNumber" value="' . md5(microtime()) . '" />';
214 // Finally, add the whole setup:
215 $this->content .= $formResultCompiler->addCssFiles()
216 . $formContent
217 . $formResultCompiler->printNeededJSFunctions();
218 } else {
219 // ERROR:
220 $this->content .= '<h2>' . htmlspecialchars($this->getLanguageService()->getLL('forms_title')) . '</h2>'
221 . '<div><span class="text-danger">'
222 . htmlspecialchars($this->getLanguageService()->getLL('table_noData'))
223 . '</span></div>';
224 }
225 // Setting up the buttons and markers for docHeader
226 $this->getButtons();
227 // Build the <body> for the module
228
229 $this->content .= '</form>';
230 $this->moduleTemplate->setContent($this->content);
231 }
232
233 /**
234 * Create the panel of buttons for submitting the form or otherwise perform operations.
235 *
236 * @return array All available buttons as an assoc. array
237 */
238 protected function getButtons()
239 {
240 $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
241 if ($this->P['table']
242 && $this->P['field']
243 && $this->P['uid']
244 && $this->checkEditAccess($this->P['table'], $this->P['uid'])) {
245 $closeUrl = GeneralUtility::sanitizeLocalUrl($this->P['returnUrl']);
246 // Getting settings for the undo button:
247 $undoButton = false;
248
249 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
250 ->getQueryBuilderForTable('sys_history');
251
252 $undoButtonR = $queryBuilder
253 ->select('tstamp')
254 ->from('sys_history')
255 ->where(
256 $queryBuilder->expr()->eq(
257 'tablename',
258 $queryBuilder->createNamedParameter($this->P['table'], \PDO::PARAM_STR)
259 ),
260 $queryBuilder->expr()->eq(
261 'recuid',
262 $queryBuilder->createNamedParameter($this->P['uid'], \PDO::PARAM_INT)
263 )
264 )
265 ->orderBy('tstamp', 'desc')
266 ->setMaxResults(1)
267 ->execute()
268 ->fetchColumn();
269
270 if ($undoButtonR !== false) {
271 $undoButton = true;
272 }
273 // Close
274 $closeButton = $buttonBar->makeLinkButton()
275 ->setHref($closeUrl)
276 ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:rm.closeDoc'))
277 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-close', Icon::SIZE_SMALL));
278 $buttonBar->addButton($closeButton, ButtonBar::BUTTON_POSITION_LEFT, 10);
279
280 // Save
281 $saveButton = $buttonBar->makeInputButton()
282 ->setName('_savedok_x')
283 ->setValue('1')
284 ->setForm('RteController')
285 ->setOnClick('TBE_EDITOR.checkAndDoSubmit(1); return false;')
286 ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:rm.saveDoc'))
287 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save', Icon::SIZE_SMALL));
288 // Save & View
289 $saveAndViewButton = $buttonBar->makeInputButton()
290 ->setName('_savedokview_x')
291 ->setValue('1')
292 ->setForm('RteController')
293 ->setOnClick('document.editform.redirect.value+= ' . GeneralUtility::quoteJSvalue('&popView=1') . '; '
294 . ' TBE_EDITOR.checkAndDoSubmit(1); return false;')
295 ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:rm.saveDocShow'))
296 ->setIcon(
297 $this->moduleTemplate->getIconFactory()->getIcon('actions-document-save-view', Icon::SIZE_SMALL)
298 );
299
300 // Save & Close
301 $saveAndCloseButton = $buttonBar->makeInputButton()
302 ->setName('_saveandclosedok_x')
303 ->setValue('1')
304 ->setForm('RteController')
305 ->setOnClick('document.editform.redirect.value=' . GeneralUtility::quoteJSvalue($closeUrl)
306 . '; TBE_EDITOR.checkAndDoSubmit(1); return false;')
307 ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:rm.saveCloseDoc'))
308 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
309 'actions-document-save-close',
310 Icon::SIZE_SMALL
311 ));
312
313 // Save SplitButton
314 $saveSplitButton = $buttonBar->makeSplitButton()
315 ->addItem($saveButton)
316 ->addItem($saveAndViewButton)
317 ->addItem($saveAndCloseButton);
318 $buttonBar->addButton($saveSplitButton, ButtonBar::BUTTON_POSITION_LEFT, 20);
319
320 // Undo/Revert:
321 if ($undoButton) {
322 $aOnClick = 'window.location.href=' .
323 GeneralUtility::quoteJSvalue(
324 BackendUtility::getModuleUrl(
325 'record_history',
326 [
327 'element' => $this->P['table'] . ':' . $this->P['uid'],
328 'revert' => 'field:' . $this->P['field'],
329 'returnUrl' => $this->R_URI,
330 ]
331 )
332 ) . '; return false;';
333
334 $undoText = $this->getLanguageService()->sL(
335 'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:rte_undoLastChange'
336 );
337 $lastChangeLabel = sprintf(
338 $undoText,
339 BackendUtility::calcAge(
340 ($GLOBALS['EXEC_TIME'] - $undoButtonR['tstamp']),
341 $this->getLanguageService()->sL(
342 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.minutesHoursDaysYears'
343 )
344 )
345 );
346
347 $undoRevertButton = $buttonBar->makeLinkButton()
348 ->setHref('#')
349 ->setOnClick($aOnClick)
350 ->setTitle($lastChangeLabel)
351 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-edit-undo', Icon::SIZE_SMALL));
352 $buttonBar->addButton($undoRevertButton, ButtonBar::BUTTON_POSITION_LEFT, 30);
353 }
354 // Shortcut
355 $shortButton = $buttonBar->makeShortcutButton()
356 ->setModuleName($this->MCONF['name'])
357 ->setGetVariables(['P']);
358 $buttonBar->addButton($shortButton);
359 }
360 }
361 }