[TASK] Cleanup double-paranthesis in calls to trim()
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Template / DocumentTemplate.php
1 <?php
2 namespace TYPO3\CMS\Backend\Template;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Backend\Utility\IconUtility;
19 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
20 use TYPO3\CMS\Core\Html\HtmlParser;
21 use TYPO3\CMS\Core\Imaging\Icon;
22 use TYPO3\CMS\Core\Imaging\IconFactory;
23 use TYPO3\CMS\Core\Page\PageRenderer;
24 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
25 use TYPO3\CMS\Core\Utility\GeneralUtility;
26 use TYPO3\CMS\Fluid\View\StandaloneView;
27
28 /**
29 * TYPO3 Backend Template Class
30 *
31 * This class contains functions for starting and ending the HTML of backend modules
32 * It also contains methods for outputting sections of content.
33 * Further there are functions for making icons, links, setting form-field widths etc.
34 * Color scheme and stylesheet definitions are also available here.
35 * Finally this file includes the language class for TYPO3's backend.
36 *
37 * After this file $LANG and $TBE_TEMPLATE are global variables / instances of their respective classes.
38 *
39 * Please refer to Inside TYPO3 for a discussion of how to use this API.
40 */
41 class DocumentTemplate {
42
43 // Vars you typically might want to/should set from outside after making instance of this class:
44 /**
45 * This can be set to the HTML-code for a formtag.
46 * Useful when you need a form to span the whole page; Inserted exactly after the body-tag.
47 *
48 * @var string
49 */
50 public $form = '';
51
52 /**
53 * Similar to $JScode (see below) but used as an associative array to prevent double inclusion of JS code.
54 * This is used to include certain external Javascript libraries before the inline JS code.
55 * <script>-Tags are not wrapped around automatically
56 *
57 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use pageRenderer directly
58 */
59 public $JScodeLibArray = array();
60
61 /**
62 * Additional header code (eg. a JavaScript section) could be accommulated in this var. It will be directly outputted in the header.
63 *
64 * @var string
65 */
66 public $JScode = '';
67
68 /**
69 * Additional header code for ExtJS. It will be included in document header and inserted in a Ext.onReady(function()
70 *
71 * @var string
72 */
73 public $extJScode = '';
74
75 /**
76 * 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.
77 *
78 * @var array
79 */
80 public $JScodeArray = array('jumpToUrl' => '
81 function jumpToUrl(URL) {
82 window.location.href = URL;
83 return false;
84 }
85 ');
86
87 /**
88 * 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.
89 *
90 * @var string
91 */
92 public $postCode = '';
93
94 /**
95 * Doc-type used in the header. Default is xhtml_trans. You can also set it to 'html_3', 'xhtml_strict' or 'xhtml_frames'.
96 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, as it is HTML5
97 */
98 public $docType = '';
99
100 /**
101 * HTML template with markers for module
102 *
103 * @var string
104 */
105 public $moduleTemplate = '';
106
107 /**
108 * The base file (not overlaid by TBE_STYLES) for the current module, useful for hooks when finding out which modules is rendered currently
109 *
110 * @var string
111 */
112 protected $moduleTemplateFilename = '';
113
114 /**
115 * Script ID
116 *
117 * @var string
118 */
119 public $scriptID = '';
120
121 /**
122 * Id which can be set for the body tag. Default value is based on script ID
123 *
124 * @var string
125 */
126 public $bodyTagId = '';
127
128 /**
129 * You can add additional attributes to the body-tag through this variable.
130 *
131 * @var string
132 */
133 public $bodyTagAdditions = '';
134
135 /**
136 * Additional CSS styles which will be added to the <style> section in the header
137 *
138 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the pageRenderer property for adding CSS styles
139 */
140 public $inDocStyles = '';
141
142 /**
143 * Additional CSS styles which will be added to the <style> section in the header
144 * used as array with associative keys to prevent double inclusion of CSS code
145 *
146 * @var array
147 */
148 public $inDocStylesArray = array();
149
150 /**
151 * Compensation for large documents (used in \TYPO3\CMS\Backend\Form\FormEngine)
152 *
153 * @var float
154 */
155 public $form_largeComp = 1.33;
156
157 /**
158 * 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.
159 *
160 * @var int
161 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
162 */
163 public $endJS = 1;
164
165 // TYPO3 Colorscheme.
166 // If you want to change this, please do so through a skin using the global var $GLOBALS['TBE_STYLES']
167
168 /**
169 * Light background color
170 *
171 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
172 */
173 public $bgColor = '#F7F3EF';
174
175 /**
176 * Steel-blue
177 *
178 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
179 */
180 public $bgColor2 = '#9BA1A8';
181
182 /**
183 * dok.color
184 *
185 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
186 */
187 public $bgColor3 = '#F6F2E6';
188
189 /**
190 * light tablerow background, brownish
191 *
192 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
193 */
194 public $bgColor4 = '#D9D5C9';
195
196 /**
197 * light tablerow background, greenish
198 *
199 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
200 */
201 public $bgColor5 = '#ABBBB4';
202
203 /**
204 * light tablerow background, yellowish, for section headers. Light.
205 *
206 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
207 */
208 public $bgColor6 = '#E7DBA8';
209
210 /**
211 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
212 */
213 public $hoverColor = '#254D7B';
214
215 /**
216 * Filename of stylesheet (relative to PATH_typo3)
217 *
218 * @var string
219 */
220 public $styleSheetFile = '';
221
222 /**
223 * Filename of stylesheet #2 - linked to right after the $this->styleSheetFile script (relative to PATH_typo3)
224 *
225 * @var string
226 */
227 public $styleSheetFile2 = '';
228
229 /**
230 * Filename of a post-stylesheet - included right after all inline styles.
231 *
232 * @var string
233 */
234 public $styleSheetFile_post = '';
235
236 /**
237 * Background image of page (relative to PATH_typo3)
238 *
239 * @var string
240 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use a stylesheet instead
241 */
242 public $backGroundImage = '';
243
244 /**
245 * Inline css styling set from TBE_STYLES array
246 *
247 * @var string
248 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use inDocStylesArray['TBEstyle']
249 */
250 public $inDocStyles_TBEstyle = '';
251
252 /**
253 * Whether to use the X-UA-Compatible meta tag
254 *
255 * @var bool
256 */
257 protected $useCompatibilityTag = TRUE;
258
259 /**
260 * X-Ua-Compatible version output in meta tag
261 *
262 * @var string
263 */
264 protected $xUaCompatibilityVersion = 'IE=edge';
265
266 // Skinning
267 /**
268 * stylesheets from core
269 *
270 * @var array
271 */
272 protected $stylesheetsCore = array(
273 'generatedSprites' => '../typo3temp/sprites/'
274 );
275
276 /**
277 * Include these CSS directories from skins by default
278 *
279 * @var array
280 */
281 protected $stylesheetsSkins = array(
282 'structure' => 'Resources/Public/Css/structure/',
283 'visual' => 'Resources/Public/Css/visual/'
284 );
285
286 /**
287 * JavaScript files loaded for every page in the Backend
288 *
289 * @var array
290 */
291 protected $jsFiles = array();
292
293 /**
294 * JavaScript files loaded for every page in the Backend, but explicitly excluded from concatenation (useful for libraries etc.)
295 *
296 * @var array
297 */
298 protected $jsFilesNoConcatenation = array();
299
300 /**
301 * Will output the parsetime of the scripts in milliseconds (for admin-users).
302 * Set this to FALSE when releasing TYPO3. Only for dev.
303 *
304 * @var bool
305 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
306 */
307 public $parseTimeFlag = FALSE;
308
309 /**
310 * internal character set, nowadays utf-8 for everything
311 *
312 * @var string
313 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, as it is always utf-8
314 */
315 protected $charset = 'utf-8';
316
317 /**
318 * Indicates if a <div>-output section is open
319 *
320 * @var int
321 * @internal
322 */
323 public $sectionFlag = 0;
324
325 /**
326 * (Default) Class for wrapping <DIV>-tag of page. Is set in class extensions.
327 *
328 * @var string
329 */
330 public $divClass = '';
331
332 /**
333 * @var string
334 */
335 public $pageHeaderBlock = '';
336
337 /**
338 * @var string
339 */
340 public $endOfPageJsBlock = '';
341
342 /**
343 * @var bool
344 */
345 public $hasDocheader = TRUE;
346
347 /**
348 * @var PageRenderer
349 */
350 protected $pageRenderer = NULL;
351
352 /**
353 * Alternative template file
354 *
355 * @var string
356 */
357 protected $pageHeaderFooterTemplateFile = '';
358
359 /**
360 * @var bool
361 */
362 protected $extDirectStateProvider = FALSE;
363
364 /**
365 * Whether flashmessages should be rendered or not
366 *
367 * @var bool $showFlashMessages
368 */
369 public $showFlashMessages = TRUE;
370
371 /**
372 * @var IconFactory
373 */
374 protected $iconFactory;
375
376 const STATUS_ICON_ERROR = 3;
377 const STATUS_ICON_WARNING = 2;
378 const STATUS_ICON_NOTIFICATION = 1;
379 const STATUS_ICON_OK = -1;
380
381 /**
382 * Constructor
383 */
384 public function __construct() {
385 // Initializes the page rendering object:
386 $this->initPageRenderer();
387
388 // load Legacy CSS Support
389 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LegacyCssClasses');
390 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
391
392 // Setting default scriptID:
393 if (($temp_M = (string)GeneralUtility::_GET('M')) && $GLOBALS['TBE_MODULES']['_PATHS'][$temp_M]) {
394 $this->scriptID = preg_replace('/^.*\\/(sysext|ext)\\//', 'ext/', $GLOBALS['TBE_MODULES']['_PATHS'][$temp_M] . 'index.php');
395 } else {
396 $this->scriptID = preg_replace('/^.*\\/(sysext|ext)\\//', 'ext/', \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix(PATH_thisScript));
397 }
398 if (TYPO3_mainDir != 'typo3/' && substr($this->scriptID, 0, strlen(TYPO3_mainDir)) == TYPO3_mainDir) {
399 // This fixes if TYPO3_mainDir has been changed so the script ids are STILL "typo3/..."
400 $this->scriptID = 'typo3/' . substr($this->scriptID, strlen(TYPO3_mainDir));
401 }
402 $this->bodyTagId = preg_replace('/[^A-Za-z0-9-]/', '-', $this->scriptID);
403 // Individual configuration per script? If so, make a recursive merge of the arrays:
404 if (is_array($GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID])) {
405 // Make copy
406 $ovr = $GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID];
407 // merge styles.
408 \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TBE_STYLES'], $ovr);
409 // Have to unset - otherwise the second instantiation will do it again!
410 unset($GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID]);
411 }
412 // Main Stylesheets:
413 if ($GLOBALS['TBE_STYLES']['stylesheet']) {
414 $this->styleSheetFile = $GLOBALS['TBE_STYLES']['stylesheet'];
415 }
416 if ($GLOBALS['TBE_STYLES']['stylesheet2']) {
417 $this->styleSheetFile2 = $GLOBALS['TBE_STYLES']['stylesheet2'];
418 }
419 if ($GLOBALS['TBE_STYLES']['styleSheetFile_post']) {
420 $this->styleSheetFile_post = $GLOBALS['TBE_STYLES']['styleSheetFile_post'];
421 }
422 if ($GLOBALS['TBE_STYLES']['inDocStyles_TBEstyle']) {
423 $this->inDocStylesArray['TBEstyle'] = $GLOBALS['TBE_STYLES']['inDocStyles_TBEstyle'];
424 }
425 // include all stylesheets
426 foreach ($this->getSkinStylesheetDirectories() as $stylesheetDirectory) {
427 $this->addStylesheetDirectory($stylesheetDirectory);
428 }
429 // Background image
430 if ($GLOBALS['TBE_STYLES']['background']) {
431 GeneralUtility::deprecationLog('Usage of $TBE_STYLES["background"] is deprecated. Please use stylesheets directly.');
432 }
433 }
434
435 /**
436 * Initializes the page renderer object
437 */
438 protected function initPageRenderer() {
439 if ($this->pageRenderer !== NULL) {
440 return;
441 }
442 $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
443 $this->pageRenderer->setLanguage($GLOBALS['LANG']->lang);
444 $this->pageRenderer->enableConcatenateFiles();
445 $this->pageRenderer->enableCompressCss();
446 $this->pageRenderer->enableCompressJavascript();
447 // Add all JavaScript files defined in $this->jsFiles to the PageRenderer
448 foreach ($this->jsFilesNoConcatenation as $file) {
449 $this->pageRenderer->addJsFile(
450 $GLOBALS['BACK_PATH'] . $file,
451 'text/javascript',
452 TRUE,
453 FALSE,
454 '',
455 TRUE
456 );
457 }
458 // Add all JavaScript files defined in $this->jsFiles to the PageRenderer
459 foreach ($this->jsFiles as $file) {
460 $this->pageRenderer->addJsFile($GLOBALS['BACK_PATH'] . $file);
461 }
462 if ((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['debug'] === 1) {
463 $this->pageRenderer->enableDebugMode();
464 }
465 }
466
467 /**
468 * Gets instance of PageRenderer configured with the current language, file references and debug settings
469 *
470 * @return PageRenderer
471 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8.
472 */
473 public function getPageRenderer() {
474 GeneralUtility::logDeprecatedFunction();
475 $this->initPageRenderer();
476
477 return $this->pageRenderer;
478 }
479
480 /**
481 * Sets inclusion of StateProvider
482 *
483 * @return void
484 */
485 public function setExtDirectStateProvider() {
486 $this->extDirectStateProvider = TRUE;
487 }
488
489 /*****************************************
490 *
491 * EVALUATION FUNCTIONS
492 * Various centralized processing
493 *
494 *****************************************/
495 /**
496 * Makes click menu link (context sensitive menu)
497 * 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)
498 * 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)
499 *
500 * @param string $str String to be wrapped in link, typ. image tag.
501 * @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
502 * @param int $uid If icon is for database record this is the UID for the record from $table
503 * @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.
504 * @param string $addParams Additional GET parameters for the link to the ClickMenu AJAX request
505 * @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.
506 * @param bool $returnTagParameters If set, will return only the onclick JavaScript, not the whole link.
507 * @return string The link-wrapped input string.
508 */
509 public function wrapClickMenuOnIcon($content, $table, $uid = 0, $listFr = TRUE, $addParams = '', $enDisItems = '', $returnTagParameters = FALSE) {
510 $tagParameters = array(
511 'class' => 't3-js-clickmenutrigger',
512 'data-table' => $table,
513 'data-uid' => (int)$uid !== 0 ? (int)$uid : '',
514 'data-listframe' => $listFr,
515 'data-iteminfo' => str_replace('+', '%2B', $enDisItems),
516 'data-parameters' => $addParams,
517 );
518
519 if ($returnTagParameters) {
520 return $tagParameters;
521 } else {
522 return '<a href="#" ' . GeneralUtility::implodeAttributes($tagParameters, TRUE) . '>' . $content . '</a>';
523 }
524 }
525
526 /**
527 * Makes link to page $id in frontend (view page)
528 * Returns an icon which links to the frontend index.php document for viewing the page with id $id
529 * $id must be a page-uid
530 * If the BE_USER has access to Web>List then a link to that module is shown as well (with return-url)
531 *
532 * @param int $id The page id
533 * @param string $_ @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
534 * @return string HTML string with linked icon(s)
535 */
536 public function viewPageIcon($id, $_ = '') {
537 // If access to Web>List for user, then link to that module.
538 $str = BackendUtility::getListViewLink(array(
539 'id' => $id,
540 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
541 ), $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.showList'));
542 // Make link to view page
543 $str .= '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick($id, '', BackendUtility::BEgetRootLine($id))) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', TRUE) . '">' . $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL) . '</a>';
544 return $str;
545 }
546
547 /**
548 * Returns a URL with a command to TYPO3 Core Engine (tce_db.php)
549 * See description of the API elsewhere.
550 *
551 * @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
552 * @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
553 * @return string URL to BackendUtility::getModuleUrl('tce_db') + parameters
554 * @see \TYPO3\CMS\Backend\Utility\BackendUtility::editOnClick()
555 */
556 public function issueCommand($params, $redirectUrl = '') {
557 /** @var BackendUserAuthentication $beUser */
558 $beUser = $GLOBALS['BE_USER'];
559 $urlParameters = [
560 'prErr' => 1,
561 'uPT' => 1,
562 'vC' => $beUser->veriCode()
563 ];
564 $url = BackendUtility::getModuleUrl('tce_db', $urlParameters) . $params . BackendUtility::getUrlToken('tceAction') . '&redirect=';
565 if ((int)$redirectUrl === -1) {
566 $url = GeneralUtility::quoteJSvalue($url) . '+T3_THIS_LOCATION';
567 } else {
568 $url .= rawurlencode($redirectUrl ?: GeneralUtility::getIndpEnv('REQUEST_URI'));
569 }
570 return $url;
571 }
572
573 /**
574 * Makes the header (icon+title) for a page (or other record). Used in most modules under Web>*
575 * $table and $row must be a tablename/record from that table
576 * $path will be shown as alt-text for the icon.
577 * The title will be truncated to 45 chars.
578 *
579 * @param string $table Table name
580 * @param array $row Record row
581 * @param string $path Alt text
582 * @param bool $noViewPageIcon Set $noViewPageIcon TRUE if you don't want a magnifier-icon for viewing the page in the frontend
583 * @param array $tWrap is an array with indexes 0 and 1 each representing HTML-tags (start/end) which will wrap the title
584 * @param bool $enableClickMenu If TRUE, render click menu code around icon image
585 * @return string HTML content
586 */
587 public function getHeader($table, $row, $path, $noViewPageIcon = FALSE, $tWrap = array('', ''), $enableClickMenu = TRUE) {
588 $viewPage = '';
589 if (is_array($row) && $row['uid']) {
590 $iconImgTag = IconUtility::getSpriteIconForRecord($table, $row, array('title' => htmlspecialchars($path)));
591 $title = strip_tags(BackendUtility::getRecordTitle($table, $row));
592 $viewPage = $noViewPageIcon ? '' : $this->viewPageIcon($row['uid']);
593 } else {
594 $iconImgTag = IconUtility::getSpriteIcon('apps-pagetree-page-domain', array('title' => htmlspecialchars($path)));
595 $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
596 }
597
598 if ($enableClickMenu) {
599 $iconImgTag = $this->wrapClickMenuOnIcon($iconImgTag, $table, $row['uid']);
600 }
601
602 return '<span class="typo3-moduleHeader">' . $iconImgTag . $viewPage . $tWrap[0] . htmlspecialchars(GeneralUtility::fixed_lgd_cs($title, 45)) . $tWrap[1] . '</span>';
603 }
604
605 /**
606 * Like ->getHeader() but for files and folders
607 * Returns the icon with the path of the file/folder set in the alt/title attribute. Shows the name after the icon.
608 *
609 * @param \TYPO3\CMS\Core\Resource\ResourceInterface $resource
610 * @param array $tWrap is an array with indexes 0 and 1 each representing HTML-tags (start/end) which will wrap the title
611 * @param bool $enableClickMenu If TRUE, render click menu code around icon image
612 * @return string
613 */
614 public function getResourceHeader(\TYPO3\CMS\Core\Resource\ResourceInterface $resource, $tWrap = array('', ''), $enableClickMenu = TRUE) {
615 $path = $resource->getStorage()->getName() . $resource->getParentFolder()->getIdentifier();
616 $iconImgTag = IconUtility::getSpriteIconForResource($resource, array('title' => htmlspecialchars($path)));
617
618 if ($enableClickMenu && ($resource instanceof \TYPO3\CMS\Core\Resource\File)) {
619 $metaData = $resource->_getMetaData();
620 $iconImgTag = $this->wrapClickMenuOnIcon($iconImgTag, 'sys_file_metadata', $metaData['uid']);
621 }
622
623 return '<span class="typo3-moduleHeader">' . $iconImgTag . $tWrap[0] . htmlspecialchars(GeneralUtility::fixed_lgd_cs($resource->getName(), 45)) . $tWrap[1] . '</span>';
624 }
625
626 /**
627 * Returns a linked shortcut-icon which will call the shortcut frame and set a shortcut there back to the calling page/module
628 *
629 * @param string $gvList Is the list of GET variables to store (if any)
630 * @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
631 * @param string $modName Module name string
632 * @param string|int $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.
633 * @return string HTML content
634 */
635 public function makeShortcutIcon($gvList, $setList, $modName, $motherModName = '') {
636 $storeUrl = $this->makeShortcutUrl($gvList, $setList);
637 $pathInfo = parse_url(GeneralUtility::getIndpEnv('REQUEST_URI'));
638 // Fallback for alt_mod. We still pass in the old xMOD... stuff, but TBE_MODULES only knows about "record_edit".
639 // We still need to pass the xMOD name to createShortcut below, since this is used for icons.
640 $moduleName = $modName === 'xMOD_alt_doc.php' ? 'record_edit' : $modName;
641 // Add the module identifier automatically if typo3/index.php is used:
642 if (GeneralUtility::_GET('M') !== NULL && isset($GLOBALS['TBE_MODULES']['_PATHS'][$moduleName])) {
643 $storeUrl = '&M=' . $moduleName . $storeUrl;
644 }
645 if ((int)$motherModName === 1) {
646 $motherModule = 'top.currentModuleLoaded';
647 } elseif ($motherModName) {
648 $motherModule = GeneralUtility::quoteJSvalue($motherModName);
649 } else {
650 $motherModule = '\'\'';
651 }
652 $confirmationText = GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.makeBookmark'));
653
654 $shortcutUrl = $pathInfo['path'] . '?' . $storeUrl;
655 $shortcutExist = BackendUtility::shortcutExists($shortcutUrl);
656
657 if ($shortcutExist) {
658 return '<a class="active" title="">' .
659 IconUtility::getSpriteIcon('actions-system-shortcut-new') . '</a>';
660 }
661
662 $url = GeneralUtility::quoteJSvalue(rawurlencode($shortcutUrl));
663 $onClick = 'top.TYPO3.ShortcutMenu.createShortcut(' . GeneralUtility::quoteJSvalue(rawurlencode($modName)) .
664 ', ' . $url . ', ' . $confirmationText . ', ' . $motherModule . ', this);return false;';
665
666 return '<a href="#" onclick="' . htmlspecialchars($onClick) . '" title="' .
667 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.makeBookmark', TRUE) . '">' .
668 IconUtility::getSpriteIcon('actions-system-shortcut-new') . '</a>';
669 }
670
671 /**
672 * MAKE url for storing
673 * Internal func
674 *
675 * @param string $gvList Is the list of GET variables to store (if any)
676 * @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
677 * @return string
678 * @access private
679 * @see makeShortcutIcon()
680 */
681 public function makeShortcutUrl($gvList, $setList) {
682 $GET = GeneralUtility::_GET();
683 $storeArray = array_merge(GeneralUtility::compileSelectedGetVarsFromArray($gvList, $GET), array('SET' => GeneralUtility::compileSelectedGetVarsFromArray($setList, (array)$GLOBALS['SOBE']->MOD_SETTINGS)));
684 $storeUrl = GeneralUtility::implodeArrayForUrl('', $storeArray);
685 return $storeUrl;
686 }
687
688 /**
689 * Returns <input> attributes to set the width of an text-type input field.
690 * For client browsers with no CSS support the cols/size attribute is returned.
691 * For CSS compliant browsers (recommended) a ' style="width: ...px;"' is returned.
692 *
693 * @param int $size A relative number which multiplied with approx. 10 will lead to the width in pixels
694 * @param bool $textarea A flag you can set for textareas - DEPRECATED as there is no difference any more between the two
695 * @param string $styleOverride A string which will be returned as attribute-value for style="" instead of the calculated width (if CSS is enabled)
696 * @return string Tag attributes for an <input> tag (regarding width)
697 */
698 public function formWidth($size = 48, $textarea = FALSE, $styleOverride = '') {
699 return ' style="' . ($styleOverride ?: 'width:' . ceil($size * 9.58) . 'px;') . '"';
700 }
701
702 /**
703 * Returns JavaScript variables setting the returnUrl and thisScript location for use by JavaScript on the page.
704 * Used in fx. db_list.php (Web>List)
705 *
706 * @param string $thisLocation URL to "this location" / current script
707 * @return string Urls are returned as JavaScript variables T3_RETURN_URL and T3_THIS_LOCATION
708 * @see typo3/db_list.php
709 */
710 public function redirectUrls($thisLocation = '') {
711 $thisLocation = $thisLocation ? $thisLocation : GeneralUtility::linkThisScript(array(
712 'CB' => '',
713 'SET' => '',
714 'cmd' => '',
715 'popViewId' => ''
716 ));
717 $out = '
718 var T3_RETURN_URL = ' . GeneralUtility::quoteJSvalue(str_replace('%20', '', rawurlencode(GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'))))) . ';
719 var T3_THIS_LOCATION = ' . GeneralUtility::quoteJSvalue(str_replace('%20', '', rawurlencode($thisLocation))) . '
720 ';
721 return $out;
722 }
723
724 /**
725 * Returns a formatted string of $tstamp
726 * Uses $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'] and $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] to format date and time
727 *
728 * @param int $tstamp UNIX timestamp, seconds since 1970
729 * @param int $type How much data to show: $type = 1: hhmm, $type = 10: ddmmmyy
730 * @return string Formatted timestamp
731 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the corresponding methods in BackendUtility
732 */
733 public function formatTime($tstamp, $type) {
734 GeneralUtility::logDeprecatedFunction();
735 $dateStr = '';
736 switch ($type) {
737 case 1:
738 $dateStr = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $tstamp);
739 break;
740 case 10:
741 $dateStr = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $tstamp);
742 break;
743 }
744 return $dateStr;
745 }
746
747 /**
748 * Returns script parsetime IF ->parseTimeFlag is set and user is "admin"
749 * Automatically outputted in page end
750 *
751 * @return string HTML formated with <p>-tags
752 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
753 */
754 public function parseTime() {
755 GeneralUtility::logDeprecatedFunction();
756 if ($this->parseTimeFlag && $GLOBALS['BE_USER']->isAdmin()) {
757 return '<p>(ParseTime: ' . (GeneralUtility::milliseconds() - $GLOBALS['PARSETIME_START']) . ' ms</p>
758 <p>REQUEST_URI-length: ' . strlen(GeneralUtility::getIndpEnv('REQUEST_URI')) . ')</p>';
759 }
760 }
761
762 /**
763 * Defines whether to use the X-UA-Compatible meta tag.
764 *
765 * @param bool $useCompatibilityTag Whether to use the tag
766 * @return void
767 */
768 public function useCompatibilityTag($useCompatibilityTag = TRUE) {
769 $this->useCompatibilityTag = (bool)$useCompatibilityTag;
770 }
771
772 /*****************************************
773 *
774 * PAGE BUILDING FUNCTIONS.
775 * Use this to build the HTML of your backend modules
776 *
777 *****************************************/
778 /**
779 * Returns page start
780 * This includes the proper header with charset, title, meta tag and beginning body-tag.
781 *
782 * @param string $title HTML Page title for the header
783 * @param bool $includeCsh flag for including CSH
784 * @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)
785 * @see endPage()
786 */
787 public function startPage($title, $includeCsh = TRUE) {
788 // hook pre start page
789 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'])) {
790 $preStartPageHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'];
791 if (is_array($preStartPageHook)) {
792 $hookParameters = array(
793 'title' => &$title
794 );
795 foreach ($preStartPageHook as $hookFunction) {
796 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
797 }
798 }
799 }
800 // alternative template for Header and Footer
801 if ($this->pageHeaderFooterTemplateFile) {
802 $file = GeneralUtility::getFileAbsFileName($this->pageHeaderFooterTemplateFile, TRUE);
803 if ($file) {
804 $this->pageRenderer->setTemplateFile($file);
805 }
806 }
807
808
809
810 // Disable rendering of XHTML tags
811 $this->pageRenderer->setRenderXhtml(FALSE);
812
813 $languageCode = $this->pageRenderer->getLanguage() === 'default' ? 'en' : $this->pageRenderer->getLanguage();
814 $this->pageRenderer->setHtmlTag('<html lang="' . $languageCode . '">');
815
816 // Include the JS for the Context Sensitive Help
817 // @todo: right now this is a hard dependency on csh manual, as the whole help system should be moved to
818 // the extension. The core provides an API for adding help, and rendering help, but the rendering
819 // should be up to the extension itself
820 if ($includeCsh && ExtensionManagementUtility::isLoaded('cshmanual')) {
821 $this->loadCshJavascript();
822 }
823
824 $headerStart = '<!DOCTYPE html>';
825 $this->pageRenderer->setXmlPrologAndDocType($headerStart);
826 $this->pageRenderer->setHeadTag('<head>' . LF . '<!-- TYPO3 Script ID: ' . htmlspecialchars($this->scriptID) . ' -->');
827 header('Content-Type:text/html;charset=utf-8');
828 $this->pageRenderer->setCharSet('utf-8');
829 $this->pageRenderer->addMetaTag($this->generator());
830 $this->pageRenderer->addMetaTag('<meta name="robots" content="noindex,follow">');
831 $this->pageRenderer->addMetaTag('<meta charset="utf-8">');
832 $this->pageRenderer->addMetaTag('<meta name="viewport" content="width=device-width, initial-scale=1">');
833 $this->pageRenderer->setFavIcon($this->getBackendFavicon());
834 if ($this->useCompatibilityTag) {
835 $this->pageRenderer->addMetaTag($this->xUaCompatible($this->xUaCompatibilityVersion));
836 }
837 $this->pageRenderer->setTitle($title);
838 // add docstyles
839 $this->docStyle();
840 if ($this->extDirectStateProvider) {
841 $this->pageRenderer->addJsFile('sysext/backend/Resources/Public/JavaScript/ExtDirect.StateProvider.js');
842 }
843 // Add jsCode for overriding the console with a debug panel connection
844 $this->pageRenderer->addJsInlineCode('consoleOverrideWithDebugPanel', 'if (typeof top.Ext === "object") {
845 top.Ext.onReady(function() {
846 if (typeof console === "undefined") {
847 if (top && top.TYPO3 && top.TYPO3.Backend && top.TYPO3.Backend.DebugConsole) {
848 console = top.TYPO3.Backend.DebugConsole;
849 } else {
850 console = {
851 log: Ext.log,
852 info: Ext.log,
853 warn: Ext.log,
854 error: Ext.log
855 };
856 }
857 }
858 });
859 }
860 ', FALSE);
861 $this->pageRenderer->addHeaderData($this->JScode);
862 foreach ($this->JScodeArray as $name => $code) {
863 $this->pageRenderer->addJsInlineCode($name, $code, FALSE);
864 }
865 if (!empty($this->JScodeLibArray)) {
866 GeneralUtility::deprecationLog('DocumentTemplate->JScodeLibArray is deprecated since TYPO3 CMS 7. Use the functionality within pageRenderer directly');
867 foreach ($this->JScodeLibArray as $library) {
868 $this->pageRenderer->addHeaderData($library);
869 }
870 }
871 if ($this->extJScode) {
872 $this->pageRenderer->addExtOnReadyCode($this->extJScode);
873 }
874
875 // Load jquery and twbs JS libraries on every backend request
876 $this->pageRenderer->loadJquery();
877 // Note: please do not reference "bootstrap" outside of the TYPO3 Core (not in your own extensions)
878 // as this is preliminary as long as Twitter bootstrap does not support AMD modules
879 // this logic will be changed once Twitter bootstrap 4 is included
880 $this->pageRenderer->addJsFile('sysext/core/Resources/Public/JavaScript/Contrib/bootstrap/bootstrap.js');
881
882 // hook for additional headerData
883 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'])) {
884 $preHeaderRenderHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'];
885 if (is_array($preHeaderRenderHook)) {
886 $hookParameters = array(
887 'pageRenderer' => &$this->pageRenderer
888 );
889 foreach ($preHeaderRenderHook as $hookFunction) {
890 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
891 }
892 }
893 }
894 // Construct page header.
895 $str = $this->pageRenderer->render(PageRenderer::PART_HEADER);
896 $this->JScode = ($this->extJScode = '');
897 $this->JScodeArray = array();
898 $this->endOfPageJsBlock = $this->pageRenderer->render(PageRenderer::PART_FOOTER);
899 $str .= $this->docBodyTagBegin() . ($this->divClass ? '
900
901 <!-- Wrapping DIV-section for whole page BEGIN -->
902 <div class="' . $this->divClass . '">
903 ' : '') . trim($this->form);
904 return $str;
905 }
906
907 /**
908 * Returns page end; This includes finishing form, div, body and html tags.
909 *
910 * @return string The HTML end of a page
911 * @see startPage()
912 */
913 public function endPage() {
914 $str = $this->sectionEnd() . $this->postCode . $this->wrapScriptTags(BackendUtility::getUpdateSignalCode()) . ($this->form ? '
915 </form>' : '');
916 // If something is in buffer like debug, put it to end of page
917 if (ob_get_contents()) {
918 $str .= ob_get_clean();
919 if (!headers_sent()) {
920 header('Content-Encoding: None');
921 }
922 }
923 $str .= ($this->divClass ? '
924
925 <!-- Wrapping DIV-section for whole page END -->
926 </div>' : '') . $this->endOfPageJsBlock;
927
928 // Logging: Can't find better place to put it:
929 if (TYPO3_DLOG) {
930 GeneralUtility::devLog('END of BACKEND session', \TYPO3\CMS\Backend\Template\DocumentTemplate::class, 0, array('_FLUSH' => TRUE));
931 }
932 return $str;
933 }
934
935 /**
936 * Shortcut for render the complete page of a module
937 *
938 * @param string $title page title
939 * @param string $content page content
940 * @param bool $includeCsh flag for including csh code
941 * @return string complete page
942 */
943 public function render($title, $content, $includeCsh = TRUE) {
944 $pageContent = $this->startPage($title, $includeCsh);
945 $pageContent .= $content;
946 $pageContent .= $this->endPage();
947 return $this->insertStylesAndJS($pageContent);
948 }
949
950 /**
951 * Returns the header-bar in the top of most backend modules
952 * Closes section if open.
953 *
954 * @param string $text The text string for the header
955 * @return string HTML content
956 */
957 public function header($text) {
958 $str = '
959
960 <!-- MAIN Header in page top -->
961 <h1>' . htmlspecialchars($text) . '</h1>
962 ';
963 return $this->sectionEnd() . $str;
964 }
965
966 /**
967 * Begins an output section and sets header and content
968 *
969 * @param string $label The header
970 * @param string $text The HTML-content
971 * @param bool $nostrtoupper A flag that will prevent the header from being converted to uppercase
972 * @param bool $sH Defines the type of header (if set, "<h3>" rather than the default "h4")
973 * @param int $type The number of an icon to show with the header (see the icon-function). -1,1,2,3
974 * @param bool $allowHTMLinHeader If set, HTML tags are allowed in $label (otherwise this value is by default htmlspecialchars()'ed)
975 * @return string HTML content
976 * @see icons(), sectionHeader()
977 */
978 public function section($label, $text, $nostrtoupper = FALSE, $sH = FALSE, $type = 0, $allowHTMLinHeader = FALSE) {
979 $str = '';
980 // Setting header
981 if ($label) {
982 if (!$allowHTMLinHeader) {
983 $label = htmlspecialchars($label);
984 }
985 $str .= $this->sectionHeader($this->icons($type) . $label, $sH, $nostrtoupper ? '' : ' class="uppercase"');
986 }
987 // Setting content
988 $str .= '
989
990 <!-- Section content -->
991 ' . $text;
992 return $this->sectionBegin() . $str;
993 }
994
995 /**
996 * Inserts a divider image
997 * Ends a section (if open) before inserting the image
998 *
999 * @param int $dist The margin-top/-bottom of the <hr> ruler.
1000 * @return string HTML content
1001 */
1002 public function divider($dist) {
1003 $dist = (int)$dist;
1004 $str = '
1005
1006 <!-- DIVIDER -->
1007 <hr style="margin-top: ' . $dist . 'px; margin-bottom: ' . $dist . 'px;" />
1008 ';
1009 return $this->sectionEnd() . $str;
1010 }
1011
1012 /**
1013 * Returns a blank <div>-section with a height
1014 *
1015 * @param int $dist Padding-top for the div-section (should be margin-top but konqueror (3.1) doesn't like it :-(
1016 * @return string HTML content
1017 */
1018 public function spacer($dist) {
1019 if ($dist > 0) {
1020 return '
1021
1022 <!-- Spacer element -->
1023 <div style="padding-top: ' . (int)$dist . 'px;"></div>
1024 ';
1025 }
1026 }
1027
1028 /**
1029 * Make a section header.
1030 * Begins a section if not already open.
1031 *
1032 * @param string $label The label between the <h3> or <h4> tags. (Allows HTML)
1033 * @param bool $sH If set, <h3> is used, otherwise <h4>
1034 * @param string $addAttrib Additional attributes to h-tag, eg. ' class=""'
1035 * @return string HTML content
1036 */
1037 public function sectionHeader($label, $sH = FALSE, $addAttrib = '') {
1038 $tag = $sH ? 'h2' : 'h3';
1039 if ($addAttrib && $addAttrib[0] !== ' ') {
1040 $addAttrib = ' ' . $addAttrib;
1041 }
1042 $str = '
1043
1044 <!-- Section header -->
1045 <' . $tag . $addAttrib . '>' . $label . '</' . $tag . '>
1046 ';
1047 return $this->sectionBegin() . $str;
1048 }
1049
1050 /**
1051 * Begins an output section.
1052 * Returns the <div>-begin tag AND sets the ->sectionFlag TRUE (if the ->sectionFlag is not already set!)
1053 * You can call this function even if a section is already begun since the function will only return something if the sectionFlag is not already set!
1054 *
1055 * @return string HTML content
1056 */
1057 public function sectionBegin() {
1058 if (!$this->sectionFlag) {
1059 $this->sectionFlag = 1;
1060 $str = '
1061
1062 <!-- ***********************
1063 Begin output section.
1064 *********************** -->
1065 <div>
1066 ';
1067 return $str;
1068 } else {
1069 return '';
1070 }
1071 }
1072
1073 /**
1074 * Ends and output section
1075 * Returns the </div>-end tag AND clears the ->sectionFlag (but does so only IF the sectionFlag is set - that is a section is 'open')
1076 * See sectionBegin() also.
1077 *
1078 * @return string HTML content
1079 */
1080 public function sectionEnd() {
1081 if ($this->sectionFlag) {
1082 $this->sectionFlag = 0;
1083 return '
1084 </div>
1085 <!-- *********************
1086 End output section.
1087 ********************* -->
1088 ';
1089 } else {
1090 return '';
1091 }
1092 }
1093
1094 /**
1095 * If a form-tag is defined in ->form then and end-tag for that <form> element is outputted
1096 * Further a JavaScript section is outputted which will update the top.busy session-expiry object (unless $this->endJS is set to FALSE)
1097 *
1098 * @return string HTML content (<script> tag section)
1099 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, nothing there to output anymore
1100 */
1101 public function endPageJS() {
1102 GeneralUtility::logDeprecatedFunction();
1103 return '';
1104 }
1105
1106 /**
1107 * Creates the bodyTag.
1108 * You can add to the bodyTag by $this->bodyTagAdditions
1109 *
1110 * @return string HTML body tag
1111 */
1112 public function docBodyTagBegin() {
1113 return '<body ' . trim($this->bodyTagAdditions . ($this->bodyTagId ? ' id="' . $this->bodyTagId . '"' : '')) . '>';
1114 }
1115
1116 /**
1117 * Outputting document style
1118 *
1119 * @return string HTML style section/link tags
1120 */
1121 public function docStyle() {
1122 // Implode it all:
1123 $inDocStyles = implode(LF, $this->inDocStylesArray);
1124
1125 // Reset styles so they won't be added again in insertStylesAndJS()
1126 $this->inDocStylesArray = array();
1127
1128 if ($this->styleSheetFile) {
1129 $this->pageRenderer->addCssFile($this->styleSheetFile);
1130 }
1131 if ($this->styleSheetFile2) {
1132 $this->pageRenderer->addCssFile($this->styleSheetFile2);
1133 }
1134
1135 if ($inDocStyles !== '') {
1136 $this->pageRenderer->addCssInlineBlock('inDocStyles', $inDocStyles . LF . '/*###POSTCSSMARKER###*/');
1137 }
1138
1139 if ($this->styleSheetFile_post) {
1140 $this->pageRenderer->addCssFile($this->styleSheetFile_post);
1141 }
1142 }
1143
1144 /**
1145 * Insert additional style sheet link
1146 *
1147 * @param string $key some key identifying the style sheet
1148 * @param string $href uri to the style sheet file
1149 * @param string $title value for the title attribute of the link element
1150 * @param string $relation value for the rel attribute of the link element
1151 * @return void
1152 */
1153 public function addStyleSheet($key, $href, $title = '', $relation = 'stylesheet') {
1154 $this->pageRenderer->addCssFile($href, $relation, 'screen', $title);
1155 }
1156
1157 /**
1158 * Add all *.css files of the directory $path to the stylesheets
1159 *
1160 * @param string $path directory to add
1161 * @return void
1162 */
1163 public function addStyleSheetDirectory($path) {
1164 // Calculation needed, when TYPO3 source is used via a symlink
1165 // absolute path to the stylesheets
1166 $filePath = dirname(GeneralUtility::getIndpEnv('SCRIPT_FILENAME')) . '/' . $GLOBALS['BACK_PATH'] . $path;
1167 // Clean the path
1168 $resolvedPath = GeneralUtility::resolveBackPath($filePath);
1169 // Read all files in directory and sort them alphabetically
1170 $files = GeneralUtility::getFilesInDir($resolvedPath, 'css', FALSE, 1);
1171 foreach ($files as $file) {
1172 $this->pageRenderer->addCssFile($GLOBALS['BACK_PATH'] . $path . $file, 'stylesheet', 'all');
1173 }
1174 }
1175
1176 /**
1177 * Insert post rendering document style into already rendered content
1178 * This is needed for extobjbase
1179 *
1180 * @param string $content style-content to insert.
1181 * @return string content with inserted styles
1182 */
1183 public function insertStylesAndJS($content) {
1184 $styles = LF . implode(LF, $this->inDocStylesArray);
1185 $content = str_replace('/*###POSTCSSMARKER###*/', $styles, $content);
1186
1187 // Insert accumulated JS
1188 $jscode = $this->JScode . LF . $this->wrapScriptTags(implode(LF, $this->JScodeArray));
1189 $content = str_replace('<!--###POSTJSMARKER###-->', $jscode, $content);
1190 return $content;
1191 }
1192
1193 /**
1194 * Returns an array of all stylesheet directories belonging to core and skins
1195 *
1196 * @return array Stylesheet directories
1197 */
1198 public function getSkinStylesheetDirectories() {
1199 $stylesheetDirectories = array();
1200 // Add default core stylesheets
1201 foreach ($this->stylesheetsCore as $stylesheetDir) {
1202 $stylesheetDirectories[] = $stylesheetDir;
1203 }
1204 // Stylesheets from skins
1205 // merge default css directories ($this->stylesheetsSkin) with additional ones and include them
1206 if (is_array($GLOBALS['TBE_STYLES']['skins'])) {
1207 // loop over all registered skins
1208 foreach ($GLOBALS['TBE_STYLES']['skins'] as $skinExtKey => $skin) {
1209 $skinStylesheetDirs = $this->stylesheetsSkins;
1210 // Skins can add custom stylesheetDirectories using
1211 // $GLOBALS['TBE_STYLES']['skins'][$_EXTKEY]['stylesheetDirectories']
1212 if (is_array($skin['stylesheetDirectories'])) {
1213 $skinStylesheetDirs = array_merge($skinStylesheetDirs, $skin['stylesheetDirectories']);
1214 }
1215 // Add all registered directories
1216 foreach ($skinStylesheetDirs as $stylesheetDir) {
1217 // for EXT:myskin/stylesheets/ syntax
1218 if (substr($stylesheetDir, 0, 4) === 'EXT:') {
1219 list($extKey, $path) = explode('/', substr($stylesheetDir, 4), 2);
1220 if (!empty($extKey) && ExtensionManagementUtility::isLoaded($extKey) && !empty($path)) {
1221 $stylesheetDirectories[] = ExtensionManagementUtility::extRelPath($extKey) . $path;
1222 }
1223 } else {
1224 // For relative paths
1225 $stylesheetDirectories[] = ExtensionManagementUtility::extRelPath($skinExtKey) . $stylesheetDir;
1226 }
1227 }
1228 }
1229 }
1230 return $stylesheetDirectories;
1231 }
1232
1233 /**
1234 * Returns generator meta tag
1235 *
1236 * @return string <meta> tag with name "generator
1237 */
1238 public function generator() {
1239 $str = 'TYPO3 CMS, ' . TYPO3_URL_GENERAL . ', &#169; Kasper Sk&#229;rh&#248;j ' . TYPO3_copyright_year . ', extensions are copyright of their respective owners.';
1240 return '<meta name="generator" content="' . $str . '" />';
1241 }
1242
1243 /**
1244 * Returns X-UA-Compatible meta tag
1245 *
1246 * @param string $content Content of the compatible tag (default: IE-8)
1247 * @return string <meta http-equiv="X-UA-Compatible" content="???" />
1248 */
1249 public function xUaCompatible($content = 'IE=8') {
1250 return '<meta http-equiv="X-UA-Compatible" content="' . $content . '" />';
1251 }
1252
1253 /*****************************************
1254 *
1255 * OTHER ELEMENTS
1256 * Tables, buttons, formatting dimmed/red strings
1257 *
1258 ******************************************/
1259 /**
1260 * Returns an image-tag with an 18x16 icon of the following types:
1261 *
1262 * $type:
1263 * -1: OK icon (Check-mark)
1264 * 1: Notice (Speach-bubble)
1265 * 2: Warning (Yellow triangle)
1266 * 3: Fatal error (Red stop sign)
1267 *
1268 * @param int $type See description
1269 * @param string $styleAttribValue Value for style attribute
1270 * @return string HTML image tag (if applicable)
1271 */
1272 public function icons($type, $styleAttribValue = '') {
1273 switch ($type) {
1274 case self::STATUS_ICON_ERROR:
1275 $icon = 'status-dialog-error';
1276 break;
1277 case self::STATUS_ICON_WARNING:
1278 $icon = 'status-dialog-warning';
1279 break;
1280 case self::STATUS_ICON_NOTIFICATION:
1281 $icon = 'status-dialog-notification';
1282 break;
1283 case self::STATUS_ICON_OK:
1284 $icon = 'status-dialog-ok';
1285 break;
1286 default:
1287 // Do nothing
1288 }
1289 if ($icon) {
1290 return IconUtility::getSpriteIcon($icon);
1291 }
1292 }
1293
1294 /**
1295 * Returns an <input> button with the $onClick action and $label
1296 *
1297 * @param string $onClick The value of the onclick attribute of the input tag (submit type)
1298 * @param string $label The label for the button (which will be htmlspecialchar'ed)
1299 * @return string A <input> tag of the type "submit
1300 */
1301 public function t3Button($onClick, $label) {
1302 $button = '<input class="btn btn-default" type="submit" onclick="' . htmlspecialchars($onClick) . '; return false;" value="' . htmlspecialchars($label) . '" />';
1303 return $button;
1304 }
1305
1306 /**
1307 * Dimmed-fontwrap. Returns the string wrapped in a <span>-tag defining the color to be gray/dimmed
1308 *
1309 * @param string $string Input string
1310 * @return string Output string
1311 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use proper HTML directly
1312 */
1313 public function dfw($string) {
1314 GeneralUtility::logDeprecatedFunction();
1315 return '<span class="text-muted">' . $string . '</span>';
1316 }
1317
1318 /**
1319 * red-fontwrap. Returns the string wrapped in a <span>-tag defining the color to be red
1320 *
1321 * @param string $string Input string
1322 * @return string Output string
1323 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use proper HTML directly
1324 */
1325 public function rfw($string) {
1326 GeneralUtility::logDeprecatedFunction();
1327 return '<span class="text-danger">' . $string . '</span>';
1328 }
1329
1330 /**
1331 * Returns string wrapped in CDATA "tags" for XML / XHTML (wrap content of <script> and <style> sections in those!)
1332 *
1333 * @param string $string Input string
1334 * @return string Output string
1335 */
1336 public function wrapInCData($string) {
1337 $string = '/*<![CDATA[*/' . $string . '/*]]>*/';
1338 return $string;
1339 }
1340
1341 /**
1342 * Wraps the input string in script tags.
1343 * Automatic re-identing of the JS code is done by using the first line as ident reference.
1344 * This is nice for identing JS code with PHP code on the same level.
1345 *
1346 * @param string $string Input string
1347 * @param bool $linebreak Wrap script element in linebreaks? Default is TRUE.
1348 * @return string Output string
1349 */
1350 public function wrapScriptTags($string, $linebreak = TRUE) {
1351 if (trim($string)) {
1352 // <script wrapped in nl?
1353 $cr = $linebreak ? LF : '';
1354 // Remove nl from the beginning
1355 $string = ltrim($string, LF);
1356 // Re-ident to one tab using the first line as reference
1357 if ($string[0] === TAB) {
1358 $string = TAB . ltrim($string, TAB);
1359 }
1360 $string = $cr . '<script type="text/javascript">
1361 /*<![CDATA[*/
1362 ' . $string . '
1363 /*]]>*/
1364 </script>' . $cr;
1365 }
1366 return trim($string);
1367 }
1368
1369 // These vars defines the layout for the table produced by the table() function.
1370 // You can override these values from outside if you like.
1371 public $tableLayout = array(
1372 'defRow' => array(
1373 'defCol' => array('<td valign="top">', '</td>')
1374 )
1375 );
1376
1377 public $table_TR = '<tr>';
1378
1379 public $table_TABLE = '<table border="0" cellspacing="0" cellpadding="0" class="typo3-dblist" id="typo3-tmpltable">';
1380
1381 /**
1382 * Returns a table based on the input $data
1383 *
1384 * @param array $data Multidim array with first levels = rows, second levels = cells
1385 * @param array $layout If set, then this provides an alternative layout array instead of $this->tableLayout
1386 * @return string The HTML table.
1387 * @internal
1388 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
1389 */
1390 public function table($data, $layout = NULL) {
1391 GeneralUtility::logDeprecatedFunction();
1392 $result = '';
1393 if (is_array($data)) {
1394 $tableLayout = is_array($layout) ? $layout : $this->tableLayout;
1395 $rowCount = 0;
1396 foreach ($data as $tableRow) {
1397 if ($rowCount % 2) {
1398 $layout = is_array($tableLayout['defRowOdd']) ? $tableLayout['defRowOdd'] : $tableLayout['defRow'];
1399 } else {
1400 $layout = is_array($tableLayout['defRowEven']) ? $tableLayout['defRowEven'] : $tableLayout['defRow'];
1401 }
1402 $rowLayout = is_array($tableLayout[$rowCount]) ? $tableLayout[$rowCount] : $layout;
1403 $rowResult = '';
1404 if (is_array($tableRow)) {
1405 $cellCount = 0;
1406 foreach ($tableRow as $tableCell) {
1407 $cellWrap = is_array($layout[$cellCount]) ? $layout[$cellCount] : $layout['defCol'];
1408 $cellWrap = is_array($rowLayout['defCol']) ? $rowLayout['defCol'] : $cellWrap;
1409 $cellWrap = is_array($rowLayout[$cellCount]) ? $rowLayout[$cellCount] : $cellWrap;
1410 $rowResult .= $cellWrap[0] . $tableCell . $cellWrap[1];
1411 $cellCount++;
1412 }
1413 }
1414 $rowWrap = is_array($layout['tr']) ? $layout['tr'] : array($this->table_TR, '</tr>');
1415 $rowWrap = is_array($rowLayout['tr']) ? $rowLayout['tr'] : $rowWrap;
1416 $result .= $rowWrap[0] . $rowResult . $rowWrap[1];
1417 $rowCount++;
1418 }
1419 $tableWrap = is_array($tableLayout['table']) ? $tableLayout['table'] : array($this->table_TABLE, '</table>');
1420 $result = $tableWrap[0] . $result . $tableWrap[1];
1421 }
1422 return $result;
1423 }
1424
1425 /**
1426 * Constructs a table with content from the $arr1, $arr2 and $arr3.
1427 *
1428 * @param array $arr1 Menu elements on first level
1429 * @param array $arr2 Secondary items
1430 * @param array $arr3 Third-level items
1431 * @return string HTML content, <table>...</table>
1432 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
1433 */
1434 public function menuTable($arr1, $arr2 = array(), $arr3 = array()) {
1435 GeneralUtility::logDeprecatedFunction();
1436 $rows = max(array(count($arr1), count($arr2), count($arr3)));
1437 $menu = '
1438 <table border="0" cellpadding="0" cellspacing="0" id="typo3-tablemenu">';
1439 for ($a = 0; $a < $rows; $a++) {
1440 $menu .= '<tr>';
1441 $cls = array();
1442 $valign = 'middle';
1443 $cls[] = '<td valign="' . $valign . '">' . $arr1[$a][0] . '</td><td>' . $arr1[$a][1] . '</td>';
1444 if (!empty($arr2)) {
1445 $cls[] = '<td valign="' . $valign . '">' . $arr2[$a][0] . '</td><td>' . $arr2[$a][1] . '</td>';
1446 if (!empty($arr3)) {
1447 $cls[] = '<td valign="' . $valign . '">' . $arr3[$a][0] . '</td><td>' . $arr3[$a][1] . '</td>';
1448 }
1449 }
1450 $menu .= implode($cls, '<td>&nbsp;&nbsp;</td>');
1451 $menu .= '</tr>';
1452 }
1453 $menu .= '
1454 </table>
1455 ';
1456 return $menu;
1457 }
1458
1459 /**
1460 * Returns a one-row/two-celled table with $content and $menu side by side.
1461 * The table is a 100% width table and each cell is aligned left / right
1462 *
1463 * @param string $content Content cell content (left)
1464 * @param string $menu Menu cell content (right)
1465 * @return string HTML output
1466 */
1467 public function funcMenu($content, $menu) {
1468 return '
1469 <table border="0" cellpadding="0" cellspacing="0" width="100%" id="typo3-funcmenu">
1470 <tr>
1471 <td valign="top" nowrap="nowrap">' . $content . '</td>
1472 <td valign="top" align="right" nowrap="nowrap">' . $menu . '</td>
1473 </tr>
1474 </table>';
1475 }
1476
1477 /**
1478 * Includes a javascript library that exists in the core /typo3/ directory
1479 *
1480 * @param string $lib: Library name. Call it with the full path like "sysext/core/Resources/Public/JavaScript/QueryGenerator.js" to load it
1481 * @return void
1482 */
1483 public function loadJavascriptLib($lib) {
1484 // @todo: maybe we can remove this one as well
1485 $this->pageRenderer->addJsFile($lib);
1486 }
1487
1488 /**
1489 * Includes the necessary Javascript function for the clickmenu (context sensitive menus) in the document
1490 *
1491 * @return void
1492 */
1493 public function getContextMenuCode() {
1494 $this->pageRenderer->loadJquery();
1495 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ClickMenu');
1496 }
1497
1498 /**
1499 * Includes the necessary javascript file for use on pages which have the
1500 * drag and drop functionality (legacy folder tree)
1501 *
1502 * @param string $table indicator of which table the drag and drop function should work on (pages or folders)
1503 * @param string $additionalJavaScriptCode adds more code to the additional javascript code
1504 * @return void
1505 */
1506 public function getDragDropCode($table, $additionalJavaScriptCode = '') {
1507 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LegacyTree', 'function() {
1508 DragDrop.table = "' . $table . '";
1509 ' . $additionalJavaScriptCode . '
1510 }');
1511 }
1512
1513 /**
1514 * This loads everything needed for the Context Sensitive Help (CSH)
1515 *
1516 * @return void
1517 */
1518 protected function loadCshJavascript() {
1519 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextHelp');
1520 $this->pageRenderer->addInlineSetting('ContextHelp', 'moduleUrl', BackendUtility::getModuleUrl('help_CshmanualCshmanual', array(
1521 'tx_cshmanual_help_cshmanualcshmanual' => array(
1522 'controller' => 'Help',
1523 'action' => 'detail'
1524 )
1525 )));
1526 }
1527
1528 /**
1529 * Creates a tab menu from an array definition
1530 *
1531 * Returns a tab menu for a module
1532 * Requires the JS function jumpToUrl() to be available
1533 *
1534 * @param mixed $mainParams is the "&id=" parameter value to be sent to the module, but it can be also a parameter array which will be passed instead of the &id=...
1535 * @param string $elementName it the form elements name, probably something like "SET[...]
1536 * @param string $currentValue is the value to be selected currently.
1537 * @param array $menuItems is an array with the menu items for the selector box
1538 * @param string $script is the script to send the &id to, if empty it's automatically found
1539 * @param string $addparams is additional parameters to pass to the script.
1540 * @return string HTML code for tab menu
1541 */
1542 public function getTabMenu($mainParams, $elementName, $currentValue, $menuItems, $script = '', $addparams = '') {
1543 $content = '';
1544 if (is_array($menuItems)) {
1545 if (!is_array($mainParams)) {
1546 $mainParams = array('id' => $mainParams);
1547 }
1548 $mainParams = GeneralUtility::implodeArrayForUrl('', $mainParams);
1549 if (!$script) {
1550 $script = basename(PATH_thisScript);
1551 }
1552 $menuDef = array();
1553 foreach ($menuItems as $value => $label) {
1554 $menuDef[$value]['isActive'] = (string)$currentValue === (string)$value;
1555 $menuDef[$value]['label'] = htmlspecialchars($label, ENT_COMPAT, 'UTF-8', FALSE);
1556 $menuDef[$value]['url'] = $script . '?' . $mainParams . $addparams . '&' . $elementName . '=' . $value;
1557 }
1558 $content = $this->getTabMenuRaw($menuDef);
1559 }
1560 return $content;
1561 }
1562
1563 /**
1564 * Creates the HTML content for the tab menu
1565 *
1566 * @param array $menuItems Menu items for tabs
1567 * @return string Table HTML
1568 * @access private
1569 */
1570 public function getTabMenuRaw($menuItems) {
1571 if (!is_array($menuItems)) {
1572 return '';
1573 }
1574
1575 $options = '';
1576 foreach ($menuItems as $id => $def) {
1577 $class = $def['isActive'] ? 'active' : '';
1578 $label = $def['label'];
1579 $url = htmlspecialchars($def['url']);
1580 $params = $def['addParams'];
1581
1582 $options .= '<li class="' . $class . '">' .
1583 '<a href="' . $url . '" ' . $params . '>' . $label . '</a>' .
1584 '</li>';
1585 }
1586
1587 return '<ul class="nav nav-tabs" role="tablist">' .
1588 $options .
1589 '</ul>';
1590
1591 }
1592
1593 /**
1594 * Creates a DYNAMIC tab-menu where the tabs or collapseable are rendered with bootstrap markup
1595 *
1596 * @param array $menuItems Numeric array where each entry is an array in itself with associative keys: "label" contains the label for the TAB, "content" contains the HTML content that goes into the div-layer of the tabs content. "description" contains description text to be shown in the layer. "linkTitle" is short text for the title attribute of the tab-menu link (mouse-over text of tab). "stateIcon" indicates a standard status icon (see ->icon(), values: -1, 1, 2, 3). "icon" is an image tag placed before the text.
1597 * @param string $identString Identification string. This should be unique for every instance of a dynamic menu!
1598 * @param int $defaultTabIndex Default tab to open (for toggle <=0). Value corresponds to integer-array index + 1 (index zero is "1", index "1" is 2 etc.). A value of zero (or something non-existing) will result in no default tab open.
1599 * @param bool $collapseable If set, the tabs are rendered as headers instead over each sheet. Effectively this means there is no tab menu, but rather a foldout/foldin menu.
1600 * @param bool $wrapContent If set, the content is wrapped in div structure which provides a padding and border style. Set this FALSE to get unstyled content pane with fullsize content area.
1601 * @param bool $storeLastActiveTab If set, the last open tab is stored in local storage and will be re-open again. If you don't need this feature, e.g. for wizards like import/export you can disable this behaviour.
1602 * @return string
1603 */
1604 public function getDynamicTabMenu(array $menuItems, $identString, $defaultTabIndex = 1, $collapseable = FALSE, $wrapContent = TRUE, $storeLastActiveTab = TRUE) {
1605 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Tabs');
1606 $templatePathAndFileName = 'EXT:backend/Resources/Private/Templates/DocumentTemplate/' . ($collapseable ? 'Collapse.html' : 'Tabs.html');
1607 $view = GeneralUtility::makeInstance(StandaloneView::class);
1608 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templatePathAndFileName));
1609 $view->assignMultiple(array(
1610 'id' => $this->getDynTabMenuId($identString),
1611 'items' => $menuItems,
1612 'defaultTabIndex' => $defaultTabIndex,
1613 'wrapContent' => $wrapContent,
1614 'storeLastActiveTab' => $storeLastActiveTab,
1615 'BACK_PATH' => $GLOBALS['BACK_PATH']
1616 ));
1617 return $view->render();
1618 }
1619
1620 /**
1621 * Creates a DYNAMIC tab-menu where the tabs are switched between with DHTML.
1622 * Should work in MSIE, Mozilla, Opera and Konqueror. On Konqueror I did find a serious problem: <textarea> fields loose their content when you switch tabs!
1623 *
1624 * @param array $menuItems Numeric array where each entry is an array in itself with associative keys: "label" contains the label for the TAB, "content" contains the HTML content that goes into the div-layer of the tabs content. "description" contains description text to be shown in the layer. "linkTitle" is short text for the title attribute of the tab-menu link (mouse-over text of tab). "stateIcon" indicates a standard status icon (see ->icon(), values: -1, 1, 2, 3). "icon" is an image tag placed before the text.
1625 * @param string $identString Identification string. This should be unique for every instance of a dynamic menu!
1626 * @param int $toggle If "1", then enabling one tab does not hide the others - they simply toggles each sheet on/off. This makes most sense together with the $foldout option. If "-1" then it acts normally where only one tab can be active at a time BUT you can click a tab and it will close so you have no active tabs.
1627 * @param bool $foldout If set, the tabs are rendered as headers instead over each sheet. Effectively this means there is no tab menu, but rather a foldout/foldin menu. Make sure to set $toggle as well for this option.
1628 * @param bool $noWrap Deprecated - delivered by CSS
1629 * @param bool $fullWidth If set, the tabs will span the full width of their position
1630 * @param int $defaultTabIndex Default tab to open (for toggle <=0). Value corresponds to integer-array index + 1 (index zero is "1", index "1" is 2 etc.). A value of zero (or something non-existing) will result in no default tab open.
1631 * @param int $tabBehaviour If set to '1' empty tabs will be remove, If set to '2' empty tabs will be disabled. setting this option to '2' is deprecated since TYPO3 CMS 7, and will be removed iwth CMS 8
1632 * @return string JavaScript section for the HTML header.
1633 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
1634 */
1635 public function getDynTabMenu($menuItems, $identString, $toggle = 0, $foldout = FALSE, $noWrap = TRUE, $fullWidth = FALSE, $defaultTabIndex = 1, $tabBehaviour = 1) {
1636 GeneralUtility::logDeprecatedFunction();
1637 return $this->getDynamicTabMenu($menuItems, $identString, $defaultTabIndex, $foldout, $noWrap);
1638 }
1639
1640 /**
1641 * Creates the id for dynTabMenus.
1642 *
1643 * @param string $identString Identification string. This should be unique for every instance of a dynamic menu!
1644 * @return string The id with a short MD5 of $identString and prefixed "DTM-", like "DTM-2e8791854a
1645 */
1646 public function getDynTabMenuId($identString) {
1647 $id = 'DTM-' . GeneralUtility::shortMD5($identString);
1648 return $id;
1649 }
1650
1651 /**
1652 * Creates the version selector for the page id inputted.
1653 * Requires the core version management extension, "version" to be loaded.
1654 *
1655 * @param int $id Page id to create selector for.
1656 * @param bool $noAction If set, there will be no button for swapping page.
1657 * @return string
1658 */
1659 public function getVersionSelector($id, $noAction = FALSE) {
1660 if (
1661 ExtensionManagementUtility::isLoaded('version') &&
1662 !ExtensionManagementUtility::isLoaded('workspaces')
1663 ) {
1664 $versionGuiObj = GeneralUtility::makeInstance(\TYPO3\CMS\Version\View\VersionView::class);
1665 return $versionGuiObj->getVersionSelector($id, $noAction);
1666 }
1667 }
1668
1669 /**
1670 * Function to load a HTML template file with markers.
1671 * When calling from own extension, use syntax getHtmlTemplate('EXT:extkey/template.html')
1672 *
1673 * @param string $filename tmpl name, usually in the typo3/template/ directory
1674 * @return string HTML of template
1675 */
1676 public function getHtmlTemplate($filename) {
1677 // setting the name of the original HTML template
1678 $this->moduleTemplateFilename = $filename;
1679 if ($GLOBALS['TBE_STYLES']['htmlTemplates'][$filename]) {
1680 $filename = $GLOBALS['TBE_STYLES']['htmlTemplates'][$filename];
1681 }
1682 if (GeneralUtility::isFirstPartOfStr($filename, 'EXT:')) {
1683 $filename = GeneralUtility::getFileAbsFileName($filename, TRUE, TRUE);
1684 } elseif (!GeneralUtility::isAbsPath($filename)) {
1685 $filename = GeneralUtility::resolveBackPath($filename);
1686 } elseif (!GeneralUtility::isAllowedAbsPath($filename)) {
1687 $filename = '';
1688 }
1689 $htmlTemplate = '';
1690 if ($filename !== '') {
1691 $htmlTemplate = GeneralUtility::getUrl($filename);
1692 }
1693 return $htmlTemplate;
1694 }
1695
1696 /**
1697 * Define the template for the module
1698 *
1699 * @param string $filename filename
1700 * @return void
1701 */
1702 public function setModuleTemplate($filename) {
1703 $this->moduleTemplate = $this->getHtmlTemplate($filename);
1704 }
1705
1706 /**
1707 * Put together the various elements for the module <body> using a static HTML
1708 * template
1709 *
1710 * @param array $pageRecord Record of the current page, used for page path and info
1711 * @param array $buttons HTML for all buttons
1712 * @param array $markerArray HTML for all other markers
1713 * @param array $subpartArray HTML for the subparts
1714 * @return string Composite HTML
1715 */
1716 public function moduleBody($pageRecord = array(), $buttons = array(), $markerArray = array(), $subpartArray = array()) {
1717 // Get the HTML template for the module
1718 $moduleBody = HtmlParser::getSubpart($this->moduleTemplate, '###FULLDOC###');
1719 // Add CSS
1720 $this->inDocStylesArray[] = 'html { overflow: hidden; }';
1721 // Get the page path for the docheader
1722 $markerArray['PAGEPATH'] = $this->getPagePath($pageRecord);
1723 // Get the page info for the docheader
1724 $markerArray['PAGEINFO'] = $this->getPageInfo($pageRecord);
1725 // Get all the buttons for the docheader
1726 $docHeaderButtons = $this->getDocHeaderButtons($buttons);
1727 // Merge docheader buttons with the marker array
1728 $markerArray = array_merge($markerArray, $docHeaderButtons);
1729 // replacing subparts
1730 foreach ($subpartArray as $marker => $content) {
1731 $moduleBody = HtmlParser::substituteSubpart($moduleBody, $marker, $content);
1732 }
1733 // adding flash messages
1734 if ($this->showFlashMessages) {
1735 $flashMessages = $this->getFlashMessages();
1736 if (!empty($flashMessages)) {
1737 $markerArray['FLASHMESSAGES'] = $flashMessages;
1738 // If there is no dedicated marker for the messages present
1739 // then force them to appear before the content
1740 if (strpos($moduleBody, '###FLASHMESSAGES###') === FALSE) {
1741 $moduleBody = str_replace('###CONTENT###', '###FLASHMESSAGES######CONTENT###', $moduleBody);
1742 }
1743 }
1744 }
1745 // Hook for adding more markers/content to the page, like the version selector
1746 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['moduleBodyPostProcess'])) {
1747 $params = array(
1748 'moduleTemplateFilename' => &$this->moduleTemplateFilename,
1749 'moduleTemplate' => &$this->moduleTemplate,
1750 'moduleBody' => &$moduleBody,
1751 'markers' => &$markerArray,
1752 'parentObject' => &$this
1753 );
1754 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['moduleBodyPostProcess'] as $funcRef) {
1755 GeneralUtility::callUserFunction($funcRef, $params, $this);
1756 }
1757 }
1758 // Replacing all markers with the finished markers and return the HTML content
1759 return HtmlParser::substituteMarkerArray($moduleBody, $markerArray, '###|###');
1760 }
1761
1762 /**
1763 * Get the default rendered FlashMessages from queue
1764 *
1765 * @return string
1766 */
1767 public function getFlashMessages() {
1768 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
1769 $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
1770 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
1771 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
1772 return $defaultFlashMessageQueue->renderFlashMessages();
1773 }
1774
1775 /**
1776 * Renders the FlashMessages from queue and returns them as AJAX.
1777 *
1778 * @param array $params Always empty.
1779 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj The AjaxRequestHandler object used to return content and set content types
1780 * @return void
1781 */
1782 public function renderFlashMessages(array $params, \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj) {
1783 $ajaxObj->addContent('result', $this->getFlashMessages());
1784 $ajaxObj->setContentFormat('html');
1785 }
1786
1787 /**
1788 * Fill the button lists with the defined HTML
1789 *
1790 * @param array $buttons HTML for all buttons
1791 * @return array Containing HTML for both buttonlists
1792 */
1793 protected function getDocHeaderButtons($buttons) {
1794 $markers = array();
1795 // Fill buttons for left and right float
1796 $floats = array('left', 'right');
1797 foreach ($floats as $key) {
1798 // Get the template for each float
1799 $buttonTemplate = HtmlParser::getSubpart($this->moduleTemplate, '###BUTTON_GROUPS_' . strtoupper($key) . '###');
1800 // Fill the button markers in this float
1801 $buttonTemplate = HtmlParser::substituteMarkerArray($buttonTemplate, $buttons, '###|###', TRUE);
1802 // getting the wrap for each group
1803 $buttonWrap = HtmlParser::getSubpart($this->moduleTemplate, '###BUTTON_GROUP_WRAP###');
1804 // looping through the groups (max 6) and remove the empty groups
1805 for ($groupNumber = 1; $groupNumber < 6; $groupNumber++) {
1806 $buttonMarker = '###BUTTON_GROUP' . $groupNumber . '###';
1807 $buttonGroup = HtmlParser::getSubpart($buttonTemplate, $buttonMarker);
1808 if (trim($buttonGroup)) {
1809 if ($buttonWrap) {
1810 $buttonGroup = HtmlParser::substituteMarker($buttonWrap, '###BUTTONS###', $buttonGroup);
1811 }
1812 $buttonTemplate = HtmlParser::substituteSubpart($buttonTemplate, $buttonMarker, trim($buttonGroup));
1813 }
1814 }
1815 // Replace the marker with the template and remove all line breaks (for IE compat)
1816 $markers['BUTTONLIST_' . strtoupper($key)] = str_replace(LF, '', $buttonTemplate);
1817 }
1818 // Hook for manipulating docHeaderButtons
1819 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['docHeaderButtonsHook'])) {
1820 $params = array(
1821 'buttons' => $buttons,
1822 'markers' => &$markers,
1823 'pObj' => &$this
1824 );
1825 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['docHeaderButtonsHook'] as $funcRef) {
1826 GeneralUtility::callUserFunction($funcRef, $params, $this);
1827 }
1828 }
1829 return $markers;
1830 }
1831
1832 /**
1833 * Generate the page path for docheader
1834 *
1835 * @param array $pageRecord Current page
1836 * @return string Page path
1837 */
1838 protected function getPagePath($pageRecord) {
1839 // Is this a real page
1840 if (is_array($pageRecord) && $pageRecord['uid']) {
1841 $title = substr($pageRecord['_thePathFull'], 0, -1);
1842 // Remove current page title
1843 $pos = strrpos($title, $pageRecord['title']);
1844 if ($pos !== FALSE) {
1845 $title = substr($title, 0, $pos);
1846 }
1847 } else {
1848 $title = '';
1849 }
1850 // Setting the path of the page
1851 $pagePath = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.path', TRUE) . ': <span class="typo3-docheader-pagePath">';
1852 // crop the title to title limit (or 50, if not defined)
1853 $cropLength = empty($GLOBALS['BE_USER']->uc['titleLen']) ? 50 : $GLOBALS['BE_USER']->uc['titleLen'];
1854 $croppedTitle = GeneralUtility::fixed_lgd_cs($title, -$cropLength);
1855 if ($croppedTitle !== $title) {
1856 $pagePath .= '<abbr title="' . htmlspecialchars($title) . '">' . htmlspecialchars($croppedTitle) . '</abbr>';
1857 } else {
1858 $pagePath .= htmlspecialchars($title);
1859 }
1860 $pagePath .= '</span>';
1861 return $pagePath;
1862 }
1863
1864 /**
1865 * Setting page icon with clickmenu + uid for docheader
1866 *
1867 * @param array $pageRecord Current page
1868 * @return string Page info
1869 */
1870 protected function getPageInfo($pageRecord) {
1871 // Add icon with clickmenu, etc:
1872 // If there IS a real page
1873 if (is_array($pageRecord) && $pageRecord['uid']) {
1874 $alttext = BackendUtility::getRecordIconAltText($pageRecord, 'pages');
1875 $iconImg = IconUtility::getSpriteIconForRecord('pages', $pageRecord, array('title' => $alttext));
1876 // Make Icon:
1877 $theIcon = $GLOBALS['SOBE']->doc->wrapClickMenuOnIcon($iconImg, 'pages', $pageRecord['uid']);
1878 $uid = $pageRecord['uid'];
1879 $title = BackendUtility::getRecordTitle('pages', $pageRecord);
1880 } else {
1881 // On root-level of page tree
1882 // Make Icon
1883 $iconImg = IconUtility::getSpriteIcon('apps-pagetree-root', array('title' => htmlspecialchars($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'])));
1884 if ($GLOBALS['BE_USER']->user['admin']) {
1885 $theIcon = $GLOBALS['SOBE']->doc->wrapClickMenuOnIcon($iconImg, 'pages', 0);
1886 } else {
1887 $theIcon = $iconImg;
1888 }
1889 $uid = '0';
1890 $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
1891 }
1892 // Setting icon with clickmenu + uid
1893 $pageInfo = $theIcon . '<strong>' . htmlspecialchars($title) . '&nbsp;[' . $uid . ']</strong>';
1894 return $pageInfo;
1895 }
1896
1897 /**
1898 * Makes a collapseable section. See reports module for an example
1899 *
1900 * @param string $title
1901 * @param string $html
1902 * @param string $id
1903 * @param string $saveStatePointer
1904 * @return string
1905 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use HTML bootstrap classes, localStorage etc.
1906 */
1907 public function collapseableSection($title, $html, $id, $saveStatePointer = '') {
1908 GeneralUtility::logDeprecatedFunction();
1909 $hasSave = (bool)$saveStatePointer;
1910 $collapsedStyle = ($collapsedClass = '');
1911 if ($hasSave) {
1912 /** @var $userSettingsController \TYPO3\CMS\Backend\Controller\UserSettingsController */
1913 $userSettingsController = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Controller\UserSettingsController::class);
1914 $value = $userSettingsController->process('get', $saveStatePointer . '.' . $id);
1915 if ($value) {
1916 $collapsedStyle = ' style="display: none"';
1917 $collapsedClass = ' collapsed';
1918 } else {
1919 $collapsedStyle = '';
1920 $collapsedClass = ' expanded';
1921 }
1922 }
1923 $this->pageRenderer->loadExtJS();
1924 $this->pageRenderer->addExtOnReadyCode('
1925 Ext.select("h2.section-header").each(function(element){
1926 element.on("click", function(event, tag) {
1927 var state = 0,
1928 el = Ext.fly(tag),
1929 div = el.next("div"),
1930 saveKey = el.getAttribute("rel");
1931 if (el.hasClass("collapsed")) {
1932 el.removeClass("collapsed").addClass("expanded");
1933 div.slideIn("t", {
1934 easing: "easeIn",
1935 duration: .5
1936 });
1937 } else {
1938 el.removeClass("expanded").addClass("collapsed");
1939 div.slideOut("t", {
1940 easing: "easeOut",
1941 duration: .5,
1942 remove: false,
1943 useDisplay: true
1944 });
1945 state = 1;
1946 }
1947 if (saveKey) {
1948 try {
1949 top.TYPO3.Storage.Persistent.set(saveKey + "." + tag.id, state);
1950 } catch(e) {}
1951 }
1952 });
1953 });
1954 ');
1955 return '
1956 <h2 id="' . $id . '" class="section-header' . $collapsedClass . '" rel="' . $saveStatePointer . '"> ' . $title . '</h2>
1957 <div' . $collapsedStyle . '>' . $html . '</div>
1958 ';
1959 }
1960
1961 /**
1962 * Retrieves configured favicon for backend (with fallback)
1963 *
1964 * @return string
1965 */
1966 protected function getBackendFavicon() {
1967 return $GLOBALS['TBE_STYLES']['favicon'] ?: 'sysext/backend/Resources/Public/Icons/favicon.ico';
1968 }
1969
1970 }