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