ea8f246d471ecff6ddfa278ba9d4bbbf6d5ebdd5
[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\DocumentTemplate;
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 * Document template object
37 *
38 * @var DocumentTemplate
39 */
40 public $doc;
41
42 /**
43 * Content accumulation for the module.
44 *
45 * @var string
46 */
47 public $content;
48
49 /**
50 * Wizard parameters, coming from FormEngine linking to the wizard.
51 *
52 * @var array
53 */
54 public $P;
55
56 /**
57 * If set, launch a new window with the current records pid.
58 *
59 * @var string
60 */
61 public $popView;
62
63 /**
64 * Set to the URL of this script including variables which is needed to re-display the form. See main()
65 *
66 * @var string
67 */
68 public $R_URI;
69
70 /**
71 * Module configuration
72 *
73 * @var array
74 */
75 public $MCONF = array();
76
77 /**
78 * @var IconFactory
79 */
80 protected $iconFactory;
81
82 /**
83 * Constructor
84 */
85 public function __construct()
86 {
87 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
88 $this->getLanguageService()->includeLLFile('EXT:lang/locallang_wizards.xlf');
89 $GLOBALS['SOBE'] = $this;
90
91 $this->init();
92 }
93
94 /**
95 * Initialization of the class
96 *
97 * @return void
98 */
99 protected function init()
100 {
101 // Setting GPvars:
102 $this->P = GeneralUtility::_GP('P');
103 $this->popView = GeneralUtility::_GP('popView');
104 $this->R_URI = GeneralUtility::linkThisScript(array('popView' => ''));
105 // "Module name":
106 $this->MCONF['name'] = 'wizard_rte';
107 // Starting the document template object:
108 $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
109 $this->doc->setModuleTemplate('EXT:backend/Resources/Private/Templates/wizard_rte.html');
110 // Need to NOT have the page wrapped in DIV since if we do that we destroy
111 // the feature that the RTE spans the whole height of the page!!!
112 $this->doc->divClass = '';
113 $this->doc->form = '<form action="' . htmlspecialchars(BackendUtility::getModuleUrl('tce_db')) . '" method="post" enctype="multipart/form-data" name="editform" onsubmit="return TBE_EDITOR.checkSubmit(1);">';
114 }
115
116 /**
117 * Injects the request object for the current request or subrequest
118 * As this controller goes only through the main() method, it is rather simple for now
119 *
120 * @param ServerRequestInterface $request
121 * @param ResponseInterface $response
122 * @return ResponseInterface
123 */
124 public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
125 {
126 $this->main();
127
128 $response->getBody()->write($this->content);
129 return $response;
130 }
131
132 /**
133 * Main function, rendering the document with the iFrame with the RTE in.
134 *
135 * @return void
136 */
137 public function main()
138 {
139 // Translate id to the workspace version:
140 if ($versionedRecord = BackendUtility::getWorkspaceVersionOfRecord($this->getBackendUserAuthentication()->workspace, $this->P['table'], $this->P['uid'], 'uid')) {
141 $this->P['uid'] = $versionedRecord['uid'];
142 }
143 // If all parameters are available:
144 if ($this->P['table'] && $this->P['field'] && $this->P['uid'] && $this->checkEditAccess($this->P['table'], $this->P['uid'])) {
145 /** @var TcaDatabaseRecord $formDataGroup */
146 $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
147 /** @var FormDataCompiler $formDataCompiler */
148 $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
149 /** @var NodeFactory $nodeFactory */
150 $nodeFactory = GeneralUtility::makeInstance(NodeFactory::class);
151
152 $formDataCompilerInput = [
153 'vanillaUid' => (int)$this->P['uid'],
154 'tableName' => $this->P['table'],
155 'command' => 'edit',
156 'disabledWizards' => true,
157 ];
158
159 $formData = $formDataCompiler->compile($formDataCompilerInput);
160
161 $formData['fieldListToRender'] = $this->P['field'];
162 $formData['renderType'] = 'outerWrapContainer';
163 $formResult = $nodeFactory->create($formData)->render();
164
165 /** @var FormResultCompiler $formResultCompiler */
166 $formResultCompiler = GeneralUtility::makeInstance(FormResultCompiler::class);
167 $formResultCompiler->mergeResult($formResult);
168
169 // override the default jumpToUrl
170 $this->doc->JScodeArray['jumpToUrl'] = '
171 function jumpToUrl(URL,formEl) {
172 if (document.editform) {
173 if (!TBE_EDITOR.isFormChanged()) {
174 window.location.href = URL;
175 } else if (formEl) {
176 if (formEl.type=="checkbox") formEl.checked = formEl.checked ? 0 : 1;
177 }
178 } else {
179 window.location.href = URL;
180 }
181 }
182 ';
183
184 // Setting JavaScript of the pid value for viewing:
185 if ($this->popView) {
186 $this->doc->JScode = $this->doc->wrapScriptTags(
187 BackendUtility::viewOnClick($formData['databaseRow']['pid'], '', BackendUtility::BEgetRootLine($formData['databaseRow']['pid']))
188 );
189 }
190
191 $pageTsConfig = $formData['pageTsConfig'];
192 if ((string)$pageTsConfig['TCEFORM.'][$this->P['table'] . '.'][$this->P['field'] . '.']['RTEfullScreenWidth'] !== '') {
193 $width = (string)$pageTsConfig['TCEFORM.'][$this->P['table'] . '.'][$this->P['field'] . '.']['RTEfullScreenWidth'];
194 } else {
195 $width = '100%';
196 }
197 // Get the form field and wrap it in the table with the buttons:
198 $formContent = $formResult['html'];
199 $formContent = '
200 <table border="0" cellpadding="0" cellspacing="0" width="' . $width . '" id="typo3-rtewizard">
201 <tr>
202 <td width="' . $width . '" colspan="2" id="c-formContent">' . $formContent . '</td>
203 <td></td>
204 </tr>
205 </table>';
206
207 // Adding hidden fields:
208 $formContent .= '<input type="hidden" name="redirect" value="' . htmlspecialchars($this->R_URI) . '" />
209 <input type="hidden" name="_serialNumber" value="' . md5(microtime()) . '" />';
210 // Finally, add the whole setup:
211 $this->content .= $formResultCompiler->JStop() . $formContent . $formResultCompiler->printNeededJSFunctions();
212 } else {
213 // ERROR:
214 $this->content .= $this->doc->section($this->getLanguageService()->getLL('forms_title'), '<span class="text-danger">' . $this->getLanguageService()->getLL('table_noData', true) . '</span>', 0, 1);
215 }
216 // Setting up the buttons and markers for docHeader
217 $docHeaderButtons = $this->getButtons();
218 $markers['CONTENT'] = $this->content;
219 // Build the <body> for the module
220 $this->content = $this->doc->startPage('');
221 $this->content .= $this->doc->moduleBody(array(), $docHeaderButtons, $markers);
222 $this->content .= $this->doc->endPage();
223 $this->content = $this->doc->insertStylesAndJS($this->content);
224 }
225
226 /**
227 * Outputting the accumulated content to screen
228 *
229 * @return void
230 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use mainAction() instead
231 */
232 public function printContent()
233 {
234 GeneralUtility::logDeprecatedFunction();
235 echo $this->content;
236 }
237
238 /**
239 * Create the panel of buttons for submitting the form or otherwise perform operations.
240 *
241 * @return array All available buttons as an assoc. array
242 */
243 protected function getButtons()
244 {
245 $buttons = array(
246 'close' => '',
247 'save' => '',
248 'save_view' => '',
249 'save_close' => '',
250 'shortcut' => '',
251 'undo' => ''
252 );
253 if ($this->P['table'] && $this->P['field'] && $this->P['uid'] && $this->checkEditAccess($this->P['table'], $this->P['uid'])) {
254 $closeUrl = GeneralUtility::sanitizeLocalUrl($this->P['returnUrl']);
255 // Getting settings for the undo button:
256 $undoButton = 0;
257 $databaseConnection = $this->getDatabaseConnection();
258 $undoRes = $databaseConnection->exec_SELECTquery('tstamp', 'sys_history', 'tablename=' . $databaseConnection->fullQuoteStr($this->P['table'], 'sys_history') . ' AND recuid=' . (int)$this->P['uid'], '', 'tstamp DESC', '1');
259 if ($undoButtonR = $databaseConnection->sql_fetch_assoc($undoRes)) {
260 $undoButton = 1;
261 }
262 // Close
263 $buttons['close'] = '<a href="#" onclick="' . htmlspecialchars('jumpToUrl(' . GeneralUtility::quoteJSvalue($closeUrl) . '); return false;') . '" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:rm.closeDoc', true) . '">' . $this->iconFactory->getIcon('actions-document-close', Icon::SIZE_SMALL)->render() . '</a>';
264 // Save
265 $buttons['save'] = '<button class="c-inputButton" name="_savedok_x" onclick="TBE_EDITOR.checkAndDoSubmit(1); return false;" title="'
266 . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc', true) . '">'
267 . $this->iconFactory->getIcon('actions-document-save', Icon::SIZE_SMALL)->render()
268 . '</button>';
269 // Save & View
270 $buttons['save_view'] = '<button class="c-inputButton" name="_savedokview_x" onclick="' . htmlspecialchars('document.editform.redirect.value+=\'&popView=1\'; TBE_EDITOR.checkAndDoSubmit(1); return false;') . '" title="'
271 . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDocShow', true) . '">'
272 . $this->iconFactory->getIcon('actions-document-save-view', Icon::SIZE_SMALL)->render()
273 . '</button>';
274 // Save & Close
275 $buttons['save_close'] = '<button class="c-inputButton" name="_saveandclosedok_x" onclick="' . htmlspecialchars('document.editform.redirect.value=' . GeneralUtility::quoteJSvalue($closeUrl) . '; TBE_EDITOR.checkAndDoSubmit(1); return false;') . '" title="'
276 . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveCloseDoc', true) . '">'
277 . $this->iconFactory->getIcon('actions-document-save-close', Icon::SIZE_SMALL)->render()
278 . '</button>';
279 // Undo/Revert:
280 if ($undoButton) {
281 $aOnClick = 'window.location.href=' .
282 GeneralUtility::quoteJSvalue(
283 BackendUtility::getModuleUrl(
284 'record_history',
285 array(
286 'element' => $this->P['table'] . ':' . $this->P['uid'],
287 'revert' => 'field:' . $this->P['field'],
288 'sumUp' => -1,
289 'returnUrl' => $this->R_URI,
290 )
291 )
292 ) . '; return false;';
293 $buttons['undo'] = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '"' . ' title="' . htmlspecialchars(sprintf($this->getLanguageService()->getLL('undoLastChange'), BackendUtility::calcAge(($GLOBALS['EXEC_TIME'] - $undoButtonR['tstamp']), $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears')))) . '">' . $this->iconFactory->getIcon('actions-edit-undo', Icon::SIZE_SMALL)->render() . '</a>';
294 }
295 // Shortcut
296 if ($this->getBackendUserAuthentication()->mayMakeShortcut()) {
297 $buttons['shortcut'] = $this->doc->makeShortcutIcon('P', '', $this->MCONF['name'], 1);
298 }
299 }
300 return $buttons;
301 }
302 }