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