DocumentTemplate.php 71 KB
Newer Older
1
2
3
<?php
namespace TYPO3\CMS\Backend\Template;

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

Nicole Cordes's avatar
Nicole Cordes committed
17
18
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Backend\Utility\IconUtility;
19
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
Nicole Cordes's avatar
Nicole Cordes committed
20
21
22
23
use TYPO3\CMS\Core\Html\HtmlParser;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
24
use TYPO3\CMS\Fluid\View\StandaloneView;
Nicole Cordes's avatar
Nicole Cordes committed
25

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
 * TYPO3 Backend Template Class
 *
 * This class contains functions for starting and ending the HTML of backend modules
 * It also contains methods for outputting sections of content.
 * Further there are functions for making icons, links, setting form-field widths etc.
 * Color scheme and stylesheet definitions are also available here.
 * Finally this file includes the language class for TYPO3's backend.
 *
 * After this file $LANG and $TBE_TEMPLATE are global variables / instances of their respective classes.
 *
 * Please refer to Inside TYPO3 for a discussion of how to use this API.
 *
 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
 */
class DocumentTemplate {

	// Vars you typically might want to/should set from outside after making instance of this class:
	/**
45
46
47
	 * 'backPath' pointing back to the PATH_typo3
	 *
	 * @var string
48
49
50
51
	 */
	public $backPath = '';

	/**
52
53
54
55
	 * This can be set to the HTML-code for a formtag.
	 * Useful when you need a form to span the whole page; Inserted exactly after the body-tag.
	 *
	 * @var string
56
57
58
59
	 */
	public $form = '';

	/**
60
61
62
63
	 * Similar to $JScode (see below) but used as an associative array to prevent double inclusion of JS code.
	 * This is used to include certain external Javascript libraries before the inline JS code.
	 * <script>-Tags are not wrapped around automatically
	 *
64
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use pageRenderer directly
65
66
67
	 */
	public $JScodeLibArray = array();

68
69
70
71
72
	/**
	 * Additional header code (eg. a JavaScript section) could be accommulated in this var. It will be directly outputted in the header.
	 *
	 * @var string
	 */
73
74
	public $JScode = '';

75
76
77
78
79
	/**
	 * Additional header code for ExtJS. It will be included in document header and inserted in a Ext.onReady(function()
	 *
	 * @var string
	 */
80
81
	public $extJScode = '';

82
83
84
85
86
	/**
	 * Similar to $JScode but for use as array with associative keys to prevent double inclusion of JS code. a <script> tag is automatically wrapped around.
	 *
	 * @var array
	 */
87
88
89
90
91
92
	public $JScodeArray = array('jumpToUrl' => '
function jumpToUrl(URL) {
	window.location.href = URL;
	return false;
}
	');
93

94
95
96
97
98
	/**
	 * Additional 'page-end' code could be accumulated in this var. It will be outputted at the end of page before </body> and some other internal page-end code.
	 *
	 * @var string
	 */
99
100
101
	public $postCode = '';

	/**
102
103
	 * Doc-type used in the header. Default is xhtml_trans. You can also set it to 'html_3', 'xhtml_strict' or 'xhtml_frames'.
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, as it is HTML5
104
105
106
	 */
	public $docType = '';

107
108
109
110
111
	/**
	 * HTML template with markers for module
	 *
	 * @var string
	 */
112
113
	public $moduleTemplate = '';

114
115
116
117
118
	/**
	 * The base file (not overlaid by TBE_STYLES) for the current module, useful for hooks when finding out which modules is rendered currently
	 *
	 * @var string
	 */
119
120
	protected $moduleTemplateFilename = '';

121
122
123
124
125
	/**
	 * Script ID
	 *
	 * @var string
	 */
126
127
	public $scriptID = '';

128
129
130
131
132
	/**
	 * Id which can be set for the body tag. Default value is based on script ID
	 *
	 * @var string
	 */
133
134
	public $bodyTagId = '';

135
136
137
138
139
	/**
	 * You can add additional attributes to the body-tag through this variable.
	 *
	 * @var string
	 */
140
141
142
	public $bodyTagAdditions = '';

	/**
143
	 * Additional CSS styles which will be added to the <style> section in the header
144
	 *
145
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the pageRenderer property for adding CSS styles
146
147
148
149
	 */
	public $inDocStyles = '';

	/**
150
151
	 * Additional CSS styles which will be added to the <style> section in the header
	 * used as array with associative keys to prevent double inclusion of CSS code
152
	 *
153
	 * @var array
154
155
156
	 */
	public $inDocStylesArray = array();

157
158
159
160
161
	/**
	 * Compensation for large documents (used in \TYPO3\CMS\Backend\Form\FormEngine)
	 *
	 * @var float
	 */
162
163
	public $form_largeComp = 1.33;

164
165
166
167
	/**
	 * If set, then a JavaScript section will be outputted in the bottom of page which will try and update the top.busy session expiry object.
	 *
	 * @var int
168
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
169
	 */
170
171
172
173
	public $endJS = 1;

	// TYPO3 Colorscheme.
	// If you want to change this, please do so through a skin using the global var $GLOBALS['TBE_STYLES']
174

175
	/**
176
177
	 * Light background color
	 *
178
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
179
180
181
182
	 */
	public $bgColor = '#F7F3EF';

	/**
183
184
	 * Steel-blue
	 *
185
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
186
187
188
189
	 */
	public $bgColor2 = '#9BA1A8';

	/**
190
191
	 * dok.color
	 *
192
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
193
194
195
196
	 */
	public $bgColor3 = '#F6F2E6';

	/**
197
198
	 * light tablerow background, brownish
	 *
199
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
200
201
202
203
	 */
	public $bgColor4 = '#D9D5C9';

	/**
204
205
	 * light tablerow background, greenish
	 *
206
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
207
208
209
210
	 */
	public $bgColor5 = '#ABBBB4';

	/**
211
212
	 * light tablerow background, yellowish, for section headers. Light.
	 *
213
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
214
215
216
217
	 */
	public $bgColor6 = '#E7DBA8';

	/**
218
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
219
220
221
222
	 */
	public $hoverColor = '#254D7B';

	/**
223
224
225
	 * Filename of stylesheet (relative to PATH_typo3)
	 *
	 * @var string
226
227
228
229
	 */
	public $styleSheetFile = '';

	/**
230
231
232
	 * Filename of stylesheet #2 - linked to right after the $this->styleSheetFile script (relative to PATH_typo3)
	 *
	 * @var string
233
234
235
236
	 */
	public $styleSheetFile2 = '';

	/**
237
238
239
	 * Filename of a post-stylesheet - included right after all inline styles.
	 *
	 * @var string
240
241
242
243
	 */
	public $styleSheetFile_post = '';

	/**
244
245
246
	 * Background image of page (relative to PATH_typo3)
	 *
	 * @var string
247
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use a stylesheet instead
248
249
250
251
	 */
	public $backGroundImage = '';

	/**
252
	 * Inline css styling set from TBE_STYLES array
253
254
	 *
	 * @var string
255
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use inDocStylesArray['TBEstyle']
256
257
258
259
260
261
	 */
	public $inDocStyles_TBEstyle = '';

	/**
	 * Whether to use the X-UA-Compatible meta tag
	 *
262
	 * @var bool
263
264
265
266
267
268
269
270
	 */
	protected $useCompatibilityTag = TRUE;

	/**
	 * X-Ua-Compatible version output in meta tag
	 *
	 * @var string
	 */
Felix Kopp's avatar
Felix Kopp committed
271
	protected $xUaCompatibilityVersion = 'IE=edge';
272
273

	// Skinning
274
275
276
277
278
	/**
	 * stylesheets from core
	 *
	 * @var array
	 */
279
280
281
282
	protected $stylesheetsCore = array(
		'generatedSprites' => '../typo3temp/sprites/'
	);

283
284
285
286
287
	/**
	 * Include these CSS directories from skins by default
	 *
	 * @var array
	 */
288
	protected $stylesheetsSkins = array(
289
290
		'structure' => 'Resources/Public/Css/structure/',
		'visual' => 'Resources/Public/Css/visual/'
291
292
293
294
295
296
297
	);

	/**
	 * JavaScript files loaded for every page in the Backend
	 *
	 * @var array
	 */
298
	protected $jsFiles = array();
299
300
301
302
303
304

	/**
	 * JavaScript files loaded for every page in the Backend, but explicitly excluded from concatenation (useful for libraries etc.)
	 *
	 * @var array
	 */
305
	protected $jsFilesNoConcatenation = array();
306
307

	/**
308
309
310
311
	 * Will output the parsetime of the scripts in milliseconds (for admin-users).
	 * Set this to FALSE when releasing TYPO3. Only for dev.
	 *
	 * @var bool
312
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
313
	 */
314
	public $parseTimeFlag = FALSE;
315
316

	/**
317
	 * internal character set, nowadays utf-8 for everything
318
319
	 *
	 * @var string
320
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, as it is always utf-8
321
	 */
322
	protected $charset = 'utf-8';
323
324

	/**
325
326
327
328
	 * Indicates if a <div>-output section is open
	 *
	 * @var int
	 * @internal
329
330
331
332
	 */
	public $sectionFlag = 0;

	/**
333
334
335
	 * (Default) Class for wrapping <DIV>-tag of page. Is set in class extensions.
	 *
	 * @var string
336
337
338
339
	 */
	public $divClass = '';

	/**
340
	 * @var string
341
342
343
344
	 */
	public $pageHeaderBlock = '';

	/**
345
	 * @var string
346
347
348
349
	 */
	public $endOfPageJsBlock = '';

	/**
350
	 * @var bool
351
352
353
354
355
356
357
358
	 */
	public $hasDocheader = TRUE;

	/**
	 * @var \TYPO3\CMS\Core\Page\PageRenderer
	 */
	protected $pageRenderer;

359
360
361
362
363
	/**
	 * Alternative template file
	 *
	 * @var string
	 */
364
365
	protected $pageHeaderFooterTemplateFile = '';

366
367
368
	/**
	 * @var bool
	 */
369
370
371
372
373
	protected $extDirectStateProvider = FALSE;

	/**
	 * Whether flashmessages should be rendered or not
	 *
374
	 * @var bool $showFlashMessages
375
376
377
378
379
380
381
	 */
	public $showFlashMessages = TRUE;

	const STATUS_ICON_ERROR = 3;
	const STATUS_ICON_WARNING = 2;
	const STATUS_ICON_NOTIFICATION = 1;
	const STATUS_ICON_OK = -1;
382

383
384
385
386
387
388
	/**
	 * Constructor
	 */
	public function __construct() {
		// Initializes the page rendering object:
		$this->getPageRenderer();
389
390
391
392

		// load Legacy CSS Support
		$this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LegacyCssClasses');

393
		// Setting default scriptID:
394
		if (($temp_M = (string)GeneralUtility::_GET('M')) && $GLOBALS['TBE_MODULES']['_PATHS'][$temp_M]) {
395
396
			$this->scriptID = preg_replace('/^.*\\/(sysext|ext)\\//', 'ext/', $GLOBALS['TBE_MODULES']['_PATHS'][$temp_M] . 'index.php');
		} else {
397
			$this->scriptID = preg_replace('/^.*\\/(sysext|ext)\\//', 'ext/', \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix(PATH_thisScript));
398
399
400
401
402
403
404
405
406
407
408
		}
		if (TYPO3_mainDir != 'typo3/' && substr($this->scriptID, 0, strlen(TYPO3_mainDir)) == TYPO3_mainDir) {
			// This fixes if TYPO3_mainDir has been changed so the script ids are STILL "typo3/..."
			$this->scriptID = 'typo3/' . substr($this->scriptID, strlen(TYPO3_mainDir));
		}
		$this->bodyTagId = preg_replace('/[^A-Za-z0-9-]/', '-', $this->scriptID);
		// Individual configuration per script? If so, make a recursive merge of the arrays:
		if (is_array($GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID])) {
			// Make copy
			$ovr = $GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID];
			// merge styles.
409
			\TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TBE_STYLES'], $ovr);
410
411
412
413
414
415
416
417
418
419
420
421
422
423
			// Have to unset - otherwise the second instantiation will do it again!
			unset($GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID]);
		}
		// Main Stylesheets:
		if ($GLOBALS['TBE_STYLES']['stylesheet']) {
			$this->styleSheetFile = $GLOBALS['TBE_STYLES']['stylesheet'];
		}
		if ($GLOBALS['TBE_STYLES']['stylesheet2']) {
			$this->styleSheetFile2 = $GLOBALS['TBE_STYLES']['stylesheet2'];
		}
		if ($GLOBALS['TBE_STYLES']['styleSheetFile_post']) {
			$this->styleSheetFile_post = $GLOBALS['TBE_STYLES']['styleSheetFile_post'];
		}
		if ($GLOBALS['TBE_STYLES']['inDocStyles_TBEstyle']) {
424
			$this->inDocStylesArray['TBEstyle'] = $GLOBALS['TBE_STYLES']['inDocStyles_TBEstyle'];
425
426
427
428
429
430
431
		}
		// include all stylesheets
		foreach ($this->getSkinStylesheetDirectories() as $stylesheetDirectory) {
			$this->addStylesheetDirectory($stylesheetDirectory);
		}
		// Background image
		if ($GLOBALS['TBE_STYLES']['background']) {
432
			GeneralUtility::deprecationLog('Usage of $TBE_STYLES["background"] is deprecated. Please use stylesheets directly.');
433
434
435
436
437
438
439
440
441
442
		}
	}

	/**
	 * Gets instance of PageRenderer configured with the current language, file references and debug settings
	 *
	 * @return \TYPO3\CMS\Core\Page\PageRenderer
	 */
	public function getPageRenderer() {
		if (!isset($this->pageRenderer)) {
443
			$this->pageRenderer = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Page\PageRenderer::class);
444
445
446
447
448
			$this->pageRenderer->setLanguage($GLOBALS['LANG']->lang);
			$this->pageRenderer->enableConcatenateFiles();
			$this->pageRenderer->enableCompressCss();
			$this->pageRenderer->enableCompressJavascript();
			// Add all JavaScript files defined in $this->jsFiles to the PageRenderer
449
450
451
452
453
454
455
456
457
458
459
			foreach ($this->jsFilesNoConcatenation as $file) {
				$this->pageRenderer->addJsFile(
					$GLOBALS['BACK_PATH'] . $file,
					'text/javascript',
					TRUE,
					FALSE,
					'',
					TRUE
				);
			}
			// Add all JavaScript files defined in $this->jsFiles to the PageRenderer
460
461
462
463
			foreach ($this->jsFiles as $file) {
				$this->pageRenderer->addJsFile($GLOBALS['BACK_PATH'] . $file);
			}
		}
464
		if ((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['debug'] === 1) {
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
			$this->pageRenderer->enableDebugMode();
		}
		return $this->pageRenderer;
	}

	/**
	 * Sets inclusion of StateProvider
	 *
	 * @return void
	 */
	public function setExtDirectStateProvider() {
		$this->extDirectStateProvider = TRUE;
	}

	/*****************************************
	 *
	 * EVALUATION FUNCTIONS
	 * Various centralized processing
	 *
	 *****************************************/
	/**
	 * Makes click menu link (context sensitive menu)
	 * Returns $str (possibly an <|img> tag/icon) wrapped in a link which will activate the context sensitive menu for the record ($table/$uid) or file ($table = file)
	 * The link will load the top frame with the parameter "&item" which is the table,uid and listFr arguments imploded by "|": rawurlencode($table.'|'.$uid.'|'.$listFr)
	 *
	 * @param string $str String to be wrapped in link, typ. image tag.
	 * @param string $table Table name/File path. If the icon is for a database record, enter the tablename from $GLOBALS['TCA']. If a file then enter the absolute filepath
492
	 * @param int $uid If icon is for database record this is the UID for the record from $table
493
	 * @param bool $listFr Tells the top frame script that the link is coming from a "list" frame which means a frame from within the backend content frame.
494
	 * @param string $addParams Additional GET parameters for the link to the ClickMenu AJAX request
495
	 * @param string $enDisItems Enable / Disable click menu items. Example: "+new,view" will display ONLY these two items (and any spacers in between), "new,view" will display all BUT these two items.
496
	 * @param bool $returnTagParameters If set, will return only the onclick JavaScript, not the whole link.
497
498
	 * @return string The link-wrapped input string.
	 */
499
500
501
502
503
504
505
506
507
508
509
510
511
	public function wrapClickMenuOnIcon($content, $table, $uid = 0, $listFr = TRUE, $addParams = '', $enDisItems = '', $returnTagParameters = FALSE) {
		$tagParameters = array(
			'class'           => 't3-js-clickmenutrigger',
			'data-table'      => $table,
			'data-uid'        => (int)$uid !== 0 ? (int)$uid : '',
			'data-listframe'  => $listFr,
			'data-iteminfo'   => str_replace('+', '%2B', $enDisItems),
			'data-parameters' => $addParams,
		);

		if ($returnTagParameters) {
			return $tagParameters;
		} else {
512
			return '<a href="#" ' . GeneralUtility::implodeAttributes($tagParameters, TRUE) . '>' . $content . '</a>';
513
		}
514
515
516
517
	}

	/**
	 * Makes link to page $id in frontend (view page)
518
	 * Returns an icon which links to the frontend index.php document for viewing the page with id $id
519
520
521
	 * $id must be a page-uid
	 * If the BE_USER has access to Web>List then a link to that module is shown as well (with return-url)
	 *
522
	 * @param int $id The page id
523
524
525
	 * @param string $backPath The current "BACK_PATH" (the back relative to the typo3/ directory)
	 * @return string HTML string with linked icon(s)
	 */
526
	public function viewPageIcon($id, $backPath) {
527
		// If access to Web>List for user, then link to that module.
Nicole Cordes's avatar
Nicole Cordes committed
528
		$str = BackendUtility::getListViewLink(array(
529
			'id' => $id,
Nicole Cordes's avatar
Nicole Cordes committed
530
			'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
531
		), $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.showList'));
532
		// Make link to view page
533
		$str .= '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick($id, $backPath, BackendUtility::BEgetRootLine($id))) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', TRUE) . '">' . IconUtility::getSpriteIcon('actions-document-view') . '</a>';
534
535
536
537
538
539
540
541
		return $str;
	}

	/**
	 * Returns a URL with a command to TYPO3 Core Engine (tce_db.php)
	 * See description of the API elsewhere.
	 *
	 * @param string $params is a set of GET params to send to tce_db.php. Example: "&cmd[tt_content][123][move]=456" or "&data[tt_content][123][hidden]=1&data[tt_content][123][title]=Hello%20World
542
	 * @param string|int $redirectUrl Redirect URL, default is to use GeneralUtility::getIndpEnv('REQUEST_URI'), -1 means to generate an URL for JavaScript using T3_THIS_LOCATION
543
	 * @return string URL to tce_db.php + parameters (backpath is taken from $this->backPath)
544
	 * @see \TYPO3\CMS\Backend\Utility\BackendUtility::editOnClick()
545
546
	 */
	public function issueCommand($params, $redirectUrl = '') {
547
548
549
550
551
552
553
554
555
556
557
558
559
560
		/** @var BackendUserAuthentication $beUser */
		$beUser = $GLOBALS['BE_USER'];
		$urlParameters = [
			'prErr' => 1,
			'uPT' => 1,
			'vC' => $beUser->veriCode()
		];
		$url = BackendUtility::getModuleUrl('tce_db', $urlParameters) . $params . BackendUtility::getUrlToken('tceAction') . '&redirect=';
		if ((int)$redirectUrl === -1) {
			$url = GeneralUtility::quoteJSvalue($url) . '+T3_THIS_LOCATION';
		} else {
			$url .= rawurlencode($redirectUrl ?: GeneralUtility::getIndpEnv('REQUEST_URI'));
		}
		return $url;
561
562
563
564
565
566
567
568
569
570
571
	}

	/**
	 * Makes the header (icon+title) for a page (or other record). Used in most modules under Web>*
	 * $table and $row must be a tablename/record from that table
	 * $path will be shown as alt-text for the icon.
	 * The title will be truncated to 45 chars.
	 *
	 * @param string $table Table name
	 * @param array $row Record row
	 * @param string $path Alt text
572
	 * @param bool $noViewPageIcon Set $noViewPageIcon TRUE if you don't want a magnifier-icon for viewing the page in the frontend
573
	 * @param array $tWrap is an array with indexes 0 and 1 each representing HTML-tags (start/end) which will wrap the title
574
	 * @param bool $enableClickMenu If TRUE, render click menu code around icon image
575
576
	 * @return string HTML content
	 */
577
	public function getHeader($table, $row, $path, $noViewPageIcon = FALSE, $tWrap = array('', ''), $enableClickMenu = TRUE) {
578
579
		$viewPage = '';
		if (is_array($row) && $row['uid']) {
Nicole Cordes's avatar
Nicole Cordes committed
580
581
			$iconImgTag = IconUtility::getSpriteIconForRecord($table, $row, array('title' => htmlspecialchars($path)));
			$title = strip_tags(BackendUtility::getRecordTitle($table, $row));
582
			$viewPage = $noViewPageIcon ? '' : $this->viewPageIcon($row['uid'], $this->backPath);
583
			if ($table == 'pages') {
Nicole Cordes's avatar
Nicole Cordes committed
584
				$path .= ' - ' . BackendUtility::titleAttribForPages($row, '', 0);
585
586
			}
		} else {
Nicole Cordes's avatar
Nicole Cordes committed
587
			$iconImgTag = IconUtility::getSpriteIcon('apps-pagetree-page-domain', array('title' => htmlspecialchars($path)));
588
589
			$title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
		}
590
591
592
593
594
595

		if ($enableClickMenu) {
			$iconImgTag = $this->wrapClickMenuOnIcon($iconImgTag, $table, $row['uid']);
		}

		return '<span class="typo3-moduleHeader">' . $iconImgTag . $viewPage . $tWrap[0] . htmlspecialchars(GeneralUtility::fixed_lgd_cs($title, 45)) . $tWrap[1] . '</span>';
596
597
	}

598
599
600
601
602
603
	/**
	 * Like ->getHeader() but for files and folders
	 * Returns the icon with the path of the file/folder set in the alt/title attribute. Shows the name after the icon.
	 *
	 * @param \TYPO3\CMS\Core\Resource\ResourceInterface $resource
	 * @param array $tWrap is an array with indexes 0 and 1 each representing HTML-tags (start/end) which will wrap the title
604
	 * @param bool $enableClickMenu If TRUE, render click menu code around icon image
605
606
	 * @return string
	 */
607
	public function getResourceHeader(\TYPO3\CMS\Core\Resource\ResourceInterface $resource, $tWrap = array('', ''), $enableClickMenu = TRUE) {
608
609
610
		$path = $resource->getStorage()->getName() . $resource->getParentFolder()->getIdentifier();
		$iconImgTag = IconUtility::getSpriteIconForResource($resource, array('title' => htmlspecialchars($path)));

611
		if ($enableClickMenu && ($resource instanceof \TYPO3\CMS\Core\Resource\File)) {
612
613
614
615
			$metaData = $resource->_getMetaData();
			$iconImgTag = $this->wrapClickMenuOnIcon($iconImgTag, 'sys_file_metadata', $metaData['uid']);
		}

616
		return '<span class="typo3-moduleHeader">' . $iconImgTag . $tWrap[0] . htmlspecialchars(GeneralUtility::fixed_lgd_cs($resource->getName(), 45)) . $tWrap[1] . '</span>';
617
618
	}

619
620
621
622
623
624
	/**
	 * Returns a linked shortcut-icon which will call the shortcut frame and set a shortcut there back to the calling page/module
	 *
	 * @param string $gvList Is the list of GET variables to store (if any)
	 * @param string $setList Is the list of SET[] variables to store (if any) - SET[] variables a stored in $GLOBALS["SOBE"]->MOD_SETTINGS for backend modules
	 * @param string $modName Module name string
625
	 * @param string $motherModName Is used to enter the "parent module name" if the module is a submodule under eg. Web>* or File>*. You can also set this value to "1" in which case the currentLoadedModule is sent to the shortcut script (so - not a fixed value!) - that is used in file_edit and wizard_rte modules where those are really running as a part of another module.
626
627
628
629
	 * @return string HTML content
	 */
	public function makeShortcutIcon($gvList, $setList, $modName, $motherModName = '') {
		$storeUrl = $this->makeShortcutUrl($gvList, $setList);
Nicole Cordes's avatar
Nicole Cordes committed
630
		$pathInfo = parse_url(GeneralUtility::getIndpEnv('REQUEST_URI'));
631
632
		// Add the module identifier automatically if typo3/mod.php is used:
		if (preg_match('/typo3\\/mod\\.php$/', $pathInfo['path']) && isset($GLOBALS['TBE_MODULES']['_PATHS'][$modName])) {
633
			$storeUrl = '&M=' . $modName . $storeUrl;
634
		}
635
		if ((int)$motherModName === 1) {
636
637
638
639
640
641
			$mMN = '&motherModName=\'+top.currentModuleLoaded+\'';
		} elseif ($motherModName) {
			$mMN = '&motherModName=' . rawurlencode($motherModName);
		} else {
			$mMN = '';
		}
642
		$confirmationText = GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.makeBookmark'));
643
		$onClick = 'top.TYPO3.ShortcutMenu.createShortcut(' . GeneralUtility::quoteJSvalue(rawurlencode($modName)) . ', ' . GeneralUtility::quoteJSvalue(rawurlencode($pathInfo['path'] . '?' . $storeUrl) . $mMN) . ', ' . $confirmationText . ');return false;';
644
		return '<a href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.makeBookmark', TRUE) . '">' . IconUtility::getSpriteIcon('actions-system-shortcut-new') . '</a>';
645
646
647
648
649
650
651
652
653
654
655
656
657
	}

	/**
	 * MAKE url for storing
	 * Internal func
	 *
	 * @param string $gvList Is the list of GET variables to store (if any)
	 * @param string $setList Is the list of SET[] variables to store (if any) - SET[] variables a stored in $GLOBALS["SOBE"]->MOD_SETTINGS for backend modules
	 * @return string
	 * @access private
	 * @see makeShortcutIcon()
	 */
	public function makeShortcutUrl($gvList, $setList) {
Nicole Cordes's avatar
Nicole Cordes committed
658
		$GET = GeneralUtility::_GET();
659
		$storeArray = array_merge(GeneralUtility::compileSelectedGetVarsFromArray($gvList, $GET), array('SET' => GeneralUtility::compileSelectedGetVarsFromArray($setList, (array)$GLOBALS['SOBE']->MOD_SETTINGS)));
Nicole Cordes's avatar
Nicole Cordes committed
660
		$storeUrl = GeneralUtility::implodeArrayForUrl('', $storeArray);
661
662
663
664
665
666
667
668
		return $storeUrl;
	}

	/**
	 * Returns <input> attributes to set the width of an text-type input field.
	 * For client browsers with no CSS support the cols/size attribute is returned.
	 * For CSS compliant browsers (recommended) a ' style="width: ...px;"' is returned.
	 *
669
	 * @param int $size A relative number which multiplied with approx. 10 will lead to the width in pixels
670
	 * @param bool $textarea A flag you can set for textareas - DEPRECATED as there is no difference any more between the two
671
672
673
674
	 * @param string $styleOverride A string which will be returned as attribute-value for style="" instead of the calculated width (if CSS is enabled)
	 * @return string Tag attributes for an <input> tag (regarding width)
	 */
	public function formWidth($size = 48, $textarea = FALSE, $styleOverride = '') {
675
		return ' style="' . ($styleOverride ?: 'width:' . ceil($size * 9.58) . 'px;') . '"';
676
677
678
679
680
681
682
683
684
685
686
	}

	/**
	 * Returns JavaScript variables setting the returnUrl and thisScript location for use by JavaScript on the page.
	 * Used in fx. db_list.php (Web>List)
	 *
	 * @param string $thisLocation URL to "this location" / current script
	 * @return string Urls are returned as JavaScript variables T3_RETURN_URL and T3_THIS_LOCATION
	 * @see typo3/db_list.php
	 */
	public function redirectUrls($thisLocation = '') {
Nicole Cordes's avatar
Nicole Cordes committed
687
		$thisLocation = $thisLocation ? $thisLocation : GeneralUtility::linkThisScript(array(
688
689
690
691
692
			'CB' => '',
			'SET' => '',
			'cmd' => '',
			'popViewId' => ''
		));
693
		$out = '
694
695
	var T3_RETURN_URL = ' . GeneralUtility::quoteJSvalue(str_replace('%20', '', rawurlencode(GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'))))) . ';
	var T3_THIS_LOCATION = ' . GeneralUtility::quoteJSvalue(str_replace('%20', '', rawurlencode($thisLocation))) . '
696
697
698
699
700
701
702
703
		';
		return $out;
	}

	/**
	 * Returns a formatted string of $tstamp
	 * Uses $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'] and $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] to format date and time
	 *
704
705
	 * @param int $tstamp UNIX timestamp, seconds since 1970
	 * @param int $type How much data to show: $type = 1: hhmm, $type = 10:	ddmmmyy
706
	 * @return string Formatted timestamp
707
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the corresponding methods in BackendUtility
708
709
	 */
	public function formatTime($tstamp, $type) {
710
		GeneralUtility::logDeprecatedFunction();
711
712
		$dateStr = '';
		switch ($type) {
713
714
715
716
717
718
			case 1:
				$dateStr = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $tstamp);
				break;
			case 10:
				$dateStr = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $tstamp);
				break;
719
720
721
722
723
724
725
726
727
		}
		return $dateStr;
	}

	/**
	 * Returns script parsetime IF ->parseTimeFlag is set and user is "admin"
	 * Automatically outputted in page end
	 *
	 * @return string HTML formated with <p>-tags
728
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
729
730
	 */
	public function parseTime() {
731
		GeneralUtility::logDeprecatedFunction();
732
		if ($this->parseTimeFlag && $GLOBALS['BE_USER']->isAdmin()) {
733
734
			return '<p>(ParseTime: ' . (GeneralUtility::milliseconds() - $GLOBALS['PARSETIME_START']) . ' ms</p>
					<p>REQUEST_URI-length: ' . strlen(GeneralUtility::getIndpEnv('REQUEST_URI')) . ')</p>';
735
736
737
738
739
740
		}
	}

	/**
	 * Defines whether to use the X-UA-Compatible meta tag.
	 *
741
	 * @param bool $useCompatibilityTag Whether to use the tag
742
743
744
	 * @return void
	 */
	public function useCompatibilityTag($useCompatibilityTag = TRUE) {
745
		$this->useCompatibilityTag = (bool)$useCompatibilityTag;
746
747
748
749
750
751
752
753
754
755
756
757
758
	}

	/*****************************************
	 *
	 *	PAGE BUILDING FUNCTIONS.
	 *	Use this to build the HTML of your backend modules
	 *
	 *****************************************/
	/**
	 * Returns page start
	 * This includes the proper header with charset, title, meta tag and beginning body-tag.
	 *
	 * @param string $title HTML Page title for the header
759
	 * @param bool $includeCsh flag for including CSH
760
761
762
763
764
765
	 * @return string Returns the whole header section of a HTML-document based on settings in internal variables (like styles, javascript code, charset, generator and docType)
	 * @see endPage()
	 */
	public function startPage($title, $includeCsh = TRUE) {
		// hook pre start page
		if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'])) {
766
			$preStartPageHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'];
767
768
769
770
771
			if (is_array($preStartPageHook)) {
				$hookParameters = array(
					'title' => &$title
				);
				foreach ($preStartPageHook as $hookFunction) {
Nicole Cordes's avatar
Nicole Cordes committed
772
					GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
773
774
775
776
777
778
				}
			}
		}
		$this->pageRenderer->backPath = $this->backPath;
		// alternative template for Header and Footer
		if ($this->pageHeaderFooterTemplateFile) {
Nicole Cordes's avatar
Nicole Cordes committed
779
			$file = GeneralUtility::getFileAbsFileName($this->pageHeaderFooterTemplateFile, TRUE);
780
781
782
783
			if ($file) {
				$this->pageRenderer->setTemplateFile($file);
			}
		}
784

785
786
787
788
789


		// Disable rendering of XHTML tags
		$this->pageRenderer->setRenderXhtml(FALSE);

Felix Kopp's avatar
Felix Kopp committed
790
791
		$languageCode = $this->pageRenderer->getLanguage() === 'default' ? 'en' : $this->pageRenderer->getLanguage();
		$this->pageRenderer->setHtmlTag('<html lang="' . $languageCode . '">');
792

793
		// Include the JS for the Context Sensitive Help
794
795
796
797
		// @todo: right now this is a hard dependency on csh manual, as the whole help system should be moved to
		// the extension. The core provides a API for adding help, and rendering help, but the rendering
		// should be up to the extension itself
		if ($includeCsh && ExtensionManagementUtility::isLoaded('cshmanual')) {
798
799
			$this->loadCshJavascript();
		}
800
801

		$headerStart = '<!DOCTYPE html>';
802
		$this->pageRenderer->setXmlPrologAndDocType($headerStart);
803
		$this->pageRenderer->setHeadTag('<head>' . LF . '<!-- TYPO3 Script ID: ' . htmlspecialchars($this->scriptID) . ' -->');
804
805
		header('Content-Type:text/html;charset=utf-8');
		$this->pageRenderer->setCharSet('utf-8');
806
		$this->pageRenderer->addMetaTag($this->generator());
Felix Kopp's avatar
Felix Kopp committed
807
808
809
		$this->pageRenderer->addMetaTag('<meta name="robots" content="noindex,follow">');
		$this->pageRenderer->addMetaTag('<meta charset="utf-8">');
		$this->pageRenderer->addMetaTag('<meta name="viewport" content="width=device-width, initial-scale=1">');
810
		$this->pageRenderer->setFavIcon($this->getBackendFavicon());
811
812
813
814
815
816
817
		if ($this->useCompatibilityTag) {
			$this->pageRenderer->addMetaTag($this->xUaCompatible($this->xUaCompatibilityVersion));
		}
		$this->pageRenderer->setTitle($title);
		// add docstyles
		$this->docStyle();
		if ($this->extDirectStateProvider) {
818
			$this->pageRenderer->addJsFile($this->backPath . 'sysext/backend/Resources/Public/JavaScript/ExtDirect.StateProvider.js');
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
		}
		// Add jsCode for overriding the console with a debug panel connection
		$this->pageRenderer->addJsInlineCode('consoleOverrideWithDebugPanel', 'if (typeof top.Ext === "object") {
				top.Ext.onReady(function() {
					if (typeof console === "undefined") {
						if (top && top.TYPO3 && top.TYPO3.Backend && top.TYPO3.Backend.DebugConsole) {
							console = top.TYPO3.Backend.DebugConsole;
						} else {
							console = {
								log: Ext.log,
								info: Ext.log,
								warn: Ext.log,
								error: Ext.log
							};
						}
					}
				});
			}
			', FALSE);
		$this->pageRenderer->addHeaderData($this->JScode);
		foreach ($this->JScodeArray as $name => $code) {
			$this->pageRenderer->addJsInlineCode($name, $code, FALSE);
		}
842
		if (!empty($this->JScodeLibArray)) {
843
			GeneralUtility::deprecationLog('DocumentTemplate->JScodeLibArray is deprecated since TYPO3 CMS 7. Use the functionality within pageRenderer directly');
844
845
846
847
848
849
850
			foreach ($this->JScodeLibArray as $library) {
				$this->pageRenderer->addHeaderData($library);
			}
		}
		if ($this->extJScode) {
			$this->pageRenderer->addExtOnReadyCode($this->extJScode);
		}
851
852
853

		// Load jquery and twbs JS libraries on every backend request
		$this->pageRenderer->loadJquery();
854
855
856
857
		// Note: please do not reference "bootstrap" outside of the TYPO3 Core (not in your own extensions)
		// as this is preliminary as long as Twitter bootstrap does not support AMD modules
		// this logic will be changed once Twitter bootstrap 4 is included
		$this->pageRenderer->addJsFile($this->backPath . 'sysext/core/Resources/Public/JavaScript/Contrib/bootstrap/bootstrap.js');
858

859
860
		// hook for additional headerData
		if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'])) {
861
			$preHeaderRenderHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'];
862
863
864
865
866
			if (is_array($preHeaderRenderHook)) {
				$hookParameters = array(
					'pageRenderer' => &$this->pageRenderer
				);
				foreach ($preHeaderRenderHook as $hookFunction) {
Nicole Cordes's avatar
Nicole Cordes committed
867
					GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
868
869
870
871
				}
			}
		}
		// Construct page header.
Nicole Cordes's avatar
Nicole Cordes committed
872
		$str = $this->pageRenderer->render(PageRenderer::PART_HEADER);
873
874
		$this->JScode = ($this->extJScode = '');
		$this->JScodeArray = array();
Nicole Cordes's avatar
Nicole Cordes committed
875
		$this->endOfPageJsBlock = $this->pageRenderer->render(PageRenderer::PART_FOOTER);
876
		$str .= $this->docBodyTagBegin() . ($this->divClass ? '
877
878

<!-- Wrapping DIV-section for whole page BEGIN -->
879
880
<div class="' . $this->divClass . '">
' : '') . trim($this->form);
881
882
883
884
885
886
887
888
889
890
		return $str;
	}

	/**
	 * Returns page end; This includes finishing form, div, body and html tags.
	 *
	 * @return string The HTML end of a page
	 * @see startPage()
	 */
	public function endPage() {
891
		$str = $this->sectionEnd() . $this->postCode . $this->wrapScriptTags(BackendUtility::getUpdateSignalCode()) . ($this->form ? '
892
893
894
895
896
897
898
899
</form>' : '');
		// If something is in buffer like debug, put it to end of page
		if (ob_get_contents()) {
			$str .= ob_get_clean();
			if (!headers_sent()) {
				header('Content-Encoding: None');
			}
		}
900
		$str .= ($this->divClass ? '
901
902
903

<!-- Wrapping DIV-section for whole page END -->
</div>' : '') . $this->endOfPageJsBlock;
904

905
906
		// Logging: Can't find better place to put it:
		if (TYPO3_DLOG) {
907
			GeneralUtility::devLog('END of BACKEND session', \TYPO3\CMS\Backend\Template\DocumentTemplate::class, 0, array('_FLUSH' => TRUE));
908
909
910
911
912
913
914
915
916
		}
		return $str;
	}

	/**
	 * Shortcut for render the complete page of a module
	 *
	 * @param string $title page title
	 * @param string $content page content
917
	 * @param bool $includeCsh flag for including csh code
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
	 * @return string complete page
	 */
	public function render($title, $content, $includeCsh = TRUE) {
		$pageContent = $this->startPage($title, $includeCsh);
		$pageContent .= $content;
		$pageContent .= $this->endPage();
		return $this->insertStylesAndJS($pageContent);
	}

	/**
	 * Returns the header-bar in the top of most backend modules
	 * Closes section if open.
	 *
	 * @param string $text The text string for the header
	 * @return string HTML content
	 */
	public function header($text) {
935
		$str = '
936
937

	<!-- MAIN Header in page top -->
938
	<h1>' . htmlspecialchars($text) . '</h1>
939
940
941
942
943
944
945
946
947
';
		return $this->sectionEnd() . $str;
	}

	/**
	 * Begins an output section and sets header and content
	 *
	 * @param string $label The header
	 * @param string $text The HTML-content
948
949
	 * @param bool $nostrtoupper	A flag that will prevent the header from being converted to uppercase
	 * @param bool $sH Defines the type of header (if set, "<h3>" rather than the default "h4")
950
	 * @param int $type The number of an icon to show with the header (see the icon-function). -1,1,2,3
951
	 * @param bool $allowHTMLinHeader If set, HTML tags are allowed in $label (otherwise this value is by default htmlspecialchars()'ed)
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
	 * @return string HTML content
	 * @see icons(), sectionHeader()
	 */
	public function section($label, $text, $nostrtoupper = FALSE, $sH = FALSE, $type = 0, $allowHTMLinHeader = FALSE) {
		$str = '';
		// Setting header
		if ($label) {
			if (!$allowHTMLinHeader) {
				$label = htmlspecialchars($label);
			}
			$str .= $this->sectionHeader($this->icons($type) . $label, $sH, $nostrtoupper ? '' : ' class="uppercase"');
		}
		// Setting content
		$str .= '

	<!-- Section content -->
' . $text;
		return $this->sectionBegin() . $str;
	}

	/**
	 * Inserts a divider image
	 * Ends a section (if open) before inserting the image
	 *
976
	 * @param int $dist The margin-top/-bottom of the <hr> ruler.
977
978
979
	 * @return string HTML content
	 */
	public function divider($dist) {
980
		$dist = (int)$dist;
981
		$str = '
982
983

	<!-- DIVIDER -->
984
	<hr style="margin-top: ' . $dist . 'px; margin-bottom: ' . $dist . 'px;" />
985
986
987
988
989
990
991
';
		return $this->sectionEnd() . $str;
	}

	/**
	 * Returns a blank <div>-section with a height
	 *
992
	 * @param int $dist Padding-top for the div-section (should be margin-top but konqueror (3.1) doesn't like it :-(
993
994
995
996
	 * @return string HTML content
	 */
	public function spacer($dist) {
		if ($dist > 0) {
997
			return '
998
999

	<!-- Spacer element -->
1000
	<div style="padding-top: ' . (int)$dist . 'px;"></div>