DocumentTemplate.php 71.2 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
/**
 * 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.
 */
class DocumentTemplate {

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

	/**
50
51
52
53
	 * 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
54
55
56
57
	 */
	public $form = '';

	/**
58
59
60
61
	 * 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
	 *
62
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use pageRenderer directly
63
64
65
	 */
	public $JScodeLibArray = array();

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

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

80
81
82
83
84
	/**
	 * 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
	 */
85
86
87
88
89
90
	public $JScodeArray = array('jumpToUrl' => '
function jumpToUrl(URL) {
	window.location.href = URL;
	return false;
}
	');
91

92
93
94
95
96
	/**
	 * 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
	 */
97
98
99
	public $postCode = '';

	/**
100
101
	 * 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
102
103
104
	 */
	public $docType = '';

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

112
113
114
115
116
	/**
	 * 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
	 */
117
118
	protected $moduleTemplateFilename = '';

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

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

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

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

	/**
148
149
	 * 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
150
	 *
151
	 * @var array
152
153
154
	 */
	public $inDocStylesArray = array();

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

162
163
164
165
	/**
	 * 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
166
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
167
	 */
168
169
170
171
	public $endJS = 1;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	/**
338
	 * @var string
339
340
341
342
	 */
	public $pageHeaderBlock = '';

	/**
343
	 * @var string
344
345
346
347
	 */
	public $endOfPageJsBlock = '';

	/**
348
	 * @var bool
349
350
351
352
	 */
	public $hasDocheader = TRUE;

	/**
353
	 * @var PageRenderer
354
	 */
355
	protected $pageRenderer = NULL;
356

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

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

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

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

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

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

391
		// Setting default scriptID:
392
		if (($temp_M = (string)GeneralUtility::_GET('M')) && $GLOBALS['TBE_MODULES']['_PATHS'][$temp_M]) {
393
394
			$this->scriptID = preg_replace('/^.*\\/(sysext|ext)\\//', 'ext/', $GLOBALS['TBE_MODULES']['_PATHS'][$temp_M] . 'index.php');
		} else {
395
			$this->scriptID = preg_replace('/^.*\\/(sysext|ext)\\//', 'ext/', \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix(PATH_thisScript));
396
397
398
399
400
401
402
403
404
405
406
		}
		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.
407
			\TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TBE_STYLES'], $ovr);
408
409
410
411
412
413
414
415
416
417
418
419
420
421
			// 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']) {
422
			$this->inDocStylesArray['TBEstyle'] = $GLOBALS['TBE_STYLES']['inDocStyles_TBEstyle'];
423
424
425
426
427
428
429
		}
		// include all stylesheets
		foreach ($this->getSkinStylesheetDirectories() as $stylesheetDirectory) {
			$this->addStylesheetDirectory($stylesheetDirectory);
		}
		// Background image
		if ($GLOBALS['TBE_STYLES']['background']) {
430
			GeneralUtility::deprecationLog('Usage of $TBE_STYLES["background"] is deprecated. Please use stylesheets directly.');
431
432
433
434
		}
	}

	/**
435
	 * Initializes the page renderer object
436
	 */
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
	protected function initPageRenderer() {
		if ($this->pageRenderer !== NULL) {
			return;
		}
		$this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
		$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
		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
		foreach ($this->jsFiles as $file) {
			$this->pageRenderer->addJsFile($GLOBALS['BACK_PATH'] . $file);
460
		}
461
		if ((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['debug'] === 1) {
462
463
			$this->pageRenderer->enableDebugMode();
		}
464
465
466
467
468
469
470
471
472
473
474
475
	}

	/**
	 * Gets instance of PageRenderer configured with the current language, file references and debug settings
	 *
	 * @return PageRenderer
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8.
	 */
	public function getPageRenderer() {
		GeneralUtility::logDeprecatedFunction();
		$this->initPageRenderer();

476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
		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
501
	 * @param int $uid If icon is for database record this is the UID for the record from $table
502
	 * @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.
503
	 * @param string $addParams Additional GET parameters for the link to the ClickMenu AJAX request
504
	 * @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.
505
	 * @param bool $returnTagParameters If set, will return only the onclick JavaScript, not the whole link.
506
507
	 * @return string The link-wrapped input string.
	 */
508
509
510
511
512
513
514
515
516
517
518
519
520
	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 {
521
			return '<a href="#" ' . GeneralUtility::implodeAttributes($tagParameters, TRUE) . '>' . $content . '</a>';
522
		}
523
524
525
526
	}

	/**
	 * Makes link to page $id in frontend (view page)
527
	 * Returns an icon which links to the frontend index.php document for viewing the page with id $id
528
529
530
	 * $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)
	 *
531
	 * @param int $id The page id
532
533
534
	 * @param string $backPath The current "BACK_PATH" (the back relative to the typo3/ directory)
	 * @return string HTML string with linked icon(s)
	 */
535
	public function viewPageIcon($id, $backPath) {
536
		// If access to Web>List for user, then link to that module.
Nicole Cordes's avatar
Nicole Cordes committed
537
		$str = BackendUtility::getListViewLink(array(
538
			'id' => $id,
Nicole Cordes's avatar
Nicole Cordes committed
539
			'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
540
		), $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.showList'));
541
		// Make link to view page
542
		$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>';
543
544
545
546
547
548
549
550
		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
551
	 * @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
552
	 * @return string URL to tce_db.php + parameters (backpath is taken from $this->backPath)
553
	 * @see \TYPO3\CMS\Backend\Utility\BackendUtility::editOnClick()
554
555
	 */
	public function issueCommand($params, $redirectUrl = '') {
556
557
558
559
560
561
562
563
564
565
566
567
568
569
		/** @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;
570
571
572
573
574
575
576
577
578
579
580
	}

	/**
	 * 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
581
	 * @param bool $noViewPageIcon Set $noViewPageIcon TRUE if you don't want a magnifier-icon for viewing the page in the frontend
582
	 * @param array $tWrap is an array with indexes 0 and 1 each representing HTML-tags (start/end) which will wrap the title
583
	 * @param bool $enableClickMenu If TRUE, render click menu code around icon image
584
585
	 * @return string HTML content
	 */
586
	public function getHeader($table, $row, $path, $noViewPageIcon = FALSE, $tWrap = array('', ''), $enableClickMenu = TRUE) {
587
588
		$viewPage = '';
		if (is_array($row) && $row['uid']) {
Nicole Cordes's avatar
Nicole Cordes committed
589
590
			$iconImgTag = IconUtility::getSpriteIconForRecord($table, $row, array('title' => htmlspecialchars($path)));
			$title = strip_tags(BackendUtility::getRecordTitle($table, $row));
591
			$viewPage = $noViewPageIcon ? '' : $this->viewPageIcon($row['uid'], $this->backPath);
592
			if ($table == 'pages') {
Nicole Cordes's avatar
Nicole Cordes committed
593
				$path .= ' - ' . BackendUtility::titleAttribForPages($row, '', 0);
594
595
			}
		} else {
Nicole Cordes's avatar
Nicole Cordes committed
596
			$iconImgTag = IconUtility::getSpriteIcon('apps-pagetree-page-domain', array('title' => htmlspecialchars($path)));
597
598
			$title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
		}
599
600
601
602
603
604

		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>';
605
606
	}

607
608
609
610
611
612
	/**
	 * 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
613
	 * @param bool $enableClickMenu If TRUE, render click menu code around icon image
614
615
	 * @return string
	 */
616
	public function getResourceHeader(\TYPO3\CMS\Core\Resource\ResourceInterface $resource, $tWrap = array('', ''), $enableClickMenu = TRUE) {
617
618
619
		$path = $resource->getStorage()->getName() . $resource->getParentFolder()->getIdentifier();
		$iconImgTag = IconUtility::getSpriteIconForResource($resource, array('title' => htmlspecialchars($path)));

620
		if ($enableClickMenu && ($resource instanceof \TYPO3\CMS\Core\Resource\File)) {
621
622
623
624
			$metaData = $resource->_getMetaData();
			$iconImgTag = $this->wrapClickMenuOnIcon($iconImgTag, 'sys_file_metadata', $metaData['uid']);
		}

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

628
629
630
631
632
633
	/**
	 * 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
634
	 * @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.
635
636
637
638
	 * @return string HTML content
	 */
	public function makeShortcutIcon($gvList, $setList, $modName, $motherModName = '') {
		$storeUrl = $this->makeShortcutUrl($gvList, $setList);
Nicole Cordes's avatar
Nicole Cordes committed
639
		$pathInfo = parse_url(GeneralUtility::getIndpEnv('REQUEST_URI'));
640
641
		// Add the module identifier automatically if typo3/index.php is used:
		if (GeneralUtility::_GET('M') !== NULL && isset($GLOBALS['TBE_MODULES']['_PATHS'][$modName])) {
642
			$storeUrl = '&M=' . $modName . $storeUrl;
643
		}
644
		if ((int)$motherModName === 1) {
645
646
647
648
649
650
			$mMN = '&motherModName=\'+top.currentModuleLoaded+\'';
		} elseif ($motherModName) {
			$mMN = '&motherModName=' . rawurlencode($motherModName);
		} else {
			$mMN = '';
		}
651
		$confirmationText = GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.makeBookmark'));
652
		$onClick = 'top.TYPO3.ShortcutMenu.createShortcut(' . GeneralUtility::quoteJSvalue(rawurlencode($modName)) . ', ' . GeneralUtility::quoteJSvalue(rawurlencode($pathInfo['path'] . '?' . $storeUrl) . $mMN) . ', ' . $confirmationText . ');return false;';
653
		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>';
654
655
656
657
658
659
660
661
662
663
664
665
666
	}

	/**
	 * 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
667
		$GET = GeneralUtility::_GET();
668
		$storeArray = array_merge(GeneralUtility::compileSelectedGetVarsFromArray($gvList, $GET), array('SET' => GeneralUtility::compileSelectedGetVarsFromArray($setList, (array)$GLOBALS['SOBE']->MOD_SETTINGS)));
Nicole Cordes's avatar
Nicole Cordes committed
669
		$storeUrl = GeneralUtility::implodeArrayForUrl('', $storeArray);
670
671
672
673
674
675
676
677
		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.
	 *
678
	 * @param int $size A relative number which multiplied with approx. 10 will lead to the width in pixels
679
	 * @param bool $textarea A flag you can set for textareas - DEPRECATED as there is no difference any more between the two
680
681
682
683
	 * @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 = '') {
684
		return ' style="' . ($styleOverride ?: 'width:' . ceil($size * 9.58) . 'px;') . '"';
685
686
687
688
689
690
691
692
693
694
695
	}

	/**
	 * 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
696
		$thisLocation = $thisLocation ? $thisLocation : GeneralUtility::linkThisScript(array(
697
698
699
700
701
			'CB' => '',
			'SET' => '',
			'cmd' => '',
			'popViewId' => ''
		));
702
		$out = '
703
704
	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))) . '
705
706
707
708
709
710
711
712
		';
		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
	 *
713
714
	 * @param int $tstamp UNIX timestamp, seconds since 1970
	 * @param int $type How much data to show: $type = 1: hhmm, $type = 10:	ddmmmyy
715
	 * @return string Formatted timestamp
716
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the corresponding methods in BackendUtility
717
718
	 */
	public function formatTime($tstamp, $type) {
719
		GeneralUtility::logDeprecatedFunction();
720
721
		$dateStr = '';
		switch ($type) {
722
723
724
725
726
727
			case 1:
				$dateStr = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $tstamp);
				break;
			case 10:
				$dateStr = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $tstamp);
				break;
728
729
730
731
732
733
734
735
736
		}
		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
737
	 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
738
739
	 */
	public function parseTime() {
740
		GeneralUtility::logDeprecatedFunction();
741
		if ($this->parseTimeFlag && $GLOBALS['BE_USER']->isAdmin()) {
742
743
			return '<p>(ParseTime: ' . (GeneralUtility::milliseconds() - $GLOBALS['PARSETIME_START']) . ' ms</p>
					<p>REQUEST_URI-length: ' . strlen(GeneralUtility::getIndpEnv('REQUEST_URI')) . ')</p>';
744
745
746
747
748
749
		}
	}

	/**
	 * Defines whether to use the X-UA-Compatible meta tag.
	 *
750
	 * @param bool $useCompatibilityTag Whether to use the tag
751
752
753
	 * @return void
	 */
	public function useCompatibilityTag($useCompatibilityTag = TRUE) {
754
		$this->useCompatibilityTag = (bool)$useCompatibilityTag;
755
756
757
758
759
760
761
762
763
764
765
766
767
	}

	/*****************************************
	 *
	 *	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
768
	 * @param bool $includeCsh flag for including CSH
769
770
771
772
773
774
	 * @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'])) {
775
			$preStartPageHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'];
776
777
778
779
780
			if (is_array($preStartPageHook)) {
				$hookParameters = array(
					'title' => &$title
				);
				foreach ($preStartPageHook as $hookFunction) {
Nicole Cordes's avatar
Nicole Cordes committed
781
					GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
782
783
784
785
786
787
				}
			}
		}
		$this->pageRenderer->backPath = $this->backPath;
		// alternative template for Header and Footer
		if ($this->pageHeaderFooterTemplateFile) {
Nicole Cordes's avatar
Nicole Cordes committed
788
			$file = GeneralUtility::getFileAbsFileName($this->pageHeaderFooterTemplateFile, TRUE);
789
790
791
792
			if ($file) {
				$this->pageRenderer->setTemplateFile($file);
			}
		}
793

794
795
796
797
798


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

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

802
		// Include the JS for the Context Sensitive Help
803
		// @todo: right now this is a hard dependency on csh manual, as the whole help system should be moved to
804
		// the extension. The core provides an API for adding help, and rendering help, but the rendering
805
806
		// should be up to the extension itself
		if ($includeCsh && ExtensionManagementUtility::isLoaded('cshmanual')) {
807
808
			$this->loadCshJavascript();
		}
809
810

		$headerStart = '<!DOCTYPE html>';
811
		$this->pageRenderer->setXmlPrologAndDocType($headerStart);
812
		$this->pageRenderer->setHeadTag('<head>' . LF . '<!-- TYPO3 Script ID: ' . htmlspecialchars($this->scriptID) . ' -->');
813
814
		header('Content-Type:text/html;charset=utf-8');
		$this->pageRenderer->setCharSet('utf-8');
815
		$this->pageRenderer->addMetaTag($this->generator());
Felix Kopp's avatar
Felix Kopp committed
816
817
818
		$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">');
819
		$this->pageRenderer->setFavIcon($this->getBackendFavicon());
820
821
822
823
824
825
826
		if ($this->useCompatibilityTag) {
			$this->pageRenderer->addMetaTag($this->xUaCompatible($this->xUaCompatibilityVersion));
		}
		$this->pageRenderer->setTitle($title);
		// add docstyles
		$this->docStyle();
		if ($this->extDirectStateProvider) {
827
			$this->pageRenderer->addJsFile($this->backPath . 'sysext/backend/Resources/Public/JavaScript/ExtDirect.StateProvider.js');
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
		}
		// 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);
		}
851
		if (!empty($this->JScodeLibArray)) {
852
			GeneralUtility::deprecationLog('DocumentTemplate->JScodeLibArray is deprecated since TYPO3 CMS 7. Use the functionality within pageRenderer directly');
853
854
855
856
857
858
859
			foreach ($this->JScodeLibArray as $library) {
				$this->pageRenderer->addHeaderData($library);
			}
		}
		if ($this->extJScode) {
			$this->pageRenderer->addExtOnReadyCode($this->extJScode);
		}
860
861
862

		// Load jquery and twbs JS libraries on every backend request
		$this->pageRenderer->loadJquery();
863
864
865
866
		// 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');
867

868
869
		// hook for additional headerData
		if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'])) {
870
			$preHeaderRenderHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'];
871
872
873
874
875
			if (is_array($preHeaderRenderHook)) {
				$hookParameters = array(
					'pageRenderer' => &$this->pageRenderer
				);
				foreach ($preHeaderRenderHook as $hookFunction) {
Nicole Cordes's avatar
Nicole Cordes committed
876
					GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
877
878
879
880
				}
			}
		}
		// Construct page header.
Nicole Cordes's avatar
Nicole Cordes committed
881
		$str = $this->pageRenderer->render(PageRenderer::PART_HEADER);
882
883
		$this->JScode = ($this->extJScode = '');
		$this->JScodeArray = array();
Nicole Cordes's avatar
Nicole Cordes committed
884
		$this->endOfPageJsBlock = $this->pageRenderer->render(PageRenderer::PART_FOOTER);
885
		$str .= $this->docBodyTagBegin() . ($this->divClass ? '
886
887

<!-- Wrapping DIV-section for whole page BEGIN -->
888
889
<div class="' . $this->divClass . '">
' : '') . trim($this->form);
890
891
892
893
894
895
896
897
898
899
		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() {
900
		$str = $this->sectionEnd() . $this->postCode . $this->wrapScriptTags(BackendUtility::getUpdateSignalCode()) . ($this->form ? '
901
902
903
904
905
906
907
908
</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');
			}
		}
909
		$str .= ($this->divClass ? '
910
911
912

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

914
915
		// Logging: Can't find better place to put it:
		if (TYPO3_DLOG) {
916
			GeneralUtility::devLog('END of BACKEND session', \TYPO3\CMS\Backend\Template\DocumentTemplate::class, 0, array('_FLUSH' => TRUE));
917
918
919
920
921
922
923
924
925
		}
		return $str;
	}

	/**
	 * Shortcut for render the complete page of a module
	 *
	 * @param string $title page title
	 * @param string $content page content
926
	 * @param bool $includeCsh flag for including csh code
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
	 * @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) {
944
		$str = '
945
946

	<!-- MAIN Header in page top -->
947
	<h1>' . htmlspecialchars($text) . '</h1>
948
949
950
951
952
953
954
955
956
';
		return $this->sectionEnd() . $str;
	}

	/**
	 * Begins an output section and sets header and content
	 *
	 * @param string $label The header
	 * @param string $text The HTML-content
957
958
	 * @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")
959
	 * @param int $type The number of an icon to show with the header (see the icon-function). -1,1,2,3
960
	 * @param bool $allowHTMLinHeader If set, HTML tags are allowed in $label (otherwise this value is by default htmlspecialchars()'ed)
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
	 * @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
	 *
985
	 * @param int $dist The margin-top/-bottom of the <hr> ruler.
986
987
988
	 * @return string HTML content
	 */
	public function divider($dist) {
989
		$dist = (int)$dist;
990
		$str = '
991
992

	<!-- DIVIDER -->
993
	<hr style="margin-top: ' . $dist . 'px; margin-bottom: ' . $dist . 'px;" />
994
995
996
997
998
999
1000
';
		return $this->sectionEnd() . $str;
	}

	/**
	 * Returns a blank <div>-section with a height
	 *