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