PageLayoutController.php 50.9 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
19
20
21
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
22
23
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Backend\Utility\IconUtility;
24
25
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
26
use TYPO3\CMS\Core\Page\PageRenderer;
27
use TYPO3\CMS\Core\Type\Bitmask\Permission;
Nicole Cordes's avatar
Nicole Cordes committed
28
29
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
30
use TYPO3\CMS\Core\Utility\HttpUtility;
Nicole Cordes's avatar
Nicole Cordes committed
31
use TYPO3\CMS\Core\Utility\MathUtility;
32
use TYPO3\CMS\Fluid\View\StandaloneView;
33
use TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper;
34
35
36
37
38
39
40
41
42
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;
43
use TYPO3\CMS\Core\Versioning\VersionState;
Nicole Cordes's avatar
Nicole Cordes committed
44

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

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

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

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

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

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

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

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

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

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

113
114
115
116
117
118
	/**
	 * 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
	 */
119
120
	public $edit_record;

121
122
123
124
125
126
127
128
	/**
	 * 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;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

256
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
	/**
	 * @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;

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

296
297
298
299
300
301
	/**
	 * Initializing the module
	 *
	 * @return void
	 */
	public function init() {
302
		$this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
Wouter Wolters's avatar
Wouter Wolters committed
303
		$this->getLanguageService()->includeLLFile('EXT:backend/Resources/Private/Language/locallang_layout.xlf');
304

305
306
		// Setting module configuration / page select clause
		$this->MCONF = $GLOBALS['MCONF'];
307
		$this->perms_clause = $this->getBackendUser()->getPagePermsClause(1);
308
		// Get session data
309
		$sessionData = $this->getBackendUser()->getSessionData(RecordList::class);
310
		$this->search_field = !empty($sessionData['search_field']) ? $sessionData['search_field'] : '';
311
		// GPvars:
312
		$this->id = (int)GeneralUtility::_GP('id');
Nicole Cordes's avatar
Nicole Cordes committed
313
314
315
316
317
		$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');
318
		$this->new_unique_uid = GeneralUtility::_GP('new_unique_uid');
319
		$this->search_field = GeneralUtility::_GP('search_field');
Nicole Cordes's avatar
Nicole Cordes committed
320
321
322
		$this->search_levels = GeneralUtility::_GP('search_levels');
		$this->showLimit = GeneralUtility::_GP('showLimit');
		$this->returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
323
		$this->externalTables = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['cms']['db_layout']['addTables'];
324
		$sessionData['search_field'] = $this->search_field;
325
		// Store session data
326
		$this->getBackendUser()->setAndSaveSessionData(RecordList::class, $sessionData);
327
		// Load page info array:
Nicole Cordes's avatar
Nicole Cordes committed
328
		$this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
329
330
331
		// Initialize menu
		$this->menuConfig();
		// Setting sys language from session var:
332
		$this->current_sys_language = (int)$this->MOD_SETTINGS['language'];
333
334
		// CSH / Descriptions:
		$this->descrTable = '_MOD_' . $this->MCONF['name'];
335
336
337

		$this->markers['SEARCHBOX'] = '';
		$this->markers['BUTTONLIST_ADDITIONAL'] = '';
338
339
340
341
342
343
344
345
	}

	/**
	 * Initialize menu array
	 *
	 * @return void
	 */
	public function menuConfig() {
346
		$lang = $this->getLanguageService();
347
348
349
350
		// MENU-ITEMS:
		$this->MOD_MENU = array(
			'tt_content_showHidden' => '',
			'function' => array(
351
352
353
				0 => $lang->getLL('m_function_0'),
				1 => $lang->getLL('m_function_1'),
				2 => $lang->getLL('m_function_2')
354
355
			),
			'language' => array(
356
				0 => $lang->getLL('m_default')
357
358
359
360
361
			)
		);
		// example settings:
		// 	$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['cms']['db_layout']['addTables']['tx_myext'] =
		//		array ('default' => array(
362
		//				'MENU' => 'LLL:EXT:tx_myext/locallang_db.xlf:menuDefault',
363
364
365
366
367
368
369
370
371
372
		//				'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) {
373
						$this->MOD_MENU[$table][$key] = $lang->sL($settings['MENU']);
374
375
376
377
378
379
					}
				}
			}
		}
		// 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);
380
381
382
		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'];
383
384
385
			}
		}
		// Find if there are ANY languages at all (and if not, remove the language option from function menu).
386
		$count = $this->getDatabaseConnection()->exec_SELECTcountRows('uid', 'sys_language', $this->getBackendUser()->isAdmin() ? '' : 'hidden=0');
387
388
389
390
		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
391
392
		$this->modSharedTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.SHARED');
		$this->modTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.' . $this->MCONF['name']);
393
394
395
		if ($this->modTSconfig['properties']['QEisDefault']) {
			ksort($this->MOD_MENU['function']);
		}
Nicole Cordes's avatar
Nicole Cordes committed
396
		$this->MOD_MENU['function'] = BackendUtility::unsetMenuItems($this->modTSconfig['properties'], $this->MOD_MENU['function'], 'menu.function');
397
		// Remove QuickEdit as option if page type is not...
398
		if (!GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['FE']['content_doktypes'] . ',6', $this->pageinfo['doktype'])) {
399
400
401
402
403
404
405
			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
406
		$this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), 'web_layout');
407
		// For all elements to be shown in draft workspaces & to also show hidden elements by default if user hasn't disabled the option
408
		if ($this->getBackendUser()->workspace != 0 || $this->MOD_SETTINGS['tt_content_showHidden'] !== '0') {
409
410
411
412
413
414
415
416
417
418
419
			$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) {
420
421
			$tce = GeneralUtility::makeInstance(DataHandler::class);
			$tce->stripslashes_values = FALSE;
422
423
424
425
426
427
428
429
430
431
432
433
			$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 = '';
434
		$lang = $this->getLanguageService();
435
		// If page is a folder
436
		if ($this->pageinfo['doktype'] == PageRepository::DOKTYPE_SYSFOLDER) {
437
			// Access to list module
438
			$moduleLoader = GeneralUtility::makeInstance(ModuleLoader::class);
439
440
441
			$moduleLoader->load($GLOBALS['TBE_MODULES']);
			$modules = $moduleLoader->modules;
			if (is_array($modules['web']['sub']['list'])) {
442
443
444
				$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>';
445
446
447
448

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

468
469
470
471
472
473
	/**
	 *
	 * @return string $title
	 */
	protected function getLocalizedPageTitle() {
		if ($this->current_sys_language > 0) {
474
			$overlayRecord = $this->getDatabaseConnection()->exec_SELECTgetSingleRow(
475
476
				'title',
				'pages_language_overlay',
477
478
				'pid = ' . (int)$this->id .
						' AND sys_language_uid = ' . (int)$this->current_sys_language .
Nicole Cordes's avatar
Nicole Cordes committed
479
480
						BackendUtility::deleteClause('pages_language_overlay') .
						BackendUtility::versioningPlaceholderClause('pages_language_overlay'),
481
482
483
484
485
486
487
488
489
490
491
				'',
				'',
				'',
				'sys_language_uid'
			);
			return $overlayRecord['title'];
		} else {
			return $this->pageinfo['title'];
		}
	}

492
493
494
495
496
497
498
	/**
	 * Main function.
	 * Creates some general objects and calls other functions for the main rendering of module content.
	 *
	 * @return void
	 */
	public function main() {
499
		$lang = $this->getLanguageService();
500
501
502
503
504
		// 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:
505
			$this->CALC_PERMS = $this->getBackendUser()->calcPerms($this->pageinfo);
506
507
			$this->EDIT_CONTENT = $this->pageIsNotLockedForEditors();

508
			// Start document template object:
509
			$this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
510
			$this->doc->setModuleTemplate('EXT:backend/Resources/Private/Templates/db_layout.html');
511
512
513
514

			// override the default jumpToUrl
			$this->doc->JScodeArray['jumpToUrl'] = '
				function jumpToUrl(URL,formEl) {
515
					if (document.editform && TBE_EDITOR.isFormChanged)	{	// Check if the function exists... (works in all browsers?)
516
						if (!TBE_EDITOR.isFormChanged()) {
517
518
519
520
							window.location.href = URL;
						} else if (formEl) {
							if (formEl.type=="checkbox") formEl.checked = formEl.checked ? 0 : 1;
						}
521
522
523
					} else {
						window.location.href = URL;
					}
524
				}
525
526
527
528
529
';

			$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 . ';
530
			' . ($this->popView ? BackendUtility::viewOnClick($this->id, '', BackendUtility::BEgetRootLine($this->id)) : '') . '
531
532

				function deleteRecord(table,id,url) {	//
533
					if (confirm(' . GeneralUtility::quoteJSvalue($lang->getLL('deleteWarning')) . ')) {
534
						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";
535
536
537
538
539
					}
					return false;
				}
			');
			// Setting doc-header
540
541
542
543
			$this->doc->form = '<form action="' . htmlspecialchars(
				BackendUtility::getModuleUrl(
					'web_layout', array('id' => $this->id, 'imagemode' =>  $this->imagemode)
				)) . '" method="post">';
544
			// Creating the top function menu:
545
			$this->topFuncMenu = BackendUtility::getFuncMenu($this->id, 'SET[function]', $this->MOD_SETTINGS['function'], $this->MOD_MENU['function'], '', '');
546
			$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'], '', '') : '';
547
			// Find backend layout / coumns
548
			$backendLayout = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getSelectedBackendLayout', $this->id, $this);
549
			if (!empty($backendLayout['__colPosList'])) {
550
551
552
				$this->colPosList = implode(',', $backendLayout['__colPosList']);
			}
			// Removing duplicates, if any
553
554
			$this->colPosList = array_unique(GeneralUtility::intExplode(',', $this->colPosList));
			// Accessible columns
555
			if (isset($this->modSharedTSconfig['properties']['colPos_list']) && trim($this->modSharedTSconfig['properties']['colPos_list']) !== '') {
556
557
				$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
558
559
				if (!empty($this->colPosList) && !empty($this->activeColPosList)) {
					$this->activeColPosList = array_unique(array_intersect(
560
561
						$this->activeColPosList,
						$this->colPosList
562
					));
563
				}
564
565
			} else {
				$this->activeColPosList = $this->colPosList;
566
			}
567
			$this->activeColPosList = implode(',', $this->activeColPosList);
568
569
			$this->colPosList = implode(',', $this->colPosList);

570
			$body = '';
571
572
573
574
575
576
			$body .= $this->getHeaderFlashMessagesForCurrentPid();
			// Render the primary module content:
			if ($this->MOD_SETTINGS['function'] == 0) {
				// QuickEdit
				$body .= $this->renderQuickEdit();
			} else {
577
578
				// Page title
				$body .= $this->doc->header($this->getLocalizedPageTitle());
579
580
581
582
583
				// All other listings
				$body .= $this->renderListContent();
			}
			// Setting up the buttons and markers for docheader
			$docHeaderButtons = $this->getButtons($this->MOD_SETTINGS['function'] == 0 ? 'quickEdit' : '');
584
585
			$this->markers['CSH'] = $docHeaderButtons['csh'];
			$this->markers['TOP_FUNCTION_MENU'] = $this->topFuncMenu . $this->editSelect;
586
			$this->markers['LANGSELECTOR'] = $languageMenu;
587
			$this->markers['CONTENT'] = $body;
588
			// Build the <body> for the module
589
			$this->content .= $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $this->markers);
590
			// Renders the module page
591
			$this->content = $this->doc->render($lang->getLL('title'), $this->content);
592
593
		} else {
			// If no access or id value, create empty document:
594
			$this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
595
			$this->doc->setModuleTemplate('EXT:backend/Resources/Private/Templates/db_layout.html');
596
			$this->doc->JScode = $this->doc->wrapScriptTags('
597
				if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';
598
			');
599
600

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

602
603
			$title = $lang->getLL('clickAPage_header');
			$message = $lang->getLL('clickAPage_content');
604
605
606
607

			$view = GeneralUtility::makeInstance(StandaloneView::class);
			$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/InfoBox.html'));
			$view->assignMultiple(array(
608
609
				'title' => $title,
				'message' => $message,
610
611
612
				'state' => InfoboxViewHelper::STATE_INFO
			));
			$body .= $view->render();
613

614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
			// 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' => '',
631
632
				'history_record' => '',
				'edit_language' => ''
633
			);
Benni Mack's avatar
Benni Mack committed
634
			$this->markers['CSH'] = '';
635
636
637
638
			$this->markers['TOP_FUNCTION_MENU'] = '';
			$this->markers['LANGSELECTOR'] = '';
			$this->markers['CONTENT'] = $body;
			$this->content .= $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $this->markers);
639
			// Renders the module page
640
			$this->content = $this->doc->render($lang->getLL('title'), $this->content);
641
642
643
644
645
646
		}
	}

	/**
	 * Rendering the quick-edit view.
	 *
647
	 * @return string
648
649
	 */
	public function renderQuickEdit() {
650
651
652
		$databaseConnection = $this->getDatabaseConnection();
		$beUser = $this->getBackendUser();
		$lang = $this->getLanguageService();
653
		// Alternative template
654
		$this->doc->setModuleTemplate('EXT:backend/Resources/Private/Templates/db_layout_quickedit.html');
655
		// Alternative form tag; Quick Edit submits its content to tce_db.php.
656
		$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);">';
657
658
659
660
		// 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;
661
		// If a command to edit all records in a column is issue, then select all those elements, and redirect to FormEngine
662
		if (substr($edit_record, 0, 9) == '_EDIT_COL') {
663
			$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');
664
			$idListA = array();
665
			while ($cRow = $databaseConnection->sql_fetch_assoc($res)) {
666
667
				$idListA[] = $cRow['uid'];
			}
668
669
			$url = BackendUtility::getModuleUrl('record_edit', array(
				'edit[tt_content][' . implode(',', $idListA) . ']' => 'edit',
670
				'returnUrl' => $this->local_linkThisScript(array('edit_record' => ''))
671
			));
672
			HttpUtility::redirect($url);
673
		}
674
675
		// 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) {
676
677
			$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);
678
679
680
681
			if (is_array($sys_log_row)) {
				$edit_record = $sys_log_row['tablename'] . ':' . $sys_log_row['recuid'];
			}
		}
682
683
684
685
686
		// Creating the selector box, allowing the user to select which element to edit:
		$opt = array();
		$is_selected = 0;
		$languageOverlayRecord = '';
		if ($this->current_sys_language) {
687
			list($languageOverlayRecord) = BackendUtility::getRecordsByField('pages_language_overlay', 'pid', $this->id, 'AND sys_language_uid=' . (int)$this->current_sys_language);
688
689
690
		}
		if (is_array($languageOverlayRecord)) {
			$inValue = 'pages_language_overlay:' . $languageOverlayRecord['uid'];
691
			$is_selected += (int)$edit_record == $inValue;
692
			$opt[] = '<option value="' . $inValue . '"' . ($edit_record == $inValue ? ' selected="selected"' : '') . '>[ ' . $lang->getLL('editLanguageHeader', TRUE) . ' ]</option>';
693
694
		} else {
			$inValue = 'pages:' . $this->id;
695
			$is_selected += (int)$edit_record == $inValue;
696
			$opt[] = '<option value="' . $inValue . '"' . ($edit_record == $inValue ? ' selected="selected"' : '') . '>[ ' . $lang->getLL('editPageProperties', TRUE) . ' ]</option>';
697
698
		}
		// Selecting all content elements from this language and allowed colPos:
699
700
701
702
703
		$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');
704
		$colPos = NULL;
705
706
707
		$first = 1;
		// Page is the pid if no record to put this after.
		$prev = $this->id;
708
		while ($cRow = $databaseConnection->sql_fetch_assoc($res)) {
Nicole Cordes's avatar
Nicole Cordes committed
709
			BackendUtility::workspaceOL('tt_content', $cRow);
710
711
712
713
714
715
716
			if (is_array($cRow)) {
				if ($first) {
					if (!$edit_record) {
						$edit_record = 'tt_content:' . $cRow['uid'];
					}
					$first = 0;
				}
717
				if (!isset($colPos) || $cRow['colPos'] !== $colPos) {
718
719
					$colPos = $cRow['colPos'];
					$opt[] = '<option value=""></option>';
720
					$opt[] = '<option value="_EDIT_COL:' . $colPos . '">__' . $lang->sL(BackendUtility::getLabelFromItemlist('tt_content', 'colPos', $colPos), TRUE) . ':__</option>';
721
722
				}
				$inValue = 'tt_content:' . $cRow['uid'];
723
				$is_selected += (int)$edit_record == $inValue;
724
				$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>';
725
726
727
728
729
				$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) {
730
731
			$edit_record = 'tt_content:new/' . $prev . '/' . $colPos;
			$inValue = 'tt_content:new/' . $prev . '/' . $colPos;
732
			$is_selected += (int)$edit_record == $inValue;
733
			$opt[] = '<option value="' . $inValue . '"' . ($edit_record == $inValue ? ' selected="selected"' : '') . '>[ ' . $lang->getLL('newLabel', 1) . ' ]</option>';
734
735
736
737
		}
		// If none is yet selected...
		if (!$is_selected) {
			$opt[] = '<option value=""></option>';
738
			$opt[] = '<option value="' . $edit_record . '"  selected="selected">[ ' . $lang->getLL('newLabel', TRUE) . ' ]</option>';
739
740
741
		}
		// Splitting the edit-record cmd value into table/uid:
		$this->eRParts = explode(':', $edit_record);
742
		$tableName = $this->eRParts[0];
743
		// Delete-button flag?
744
		$this->deleteButton = MathUtility::canBeInterpretedAsInteger($this->eRParts[1]) && $edit_record && ($tableName !== 'pages' && $this->EDIT_CONTENT || $tableName === 'pages' && $this->CALC_PERMS & Permission::PAGE_DELETE);
745
		// If undo-button should be rendered (depends on available items in sys_history)
746
		$this->undoButton = FALSE;
747
		$undoRes = $databaseConnection->exec_SELECTquery('tstamp', 'sys_history', 'tablename=' . $databaseConnection->fullQuoteStr($tableName, 'sys_history') . ' AND recuid=' . (int)$this->eRParts[1], '', 'tstamp DESC', '1');
748
749
		if ($this->undoButtonR = $databaseConnection->sql_fetch_assoc($undoRes)) {
			$this->undoButton = TRUE;
750
751
		}
		// 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
752
753
		$R_URL_parts = parse_url(GeneralUtility::getIndpEnv('REQUEST_URI'));
		$R_URL_getvars = GeneralUtility::_GET();
754
		unset($R_URL_getvars['popView']);
755
		unset($R_URL_getvars['new_unique_uid']);
756
		$R_URL_getvars['edit_record'] = $edit_record;
Nicole Cordes's avatar
Nicole Cordes committed
757
		$this->R_URI = $R_URL_parts['path'] . '?' . GeneralUtility::implodeArrayForUrl('', $R_URL_getvars);
758
759
760
761
762
763
764
		// 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:
765
		$retUrlStr = $this->returnUrl ? '+\'&returnUrl=\'+' . GeneralUtility::quoteJSvalue(rawurlencode($this->returnUrl)) : '';
766
		// Drawing the edit record selectbox
767
768
769
		$this->editSelect = '<select name="edit_record" onchange="' . htmlspecialchars('jumpToUrl(' . GeneralUtility::quoteJSvalue(
			BackendUtility::getModuleUrl('web_layout') . '&id=' . $this->id . '&edit_record='
		) . '+escape(this.options[this.selectedIndex].value)' . $retUrlStr . ',this);') . '">' . implode('', $opt) . '</select>';
770

771
		// Creating editing form:
772
773
774
		$content = '';

		if ($edit_record) {
775
			// Splitting uid parts for special features, if new:
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
			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'];
792
793
				}
			}
794
795
796

			// @todo: Hack because DatabaseInitializeNewRow reads from _GP directly
			$GLOBALS['_GET']['defVals'][$tableName] = array(
797
798
				'colPos' => (int)$ex_colPos,
				'sys_language_uid' => (int)$this->current_sys_language
799
			);
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835

			/** @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'];
				}

836
837
				// Add hidden fields:
				if ($uidVal == 'new') {
838
					$panel .= '<input type="hidden" name="data[' . $tableName . '][' . $row['uid'] . '][pid]" value="' . $row['pid'] . '" />';
839
				}
840
				$panel .= '
841
842
					<input type="hidden" name="_serialNumber" value="' . md5(microtime()) . '" />
					<input type="hidden" name="edit_record" value="' . $edit_record . '" />
843
844
845
846
847
848
849
850
					<input type="hidden" name="redirect" value="' . htmlspecialchars(($uidVal == 'new' ? BackendUtility::getModuleUrl(
						'web_layout',
						array(
							'id' => $this->id,
							'new_unique_uid' => $new_unique_uid,
							'returnUrl' => $this->returnUrl
						)
					) : $this->R_URI)) . '" />
851
					';
852
				// Add JavaScript as needed around the form:
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
				$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);
					}
868
				}
869
870
871
872
873
874
			} 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
				);
875
876
877
			}
		} else {
			// If no edit access, print error message:
878
			$content = $this->doc->section($lang->getLL('noAccess'), $lang->getLL('noAccess_msg') . '<br /><br />', 0, 1);
879
		}
880

881
882
		// Bottom controls (function menus):
		$q_count = $this->getNumberOfHiddenElements();
883
884
885
886
887
888
889
890
891
892
893
		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);
		}
894

895
		// Select element matrix:
896
		if ($tableName === 'tt_content' && MathUtility::canBeInterpretedAsInteger($this->eRParts[1])) {
897
			$posMap = GeneralUtility::makeInstance(ContentLayoutPagePositionMap::class);
898
899
900
			$posMap->cur_sys_language = $this->current_sys_language;
			$HTMLcode = '';
			// CSH:
Benni Mack's avatar
Benni Mack committed
901
			$HTMLcode .= BackendUtility::cshItem($this->descrTable, 'quickEdit_selElement', NULL, '|<br />');
902
903
			$HTMLcode .= $posMap->printContentElementColumns($this->id, $this->eRParts[1], $this->colPosList, $this->MOD_SETTINGS['tt_content_showHidden'], $this->R_URI);
			$content .= $this->doc->spacer(20);
904
			$content .= $this->doc->section($lang->getLL('CEonThisPage'), $HTMLcode, 0, 1);
905
906
			$content .= $this->doc->spacer(20);
		}
907

908
909
910
911
912
913
		return $content;
	}

	/**
	 * Rendering all other listings than QuickEdit
	 *
914
	 * @return string
915
916
	 */
	public function renderListContent() {
917
918
919
920
921
		/** @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
922
		$this->pointer = MathUtility::forceIntegerInRange($this->pointer, 0, 100000);
923
924
925
926
927
928
929
930
931
932
933
934
		$dbList->script = BackendUtility::getModuleUrl('web_layout');
		$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;
935
		}
936
		$dbList->externalTables = $this->externalTables;
937
		// Create menu for selecting a table to jump to (this is, if more than just pages/tt_content elements are found on the page!)
938
939
		// also fills $dbList->activeTables
		$dbList->getTableMenu($this->id);
940
941
942
943
944
945
946
		// 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()):
947
948
949
		foreach ($dbList->activeTables as $table => $value) {
			$h_func_b = '';
			if (!isset($dbList->externalTables[$table])) {
950
				$q_count = $this->getNumberOfHiddenElements();
951

952
953
954
				if ($q_count > 0) {
					$h_func_b =
						'<div class="checkbox">'
955
						. '<label for="checkTt_content_showHidden">'
956
957
						. '<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>)'
958
						. '</label>'
959
960
						. '</div>';
				}
961
				// Boolean: Display up/down arrows and edit icons for tt_content records
962
				$dbList->tt_contentConfig['showCommands'] = 1;
963
				// Boolean: Display info-marks or not
964
				$dbList->tt_contentConfig['showInfo'] = 1;
965
966
967
				// Setting up the tt_content columns to show:
				if (is_array($GLOBALS['TCA']['tt_content']['columns']['colPos']['config']['items'])) {
					$colList = array();
968
					$tcaItems = GeneralUtility::callUserFunction(BackendLayoutView::class . '->getColPosListItemsParsed', $this->id, $this);
969
970
971
972
973
974
975
					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');
				}
976
				if ($this->colPosList !== '') {
Nicole Cordes's avatar
Nicole Cordes committed
977
					$colList = array_intersect(GeneralUtility::intExplode(',', $this->colPosList), $colList);
978
979
				}
				// The order of the rows: Default is left(1), Normal(0), right(2), margin(3)
980
981
982
983
				$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;
984
985
				// If the function menu is set to "Language":
				if ($this->MOD_SETTINGS['function'] == 2) {
986
987
988
					$dbList->tt_contentConfig['languageMode'] = 1;
					$dbList->tt_contentConfig['languageCols'] = $this->MOD_MENU['language'];
					$dbList->tt_contentConfig['languageColsPointer'] = $this->current_sys_language;
989
990
991
				}
			} else {
				if (isset($this->MOD_SETTINGS) && isset($this->MOD_MENU)) {
992
					$h_func = BackendUtility::getFuncMenu($this->id, 'SET[' . $table . ']', $this->MOD_SETTINGS[$table], $this->MOD_MENU[$table], '', '');
993
994
995
996
997
				} else {
					$h_func = '';
				}
			}
			// Start the dblist object:
998
999
1000
1001
			$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'];
1002
			// Render versioning selector:
1003
			$dbList->HTMLcode .= $this->doc->getVersionSelector($this->id);
1004
			// Generate the list of elements here:
1005
			$dbList->generateList();
1006
			// Adding the list content to the tableOutput variable:
1007
			$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 : '');
1008
			// ... and any accumulated JavaScript goes the same way!
1009
			$tableJSOutput[$table] = $dbList->JScode;
1010
			// Increase global counter:
1011
			$CMcounter += $dbList->counter;
1012
			// Reset variables after operation:
1013
1014
			$dbList->HTMLcode = '';
			$dbList->JScode = '';
1015
1016
1017
1018
1019
			$h_func = '';
		}
		// END: traverse tables
		// For Context Sensitive Menus:
		$this->doc->getContextMenuCode();
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
		// 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);
			}
		}
1030
1031
1032
1033
1034
1035
		// 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:
1036
		if (!$this->modTSconfig['properties']['disableSearchBox'] && !empty($tableOutput)) {
1037
			$this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ToggleSearchToolbox');
1038
			$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) . '</a>';
1039
			$this->markers['SEARCHBOX'] = $dbList->getSearchBox(0);
1040
1041
1042
1043
1044
1045
		}
		// 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
1046
				$content .= GeneralUtility::callUserFunction($hook, $params, $this);
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
			}
		}
		return $content;
	}

	/**
	 * Print accumulated content of module
	 *
	 * @return void
	 */
	public function printContent() {
		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 = '') {
1073
		$lang = $this->getLanguageService();
1074
1075
1076
1077
1078
1079
1080
1081
		$buttons = array(
			'view' => '',
			'history_page' => '',
			'new_content' => '',
			'move_page' => '',
			'move_record' => '',
			'new_page' => '',
			'edit_page' => '',
1082
			'edit_language' => '',
1083
1084
1085
1086
			'csh' => '',
			'shortcut' => '',
			'cache' => '',
			'savedok' => '',
1087
			'save_close' => '',
1088
1089
1090
1091
1092
1093
1094
			'savedokshow' => '',
			'closedok' => '',
			'deletedok' => '',
			'undo' => '',
			'history_record' => ''
		);
		// View page
1095
		if (!VersionState::cast($this->pageinfo['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) {