PageLayoutController.php 52 KB
Newer Older
1
2
3
<?php
namespace TYPO3\CMS\Backend\Controller;

4
/*
5
 * This file is part of the TYPO3 CMS project.
6
 *
7
8
9
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
10
 *
11
12
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
13
 *
14
15
 * The TYPO3 project - inspiring people to share!
 */
16

17
18
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
19
20
21
22
23
use TYPO3\CMS\Backend\Form\Exception\AccessDeniedException;
use TYPO3\CMS\Backend\Form\FormDataCompiler;
use TYPO3\CMS\Backend\Form\FormDataGroup\TcaDatabaseRecord;
use TYPO3\CMS\Backend\Form\FormResultCompiler;
use TYPO3\CMS\Backend\Form\NodeFactory;
Nicole Cordes's avatar
Nicole Cordes committed
24
use TYPO3\CMS\Backend\Utility\BackendUtility;
25
26
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
27
use TYPO3\CMS\Core\Page\PageRenderer;
28
use TYPO3\CMS\Core\Type\Bitmask\Permission;
Nicole Cordes's avatar
Nicole Cordes committed
29
30
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
31
use TYPO3\CMS\Core\Utility\HttpUtility;
Nicole Cordes's avatar
Nicole Cordes committed
32
use TYPO3\CMS\Core\Utility\MathUtility;
33
use TYPO3\CMS\Fluid\View\StandaloneView;
34
use TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper;
35
36
37
38
39
40
41
42
43
use TYPO3\CMS\Recordlist\RecordList;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Frontend\Page\PageRepository;
use TYPO3\CMS\Backend\Module\ModuleLoader;
use TYPO3\CMS\Backend\Template\DocumentTemplate;
use TYPO3\CMS\Backend\View\BackendLayoutView;
use TYPO3\CMS\Core\Messaging\FlashMessageService;
use TYPO3\CMS\Backend\View\PageLayoutView;
use TYPO3\CMS\Backend\Tree\View\ContentLayoutPagePositionMap;
44
use TYPO3\CMS\Core\Versioning\VersionState;
Nicole Cordes's avatar
Nicole Cordes committed
45

46
47
48
49
50
/**
 * Script Class for Web > Layout module
 */
class PageLayoutController {

51
52
53
54
55
	/**
	 * Page Id for which to make the listing
	 *
	 * @var int
	 */
56
57
	public $id;

58
59
60
61
62
	/**
	 * Pointer - for browsing list of records.
	 *
	 * @var int
	 */
63
64
	public $pointer;

65
66
67
68
69
	/**
	 * Thumbnails or not
	 *
	 * @var string
	 */
70
71
	public $imagemode;

72
73
74
75
76
	/**
	 * Search-fields
	 *
	 * @var string
	 */
77
78
	public $search_field;

79
80
81
82
83
	/**
	 * Search-levels
	 *
	 * @var int
	 */
84
85
	public $search_levels;

86
87
88
89
90
	/**
	 * Show-limit
	 *
	 * @var int
	 */
91
92
	public $showLimit;

93
94
95
96
97
	/**
	 * Return URL
	 *
	 * @var string
	 */
98
99
	public $returnUrl;

100
101
102
103
104
	/**
	 * Clear-cache flag - if set, clears page cache for current id.
	 *
	 * @var bool
	 */
105
106
	public $clear_cache;

107
108
109
110
111
	/**
	 * PopView id - for opening a window with the page
	 *
	 * @var bool
	 */
112
113
	public $popView;

114
115
116
117
118
119
	/**
	 * QuickEdit: Variable, that tells quick edit what to show/edit etc.
	 * Format is [tablename]:[uid] with some exceptional values for both parameters (with special meanings).
	 *
	 * @var string
	 */
120
121
	public $edit_record;

122
123
124
125
126
127
128
129
	/**
	 * QuickEdit: If set, this variable tells quick edit that the last edited record had
	 * this value as UID and we should look up the new, real uid value in sys_log.
	 *
	 * @var string
	 */
	public $new_unique_uid;

130
131
132
133
134
	/**
	 * Page select perms clause
	 *
	 * @var string
	 */
135
136
	public $perms_clause;

137
138
139
140
141
	/**
	 * Module TSconfig
	 *
	 * @var array
	 */
142
143
	public $modTSconfig;

144
145
146
147
148
149
150
	/**
	 * Module shared TSconfig
	 *
	 * @var array
	 */
	public $modSharedTSconfig;

151
152
153
154
155
	/**
	 * Current ids page record
	 *
	 * @var array
	 */
156
157
158
159
160
	public $pageinfo;

	/**
	 * Document template object
	 *
161
	 * @var \TYPO3\CMS\Backend\Template\DocumentTemplate
162
163
164
	 */
	public $doc;

165
166
167
168
169
	/**
	 * "Pseudo" Description -table name
	 *
	 * @var string
	 */
170
171
	public $descrTable;

172
173
174
175
176
	/**
	 * List of column-integers to edit. Is set from TSconfig, default is "1,0,2,3"
	 *
	 * @var string
	 */
177
178
	public $colPosList;

179
180
181
182
183
	/**
	 * Flag: If content can be edited or not.
	 *
	 * @var bool
	 */
184
185
	public $EDIT_CONTENT;

186
187
188
189
190
	/**
	 * Users permissions integer for this page.
	 *
	 * @var int
	 */
191
192
	public $CALC_PERMS;

193
194
195
196
197
	/**
	 * Currently selected language for editing content elements
	 *
	 * @var int
	 */
198
199
	public $current_sys_language;

200
201
202
203
204
	/**
	 * Module configuration
	 *
	 * @var array
	 */
205
206
	public $MCONF = array();

207
208
209
210
211
	/**
	 * Menu configuration
	 *
	 * @var array
	 */
212
213
	public $MOD_MENU = array();

214
215
216
217
218
	/**
	 * Module settings (session variable)
	 *
	 * @var array
	 */
219
220
	public $MOD_SETTINGS = array();

221
222
223
224
225
	/**
	 * Array of tables to be listed by the Web > Page module in addition to the default tables
	 *
	 * @var array
	 */
226
227
	public $externalTables = array();

228
229
230
231
232
	/**
	 * Module output accumulation
	 *
	 * @var string
	 */
233
234
	public $content;

235
236
237
238
239
	/**
	 * Function menu temporary storage
	 *
	 * @var string
	 */
240
241
	public $topFuncMenu;

242
243
244
245
246
247
248
249
	/**
	 * List of column-integers accessible to the current BE user.
	 * Is set from TSconfig, default is $colPosList
	 *
	 * @var string
	 */
	public $activeColPosList;

250
	/**
251
252
253
	 * Markers array
	 *
	 * @var array
254
255
256
	 */
	protected $markers = array();

257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
	/**
	 * @var array
	 */
	protected $eRParts = array();

	/**
	 * @var string
	 */
	protected $editSelect;

	/**
	 * @var bool
	 */
	protected $deleteButton;

	/**
	 * @var bool
	 */
	protected $undoButton;

	/**
	 * @var array
	 */
	protected $undoButtonR;

	/**
	 * @var string
	 */
	protected $R_URI;

	/**
	 * @var string
	 */
	protected $closeUrl;

292
293
294
295
296
	/**
	 * @var IconFactory
	 */
	protected $iconFactory;

297
298
299
300
301
302
303
	/**
	 * The name of the module
	 *
	 * @var string
	 */
	protected $moduleName = 'web_layout';

304
305
306
307
308
309
	/**
	 * Initializing the module
	 *
	 * @return void
	 */
	public function init() {
310
		$this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
Wouter Wolters's avatar
Wouter Wolters committed
311
		$this->getLanguageService()->includeLLFile('EXT:backend/Resources/Private/Language/locallang_layout.xlf');
312

313
		// Setting module configuration / page select clause
314
315
		$this->MCONF['name'] = $this->moduleName;

316
		$this->perms_clause = $this->getBackendUser()->getPagePermsClause(1);
317
		// Get session data
318
		$sessionData = $this->getBackendUser()->getSessionData(RecordList::class);
319
		$this->search_field = !empty($sessionData['search_field']) ? $sessionData['search_field'] : '';
320
		// GPvars:
321
		$this->id = (int)GeneralUtility::_GP('id');
Nicole Cordes's avatar
Nicole Cordes committed
322
323
324
325
326
		$this->pointer = GeneralUtility::_GP('pointer');
		$this->imagemode = GeneralUtility::_GP('imagemode');
		$this->clear_cache = GeneralUtility::_GP('clear_cache');
		$this->popView = GeneralUtility::_GP('popView');
		$this->edit_record = GeneralUtility::_GP('edit_record');
327
		$this->new_unique_uid = GeneralUtility::_GP('new_unique_uid');
328
		$this->search_field = GeneralUtility::_GP('search_field');
Nicole Cordes's avatar
Nicole Cordes committed
329
330
331
		$this->search_levels = GeneralUtility::_GP('search_levels');
		$this->showLimit = GeneralUtility::_GP('showLimit');
		$this->returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
332
		$this->externalTables = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['cms']['db_layout']['addTables'];
333
		$sessionData['search_field'] = $this->search_field;
334
		// Store session data
335
		$this->getBackendUser()->setAndSaveSessionData(RecordList::class, $sessionData);
336
		// Load page info array:
Nicole Cordes's avatar
Nicole Cordes committed
337
		$this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
338
339
340
		// Initialize menu
		$this->menuConfig();
		// Setting sys language from session var:
341
		$this->current_sys_language = (int)$this->MOD_SETTINGS['language'];
342
		// CSH / Descriptions:
343
		$this->descrTable = '_MOD_' . $this->moduleName;
344
345
346

		$this->markers['SEARCHBOX'] = '';
		$this->markers['BUTTONLIST_ADDITIONAL'] = '';
347
348
349
350
351
352
353
354
	}

	/**
	 * Initialize menu array
	 *
	 * @return void
	 */
	public function menuConfig() {
355
		$lang = $this->getLanguageService();
356
357
358
359
		// MENU-ITEMS:
		$this->MOD_MENU = array(
			'tt_content_showHidden' => '',
			'function' => array(
360
361
362
				0 => $lang->getLL('m_function_0'),
				1 => $lang->getLL('m_function_1'),
				2 => $lang->getLL('m_function_2')
363
364
			),
			'language' => array(
365
				0 => $lang->getLL('m_default')
366
367
368
369
370
			)
		);
		// example settings:
		// 	$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['cms']['db_layout']['addTables']['tx_myext'] =
		//		array ('default' => array(
371
		//				'MENU' => 'LLL:EXT:tx_myext/locallang_db.xlf:menuDefault',
372
373
374
375
376
377
378
379
380
381
		//				'fList' =>  'title,description,image',
		//				'icon' => TRUE));
		if (is_array($this->externalTables)) {
			foreach ($this->externalTables as $table => $tableSettings) {
				// delete the default settings from above
				if (is_array($this->MOD_MENU[$table])) {
					unset($this->MOD_MENU[$table]);
				}
				if (is_array($tableSettings) && count($tableSettings) > 1) {
					foreach ($tableSettings as $key => $settings) {
382
						$this->MOD_MENU[$table][$key] = $lang->sL($settings['MENU']);
383
384
385
386
387
388
					}
				}
			}
		}
		// First, select all pages_language_overlay records on the current page. Each represents a possibility for a language on the page. Add these to language selector.
		$res = $this->exec_languageQuery($this->id);
389
390
391
		while ($lRow = $this->getDatabaseConnection()->sql_fetch_assoc($res)) {
			if ($this->getBackendUser()->checkLanguageAccess($lRow['uid'])) {
				$this->MOD_MENU['language'][$lRow['uid']] = $lRow['hidden'] ? '(' . $lRow['title'] . ')' : $lRow['title'];
392
393
394
			}
		}
		// Find if there are ANY languages at all (and if not, remove the language option from function menu).
395
		$count = $this->getDatabaseConnection()->exec_SELECTcountRows('uid', 'sys_language', $this->getBackendUser()->isAdmin() ? '' : 'hidden=0');
396
397
398
399
		if (!$count) {
			unset($this->MOD_MENU['function']['2']);
		}
		// page/be_user TSconfig settings and blinding of menu-items
Nicole Cordes's avatar
Nicole Cordes committed
400
		$this->modSharedTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.SHARED');
401
		$this->modTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.' . $this->moduleName);
402
403
404
		if ($this->modTSconfig['properties']['QEisDefault']) {
			ksort($this->MOD_MENU['function']);
		}
Nicole Cordes's avatar
Nicole Cordes committed
405
		$this->MOD_MENU['function'] = BackendUtility::unsetMenuItems($this->modTSconfig['properties'], $this->MOD_MENU['function'], 'menu.function');
406
		// Remove QuickEdit as option if page type is not...
407
		if (!GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['FE']['content_doktypes'] . ',6', $this->pageinfo['doktype'])) {
408
409
410
411
412
413
414
			unset($this->MOD_MENU['function'][0]);
		}
		// Setting alternative default label:
		if (($this->modSharedTSconfig['properties']['defaultLanguageLabel'] || $this->modTSconfig['properties']['defaultLanguageLabel']) && isset($this->MOD_MENU['language'][0])) {
			$this->MOD_MENU['language'][0] = $this->modTSconfig['properties']['defaultLanguageLabel'] ? $this->modSharedTSconfig['properties']['defaultLanguageLabel'] : $this->modSharedTSconfig['properties']['defaultLanguageLabel'];
		}
		// Clean up settings
415
		$this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), $this->moduleName);
416
		// For all elements to be shown in draft workspaces & to also show hidden elements by default if user hasn't disabled the option
417
		if ($this->getBackendUser()->workspace != 0 || $this->MOD_SETTINGS['tt_content_showHidden'] !== '0') {
418
419
420
421
422
423
424
425
426
427
428
			$this->MOD_SETTINGS['tt_content_showHidden'] = 1;
		}
	}

	/**
	 * Clears page cache for the current id, $this->id
	 *
	 * @return void
	 */
	public function clearCache() {
		if ($this->clear_cache) {
429
430
			$tce = GeneralUtility::makeInstance(DataHandler::class);
			$tce->stripslashes_values = FALSE;
431
432
433
434
435
436
437
438
439
440
441
442
			$tce->start(array(), array());
			$tce->clear_cacheCmd($this->id);
		}
	}

	/**
	 * Generate the flashmessages for current pid
	 *
	 * @return string HTML content with flashmessages
	 */
	protected function getHeaderFlashMessagesForCurrentPid() {
		$content = '';
443
		$lang = $this->getLanguageService();
444
		// If page is a folder
445
		if ($this->pageinfo['doktype'] == PageRepository::DOKTYPE_SYSFOLDER) {
446
			// Access to list module
447
			$moduleLoader = GeneralUtility::makeInstance(ModuleLoader::class);
448
449
450
			$moduleLoader->load($GLOBALS['TBE_MODULES']);
			$modules = $moduleLoader->modules;
			if (is_array($modules['web']['sub']['list'])) {
451
452
453
				$title = $lang->getLL('goToListModule');
				$message = '<p>' . $lang->getLL('goToListModuleMessage') . '</p>';
				$message .= '<a class="btn btn-info" href="javascript:top.goToModule(\'web_list\',1);">' . $lang->getLL('goToListModule') . '</a>';
454
455
456
457

				$view = GeneralUtility::makeInstance(StandaloneView::class);
				$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/InfoBox.html'));
				$view->assignMultiple(array(
458
459
					'title' => $title,
					'message' => $message,
460
461
462
					'state' => InfoboxViewHelper::STATE_INFO
				));
				$content .= $view->render();
463
464
465
466
			}
		}
		// If content from different pid is displayed
		if ($this->pageinfo['content_from_pid']) {
467
			$contentPage = BackendUtility::getRecord('pages', (int)$this->pageinfo['content_from_pid']);
Nicole Cordes's avatar
Nicole Cordes committed
468
			$title = BackendUtility::getRecordTitle('pages', $contentPage);
469
			$linkToPid = $this->local_linkThisScript(array('id' => $this->pageinfo['content_from_pid']));
470
			$link = '<a href="' . $linkToPid . '">' . htmlspecialchars($title) . ' (PID ' . (int)$this->pageinfo['content_from_pid'] . ')</a>';
471
			$flashMessage = GeneralUtility::makeInstance(FlashMessage::class, sprintf($lang->getLL('content_from_pid_title'), $link), '', FlashMessage::INFO);
472
473
474
475
476
			$content .= $flashMessage->render();
		}
		return $content;
	}

477
478
479
480
481
482
	/**
	 *
	 * @return string $title
	 */
	protected function getLocalizedPageTitle() {
		if ($this->current_sys_language > 0) {
483
			$overlayRecord = $this->getDatabaseConnection()->exec_SELECTgetSingleRow(
484
485
				'title',
				'pages_language_overlay',
486
487
				'pid = ' . (int)$this->id .
						' AND sys_language_uid = ' . (int)$this->current_sys_language .
Nicole Cordes's avatar
Nicole Cordes committed
488
489
						BackendUtility::deleteClause('pages_language_overlay') .
						BackendUtility::versioningPlaceholderClause('pages_language_overlay'),
490
491
492
493
494
495
496
497
498
499
500
				'',
				'',
				'',
				'sys_language_uid'
			);
			return $overlayRecord['title'];
		} else {
			return $this->pageinfo['title'];
		}
	}

501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
	/**
	 * Injects the request object for the current request or subrequest
	 * As this controller goes only through the main() method, it is rather simple for now
	 *
	 * @param ServerRequestInterface $request the current request
	 * @param ResponseInterface $response
	 * @return ResponseInterface the response with the content
	 */
	public function mainAction(ServerRequestInterface $request, ResponseInterface $response) {
		$GLOBALS['SOBE'] = $this;
		$this->init();
		$this->clearCache();
		$this->main();
		$response->getBody()->write($this->content);
		return $response;
	}

518
519
520
521
522
523
524
	/**
	 * Main function.
	 * Creates some general objects and calls other functions for the main rendering of module content.
	 *
	 * @return void
	 */
	public function main() {
525
		$lang = $this->getLanguageService();
526
527
528
529
530
		// Access check...
		// The page will show only if there is a valid page and if this page may be viewed by the user
		$access = is_array($this->pageinfo) ? 1 : 0;
		if ($this->id && $access) {
			// Initialize permission settings:
531
			$this->CALC_PERMS = $this->getBackendUser()->calcPerms($this->pageinfo);
532
533
			$this->EDIT_CONTENT = $this->pageIsNotLockedForEditors();

534
			// Start document template object:
535
			$this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
536
			$this->doc->setModuleTemplate('EXT:backend/Resources/Private/Templates/db_layout.html');
537
538
539
540

			// override the default jumpToUrl
			$this->doc->JScodeArray['jumpToUrl'] = '
				function jumpToUrl(URL,formEl) {
541
					if (document.editform && TBE_EDITOR.isFormChanged)	{	// Check if the function exists... (works in all browsers?)
542
						if (!TBE_EDITOR.isFormChanged()) {
543
544
545
546
							window.location.href = URL;
						} else if (formEl) {
							if (formEl.type=="checkbox") formEl.checked = formEl.checked ? 0 : 1;
						}
547
548
549
					} else {
						window.location.href = URL;
					}
550
				}
551
552
553
554
555
';

			$this->doc->JScode .= $this->doc->wrapScriptTags('
				if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';
				if (top.fsMod) top.fsMod.navFrameHighlightedID["web"] = "pages' . (int)$this->id . '_"+top.fsMod.currentBank; ' . (int)$this->id . ';
556
			' . ($this->popView ? BackendUtility::viewOnClick($this->id, '', BackendUtility::BEgetRootLine($this->id)) : '') . '
557
558

				function deleteRecord(table,id,url) {	//
559
					if (confirm(' . GeneralUtility::quoteJSvalue($lang->getLL('deleteWarning')) . ')) {
560
						window.location.href = ' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('tce_db') . '&cmd[') . '+table+"]["+id+"][delete]=1&redirect="+escape(url)+"&vC=' . $this->getBackendUser()->veriCode() . '&prErr=1&uPT=1";
561
562
563
564
565
					}
					return false;
				}
			');
			// Setting doc-header
566
567
			$this->doc->form = '<form action="' . htmlspecialchars(
				BackendUtility::getModuleUrl(
568
					$this->moduleName, array('id' => $this->id, 'imagemode' =>  $this->imagemode)
569
				)) . '" method="post">';
570
			// Creating the top function menu:
571
			$this->topFuncMenu = BackendUtility::getFuncMenu($this->id, 'SET[function]', $this->MOD_SETTINGS['function'], $this->MOD_MENU['function'], '', '');
572
			$languageMenu = count($this->MOD_MENU['language']) > 1 ? $lang->sL('LLL:EXT:lang/locallang_general.xlf:LGL.language', TRUE) . BackendUtility::getFuncMenu($this->id, 'SET[language]', $this->current_sys_language, $this->MOD_MENU['language'], '', '') : '';
573
			// Find backend layout / coumns
574
			$backendLayout = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getSelectedBackendLayout', $this->id, $this);
575
			if (!empty($backendLayout['__colPosList'])) {
576
577
578
				$this->colPosList = implode(',', $backendLayout['__colPosList']);
			}
			// Removing duplicates, if any
579
580
			$this->colPosList = array_unique(GeneralUtility::intExplode(',', $this->colPosList));
			// Accessible columns
581
			if (isset($this->modSharedTSconfig['properties']['colPos_list']) && trim($this->modSharedTSconfig['properties']['colPos_list']) !== '') {
582
583
				$this->activeColPosList = array_unique(GeneralUtility::intExplode(',', trim($this->modSharedTSconfig['properties']['colPos_list'])));
				// Match with the list which is present in the colPosList for the current page
584
585
				if (!empty($this->colPosList) && !empty($this->activeColPosList)) {
					$this->activeColPosList = array_unique(array_intersect(
586
587
						$this->activeColPosList,
						$this->colPosList
588
					));
589
				}
590
591
			} else {
				$this->activeColPosList = $this->colPosList;
592
			}
593
			$this->activeColPosList = implode(',', $this->activeColPosList);
594
595
			$this->colPosList = implode(',', $this->colPosList);

596
			$body = '';
597
598
599
600
601
602
			$body .= $this->getHeaderFlashMessagesForCurrentPid();
			// Render the primary module content:
			if ($this->MOD_SETTINGS['function'] == 0) {
				// QuickEdit
				$body .= $this->renderQuickEdit();
			} else {
603
604
				// Page title
				$body .= $this->doc->header($this->getLocalizedPageTitle());
605
606
607
608
609
				// All other listings
				$body .= $this->renderListContent();
			}
			// Setting up the buttons and markers for docheader
			$docHeaderButtons = $this->getButtons($this->MOD_SETTINGS['function'] == 0 ? 'quickEdit' : '');
610
611
			$this->markers['CSH'] = $docHeaderButtons['csh'];
			$this->markers['TOP_FUNCTION_MENU'] = $this->topFuncMenu . $this->editSelect;
612
			$this->markers['LANGSELECTOR'] = $languageMenu;
613
			$this->markers['CONTENT'] = $body;
614
			// Build the <body> for the module
615
			$this->content .= $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $this->markers);
616
			// Renders the module page
617
			$this->content = $this->doc->render($lang->getLL('title'), $this->content);
618
619
		} else {
			// If no access or id value, create empty document:
620
			$this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
621
			$this->doc->setModuleTemplate('EXT:backend/Resources/Private/Templates/db_layout.html');
622
			$this->doc->JScode = $this->doc->wrapScriptTags('
623
				if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';
624
			');
625
626

			$body = $this->doc->header($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']);
627

628
629
			$title = $lang->getLL('clickAPage_header');
			$message = $lang->getLL('clickAPage_content');
630
631
632
633

			$view = GeneralUtility::makeInstance(StandaloneView::class);
			$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/InfoBox.html'));
			$view->assignMultiple(array(
634
635
				'title' => $title,
				'message' => $message,
636
637
638
				'state' => InfoboxViewHelper::STATE_INFO
			));
			$body .= $view->render();
639

640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
			// Setting up the buttons and markers for docheader
			$docHeaderButtons = array(
				'view' => '',
				'history_page' => '',
				'new_content' => '',
				'move_page' => '',
				'move_record' => '',
				'new_page' => '',
				'edit_page' => '',
				'csh' => '',
				'shortcut' => '',
				'cache' => '',
				'savedok' => '',
				'savedokshow' => '',
				'closedok' => '',
				'deletedok' => '',
				'undo' => '',
657
658
				'history_record' => '',
				'edit_language' => ''
659
			);
Benni Mack's avatar
Benni Mack committed
660
			$this->markers['CSH'] = '';
661
662
663
664
			$this->markers['TOP_FUNCTION_MENU'] = '';
			$this->markers['LANGSELECTOR'] = '';
			$this->markers['CONTENT'] = $body;
			$this->content .= $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $this->markers);
665
			// Renders the module page
666
			$this->content = $this->doc->render($lang->getLL('title'), $this->content);
667
668
669
670
671
672
		}
	}

	/**
	 * Rendering the quick-edit view.
	 *
673
	 * @return string
674
675
	 */
	public function renderQuickEdit() {
676
677
678
		$databaseConnection = $this->getDatabaseConnection();
		$beUser = $this->getBackendUser();
		$lang = $this->getLanguageService();
679
		// Alternative template
680
		$this->doc->setModuleTemplate('EXT:backend/Resources/Private/Templates/db_layout_quickedit.html');
681
		// Alternative form tag; Quick Edit submits its content to tce_db.php.
682
		$this->doc->form = '<form action="' . htmlspecialchars(BackendUtility::getModuleUrl('tce_db', ['prErr' => 1, 'uPT' => 1])) . '" method="post" enctype="multipart/form-data" name="editform" onsubmit="return TBE_EDITOR.checkSubmit(1);">';
683
684
685
686
		// Setting up the context sensitive menu:
		$this->doc->getContextMenuCode();
		// Set the edit_record value for internal use in this function:
		$edit_record = $this->edit_record;
687
		// If a command to edit all records in a column is issue, then select all those elements, and redirect to FormEngine
688
		if (substr($edit_record, 0, 9) == '_EDIT_COL') {
689
			$res = $databaseConnection->exec_SELECTquery('*', 'tt_content', 'pid=' . (int)$this->id . ' AND colPos=' . (int)substr($edit_record, 10) . ' AND sys_language_uid=' . (int)$this->current_sys_language . ($this->MOD_SETTINGS['tt_content_showHidden'] ? '' : BackendUtility::BEenableFields('tt_content')) . BackendUtility::deleteClause('tt_content') . BackendUtility::versioningPlaceholderClause('tt_content'), '', 'sorting');
690
			$idListA = array();
691
			while ($cRow = $databaseConnection->sql_fetch_assoc($res)) {
692
693
				$idListA[] = $cRow['uid'];
			}
694
695
			$url = BackendUtility::getModuleUrl('record_edit', array(
				'edit[tt_content][' . implode(',', $idListA) . ']' => 'edit',
696
				'returnUrl' => $this->local_linkThisScript(array('edit_record' => ''))
697
			));
698
			HttpUtility::redirect($url);
699
		}
700
701
		// If the former record edited was the creation of a NEW record, this will look up the created records uid:
		if ($this->new_unique_uid) {
702
703
			$res = $databaseConnection->exec_SELECTquery('*', 'sys_log', 'userid=' . (int)$beUser->user['uid'] . ' AND NEWid=' . $databaseConnection->fullQuoteStr($this->new_unique_uid, 'sys_log'));
			$sys_log_row = $databaseConnection->sql_fetch_assoc($res);
704
705
706
707
			if (is_array($sys_log_row)) {
				$edit_record = $sys_log_row['tablename'] . ':' . $sys_log_row['recuid'];
			}
		}
708
709
710
711
712
		// Creating the selector box, allowing the user to select which element to edit:
		$opt = array();
		$is_selected = 0;
		$languageOverlayRecord = '';
		if ($this->current_sys_language) {
713
			list($languageOverlayRecord) = BackendUtility::getRecordsByField('pages_language_overlay', 'pid', $this->id, 'AND sys_language_uid=' . (int)$this->current_sys_language);
714
715
716
		}
		if (is_array($languageOverlayRecord)) {
			$inValue = 'pages_language_overlay:' . $languageOverlayRecord['uid'];
717
			$is_selected += (int)$edit_record == $inValue;
718
			$opt[] = '<option value="' . $inValue . '"' . ($edit_record == $inValue ? ' selected="selected"' : '') . '>[ ' . $lang->getLL('editLanguageHeader', TRUE) . ' ]</option>';
719
720
		} else {
			$inValue = 'pages:' . $this->id;
721
			$is_selected += (int)$edit_record == $inValue;
722
			$opt[] = '<option value="' . $inValue . '"' . ($edit_record == $inValue ? ' selected="selected"' : '') . '>[ ' . $lang->getLL('editPageProperties', TRUE) . ' ]</option>';
723
724
		}
		// Selecting all content elements from this language and allowed colPos:
725
726
727
728
729
		$whereClause = 'pid=' . (int)$this->id . ' AND sys_language_uid=' . (int)$this->current_sys_language . ' AND colPos IN (' . $this->colPosList . ')' . ($this->MOD_SETTINGS['tt_content_showHidden'] ? '' : BackendUtility::BEenableFields('tt_content')) . BackendUtility::deleteClause('tt_content') . BackendUtility::versioningPlaceholderClause('tt_content');
		if (!$this->getBackendUser()->user['admin']) {
			$whereClause .= ' AND editlock = 0';
		}
		$res = $databaseConnection->exec_SELECTquery('*', 'tt_content', $whereClause, '', 'colPos,sorting');
730
		$colPos = NULL;
731
732
733
		$first = 1;
		// Page is the pid if no record to put this after.
		$prev = $this->id;
734
		while ($cRow = $databaseConnection->sql_fetch_assoc($res)) {
Nicole Cordes's avatar
Nicole Cordes committed
735
			BackendUtility::workspaceOL('tt_content', $cRow);
736
737
738
739
740
741
742
			if (is_array($cRow)) {
				if ($first) {
					if (!$edit_record) {
						$edit_record = 'tt_content:' . $cRow['uid'];
					}
					$first = 0;
				}
743
				if (!isset($colPos) || $cRow['colPos'] !== $colPos) {
744
745
					$colPos = $cRow['colPos'];
					$opt[] = '<option value=""></option>';
746
					$opt[] = '<option value="_EDIT_COL:' . $colPos . '">__' . $lang->sL(BackendUtility::getLabelFromItemlist('tt_content', 'colPos', $colPos), TRUE) . ':__</option>';
747
748
				}
				$inValue = 'tt_content:' . $cRow['uid'];
749
				$is_selected += (int)$edit_record == $inValue;
750
				$opt[] = '<option value="' . $inValue . '"' . ($edit_record == $inValue ? ' selected="selected"' : '') . '>' . htmlspecialchars(GeneralUtility::fixed_lgd_cs(($cRow['header'] ? $cRow['header'] : '[' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.no_title') . '] ' . strip_tags($cRow['bodytext'])), $beUser->uc['titleLen'])) . '</option>';
751
752
753
754
755
				$prev = -$cRow['uid'];
			}
		}
		// If edit_record is not set (meaning, no content elements was found for this language) we simply set it to create a new element:
		if (!$edit_record) {
756
757
			$edit_record = 'tt_content:new/' . $prev . '/' . $colPos;
			$inValue = 'tt_content:new/' . $prev . '/' . $colPos;
758
			$is_selected += (int)$edit_record == $inValue;
759
			$opt[] = '<option value="' . $inValue . '"' . ($edit_record == $inValue ? ' selected="selected"' : '') . '>[ ' . $lang->getLL('newLabel', 1) . ' ]</option>';
760
761
762
763
		}
		// If none is yet selected...
		if (!$is_selected) {
			$opt[] = '<option value=""></option>';
764
			$opt[] = '<option value="' . $edit_record . '"  selected="selected">[ ' . $lang->getLL('newLabel', TRUE) . ' ]</option>';
765
766
767
		}
		// Splitting the edit-record cmd value into table/uid:
		$this->eRParts = explode(':', $edit_record);
768
		$tableName = $this->eRParts[0];
769
		// Delete-button flag?
770
		$this->deleteButton = MathUtility::canBeInterpretedAsInteger($this->eRParts[1]) && $edit_record && ($tableName !== 'pages' && $this->EDIT_CONTENT || $tableName === 'pages' && $this->CALC_PERMS & Permission::PAGE_DELETE);
771
		// If undo-button should be rendered (depends on available items in sys_history)
772
		$this->undoButton = FALSE;
773
		$undoRes = $databaseConnection->exec_SELECTquery('tstamp', 'sys_history', 'tablename=' . $databaseConnection->fullQuoteStr($tableName, 'sys_history') . ' AND recuid=' . (int)$this->eRParts[1], '', 'tstamp DESC', '1');
774
775
		if ($this->undoButtonR = $databaseConnection->sql_fetch_assoc($undoRes)) {
			$this->undoButton = TRUE;
776
777
		}
		// Setting up the Return URL for coming back to THIS script (if links take the user to another script)
Nicole Cordes's avatar
Nicole Cordes committed
778
779
		$R_URL_parts = parse_url(GeneralUtility::getIndpEnv('REQUEST_URI'));
		$R_URL_getvars = GeneralUtility::_GET();
780
		unset($R_URL_getvars['popView']);
781
		unset($R_URL_getvars['new_unique_uid']);
782
		$R_URL_getvars['edit_record'] = $edit_record;
Nicole Cordes's avatar
Nicole Cordes committed
783
		$this->R_URI = $R_URL_parts['path'] . '?' . GeneralUtility::implodeArrayForUrl('', $R_URL_getvars);
784
785
786
787
788
789
790
		// Setting close url/return url for exiting this script:
		// Goes to 'Columns' view if close is pressed (default)
		$this->closeUrl = $this->local_linkThisScript(array('SET' => array('function' => 1)));
		if ($this->returnUrl) {
			$this->closeUrl = $this->returnUrl;
		}
		// Return-url for JavaScript:
791
		$retUrlStr = $this->returnUrl ? '+\'&returnUrl=\'+' . GeneralUtility::quoteJSvalue(rawurlencode($this->returnUrl)) : '';
792
		// Drawing the edit record selectbox
793
		$this->editSelect = '<select name="edit_record" onchange="' . htmlspecialchars('jumpToUrl(' . GeneralUtility::quoteJSvalue(
794
			BackendUtility::getModuleUrl($this->moduleName) . '&id=' . $this->id . '&edit_record='
795
		) . '+escape(this.options[this.selectedIndex].value)' . $retUrlStr . ',this);') . '">' . implode('', $opt) . '</select>';
796

797
		// Creating editing form:
798
799
800
		$content = '';

		if ($edit_record) {
801
			// Splitting uid parts for special features, if new:
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
			list($uidVal, $neighborRecordUid, $ex_colPos) = explode('/', $this->eRParts[1]);

			if ($uidVal === 'new') {
				$command = 'new';
				// Page id of this new record
				$theUid = $this->id;
				if ($neighborRecordUid) {
					$theUid = $neighborRecordUid;
				}
			} else {
				$command = 'edit';
				$theUid = $uidVal;
				// Convert $uidVal to workspace version if any:
				$draftRecord = BackendUtility::getWorkspaceVersionOfRecord($beUser->workspace, $tableName, $theUid, 'uid');
				if ($draftRecord) {
					$theUid = $draftRecord['uid'];
818
819
				}
			}
820
821
822

			// @todo: Hack because DatabaseInitializeNewRow reads from _GP directly
			$GLOBALS['_GET']['defVals'][$tableName] = array(
823
824
				'colPos' => (int)$ex_colPos,
				'sys_language_uid' => (int)$this->current_sys_language
825
			);
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861

			/** @var TcaDatabaseRecord $formDataGroup */
			$formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
			/** @var FormDataCompiler $formDataCompiler */
			$formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
			/** @var NodeFactory $nodeFactory */
			$nodeFactory = GeneralUtility::makeInstance(NodeFactory::class);

			try {
				$formDataCompilerInput = [
					'tableName' => $tableName,
					'vanillaUid' => (int)$theUid,
					'command' => $command,
				];
				$formData = $formDataCompiler->compile($formDataCompilerInput);

				if ($command !== 'new') {
					BackendUtility::lockRecords($tableName, $formData['databaseRow']['uid'], $tableName === 'tt_content' ? $formData['databaseRow']['pid'] : 0);
				}

				$formData['renderType'] = 'outerWrapContainer';
				$formResult = $nodeFactory->create($formData)->render();

				$panel = $formResult['html'];
				$formResult['html'] = '';

				/** @var FormResultCompiler $formResultCompiler */
				$formResultCompiler = GeneralUtility::makeInstance(FormResultCompiler::class);
				$formResultCompiler->mergeResult($formResult);

				$row = $formData['databaseRow'];
				$new_unique_uid = '';
				if ($command === 'new') {
					$new_unique_uid = $row['uid'];
				}

862
863
				// Add hidden fields:
				if ($uidVal == 'new') {
864
					$panel .= '<input type="hidden" name="data[' . $tableName . '][' . $row['uid'] . '][pid]" value="' . $row['pid'] . '" />';
865
				}
866
				$panel .= '
867
868
					<input type="hidden" name="_serialNumber" value="' . md5(microtime()) . '" />
					<input type="hidden" name="edit_record" value="' . $edit_record . '" />
869
					<input type="hidden" name="redirect" value="' . htmlspecialchars(($uidVal == 'new' ? BackendUtility::getModuleUrl(
870
						$this->moduleName,
871
872
873
874
875
876
						array(
							'id' => $this->id,
							'new_unique_uid' => $new_unique_uid,
							'returnUrl' => $this->returnUrl
						)
					) : $this->R_URI)) . '" />
877
					';
878
				// Add JavaScript as needed around the form:
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
				$panel = $formResultCompiler->JStop() . $panel . $formResultCompiler->printNeededJSFunctions();
				$content = $this->doc->section('', $panel);

				// Display "is-locked" message:
				if ($command === 'edit') {
					$lockInfo = BackendUtility::isRecordLocked($tableName, $formData['databaseRow']['uid']);
					if ($lockInfo) {
						/** @var \TYPO3\CMS\Core\Messaging\FlashMessage $flashMessage */
						$flashMessage = GeneralUtility::makeInstance(FlashMessage::class, htmlspecialchars($lockInfo['msg']), '', FlashMessage::WARNING);
						/** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
						$flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
						/** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
						$defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
						$defaultFlashMessageQueue->enqueue($flashMessage);
					}
894
				}
895
896
897
898
899
900
			} catch (AccessDeniedException $e) {
				// If no edit access, print error message:
				$content = $this->doc->section($lang->getLL('noAccess'), $lang->getLL('noAccess_msg')
					. '<br /><br />'
					. ($beUser->errorMsg ? 'Reason: ' . $beUser->errorMsg . '<br /><br />' : ''), 0, 1
				);
901
902
903
			}
		} else {
			// If no edit access, print error message:
904
			$content = $this->doc->section($lang->getLL('noAccess'), $lang->getLL('noAccess_msg') . '<br /><br />', 0, 1);
905
		}
906

907
908
		// Bottom controls (function menus):
		$q_count = $this->getNumberOfHiddenElements();
909
910
911
912
913
914
915
916
917
918
919
		if ($q_count) {
			$h_func_b = '<div class="checkbox">' .
				'<label for="checkTt_content_showHidden">' .
				BackendUtility::getFuncCheck($this->id, 'SET[tt_content_showHidden]', $this->MOD_SETTINGS['tt_content_showHidden'], '', '', 'id="checkTt_content_showHidden"') .
				(!$q_count ? ('<span class="text-muted">' . $lang->getLL('hiddenCE', TRUE) . '</span>') : $lang->getLL('hiddenCE', TRUE) . ' (' . $q_count . ')') .
				'</label>' .
				'</div>';

			$content .= $this->doc->section('', $h_func_b, 0, 0);
			$content .= $this->doc->spacer(10);
		}
920

921
		// Select element matrix:
922
		if ($tableName === 'tt_content' && MathUtility::canBeInterpretedAsInteger($this->eRParts[1])) {
923
			$posMap = GeneralUtility::makeInstance(ContentLayoutPagePositionMap::class);
924
925
926
			$posMap->cur_sys_language = $this->current_sys_language;
			$HTMLcode = '';
			// CSH:
Benni Mack's avatar
Benni Mack committed
927
			$HTMLcode .= BackendUtility::cshItem($this->descrTable, 'quickEdit_selElement', NULL, '|<br />');
928
929
			$HTMLcode .= $posMap->printContentElementColumns($this->id, $this->eRParts[1], $this->colPosList, $this->MOD_SETTINGS['tt_content_showHidden'], $this->R_URI);
			$content .= $this->doc->spacer(20);
930
			$content .= $this->doc->section($lang->getLL('CEonThisPage'), $HTMLcode, 0, 1);
931
932
			$content .= $this->doc->spacer(20);
		}
933

934
935
936
937
938
939
		return $content;
	}

	/**
	 * Rendering all other listings than QuickEdit
	 *
940
	 * @return string
941
942
	 */
	public function renderListContent() {
943
944
945
946
947
		/** @var $dbList \TYPO3\CMS\Backend\View\PageLayoutView */
		$dbList = GeneralUtility::makeInstance(PageLayoutView::class);
		$dbList->thumbs = $this->imagemode;
		$dbList->no_noWrap = 1;
		$dbList->descrTable = $this->descrTable;
Nicole Cordes's avatar
Nicole Cordes committed
948
		$this->pointer = MathUtility::forceIntegerInRange($this->pointer, 0, 100000);
949
		$dbList->script = BackendUtility::getModuleUrl($this->moduleName);
950
951
952
953
954
955
956
957
958
959
960
		$dbList->showIcon = 0;
		$dbList->setLMargin = 0;
		$dbList->doEdit = $this->EDIT_CONTENT;
		$dbList->ext_CALC_PERMS = $this->CALC_PERMS;
		$dbList->agePrefixes = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.minutesHoursDaysYears');
		$dbList->id = $this->id;
		$dbList->nextThree = MathUtility::forceIntegerInRange($this->modTSconfig['properties']['editFieldsAtATime'], 0, 10);
		$dbList->option_newWizard = $this->modTSconfig['properties']['disableNewContentElementWizard'] ? 0 : 1;
		$dbList->defLangBinding = $this->modTSconfig['properties']['defLangBinding'] ? 1 : 0;
		if (!$dbList->nextThree) {
			$dbList->nextThree = 1;
961
		}
962
		$dbList->externalTables = $this->externalTables;
963
		// Create menu for selecting a table to jump to (this is, if more than just pages/tt_content elements are found on the page!)
964
965
		// also fills $dbList->activeTables
		$dbList->getTableMenu($this->id);
966
967
968
969
970
971
972
		// Initialize other variables:
		$h_func = '';
		$tableOutput = array();
		$tableJSOutput = array();
		$CMcounter = 0;
		// Traverse the list of table names which has records on this page (that array is populated
		// by the $dblist object during the function getTableMenu()):
973
974
975
		foreach ($dbList->activeTables as $table => $value) {
			$h_func_b = '';
			if (!isset($dbList->externalTables[$table])) {
976
				$q_count = $this->getNumberOfHiddenElements();
977

978
979
980
				if ($q_count > 0) {
					$h_func_b =
						'<div class="checkbox">'
981
						. '<label for="checkTt_content_showHidden">'
982
983
						. '<input type="checkbox" id="checkTt_content_showHidden" class="checkbox" name="SET[tt_content_showHidden]" value="1" ' . ($this->MOD_SETTINGS['tt_content_showHidden'] ? 'checked="checked"' : '') . ' />'
						. $this->getLanguageService()->getLL('hiddenCE', TRUE) . ' (<span class="t3js-hidden-counter">' . $q_count . '</span>)'
984
						. '</label>'
985
986
						. '</div>';
				}
987
				// Boolean: Display up/down arrows and edit icons for tt_content records
988
				$dbList->tt_contentConfig['showCommands'] = 1;
989
				// Boolean: Display info-marks or not
990
				$dbList->tt_contentConfig['showInfo'] = 1;
991
992
993
				// Setting up the tt_content columns to show:
				if (is_array($GLOBALS['TCA']['tt_content']['columns']['colPos']['config']['items'])) {
					$colList = array();
994
					$tcaItems = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getColPosListItemsParsed', $this->id, $this);
995
996
997
998
999
1000
1001
					foreach ($tcaItems as $temp) {
						$colList[] = $temp[1];
					}
				} else {
					// ... should be impossible that colPos has no array. But this is the fallback should it make any sense:
					$colList = array('1', '0', '2', '3');
				}
1002
				if ($this->colPosList !== '') {
Nicole Cordes's avatar
Nicole Cordes committed
1003
					$colList = array_intersect(GeneralUtility::intExplode(',', $this->colPosList), $colList);
1004
1005
				}
				// The order of the rows: Default is left(1), Normal(0), right(2), margin(3)
1006
1007
1008
1009
				$dbList->tt_contentConfig['cols'] = implode(',', $colList);
				$dbList->tt_contentConfig['activeCols'] = $this->activeColPosList;
				$dbList->tt_contentConfig['showHidden'] = $this->MOD_SETTINGS['tt_content_showHidden'];
				$dbList->tt_contentConfig['sys_language_uid'] = (int)$this->current_sys_language;
1010
1011
				// If the function menu is set to "Language":
				if ($this->MOD_SETTINGS['function'] == 2) {
1012
1013
1014
					$dbList->tt_contentConfig['languageMode'] = 1;
					$dbList->tt_contentConfig['languageCols'] = $this->MOD_MENU['language'];
					$dbList->tt_contentConfig['languageColsPointer'] = $this->current_sys_language;
1015
1016
1017
				}
			} else {
				if (isset($this->MOD_SETTINGS) && isset($this->MOD_MENU)) {
1018
					$h_func = BackendUtility::getFuncMenu($this->id, 'SET[' . $table . ']', $this->MOD_SETTINGS[$table], $this->MOD_MENU[$table], '', '');
1019
1020
1021
1022
1023
				} else {
					$h_func = '';
				}
			}
			// Start the dblist object:
1024
1025
1026
1027
			$dbList->itemsLimitSingleTable = 1000;
			$dbList->start($this->id, $table, $this->pointer, $this->search_field, $this->search_levels, $this->showLimit);
			$dbList->counter = $CMcounter;
			$dbList->ext_function = $this->MOD_SETTINGS['function'];
1028
			// Render versioning selector:
1029
			$dbList->HTMLcode .= $this->doc->getVersionSelector($this->id);
1030
			// Generate the list of elements here:
1031
			$dbList->generateList();
1032
			// Adding the list content to the tableOutput variable:
1033
			$tableOutput[$table] = ($h_func ? $h_func . '<br /><span style="width: 1px; height: 4px; display: inline-block;"></span><br />' : '') . $dbList->HTMLcode . ($h_func_b ? '<span style="width: 1px; height: 10px; display:inline-block;"></span><br />' . $h_func_b : '');
1034
			// ... and any accumulated JavaScript goes the same way!
1035
			$tableJSOutput[$table] = $dbList->JScode;
1036
			// Increase global counter:
1037
			$CMcounter += $dbList->counter;
1038
			// Reset variables after operation:
1039
1040
			$dbList->HTMLcode = '';
			$dbList->JScode = '';
1041
1042
1043
1044
1045
			$h_func = '';
		}
		// END: traverse tables
		// For Context Sensitive Menus:
		$this->doc->getContextMenuCode();
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
		// Init the content
		$content = '';
		// Additional header content
		$headerContentHook = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawHeaderHook'];
		if (is_array($headerContentHook)) {
			foreach ($headerContentHook as $hook) {
				$params = array();
				$content .= GeneralUtility::callUserFunction($hook, $params, $this);
			}
		}
1056
1057
1058
1059
1060
1061
		// Add the content for each table we have rendered (traversing $tableOutput variable)
		foreach ($tableOutput as $table => $output) {
			$content .= $this->doc->section('', $output, TRUE, TRUE, 0, TRUE);
			$content .= $this->doc->sectionEnd();
		}
		// Making search form:
1062
		if (!$this->modTSconfig['properties']['disableSearchBox'] && !empty($tableOutput)) {
1063
			$this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ToggleSearchToolbox');
1064
			$this->markers['BUTTONLIST_ADDITIONAL'] = '<a href="#" class="t3js-toggle-search-toolbox" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.title.searchIcon', TRUE) . '">' . $this->iconFactory->getIcon('actions-search', Icon::SIZE_SMALL)->render() . '</a>';
1065
			$this->markers['SEARCHBOX'] = $dbList->getSearchBox(0);
1066
1067
1068
1069
1070
1071
		}
		// Additional footer content
		$footerContentHook = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawFooterHook'];
		if (is_array($footerContentHook)) {
			foreach ($footerContentHook as $hook) {
				$params = array();
Nicole Cordes's avatar
Nicole Cordes committed
1072
				$content .= GeneralUtility::callUserFunction($hook, $params, $this);
1073
1074
1075
1076
1077
1078
1079
1080
1081
			}
		}
		return $content;
	}

	/**
	 * Print accumulated content of module
	 *
	 * @return void
1082
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
1083
1084
	 */
	public function printContent() {
1085
		GeneralUtility::logDeprecatedFunction();
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
		echo $this->content;
	}

	/***************************
	 *
	 * Sub-content functions, rendering specific parts of the module content.
	 *
	 ***************************/
	/**
	 * Create the panel of buttons for submitting the form or otherwise perform operations.
	 *
	 * @param string $function Identifier for function of module
	 * @return array all available buttons as an assoc. array
	 */
	protected function getButtons($function =