[TASK] Editors do not have rights to edit file metadata
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / EditDocumentController.php
1 <?php
2 namespace TYPO3\CMS\Backend\Controller;
3
4 /**
5 * Script Class: Drawing the editing form for editing records in TYPO3.
6 * Notice: It does NOT use tce_db.php to submit data to, rather it handles submissions itself
7 *
8 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
9 * @package TYPO3
10 * @subpackage core
11 */
12 class EditDocumentController {
13
14 // Internal, static: GPvars:
15 // GPvar "edit": Is an array looking approx like [tablename][list-of-ids]=command, eg.
16 // "&edit[pages][123]=edit". See t3lib_BEfunc::editOnClick(). Value can be seen modified
17 // internally (converting NEW keyword to id, workspace/versioning etc).
18 /**
19 * @todo Define visibility
20 */
21 public $editconf;
22
23 // Commalist of fieldnames to edit. The point is IF you specify this list, only those
24 // fields will be rendered in the form. Otherwise all (available) fields in the record
25 // is shown according to the types configuration in $GLOBALS['TCA']
26 /**
27 * @todo Define visibility
28 */
29 public $columnsOnly;
30
31 // Default values for fields (array with tablenames, fields etc. as keys).
32 // Can be seen modified internally.
33 /**
34 * @todo Define visibility
35 */
36 public $defVals;
37
38 // Array of values to force being set (as hidden fields). Will be set as $this->defVals
39 // IF defVals does not exist.
40 /**
41 * @todo Define visibility
42 */
43 public $overrideVals;
44
45 // If set, this value will be set in $this->retUrl (which is used quite many places
46 // as the return URL). If not set, "dummy.php" will be set in $this->retUrl
47 /**
48 * @todo Define visibility
49 */
50 public $returnUrl;
51
52 // Close-document command. Not really sure of all options...
53 /**
54 * @todo Define visibility
55 */
56 public $closeDoc;
57
58 // Quite simply, if this variable is set, then the processing of incoming data will be performed
59 // - as if a save-button is pressed. Used in the forms as a hidden field which can be set through
60 // JavaScript if the form is somehow submitted by JavaScript).
61 /**
62 * @todo Define visibility
63 */
64 public $doSave;
65
66 // GPvar (for processing only) : The data array from which the data comes...
67 /**
68 * @todo Define visibility
69 */
70 public $data;
71
72 // GPvar (for processing only) : ?
73 /**
74 * @todo Define visibility
75 */
76 public $mirror;
77
78 // GPvar (for processing only) : Clear-cache cmd.
79 /**
80 * @todo Define visibility
81 */
82 public $cacheCmd;
83
84 // GPvar (for processing only) : Redirect (not used???)
85 /**
86 * @todo Define visibility
87 */
88 public $redirect;
89
90 // GPvar (for processing only) : Boolean: If set, then the GET var "&id=" will be added to the
91 // retUrl string so that the NEW id of something is returned to the script calling the form.
92 /**
93 * @todo Define visibility
94 */
95 public $returnNewPageId;
96
97 // GPvar (for processing only) : Verification code, internal stuff.
98 /**
99 * @todo Define visibility
100 */
101 public $vC;
102
103 // GPvar : update BE_USER->uc
104 /**
105 * @todo Define visibility
106 */
107 public $uc;
108
109 // GPvar (module) : ID for displaying the page in the frontend (used for SAVE/VIEW operations)
110 /**
111 * @todo Define visibility
112 */
113 public $popViewId;
114
115 // GPvar (module) : Additional GET vars for the link, eg. "&L=xxx"
116 /**
117 * @todo Define visibility
118 */
119 public $popViewId_addParams;
120
121 // GPvar (module) : Alternative URL for viewing the frontend pages.
122 /**
123 * @todo Define visibility
124 */
125 public $viewUrl;
126
127 // If this is pointing to a page id it will automatically load all content elements
128 // (NORMAL column/default language) from that page into the form!
129 /**
130 * @todo Define visibility
131 */
132 public $editRegularContentFromId;
133
134 // Alternative title for the document handler.
135 /**
136 * @todo Define visibility
137 */
138 public $recTitle;
139
140 // Disable help... ?
141 /**
142 * @todo Define visibility
143 */
144 public $disHelp;
145
146 // If set, then no SAVE/VIEW button is printed
147 /**
148 * @todo Define visibility
149 */
150 public $noView;
151
152 // If set, the $this->editconf array is returned to the calling script
153 // (used by wizard_add.php for instance)
154 /**
155 * @todo Define visibility
156 */
157 public $returnEditConf;
158
159 // GP var, localization mode for TCEforms (eg. "text")
160 /**
161 * @todo Define visibility
162 */
163 public $localizationMode;
164
165 // Internal, static:
166 /**
167 * document template object
168 *
169 * @var \TYPO3\CMS\Backend\Template\MediumDocumentTemplate
170 * @todo Define visibility
171 */
172 public $doc;
173
174 // a static HTML template, usually in templates/alt_doc.html
175 /**
176 * @todo Define visibility
177 */
178 public $template;
179
180 // Content accumulation
181 /**
182 * @todo Define visibility
183 */
184 public $content;
185
186 // Return URL script, processed. This contains the script (if any) that we should
187 // RETURN TO from the alt_doc.php script IF we press the close button. Thus this
188 // variable is normally passed along from the calling script so we can properly return if needed.
189 /**
190 * @todo Define visibility
191 */
192 public $retUrl;
193
194 // Contains the parts of the REQUEST_URI (current url). By parts we mean the result of resolving
195 // REQUEST_URI (current url) by the parse_url() function. The result is an array where eg. "path"
196 // is the script path and "query" is the parameters...
197 /**
198 * @todo Define visibility
199 */
200 public $R_URL_parts;
201
202 // Contains the current GET vars array; More specifically this array is the foundation for creating
203 // the R_URI internal var (which becomes the "url of this script" to which we submit the forms etc.)
204 /**
205 * @todo Define visibility
206 */
207 public $R_URL_getvars;
208
209 // Set to the URL of this script including variables which is needed to re-display the form. See main()
210 /**
211 * @todo Define visibility
212 */
213 public $R_URI;
214
215 // Is loaded with the "title" of the currently "open document" - this is used in the
216 // Document Selector box. (see makeDocSel())
217 /**
218 * @todo Define visibility
219 */
220 public $storeTitle;
221
222 // Contains an array with key/value pairs of GET parameters needed to reach the
223 // current document displayed - used in the Document Selector box. (see compileStoreDat())
224 /**
225 * @todo Define visibility
226 */
227 public $storeArray;
228
229 // Contains storeArray, but imploded into a GET parameter string (see compileStoreDat())
230 /**
231 * @todo Define visibility
232 */
233 public $storeUrl;
234
235 // Hashed value of storeURL (see compileStoreDat())
236 /**
237 * @todo Define visibility
238 */
239 public $storeUrlMd5;
240
241 // Module session data
242 /**
243 * @todo Define visibility
244 */
245 public $docDat;
246
247 // An array of the "open documents" - keys are md5 hashes (see $storeUrlMd5) identifying
248 // the various documents on the GET parameter list needed to open it. The values are
249 // arrays with 0,1,2 keys with information about the document (see compileStoreDat()).
250 // The docHandler variable is stored in the $docDat session data, key "0".
251 /**
252 * @todo Define visibility
253 */
254 public $docHandler;
255
256 // Internal: Related to the form rendering:
257 // Array of the elements to create edit forms for.
258 /**
259 * @todo Define visibility
260 */
261 public $elementsData;
262
263 // Pointer to the first element in $elementsData
264 /**
265 * @todo Define visibility
266 */
267 public $firstEl;
268
269 // Counter, used to count the number of errors (when users do not have edit permissions)
270 /**
271 * @todo Define visibility
272 */
273 public $errorC;
274
275 // Counter, used to count the number of new record forms displayed
276 /**
277 * @todo Define visibility
278 */
279 public $newC;
280
281 // Is set to the pid value of the last shown record - thus indicating which page to
282 // show when clicking the SAVE/VIEW button
283 /**
284 * @todo Define visibility
285 */
286 public $viewId;
287
288 // Is set to additional parameters (like "&L=xxx") if the record supports it.
289 /**
290 * @todo Define visibility
291 */
292 public $viewId_addParams;
293
294 // Module TSconfig, loaded from main() based on the page id value of viewId
295 /**
296 * @todo Define visibility
297 */
298 public $modTSconfig;
299
300 /**
301 * instance of TCEforms class
302 *
303 * @var \TYPO3\CMS\Backend\Form\FormEngine
304 * @todo Define visibility
305 */
306 public $tceforms;
307
308 // Contains the root-line path of the currently edited record(s) - for display.
309 /**
310 * @todo Define visibility
311 */
312 public $generalPathOfForm;
313
314 // Internal, dynamic:
315 // Used internally to disable the storage of the document reference (eg. new records)
316 /**
317 * @todo Define visibility
318 */
319 public $dontStoreDocumentRef;
320
321 /**
322 * First initialization.
323 *
324 * @return void
325 * @todo Define visibility
326 */
327 public function preInit() {
328 if (\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('justLocalized')) {
329 $this->localizationRedirect(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('justLocalized'));
330 }
331 // Setting GPvars:
332 $this->editconf = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('edit');
333 $this->defVals = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('defVals');
334 $this->overrideVals = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('overrideVals');
335 $this->columnsOnly = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('columnsOnly');
336 $this->returnUrl = \TYPO3\CMS\Core\Utility\GeneralUtility::sanitizeLocalUrl(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('returnUrl'));
337 $this->closeDoc = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('closeDoc');
338 $this->doSave = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('doSave');
339 $this->returnEditConf = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('returnEditConf');
340 $this->localizationMode = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('localizationMode');
341 $this->uc = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('uc');
342 // Setting override values as default if defVals does not exist.
343 if (!is_array($this->defVals) && is_array($this->overrideVals)) {
344 $this->defVals = $this->overrideVals;
345 }
346 // Setting return URL
347 $this->retUrl = $this->returnUrl ? $this->returnUrl : 'dummy.php';
348 // Fix $this->editconf if versioning applies to any of the records
349 $this->fixWSversioningInEditConf();
350 // Make R_URL (request url) based on input GETvars:
351 $this->R_URL_parts = parse_url(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('REQUEST_URI'));
352 $this->R_URL_getvars = \TYPO3\CMS\Core\Utility\GeneralUtility::_GET();
353 $this->R_URL_getvars['edit'] = $this->editconf;
354 // MAKE url for storing
355 $this->compileStoreDat();
356 // Initialize more variables.
357 $this->dontStoreDocumentRef = 0;
358 $this->storeTitle = '';
359 // Get session data for the module:
360 $this->docDat = $GLOBALS['BE_USER']->getModuleData('alt_doc.php', 'ses');
361 $this->docHandler = $this->docDat[0];
362 // If a request for closing the document has been sent, act accordingly:
363 if ($this->closeDoc > 0) {
364 $this->closeDocument($this->closeDoc);
365 }
366 // If NO vars are sent to the script, try to read first document:
367 // Added !is_array($this->editconf) because editConf must not be set either.
368 // Anyways I can't figure out when this situation here will apply...
369 if (is_array($this->R_URL_getvars) && count($this->R_URL_getvars) < 2 && !is_array($this->editconf)) {
370 $this->setDocument($this->docDat[1]);
371 }
372 }
373
374 /**
375 * Detects, if a save command has been triggered.
376 *
377 * @return boolean TRUE, then save the document (data submitted)
378 * @todo Define visibility
379 */
380 public function doProcessData() {
381 $out = $this->doSave || isset($_POST['_savedok_x']) || isset($_POST['_saveandclosedok_x']) || isset($_POST['_savedokview_x']) || isset($_POST['_savedoknew_x']) || isset($_POST['_translation_savedok_x']) || isset($_POST['_translation_savedokclear_x']);
382 return $out;
383 }
384
385 /**
386 * Do processing of data, submitting it to TCEmain.
387 *
388 * @return void
389 * @todo Define visibility
390 */
391 public function processData() {
392 // GPvars specifically for processing:
393 $this->data = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('data');
394 $this->cmd = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('cmd');
395 $this->mirror = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('mirror');
396 $this->cacheCmd = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('cacheCmd');
397 $this->redirect = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('redirect');
398 $this->returnNewPageId = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('returnNewPageId');
399 $this->vC = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('vC');
400 // See tce_db.php for relevate options here:
401 // Only options related to $this->data submission are included here.
402 /** @var $tce \TYPO3\CMS\Core\DataHandling\DataHandler */
403 $tce = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\DataHandling\\DataHandler');
404 $tce->stripslashes_values = 0;
405 if (isset($_POST['_translation_savedok_x'])) {
406 $tce->updateModeL10NdiffData = 'FORCE_FFUPD';
407 }
408 if (isset($_POST['_translation_savedokclear_x'])) {
409 $tce->updateModeL10NdiffData = 'FORCE_FFUPD';
410 $tce->updateModeL10NdiffDataClear = TRUE;
411 }
412 // Setting default values specific for the user:
413 $TCAdefaultOverride = $GLOBALS['BE_USER']->getTSConfigProp('TCAdefaults');
414 if (is_array($TCAdefaultOverride)) {
415 $tce->setDefaultsFromUserTS($TCAdefaultOverride);
416 }
417 // Setting internal vars:
418 if ($GLOBALS['BE_USER']->uc['neverHideAtCopy']) {
419 $tce->neverHideAtCopy = 1;
420 }
421 $tce->debug = 0;
422 $tce->disableRTE = !$GLOBALS['BE_USER']->isRTE();
423 // Loading TCEmain with data:
424 $tce->start($this->data, $this->cmd);
425 if (is_array($this->mirror)) {
426 $tce->setMirror($this->mirror);
427 }
428 // If pages are being edited, we set an instruction about updating the page tree after this operation.
429 if (isset($this->data['pages']) || $GLOBALS['BE_USER']->workspace != 0 && count($this->data)) {
430 \TYPO3\CMS\Backend\Utility\BackendUtility::setUpdateSignal('updatePageTree');
431 }
432 // Checking referer / executing
433 $refInfo = parse_url(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('HTTP_REFERER'));
434 $httpHost = \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY');
435 if ($httpHost != $refInfo['host'] && $this->vC != $GLOBALS['BE_USER']->veriCode() && !$GLOBALS['TYPO3_CONF_VARS']['SYS']['doNotCheckReferer']) {
436 $tce->log('', 0, 0, 0, 1, 'Referer host \'%s\' and server host \'%s\' did not match and veriCode was not valid either!', 1, array($refInfo['host'], $httpHost));
437 debug('Error: Referer host did not match with server host.');
438 } else {
439 // Perform the saving operation with TCEmain:
440 $tce->process_uploads($_FILES);
441 $tce->process_datamap();
442 $tce->process_cmdmap();
443 // If there was saved any new items, load them:
444 if (count($tce->substNEWwithIDs_table)) {
445 // save the expanded/collapsed states for new inline records, if any
446 \TYPO3\CMS\Backend\Form\Element\InlineElement::updateInlineView($this->uc, $tce);
447 $newEditConf = array();
448 foreach ($this->editconf as $tableName => $tableCmds) {
449 $keys = array_keys($tce->substNEWwithIDs_table, $tableName);
450 if (count($keys) > 0) {
451 foreach ($keys as $key) {
452 $editId = $tce->substNEWwithIDs[$key];
453 // Check if the $editId isn't a child record of an IRRE action
454 if (!(is_array($tce->newRelatedIDs[$tableName]) && in_array($editId, $tce->newRelatedIDs[$tableName]))) {
455 // Translate new id to the workspace version:
456 if ($versionRec = \TYPO3\CMS\Backend\Utility\BackendUtility::getWorkspaceVersionOfRecord($GLOBALS['BE_USER']->workspace, $tableName, $editId, 'uid')) {
457 $editId = $versionRec['uid'];
458 }
459 $newEditConf[$tableName][$editId] = 'edit';
460 }
461 // Traverse all new records and forge the content of ->editconf so we can continue to EDIT these records!
462 if ($tableName == 'pages' && $this->retUrl != 'dummy.php' && $this->returnNewPageId) {
463 $this->retUrl .= '&id=' . $tce->substNEWwithIDs[$key];
464 }
465 }
466 } else {
467 $newEditConf[$tableName] = $tableCmds;
468 }
469 }
470 // Resetting editconf if newEditConf has values:
471 if (count($newEditConf)) {
472 $this->editconf = $newEditConf;
473 }
474 // Finally, set the editconf array in the "getvars" so they will be passed along in URLs as needed.
475 $this->R_URL_getvars['edit'] = $this->editconf;
476 // Unsetting default values since we don't need them anymore.
477 unset($this->R_URL_getvars['defVals']);
478 // Re-compile the store* values since editconf changed...
479 $this->compileStoreDat();
480 }
481 // See if any records was auto-created as new versions?
482 if (count($tce->autoVersionIdMap)) {
483 $this->fixWSversioningInEditConf($tce->autoVersionIdMap);
484 }
485 // If a document is saved and a new one is created right after.
486 if (isset($_POST['_savedoknew_x']) && is_array($this->editconf)) {
487 // Finding the current table:
488 reset($this->editconf);
489 $nTable = key($this->editconf);
490 // Finding the first id, getting the records pid+uid
491 reset($this->editconf[$nTable]);
492 $nUid = key($this->editconf[$nTable]);
493 $nRec = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord($nTable, $nUid, 'pid,uid');
494 // Setting a blank editconf array for a new record:
495 $this->editconf = array();
496 if ($this->getNewIconMode($nTable) == 'top') {
497 $this->editconf[$nTable][$nRec['pid']] = 'new';
498 } else {
499 $this->editconf[$nTable][-$nRec['uid']] = 'new';
500 }
501 // Finally, set the editconf array in the "getvars" so they will be passed along in URLs as needed.
502 $this->R_URL_getvars['edit'] = $this->editconf;
503 // Re-compile the store* values since editconf changed...
504 $this->compileStoreDat();
505 }
506 $tce->printLogErrorMessages(isset($_POST['_saveandclosedok_x']) || isset($_POST['_translation_savedok_x']) ? $this->retUrl : $this->R_URL_parts['path'] . '?' . \TYPO3\CMS\Core\Utility\GeneralUtility::implodeArrayForUrl('', $this->R_URL_getvars));
507 }
508 // || count($tce->substNEWwithIDs)... If any new items has been save, the document is CLOSED
509 // because if not, we just get that element re-listed as new. And we don't want that!
510 if (isset($_POST['_saveandclosedok_x']) || isset($_POST['_translation_savedok_x']) || $this->closeDoc < 0) {
511 $this->closeDocument(abs($this->closeDoc));
512 }
513 }
514
515 /**
516 * Initialize the normal module operation
517 *
518 * @return void
519 * @todo Define visibility
520 */
521 public function init() {
522 // Setting more GPvars:
523 $this->popViewId = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('popViewId');
524 $this->popViewId_addParams = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('popViewId_addParams');
525 $this->viewUrl = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('viewUrl');
526 $this->editRegularContentFromId = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('editRegularContentFromId');
527 $this->recTitle = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('recTitle');
528 $this->disHelp = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('disHelp');
529 $this->noView = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('noView');
530 $this->perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
531 // Set other internal variables:
532 $this->R_URL_getvars['returnUrl'] = $this->retUrl;
533 $this->R_URI = $this->R_URL_parts['path'] . '?' . \TYPO3\CMS\Core\Utility\GeneralUtility::implodeArrayForUrl('', $this->R_URL_getvars);
534 // MENU-ITEMS:
535 // If array, then it's a selector box menu
536 // If empty string it's just a variable, that'll be saved.
537 // Values NOT in this array will not be saved in the settings-array for the module.
538 $this->MOD_MENU = array(
539 'showPalettes' => ''
540 );
541 // Setting virtual document name
542 $this->MCONF['name'] = 'xMOD_alt_doc.php';
543 // CLEANSE SETTINGS
544 $this->MOD_SETTINGS = \TYPO3\CMS\Backend\Utility\BackendUtility::getModuleData($this->MOD_MENU, \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('SET'), $this->MCONF['name']);
545 // Create an instance of the document template object
546 $this->doc = $GLOBALS['TBE_TEMPLATE'];
547 $this->doc->backPath = $GLOBALS['BACK_PATH'];
548 $this->doc->setModuleTemplate('templates/alt_doc.html');
549 $this->doc->form = '<form action="' . htmlspecialchars($this->R_URI) . '" method="post" enctype="' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['form_enctype'] . '" name="editform" onsubmit="document.editform._scrollPosition.value=(document.documentElement.scrollTop || document.body.scrollTop); return TBE_EDITOR.checkSubmit(1);">';
550 $this->doc->getPageRenderer()->loadPrototype();
551 $this->doc->JScode = $this->doc->wrapScriptTags('
552 function jumpToUrl(URL,formEl) { //
553 if (!TBE_EDITOR.isFormChanged()) {
554 window.location.href = URL;
555 } else if (formEl && formEl.type=="checkbox") {
556 formEl.checked = formEl.checked ? 0 : 1;
557 }
558 }
559 // Object: TS:
560 // passwordDummy and decimalSign are used by tbe_editor.js and have to be declared here as
561 // TS object overwrites the object declared in tbe_editor.js
562 function typoSetup() { //
563 this.uniqueID = "";
564 this.passwordDummy = "********";
565 this.PATH_typo3 = " ";
566 this.decimalSign = ".";
567 }
568 var TS = new typoSetup();
569
570 // Info view:
571 function launchView(table,uid,bP) { //
572 var backPath= bP ? bP : "";
573 var thePreviewWindow="";
574 thePreviewWindow = window.open(backPath+"show_item.php?table="+encodeURIComponent(table)+"&uid="+encodeURIComponent(uid),"ShowItem"+TS.uniqueID,"height=300,width=410,status=0,menubar=0,resizable=0,location=0,directories=0,scrollbars=1,toolbar=0");
575 if (thePreviewWindow && thePreviewWindow.focus) {
576 thePreviewWindow.focus();
577 }
578 }
579 function deleteRecord(table,id,url) { //
580 if (
581 ' . ($GLOBALS['BE_USER']->jsConfirmation(4) ? 'confirm(' . $GLOBALS['LANG']->JScharCode($GLOBALS['LANG']->getLL('deleteWarning')) . ')' : '1==1') . '
582 ) {
583 window.location.href = "tce_db.php?cmd["+table+"]["+id+"][delete]=1' . \TYPO3\CMS\Backend\Utility\BackendUtility::getUrlToken('tceAction') . '&redirect="+escape(url)+"&vC=' . $GLOBALS['BE_USER']->veriCode() . '&prErr=1&uPT=1";
584 }
585 return false;
586 }
587 ' . (isset($_POST['_savedokview_x']) && $this->popViewId ? 'if (window.opener) { ' . \TYPO3\CMS\Backend\Utility\BackendUtility::viewOnClick($this->popViewId, '', \TYPO3\CMS\Backend\Utility\BackendUtility::BEgetRootLine($this->popViewId), '', $this->viewUrl, $this->popViewId_addParams, FALSE) . ' } else { ' . \TYPO3\CMS\Backend\Utility\BackendUtility::viewOnClick($this->popViewId, '', \TYPO3\CMS\Backend\Utility\BackendUtility::BEgetRootLine($this->popViewId), '', $this->viewUrl, $this->popViewId_addParams) . ' } ' : ''));
588 // Setting up the context sensitive menu:
589 $this->doc->getContextMenuCode();
590 $this->doc->bodyTagAdditions = 'onload="window.scrollTo(0,' . \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('_scrollPosition'), 0, 10000) . ');"';
591 }
592
593 /**
594 * Main module operation
595 *
596 * @return void
597 * @todo Define visibility
598 */
599 public function main() {
600 // Begin edit:
601 if (is_array($this->editconf)) {
602 // Initialize TCEforms (rendering the forms)
603 $this->tceforms = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\FormEngine');
604 $this->tceforms->initDefaultBEMode();
605 $this->tceforms->doSaveFieldName = 'doSave';
606 $this->tceforms->localizationMode = \TYPO3\CMS\Core\Utility\GeneralUtility::inList('text,media', $this->localizationMode) ? $this->localizationMode : '';
607 // text,media is keywords defined in TYPO3 Core API..., see "l10n_cat"
608 $this->tceforms->returnUrl = $this->R_URI;
609 $this->tceforms->palettesCollapsed = !$this->MOD_SETTINGS['showPalettes'];
610 $this->tceforms->disableRTE = !$GLOBALS['BE_USER']->isRTE();
611 $this->tceforms->enableClickMenu = TRUE;
612 $this->tceforms->enableTabMenu = TRUE;
613 // Clipboard is initialized:
614 // Start clipboard
615 $this->tceforms->clipObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Clipboard\\Clipboard');
616 // Initialize - reads the clipboard content from the user session
617 $this->tceforms->clipObj->initializeClipboard();
618 // Setting external variables:
619 $this->tceforms->edit_showFieldHelp = $GLOBALS['BE_USER']->uc['edit_showFieldHelp'];
620 if ($this->editRegularContentFromId) {
621 $this->editRegularContentFromId();
622 }
623 // Creating the editing form, wrap it with buttons, document selector etc.
624 $editForm = $this->makeEditForm();
625 if ($editForm) {
626 $this->firstEl = reset($this->elementsData);
627 // Checking if the currently open document is stored in the list of "open documents" - if not, then add it:
628 if ((strcmp($this->docDat[1], $this->storeUrlMd5) || !isset($this->docHandler[$this->storeUrlMd5])) && !$this->dontStoreDocumentRef) {
629 $this->docHandler[$this->storeUrlMd5] = array($this->storeTitle, $this->storeArray, $this->storeUrl, $this->firstEl);
630 $GLOBALS['BE_USER']->pushModuleData('alt_doc.php', array($this->docHandler, $this->storeUrlMd5));
631 \TYPO3\CMS\Backend\Utility\BackendUtility::setUpdateSignal('OpendocsController::updateNumber', count($this->docHandler));
632 }
633 // Module configuration
634 $this->modTSconfig = $this->viewId ? \TYPO3\CMS\Backend\Utility\BackendUtility::getModTSconfig($this->viewId, 'mod.xMOD_alt_doc') : array();
635 $body .= $this->tceforms->printNeededJSFunctions_top();
636 $body .= $this->compileForm($editForm);
637 $body .= $this->tceforms->printNeededJSFunctions();
638 $body .= $this->functionMenus();
639 $body .= $this->tceformMessages();
640 }
641 }
642 // Access check...
643 // The page will show only if there is a valid page and if this page may be viewed by the user
644 $this->pageinfo = \TYPO3\CMS\Backend\Utility\BackendUtility::readPageAccess($this->viewId, $this->perms_clause);
645 // Setting up the buttons and markers for docheader
646 $docHeaderButtons = $this->getButtons();
647 $markers = array(
648 'LANGSELECTOR' => $this->langSelector(),
649 'EXTRAHEADER' => $this->extraFormHeaders(),
650 'CSH' => $docHeaderButtons['csh'],
651 'CONTENT' => $body
652 );
653 // Build the <body> for the module
654 $this->content = $this->doc->startPage('TYPO3 Edit Document');
655 $this->content .= $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
656 $this->content .= $this->doc->endPage();
657 $this->content = $this->doc->insertStylesAndJS($this->content);
658 }
659
660 /**
661 * Outputting the accumulated content to screen
662 *
663 * @return void
664 * @todo Define visibility
665 */
666 public function printContent() {
667 echo $this->content;
668 }
669
670 /***************************
671 *
672 * Sub-content functions, rendering specific parts of the module content.
673 *
674 ***************************/
675 /**
676 * Creates the editing form with TCEforms, based on the input from GPvars.
677 *
678 * @return string HTML form elements wrapped in tables
679 * @todo Define visibility
680 */
681 public function makeEditForm() {
682 // Initialize variables:
683 $this->elementsData = array();
684 $this->errorC = 0;
685 $this->newC = 0;
686 $thePrevUid = '';
687 $editForm = '';
688 $trData = NULL;
689 // Traverse the GPvar edit array
690 // Tables:
691 foreach ($this->editconf as $table => $conf) {
692 if (is_array($conf) && $GLOBALS['TCA'][$table] && $GLOBALS['BE_USER']->check('tables_modify', $table)) {
693 // Traverse the keys/comments of each table (keys can be a commalist of uids)
694 foreach ($conf as $cKey => $cmd) {
695 if ($cmd == 'edit' || $cmd == 'new') {
696 // Get the ids:
697 $ids = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $cKey, 1);
698 // Traverse the ids:
699 foreach ($ids as $theUid) {
700 // Checking if the user has permissions? (Only working as a precaution,
701 // because the final permission check is always down in TCE. But it's
702 // good to notify the user on beforehand...)
703 // First, resetting flags.
704 $hasAccess = 1;
705 $deniedAccessReason = '';
706 $deleteAccess = 0;
707 $this->viewId = 0;
708 // If the command is to create a NEW record...:
709 if ($cmd == 'new') {
710 // NOTICE: the id values in this case points to the page uid onto which the
711 // record should be create OR (if the id is negativ) to a record from the
712 // same table AFTER which to create the record.
713 if (intval($theUid)) {
714 // Find parent page on which the new record reside
715 // Less than zero - find parent page
716 if ($theUid < 0) {
717 $calcPRec = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord($table, abs($theUid));
718 $calcPRec = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('pages', $calcPRec['pid']);
719 } else {
720 // always a page
721 $calcPRec = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('pages', abs($theUid));
722 }
723 // Now, calculate whether the user has access to creating new records on this position:
724 if (is_array($calcPRec)) {
725 // Permissions for the parent page
726 $CALC_PERMS = $GLOBALS['BE_USER']->calcPerms($calcPRec);
727 if ($table == 'pages') {
728 // If pages:
729 $hasAccess = $CALC_PERMS & 8 ? 1 : 0;
730 $this->viewId = 0;
731 } else {
732 $hasAccess = $CALC_PERMS & 16 ? 1 : 0;
733 $this->viewId = $calcPRec['uid'];
734 }
735 }
736 }
737 // Don't save this document title in the document selector if the document is new.
738 $this->dontStoreDocumentRef = 1;
739 } else {
740 // Edit:
741 $calcPRec = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord($table, $theUid);
742 \TYPO3\CMS\Backend\Utility\BackendUtility::fixVersioningPid($table, $calcPRec);
743 if (is_array($calcPRec)) {
744 if ($table == 'pages') { // If pages:
745 $CALC_PERMS = $GLOBALS['BE_USER']->calcPerms($calcPRec);
746 $hasAccess = $CALC_PERMS & 2 ? 1 : 0;
747 $deleteAccess = $CALC_PERMS & 4 ? 1 : 0;
748 $this->viewId = $calcPRec['uid'];
749 } else {
750 // Fetching pid-record first
751 $CALC_PERMS = $GLOBALS['BE_USER']->calcPerms(\TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('pages', $calcPRec['pid']));
752 $hasAccess = $CALC_PERMS & 16 ? 1 : 0;
753 $deleteAccess = $CALC_PERMS & 16 ? 1 : 0;
754 $this->viewId = $calcPRec['pid'];
755 // Adding "&L=xx" if the record being edited has a languageField with a value larger than zero!
756 if ($GLOBALS['TCA'][$table]['ctrl']['languageField'] && $calcPRec[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0) {
757 $this->viewId_addParams = '&L=' . $calcPRec[$GLOBALS['TCA'][$table]['ctrl']['languageField']];
758 }
759 }
760 // Check internals regarding access:
761 $isRootLevelRestrictionIgnored = \TYPO3\CMS\Backend\Utility\BackendUtility::isRootLevelRestrictionIgnored($table);
762 if ($hasAccess || (string) $calcPRec['pid'] === '0' && $isRootLevelRestrictionIgnored) {
763 $hasAccess = $GLOBALS['BE_USER']->recordEditAccessInternals($table, $calcPRec);
764 $deniedAccessReason = $GLOBALS['BE_USER']->errorMsg;
765 }
766 } else {
767 $hasAccess = 0;
768 }
769 }
770 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/alt_doc.php']['makeEditForm_accessCheck'])) {
771 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/alt_doc.php']['makeEditForm_accessCheck'] as $_funcRef) {
772 $_params = array(
773 'table' => $table,
774 'uid' => $theUid,
775 'cmd' => $cmd,
776 'hasAccess' => $hasAccess
777 );
778 $hasAccess = \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($_funcRef, $_params, $this);
779 }
780 }
781 // AT THIS POINT we have checked the access status of the editing/creation of
782 // records and we can now proceed with creating the form elements:
783 if ($hasAccess) {
784 $prevPageID = is_object($trData) ? $trData->prevPageID : '';
785 $trData = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Form\\DataPreprocessor');
786 $trData->addRawData = TRUE;
787 $trData->defVals = $this->defVals;
788 $trData->lockRecords = 1;
789 $trData->disableRTE = !$GLOBALS['BE_USER']->isRTE();
790 $trData->prevPageID = $prevPageID;
791 // 'new'
792 $trData->fetchRecord($table, $theUid, $cmd == 'new' ? 'new' : '');
793 $rec = reset($trData->regTableItems_data);
794 $rec['uid'] = $cmd == 'new' ? uniqid('NEW') : $theUid;
795 if ($cmd == 'new') {
796 $rec['pid'] = $theUid == 'prev' ? $thePrevUid : $theUid;
797 }
798 $this->elementsData[] = array(
799 'table' => $table,
800 'uid' => $rec['uid'],
801 'pid' => $rec['pid'],
802 'cmd' => $cmd,
803 'deleteAccess' => $deleteAccess
804 );
805 // Now, render the form:
806 if (is_array($rec)) {
807 // Setting visual path / title of form:
808 $this->generalPathOfForm = $this->tceforms->getRecordPath($table, $rec);
809 if (!$this->storeTitle) {
810 $this->storeTitle = $this->recTitle ? htmlspecialchars($this->recTitle) : \TYPO3\CMS\Backend\Utility\BackendUtility::getRecordTitle($table, $rec, TRUE);
811 }
812 // Setting variables in TCEforms object:
813 $this->tceforms->hiddenFieldList = '';
814 $this->tceforms->globalShowHelp = $this->disHelp ? 0 : 1;
815 if (is_array($this->overrideVals[$table])) {
816 $this->tceforms->hiddenFieldListArr = array_keys($this->overrideVals[$table]);
817 }
818 // Register default language labels, if any:
819 $this->tceforms->registerDefaultLanguageData($table, $rec);
820 // Create form for the record (either specific list of fields or the whole record):
821 $panel = '';
822 if ($this->columnsOnly) {
823 if (is_array($this->columnsOnly)) {
824 $panel .= $this->tceforms->getListedFields($table, $rec, $this->columnsOnly[$table]);
825 } else {
826 $panel .= $this->tceforms->getListedFields($table, $rec, $this->columnsOnly);
827 }
828 } else {
829 $panel .= $this->tceforms->getMainFields($table, $rec);
830 }
831 $panel = $this->tceforms->wrapTotal($panel, $rec, $table);
832 // Setting the pid value for new records:
833 if ($cmd == 'new') {
834 $panel .= '<input type="hidden" name="data[' . $table . '][' . $rec['uid'] . '][pid]" value="' . $rec['pid'] . '" />';
835 $this->newC++;
836 }
837 // Display "is-locked" message:
838 if ($lockInfo = \TYPO3\CMS\Backend\Utility\BackendUtility::isRecordLocked($table, $rec['uid'])) {
839 $lockedMessage = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessage', htmlspecialchars($lockInfo['msg']), '', \TYPO3\CMS\Core\Messaging\FlashMessage::WARNING);
840 \TYPO3\CMS\Core\Messaging\FlashMessageQueue::addMessage($lockedMessage);
841 }
842 // Combine it all:
843 $editForm .= $panel;
844 }
845 $thePrevUid = $rec['uid'];
846 } else {
847 $this->errorC++;
848 $editForm .= $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.noEditPermission', 1) . '<br /><br />' . ($deniedAccessReason ? 'Reason: ' . htmlspecialchars($deniedAccessReason) . '<br /><br />' : '');
849 }
850 }
851 }
852 }
853 }
854 }
855 return $editForm;
856 }
857
858 /**
859 * Create the panel of buttons for submitting the form or otherwise perform operations.
860 *
861 * @return array All available buttons as an assoc. array
862 */
863 protected function getButtons() {
864 $buttons = array(
865 'save' => '',
866 'save_view' => '',
867 'save_new' => '',
868 'save_close' => '',
869 'close' => '',
870 'delete' => '',
871 'undo' => '',
872 'history' => '',
873 'columns_only' => '',
874 'csh' => '',
875 'translation_save' => '',
876 'translation_saveclear' => ''
877 );
878 // Render SAVE type buttons:
879 // The action of each button is decided by its name attribute. (See doProcessData())
880 if (!$this->errorC && !$GLOBALS['TCA'][$this->firstEl['table']]['ctrl']['readOnly']) {
881 // SAVE button:
882 $buttons['save'] = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-save', array('html' => '<input type="image" name="_savedok" class="c-inputButton" src="clear.gif" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:rm.saveDoc', 1) . '" />'));
883 // SAVE / VIEW button:
884 if ($this->viewId && !$this->noView && \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('cms') && $this->getNewIconMode($this->firstEl['table'], 'saveDocView')) {
885 $buttons['save_view'] = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-save-view', array('html' => '<input type="image" class="c-inputButton" name="_savedokview" src="clear.gif" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:rm.saveDocShow', 1) . '" />'));
886 }
887 // SAVE / NEW button:
888 if (count($this->elementsData) == 1 && $this->getNewIconMode($this->firstEl['table'])) {
889 $buttons['save_new'] = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-save-new', array('html' => '<input type="image" class="c-inputButton" name="_savedoknew" src="clear.gif" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:rm.saveNewDoc', 1) . '" />'));
890 }
891 // SAVE / CLOSE
892 $buttons['save_close'] = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-save-close', array('html' => '<input type="image" class="c-inputButton" name="_saveandclosedok" src="clear.gif" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:rm.saveCloseDoc', 1) . '" />'));
893 // FINISH TRANSLATION / SAVE / CLOSE
894 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['explicitConfirmationOfTranslation']) {
895 $buttons['translation_save'] = '<input type="image" class="c-inputButton" name="_translation_savedok" src="' . \TYPO3\CMS\Backend\Utility\IconUtility::skinImg($this->doc->backPath, 'gfx/translationsavedok.gif', '', 1) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:rm.translationSaveDoc', 1) . '" />';
896 $buttons['translation_saveclear'] = '<input type="image" class="c-inputButton" name="_translation_savedokclear" src="' . \TYPO3\CMS\Backend\Utility\IconUtility::skinImg($this->doc->backPath, 'gfx/translationsavedok_clear.gif', '', 1) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:rm.translationSaveDocClear', 1) . '" />';
897 }
898 }
899 // CLOSE button:
900 $buttons['close'] = '<a href="#" onclick="document.editform.closeDoc.value=1; document.editform.submit(); return false;" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:rm.closeDoc', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-close') . '</a>';
901 // DELETE + UNDO buttons:
902 if (!$this->errorC && !$GLOBALS['TCA'][$this->firstEl['table']]['ctrl']['readOnly'] && count($this->elementsData) == 1) {
903 if ($this->firstEl['cmd'] != 'new' && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($this->firstEl['uid'])) {
904 // Delete:
905 if ($this->firstEl['deleteAccess'] && !$GLOBALS['TCA'][$this->firstEl['table']]['ctrl']['readOnly'] && !$this->getNewIconMode($this->firstEl['table'], 'disableDelete')) {
906 $aOnClick = 'return deleteRecord(\'' . $this->firstEl['table'] . '\',\'' . $this->firstEl['uid'] . '\', unescape(\'' . rawurlencode($this->retUrl) . '\'));';
907 $buttons['delete'] = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '" title="' . $GLOBALS['LANG']->getLL('deleteItem', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-delete') . '</a>';
908 }
909 // Undo:
910 $undoRes = $GLOBALS['TYPO3_DB']->exec_SELECTquery('tstamp', 'sys_history', 'tablename=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->firstEl['table'], 'sys_history') . ' AND recuid=' . intval($this->firstEl['uid']), '', 'tstamp DESC', '1');
911 if ($undoButtonR = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($undoRes)) {
912 $aOnClick = 'window.location.href=\'show_rechis.php?element=' . rawurlencode(($this->firstEl['table'] . ':' . $this->firstEl['uid'])) . '&revert=ALL_FIELDS&sumUp=-1&returnUrl=' . rawurlencode($this->R_URI) . '\'; return false;';
913 $buttons['undo'] = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '"' . ' title="' . htmlspecialchars(sprintf($GLOBALS['LANG']->getLL('undoLastChange'), \TYPO3\CMS\Backend\Utility\BackendUtility::calcAge(($GLOBALS['EXEC_TIME'] - $undoButtonR['tstamp']), $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears')))) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-undo') . '</a>';
914 }
915 if ($this->getNewIconMode($this->firstEl['table'], 'showHistory')) {
916 $aOnClick = 'window.location.href=\'show_rechis.php?element=' . rawurlencode(($this->firstEl['table'] . ':' . $this->firstEl['uid'])) . '&returnUrl=' . rawurlencode($this->R_URI) . '\'; return false;';
917 $buttons['history'] = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-history-open') . '</a>';
918 }
919 // If only SOME fields are shown in the form, this will link the user to the FULL form:
920 if ($this->columnsOnly) {
921 $buttons['columns_only'] = '<a href="' . htmlspecialchars(($this->R_URI . '&columnsOnly=')) . '" title="' . $GLOBALS['LANG']->getLL('editWholeRecord', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-open') . '</a>';
922 }
923 }
924 }
925 // add the CSH icon
926 $buttons['csh'] = \TYPO3\CMS\Backend\Utility\BackendUtility::cshItem('xMOD_csh_corebe', 'TCEforms', $GLOBALS['BACK_PATH'], '', TRUE);
927 $buttons['shortcut'] = $this->shortCutLink();
928 $buttons['open_in_new_window'] = $this->openInNewWindowLink();
929 return $buttons;
930 }
931
932 /**
933 * Returns the language switch/selector for editing,
934 * show only when a single record is edited
935 * - multiple records are too confusing
936 *
937 * @return string The HTML
938 * @todo Define visibility
939 */
940 public function langSelector() {
941 $langSelector = '';
942 if (count($this->elementsData) == 1) {
943 $langSelector = $this->languageSwitch($this->firstEl['table'], $this->firstEl['uid'], $this->firstEl['pid']);
944 }
945 return $langSelector;
946 }
947
948 /**
949 * Compiles the extra form headers if the tceforms
950 *
951 * @return string The HTML
952 * @todo Define visibility
953 */
954 public function extraFormHeaders() {
955 $extraTemplate = '';
956 if (is_array($this->tceforms->extraFormHeaders)) {
957 $extraTemplate = \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($this->doc->moduleTemplate, '###DOCHEADER_EXTRAHEADER###');
958 $extraTemplate = \TYPO3\CMS\Core\Html\HtmlParser::substituteMarker($extraTemplate, '###EXTRAHEADER###', implode(LF, $this->tceforms->extraFormHeaders));
959 }
960 return $extraTemplate;
961 }
962
963 /**
964 * Put together the various elements (buttons, selectors, form) into a table
965 *
966 * @param string $editForm HTML form.
967 * @return string Composite HTML
968 * @todo Define visibility
969 */
970 public function compileForm($editForm) {
971 $formContent = '
972 <!-- EDITING FORM -->
973 ' . $editForm . '
974
975 <input type="hidden" name="returnUrl" value="' . htmlspecialchars($this->retUrl) . '" />
976 <input type="hidden" name="viewUrl" value="' . htmlspecialchars($this->viewUrl) . '" />';
977 if ($this->returnNewPageId) {
978 $formContent .= '<input type="hidden" name="returnNewPageId" value="1" />';
979 }
980 $formContent .= '<input type="hidden" name="popViewId" value="' . htmlspecialchars($this->viewId) . '" />';
981 if ($this->viewId_addParams) {
982 $formContent .= '<input type="hidden" name="popViewId_addParams" value="' . htmlspecialchars($this->viewId_addParams) . '" />';
983 }
984 $formContent .= '
985 <input type="hidden" name="closeDoc" value="0" />
986 <input type="hidden" name="doSave" value="0" />
987 <input type="hidden" name="_serialNumber" value="' . md5(microtime()) . '" />
988 <input type="hidden" name="_scrollPosition" value="" />' . \TYPO3\CMS\Backend\Form\FormEngine::getHiddenTokenField('editRecord');
989 return $formContent;
990 }
991
992 /**
993 * Create the checkbox buttons in the bottom of the pages.
994 *
995 * @return string HTML for function menus.
996 * @todo Define visibility
997 */
998 public function functionMenus() {
999 if ($GLOBALS['BE_USER']->getTSConfigVal('options.enableShowPalettes')) {
1000 // Show palettes:
1001 return '
1002 <!-- Function menu (checkbox for showing all palettes): -->
1003 <br />' . \TYPO3\CMS\Backend\Utility\BackendUtility::getFuncCheck('', 'SET[showPalettes]', $this->MOD_SETTINGS['showPalettes'], 'alt_doc.php', (\TYPO3\CMS\Core\Utility\GeneralUtility::implodeArrayForUrl('', array_merge($this->R_URL_getvars, array('SET' => ''))) . \TYPO3\CMS\Backend\Utility\BackendUtility::getUrlToken('editRecord')), 'id="checkShowPalettes"') . '<label for="checkShowPalettes">' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.showPalettes', 1) . '</label>';
1004 } else {
1005 return '';
1006 }
1007 }
1008
1009 /**
1010 * Create shortcut icon
1011 *
1012 * @return string
1013 * @todo Define visibility
1014 */
1015 public function shortCutLink() {
1016 if ($this->returnUrl == 'close.html' || !$GLOBALS['BE_USER']->mayMakeShortcut()) {
1017 return '';
1018 }
1019 return $this->doc->makeShortcutIcon('returnUrl,edit,defVals,overrideVals,columnsOnly,returnNewPageId,editRegularContentFromId,disHelp,noView', implode(',', array_keys($this->MOD_MENU)), $this->MCONF['name'], 1);
1020 }
1021
1022 /**
1023 * Creates open-in-window link
1024 *
1025 * @return string
1026 * @todo Define visibility
1027 */
1028 public function openInNewWindowLink() {
1029 if ($this->returnUrl == 'close.html') {
1030 return '';
1031 }
1032 $aOnClick = 'vHWin=window.open(\'' . \TYPO3\CMS\Core\Utility\GeneralUtility::linkThisScript(array('returnUrl' => 'close.html')) . '\',\'' . md5($this->R_URI) . '\',\'width=670,height=500,status=0,menubar=0,scrollbars=1,resizable=1\');vHWin.focus();return false;';
1033 return '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.openInNewWindow', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-window-open') . '</a>';
1034 }
1035
1036 /**
1037 * Reads comment messages from TCEforms and prints them in a HTML comment in the bottom of the page.
1038 *
1039 * @return void
1040 * @todo Define visibility
1041 */
1042 public function tceformMessages() {
1043 if (count($this->tceforms->commentMessages)) {
1044 $tceformMessages = '
1045 <!-- TCEFORM messages
1046 ' . htmlspecialchars(implode(LF, $this->tceforms->commentMessages)) . '
1047 -->
1048 ';
1049 }
1050 return $tceformMessages;
1051 }
1052
1053 /***************************
1054 *
1055 * Localization stuff
1056 *
1057 ***************************/
1058 /**
1059 * Make selector box for creating new translation for a record or switching to edit the record in an existing language.
1060 * Displays only languages which are available for the current page.
1061 *
1062 * @param string $table Table name
1063 * @param integer $uid Uid for which to create a new language
1064 * @param integer $pid Pid of the record
1065 * @return string <select> HTML element (if there were items for the box anyways...)
1066 * @todo Define visibility
1067 */
1068 public function languageSwitch($table, $uid, $pid = NULL) {
1069 $content = '';
1070 $languageField = $GLOBALS['TCA'][$table]['ctrl']['languageField'];
1071 $transOrigPointerField = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'];
1072 // Table editable and activated for languages?
1073 if ($GLOBALS['BE_USER']->check('tables_modify', $table) && $languageField && $transOrigPointerField && !$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']) {
1074 if (is_null($pid)) {
1075 $row = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord($table, $uid, 'pid');
1076 $pid = $row['pid'];
1077 }
1078 // Get all avalibale languages for the page
1079 $langRows = $this->getLanguages($pid);
1080 // Page available in other languages than default language?
1081 if (is_array($langRows) && count($langRows) > 1) {
1082 $rowsByLang = array();
1083 $fetchFields = 'uid,' . $languageField . ',' . $transOrigPointerField;
1084 // Get record in current language
1085 $rowCurrent = \TYPO3\CMS\Backend\Utility\BackendUtility::getLiveVersionOfRecord($table, $uid, $fetchFields);
1086 if (!is_array($rowCurrent)) {
1087 $rowCurrent = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord($table, $uid, $fetchFields);
1088 }
1089 $currentLanguage = $rowCurrent[$languageField];
1090 // Disabled for records with [all] language!
1091 if ($currentLanguage > -1) {
1092 // Get record in default language if needed
1093 if ($currentLanguage && $rowCurrent[$transOrigPointerField]) {
1094 $rowsByLang[0] = \TYPO3\CMS\Backend\Utility\BackendUtility::getLiveVersionOfRecord($table, $rowCurrent[$transOrigPointerField], $fetchFields);
1095 if (!is_array($rowsByLang[0])) {
1096 $rowsByLang[0] = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord($table, $rowCurrent[$transOrigPointerField], $fetchFields);
1097 }
1098 } else {
1099 $rowsByLang[$rowCurrent[$languageField]] = $rowCurrent;
1100 }
1101 if ($rowCurrent[$transOrigPointerField] || $currentLanguage === '0') {
1102 // Get record in other languages to see what's already available
1103 $translations = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows($fetchFields, $table, 'pid=' . intval($pid) . ' AND ' . $languageField . '>0' . ' AND ' . $transOrigPointerField . '=' . intval($rowsByLang[0]['uid']) . \TYPO3\CMS\Backend\Utility\BackendUtility::deleteClause($table) . \TYPO3\CMS\Backend\Utility\BackendUtility::versioningPlaceholderClause($table));
1104 foreach ($translations as $row) {
1105 $rowsByLang[$row[$languageField]] = $row;
1106 }
1107 }
1108 $langSelItems = array();
1109 foreach ($langRows as $lang) {
1110 if ($GLOBALS['BE_USER']->checkLanguageAccess($lang['uid'])) {
1111 $newTranslation = isset($rowsByLang[$lang['uid']]) ? '' : ' [' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:labels.new', 1) . ']';
1112 // Create url for creating a localized record
1113 if ($newTranslation) {
1114 $href = $this->doc->issueCommand('&cmd[' . $table . '][' . $rowsByLang[0]['uid'] . '][localize]=' . $lang['uid'], $this->backPath . 'alt_doc.php?justLocalized=' . rawurlencode(($table . ':' . $rowsByLang[0]['uid'] . ':' . $lang['uid'])) . '&returnUrl=' . rawurlencode($this->retUrl) . \TYPO3\CMS\Backend\Utility\BackendUtility::getUrlToken('editRecord'));
1115 } else {
1116 $href = $this->backPath . 'alt_doc.php?';
1117 $href .= '&edit[' . $table . '][' . $rowsByLang[$lang['uid']]['uid'] . ']=edit';
1118 $href .= '&returnUrl=' . rawurlencode($this->retUrl) . \TYPO3\CMS\Backend\Utility\BackendUtility::getUrlToken('editRecord');
1119 }
1120 $langSelItems[$lang['uid']] = '
1121 <option value="' . htmlspecialchars($href) . '"' . ($currentLanguage == $lang['uid'] ? ' selected="selected"' : '') . '>' . htmlspecialchars(($lang['title'] . $newTranslation)) . '</option>';
1122 }
1123 }
1124 // If any languages are left, make selector:
1125 if (count($langSelItems) > 1) {
1126 $onChange = 'if(this.options[this.selectedIndex].value){window.location.href=(this.options[this.selectedIndex].value);}';
1127 $content = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_general.xml:LGL.language', 1) . ' <select name="_langSelector" onchange="' . htmlspecialchars($onChange) . '">
1128 ' . implode('', $langSelItems) . '
1129 </select>';
1130 }
1131 }
1132 }
1133 }
1134 return $content;
1135 }
1136
1137 /**
1138 * Redirects to alt_doc with new parameters to edit a just created localized record
1139 *
1140 * @param string $justLocalized String passed by GET &justLocalized=
1141 * @return void
1142 * @todo Define visibility
1143 */
1144 public function localizationRedirect($justLocalized) {
1145 list($table, $orig_uid, $language) = explode(':', $justLocalized);
1146 if ($GLOBALS['TCA'][$table] && $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) {
1147 $localizedRecord = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('uid', $table, $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '=' . intval($language) . ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . '=' . intval($orig_uid) . \TYPO3\CMS\Backend\Utility\BackendUtility::deleteClause($table) . \TYPO3\CMS\Backend\Utility\BackendUtility::versioningPlaceholderClause($table));
1148 if (is_array($localizedRecord)) {
1149 // Create parameters and finally run the classic page module for creating a new page translation
1150 $params = '&edit[' . $table . '][' . $localizedRecord['uid'] . ']=edit';
1151 $returnUrl = '&returnUrl=' . rawurlencode(\TYPO3\CMS\Core\Utility\GeneralUtility::sanitizeLocalUrl(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('returnUrl')));
1152 $location = $GLOBALS['BACK_PATH'] . 'alt_doc.php?' . $params . $returnUrl . \TYPO3\CMS\Backend\Utility\BackendUtility::getUrlToken('editRecord');
1153 \TYPO3\CMS\Core\Utility\HttpUtility::redirect($location);
1154 }
1155 }
1156 }
1157
1158 /**
1159 * Returns sys_language records available for record translations on given page.
1160 *
1161 * @param integer $id Page id: If zero, the query will select all sys_language records from root level which are NOT hidden. If set to another value, the query will select all sys_language records that has a pages_language_overlay record on that page (and is not hidden, unless you are admin user)
1162 * @return array Language records including faked record for default language
1163 * @todo Define visibility
1164 */
1165 public function getLanguages($id) {
1166 $modSharedTSconfig = \TYPO3\CMS\Backend\Utility\BackendUtility::getModTSconfig($id, 'mod.SHARED');
1167 // Fallback non sprite-configuration
1168 if (preg_match('/\\.gif$/', $modSharedTSconfig['properties']['defaultLanguageFlag'])) {
1169 $modSharedTSconfig['properties']['defaultLanguageFlag'] = str_replace('.gif', '', $modSharedTSconfig['properties']['defaultLanguageFlag']);
1170 }
1171 $languages = array(
1172 0 => array(
1173 'uid' => 0,
1174 'pid' => 0,
1175 'hidden' => 0,
1176 'title' => strlen($modSharedTSconfig['properties']['defaultLanguageLabel']) ? $modSharedTSconfig['properties']['defaultLanguageLabel'] . ' (' . $GLOBALS['LANG']->sl('LLL:EXT:lang/locallang_mod_web_list.xml:defaultLanguage') . ')' : $GLOBALS['LANG']->sl('LLL:EXT:lang/locallang_mod_web_list.xml:defaultLanguage'),
1177 'flag' => $modSharedTSconfig['properties']['defaultLanguageFlag']
1178 )
1179 );
1180 $exQ = $GLOBALS['BE_USER']->isAdmin() ? '' : ' AND sys_language.hidden=0';
1181 if ($id) {
1182 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('sys_language.*', 'pages_language_overlay,sys_language', 'pages_language_overlay.sys_language_uid=sys_language.uid AND pages_language_overlay.pid=' . intval($id) . \TYPO3\CMS\Backend\Utility\BackendUtility::deleteClause('pages_language_overlay') . $exQ, 'pages_language_overlay.sys_language_uid,sys_language.uid,sys_language.pid,sys_language.tstamp,sys_language.hidden,sys_language.title,sys_language.static_lang_isocode,sys_language.flag', 'sys_language.title');
1183 } else {
1184 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('sys_language.*', 'sys_language', 'sys_language.hidden=0', '', 'sys_language.title');
1185 }
1186 if ($rows) {
1187 foreach ($rows as $row) {
1188 $languages[$row['uid']] = $row;
1189 }
1190 }
1191 return $languages;
1192 }
1193
1194 /***************************
1195 *
1196 * Other functions
1197 *
1198 ***************************/
1199 /**
1200 * Fix $this->editconf if versioning applies to any of the records
1201 *
1202 * @param array $mapArray Mapping between old and new ids if auto-versioning has been performed.
1203 * @return void
1204 * @todo Define visibility
1205 */
1206 public function fixWSversioningInEditConf($mapArray = FALSE) {
1207 // Traverse the editConf array
1208 if (is_array($this->editconf)) {
1209 // Tables:
1210 foreach ($this->editconf as $table => $conf) {
1211 if (is_array($conf) && $GLOBALS['TCA'][$table]) {
1212 // Traverse the keys/comments of each table (keys can be a commalist of uids)
1213 $newConf = array();
1214 foreach ($conf as $cKey => $cmd) {
1215 if ($cmd == 'edit') {
1216 // Traverse the ids:
1217 $ids = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $cKey, 1);
1218 foreach ($ids as $idKey => $theUid) {
1219 if (is_array($mapArray)) {
1220 if ($mapArray[$table][$theUid]) {
1221 $ids[$idKey] = $mapArray[$table][$theUid];
1222 }
1223 } else {
1224 // Default, look for versions in workspace for record:
1225 $calcPRec = $this->getRecordForEdit($table, $theUid);
1226 if (is_array($calcPRec)) {
1227 // Setting UID again if it had changed, eg. due to workspace versioning.
1228 $ids[$idKey] = $calcPRec['uid'];
1229 }
1230 }
1231 }
1232 // Add the possibly manipulated IDs to the new-build newConf array:
1233 $newConf[implode(',', $ids)] = $cmd;
1234 } else {
1235 $newConf[$cKey] = $cmd;
1236 }
1237 }
1238 // Store the new conf array:
1239 $this->editconf[$table] = $newConf;
1240 }
1241 }
1242 }
1243 }
1244
1245 /**
1246 * Get record for editing.
1247 *
1248 * @param string $table Table name
1249 * @param integer $theUid Record UID
1250 * @return array Returns record to edit, FALSE if none
1251 * @todo Define visibility
1252 */
1253 public function getRecordForEdit($table, $theUid) {
1254 // Fetch requested record:
1255 $reqRecord = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord($table, $theUid, 'uid,pid');
1256 if (is_array($reqRecord)) {
1257 // If workspace is OFFLINE:
1258 if ($GLOBALS['BE_USER']->workspace != 0) {
1259 // Check for versioning support of the table:
1260 if ($GLOBALS['TCA'][$table] && $GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
1261 // If the record is already a version of "something" pass it by.
1262 if ($reqRecord['pid'] == -1) {
1263 // (If it turns out not to be a version of the current workspace there will be trouble, but that is handled inside TCEmain then and in the interface it would clearly be an error of links if the user accesses such a scenario)
1264 return $reqRecord;
1265 } else {
1266 // The input record was online and an offline version must be found or made:
1267 // Look for version of this workspace:
1268 $versionRec = \TYPO3\CMS\Backend\Utility\BackendUtility::getWorkspaceVersionOfRecord($GLOBALS['BE_USER']->workspace, $table, $reqRecord['uid'], 'uid,pid,t3ver_oid');
1269 return is_array($versionRec) ? $versionRec : $reqRecord;
1270 }
1271 } else {
1272 // This means that editing cannot occur on this record because it was not supporting versioning which is required inside an offline workspace.
1273 return FALSE;
1274 }
1275 } else {
1276 // In ONLINE workspace, just return the originally requested record:
1277 return $reqRecord;
1278 }
1279 } else {
1280 // Return FALSE because the table/uid was not found anyway.
1281 return FALSE;
1282 }
1283 }
1284
1285 /**
1286 * Function, which populates the internal editconf array with editing commands for all tt_content elements from the normal column in normal language from the page pointed to by $this->editRegularContentFromId
1287 *
1288 * @return void
1289 * @todo Define visibility
1290 */
1291 public function editRegularContentFromId() {
1292 if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('cms')) {
1293 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'tt_content', 'pid=' . intval($this->editRegularContentFromId) . \TYPO3\CMS\Backend\Utility\BackendUtility::deleteClause('tt_content') . \TYPO3\CMS\Backend\Utility\BackendUtility::versioningPlaceholderClause('tt_content') . ' AND colPos=0 AND sys_language_uid=0', '', 'sorting');
1294 if ($GLOBALS['TYPO3_DB']->sql_num_rows($res)) {
1295 $ecUids = array();
1296 while ($ecRec = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
1297 $ecUids[] = $ecRec['uid'];
1298 }
1299 $this->editconf['tt_content'][implode(',', $ecUids)] = 'edit';
1300 }
1301 $GLOBALS['TYPO3_DB']->sql_free_result($res);
1302 }
1303 }
1304
1305 /**
1306 * Populates the variables $this->storeArray, $this->storeUrl, $this->storeUrlMd5
1307 *
1308 * @return void
1309 * @see makeDocSel()
1310 * @todo Define visibility
1311 */
1312 public function compileStoreDat() {
1313 $this->storeArray = \TYPO3\CMS\Core\Utility\GeneralUtility::compileSelectedGetVarsFromArray('edit,defVals,overrideVals,columnsOnly,disHelp,noView,editRegularContentFromId', $this->R_URL_getvars);
1314 $this->storeUrl = \TYPO3\CMS\Core\Utility\GeneralUtility::implodeArrayForUrl('', $this->storeArray);
1315 $this->storeUrlMd5 = md5($this->storeUrl);
1316 }
1317
1318 /**
1319 * Function used to look for configuration of buttons in the form: Fx. disabling buttons or showing them at various positions.
1320 *
1321 * @param string $table The table for which the configuration may be specific
1322 * @param string $key The option for look for. Default is checking if the saveDocNew button should be displayed.
1323 * @return string Return value fetched from USER TSconfig
1324 * @todo Define visibility
1325 */
1326 public function getNewIconMode($table, $key = 'saveDocNew') {
1327 $TSconfig = $GLOBALS['BE_USER']->getTSConfig('options.' . $key);
1328 $output = trim(isset($TSconfig['properties'][$table]) ? $TSconfig['properties'][$table] : $TSconfig['value']);
1329 return $output;
1330 }
1331
1332 /**
1333 * Handling the closing of a document
1334 *
1335 * @param integer $code Close code: 0/1 will redirect to $this->retUrl, 3 will clear the docHandler (thus closing all documents) and otehr values will call setDocument with ->retUrl
1336 * @return void
1337 * @todo Define visibility
1338 */
1339 public function closeDocument($code = 0) {
1340 // If current document is found in docHandler,
1341 // then unset it, possibly unset it ALL and finally, write it to the session data
1342 if (isset($this->docHandler[$this->storeUrlMd5])) {
1343 // add the closing document to the recent documents
1344 $recentDocs = $GLOBALS['BE_USER']->getModuleData('opendocs::recent');
1345 if (!is_array($recentDocs)) {
1346 $recentDocs = array();
1347 }
1348 $closedDoc = $this->docHandler[$this->storeUrlMd5];
1349 $recentDocs = array_merge(array($this->storeUrlMd5 => $closedDoc), $recentDocs);
1350 if (count($recentDocs) > 8) {
1351 $recentDocs = array_slice($recentDocs, 0, 8);
1352 }
1353 // remove it from the list of the open documents
1354 unset($this->docHandler[$this->storeUrlMd5]);
1355 if ($code == '3') {
1356 $recentDocs = array_merge($this->docHandler, $recentDocs);
1357 $this->docHandler = array();
1358 }
1359 $GLOBALS['BE_USER']->pushModuleData('opendocs::recent', $recentDocs);
1360 $GLOBALS['BE_USER']->pushModuleData('alt_doc.php', array($this->docHandler, $this->docDat[1]));
1361 \TYPO3\CMS\Backend\Utility\BackendUtility::setUpdateSignal('OpendocsController::updateNumber', count($this->docHandler));
1362 }
1363 // If ->returnEditConf is set, then add the current content of editconf to the ->retUrl variable: (used by other scripts, like wizard_add, to know which records was created or so...)
1364 if ($this->returnEditConf && $this->retUrl != 'dummy.php') {
1365 $this->retUrl .= '&returnEditConf=' . rawurlencode(serialize($this->editconf));
1366 }
1367 // If code is NOT set OR set to 1, then make a header location redirect to $this->retUrl
1368 if (!$code || $code == 1) {
1369 \TYPO3\CMS\Core\Utility\HttpUtility::redirect($this->retUrl);
1370 } else {
1371 $this->setDocument('', $this->retUrl);
1372 }
1373 }
1374
1375 /**
1376 * Redirects to the document pointed to by $currentDocFromHandlerMD5 OR $retUrl (depending on some internal calculations).
1377 * Most likely you will get a header-location redirect from this function.
1378 *
1379 * @param string $currentDocFromHandlerMD5 Pointer to the document in the docHandler array
1380 * @param string $retUrl Alternative/Default retUrl
1381 * @return void
1382 * @todo Define visibility
1383 */
1384 public function setDocument($currentDocFromHandlerMD5 = '', $retUrl = 'alt_doc_nodoc.php') {
1385 if (!\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('cms') && !strcmp($retUrl, 'alt_doc_nodoc.php')) {
1386 return;
1387 }
1388 if (!$this->modTSconfig['properties']['disableDocSelector'] && is_array($this->docHandler) && count($this->docHandler)) {
1389 if (isset($this->docHandler[$currentDocFromHandlerMD5])) {
1390 $setupArr = $this->docHandler[$currentDocFromHandlerMD5];
1391 } else {
1392 $setupArr = reset($this->docHandler);
1393 }
1394 if ($setupArr[2]) {
1395 $sParts = parse_url(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('REQUEST_URI'));
1396 $retUrl = $sParts['path'] . '?' . $setupArr[2] . '&returnUrl=' . rawurlencode($retUrl);
1397 }
1398 }
1399 \TYPO3\CMS\Core\Utility\HttpUtility::redirect($retUrl);
1400 }
1401
1402 }
1403
1404
1405 ?>