2 namespace TYPO3\CMS\Backend\Template
;
5 * This file is part of the TYPO3 CMS project.
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.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
17 use Psr\Http\Message\ResponseInterface
;
18 use Psr\Http\Message\ServerRequestInterface
;
19 use TYPO3\CMS\Backend\Utility\BackendUtility
;
20 use TYPO3\CMS\Core\Imaging\Icon
;
21 use TYPO3\CMS\Core\Imaging\IconFactory
;
22 use TYPO3\CMS\Core\Page\PageRenderer
;
23 use TYPO3\CMS\Core\Service\MarkerBasedTemplateService
;
24 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility
;
25 use TYPO3\CMS\Core\Utility\GeneralUtility
;
28 * TYPO3 Backend Template Class
30 * This class contains functions for starting and ending the HTML of backend modules
31 * It also contains methods for outputting sections of content.
32 * Further there are functions for making icons, links, setting form-field widths etc.
33 * Color scheme and stylesheet definitions are also available here.
34 * Finally this file includes the language class for TYPO3's backend.
36 * After this file $LANG and $TBE_TEMPLATE are global variables / instances of their respective classes.
38 * Please refer to Inside TYPO3 for a discussion of how to use this API.
40 class DocumentTemplate
42 // Vars you typically might want to/should set from outside after making instance of this class:
44 * This can be set to the HTML-code for a formtag.
45 * Useful when you need a form to span the whole page; Inserted exactly after the body-tag.
52 * Additional header code (eg. a JavaScript section) could be accommulated in this var. It will be directly outputted in the header.
59 * Additional header code for ExtJS. It will be included in document header and inserted in a Ext.onReady(function()
63 public $extJScode = '';
66 * 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.
70 public $JScodeArray = array('jumpToUrl' => '
71 function jumpToUrl(URL) {
72 window.location.href = URL;
78 * 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.
82 public $postCode = '';
85 * HTML template with markers for module
89 public $moduleTemplate = '';
92 * The base file (not overlaid by TBE_STYLES) for the current module, useful for hooks when finding out which modules is rendered currently
96 protected $moduleTemplateFilename = '';
103 public $scriptID = '';
106 * Id which can be set for the body tag. Default value is based on script ID
110 public $bodyTagId = '';
113 * You can add additional attributes to the body-tag through this variable.
117 public $bodyTagAdditions = '';
120 * Additional CSS styles which will be added to the <style> section in the header
121 * used as array with associative keys to prevent double inclusion of CSS code
125 public $inDocStylesArray = array();
128 * Compensation for large documents (used in \TYPO3\CMS\Backend\Form\FormEngine)
132 public $form_largeComp = 1.33;
135 * Filename of stylesheet (relative to PATH_typo3)
139 public $styleSheetFile = '';
142 * Filename of stylesheet #2 - linked to right after the $this->styleSheetFile script (relative to PATH_typo3)
146 public $styleSheetFile2 = '';
149 * Filename of a post-stylesheet - included right after all inline styles.
153 public $styleSheetFile_post = '';
156 * Whether to use the X-UA-Compatible meta tag
160 protected $useCompatibilityTag = true;
163 * X-Ua-Compatible version output in meta tag
167 protected $xUaCompatibilityVersion = 'IE=edge';
171 * Include these CSS directories from skins by default
175 protected $stylesheetsSkins = array(
176 'structure' => 'Resources/Public/Css/structure/',
177 'visual' => 'Resources/Public/Css/visual/'
181 * JavaScript files loaded for every page in the Backend
185 protected $jsFiles = array();
188 * JavaScript files loaded for every page in the Backend, but explicitly excluded from concatenation (useful for libraries etc.)
192 protected $jsFilesNoConcatenation = array();
195 * Indicates if a <div>-output section is open
200 public $sectionFlag = 0;
203 * (Default) Class for wrapping <DIV>-tag of page. Is set in class extensions.
207 public $divClass = '';
212 public $pageHeaderBlock = '';
217 public $endOfPageJsBlock = '';
222 public $hasDocheader = true;
227 protected $pageRenderer = null;
230 * Alternative template file
234 protected $pageHeaderFooterTemplateFile = '';
239 protected $extDirectStateProvider = false;
242 * Whether flashmessages should be rendered or not
244 * @var bool $showFlashMessages
246 public $showFlashMessages = true;
251 protected $iconFactory;
254 * @var MarkerBasedTemplateService
256 protected $templateService;
258 const STATUS_ICON_ERROR
= 3;
259 const STATUS_ICON_WARNING
= 2;
260 const STATUS_ICON_NOTIFICATION
= 1;
261 const STATUS_ICON_OK
= -1;
266 public function __construct()
268 // Initializes the page rendering object:
269 $this->initPageRenderer();
271 // load Legacy CSS Support
272 $this->pageRenderer
->loadRequireJsModule('TYPO3/CMS/Backend/LegacyCssClasses');
273 $this->iconFactory
= GeneralUtility
::makeInstance(IconFactory
::class);
275 // initialize Marker Support
276 $this->templateService
= GeneralUtility
::makeInstance(MarkerBasedTemplateService
::class);
278 // Setting default scriptID:
279 $this->scriptID
= GeneralUtility
::_GET('M') !== null ? GeneralUtility
::_GET('M') : GeneralUtility
::_GET('route');
280 $this->bodyTagId
= preg_replace('/[^A-Za-z0-9-]/', '-', $this->scriptID
);
281 // Individual configuration per script? If so, make a recursive merge of the arrays:
282 if (is_array($GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID
])) {
284 $ovr = $GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID
];
286 \TYPO3\CMS\Core\Utility\ArrayUtility
::mergeRecursiveWithOverrule($GLOBALS['TBE_STYLES'], $ovr);
287 // Have to unset - otherwise the second instantiation will do it again!
288 unset($GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID
]);
291 if ($GLOBALS['TBE_STYLES']['stylesheet']) {
292 $this->styleSheetFile
= $GLOBALS['TBE_STYLES']['stylesheet'];
294 if ($GLOBALS['TBE_STYLES']['stylesheet2']) {
295 $this->styleSheetFile2
= $GLOBALS['TBE_STYLES']['stylesheet2'];
297 if ($GLOBALS['TBE_STYLES']['styleSheetFile_post']) {
298 $this->styleSheetFile_post
= $GLOBALS['TBE_STYLES']['styleSheetFile_post'];
300 if ($GLOBALS['TBE_STYLES']['inDocStyles_TBEstyle']) {
301 $this->inDocStylesArray
['TBEstyle'] = $GLOBALS['TBE_STYLES']['inDocStyles_TBEstyle'];
303 // include all stylesheets
304 foreach ($this->getSkinStylesheetDirectories() as $stylesheetDirectory) {
305 $this->addStylesheetDirectory($stylesheetDirectory);
308 if ($GLOBALS['TBE_STYLES']['background']) {
309 GeneralUtility
::deprecationLog('Usage of $TBE_STYLES["background"] is deprecated. Please use stylesheets directly.');
314 * Initializes the page renderer object
316 protected function initPageRenderer()
318 if ($this->pageRenderer
!== null) {
321 $this->pageRenderer
= GeneralUtility
::makeInstance(PageRenderer
::class);
322 $this->pageRenderer
->setLanguage($GLOBALS['LANG']->lang
);
323 $this->pageRenderer
->enableConcatenateFiles();
324 $this->pageRenderer
->enableCompressCss();
325 $this->pageRenderer
->enableCompressJavascript();
326 // Add all JavaScript files defined in $this->jsFiles to the PageRenderer
327 foreach ($this->jsFilesNoConcatenation
as $file) {
328 $this->pageRenderer
->addJsFile(
337 // Add all JavaScript files defined in $this->jsFiles to the PageRenderer
338 foreach ($this->jsFiles
as $file) {
339 $this->pageRenderer
->addJsFile($file);
341 if ((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['debug'] === 1) {
342 $this->pageRenderer
->enableDebugMode();
347 * Sets inclusion of StateProvider
351 public function setExtDirectStateProvider()
353 $this->extDirectStateProvider
= true;
356 /*****************************************
358 * EVALUATION FUNCTIONS
359 * Various centralized processing
361 *****************************************/
364 * Makes link to page $id in frontend (view page)
365 * Returns an icon which links to the frontend index.php document for viewing the page with id $id
366 * $id must be a page-uid
367 * If the BE_USER has access to Web>List then a link to that module is shown as well (with return-url)
369 * @param int $id The page id
370 * @return string HTML string with linked icon(s)
372 public function viewPageIcon($id)
374 // If access to Web>List for user, then link to that module.
375 $str = BackendUtility
::getListViewLink(array(
377 'returnUrl' => GeneralUtility
::getIndpEnv('REQUEST_URI')
378 ), $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.showList'));
379 // Make link to view page
380 $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
)->render() . '</a>';
385 * Makes the header (icon+title) for a page (or other record). Used in most modules under Web>*
386 * $table and $row must be a tablename/record from that table
387 * $path will be shown as alt-text for the icon.
388 * The title will be truncated to 45 chars.
390 * @param string $table Table name
391 * @param array $row Record row
392 * @param string $path Alt text
393 * @param bool $noViewPageIcon Set $noViewPageIcon TRUE if you don't want a magnifier-icon for viewing the page in the frontend
394 * @param array $tWrap is an array with indexes 0 and 1 each representing HTML-tags (start/end) which will wrap the title
395 * @param bool $enableClickMenu If TRUE, render click menu code around icon image
396 * @return string HTML content
398 public function getHeader($table, $row, $path, $noViewPageIcon = false, $tWrap = array('', ''), $enableClickMenu = true)
401 if (is_array($row) && $row['uid']) {
402 $iconImgTag = '<span title="' . htmlspecialchars($path) . '">' . $this->iconFactory
->getIconForRecord($table, $row, Icon
::SIZE_SMALL
)->render() . '</span>';
403 $title = strip_tags(BackendUtility
::getRecordTitle($table, $row));
404 $viewPage = $noViewPageIcon ?
'' : $this->viewPageIcon($row['uid']);
406 $iconImgTag = '<span title="' . htmlspecialchars($path) . '">' . $this->iconFactory
->getIcon('apps-pagetree-page-domain', Icon
::SIZE_SMALL
)->render() . '</span>';
407 $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
410 if ($enableClickMenu) {
411 $iconImgTag = BackendUtility
::wrapClickMenuOnIcon($iconImgTag, $table, $row['uid']);
414 return '<span class="typo3-moduleHeader">' . $iconImgTag . $viewPage . $tWrap[0] . htmlspecialchars(GeneralUtility
::fixed_lgd_cs($title, 45)) . $tWrap[1] . '</span>';
418 * Like ->getHeader() but for files and folders
419 * Returns the icon with the path of the file/folder set in the alt/title attribute. Shows the name after the icon.
421 * @param \TYPO3\CMS\Core\Resource\ResourceInterface $resource
422 * @param array $tWrap is an array with indexes 0 and 1 each representing HTML-tags (start/end) which will wrap the title
423 * @param bool $enableClickMenu If TRUE, render click menu code around icon image
426 public function getResourceHeader(\TYPO3\CMS\Core\
Resource\ResourceInterface
$resource, $tWrap = array('', ''), $enableClickMenu = true)
429 $path = $resource->getStorage()->getName() . $resource->getParentFolder()->getIdentifier();
430 $iconImgTag = '<span title="' . htmlspecialchars($path) . '">' . $this->iconFactory
->getIconForResource($resource, Icon
::SIZE_SMALL
)->render() . '</span>';
431 } catch (\TYPO3\CMS\Core\
Resource\Exception\ResourceDoesNotExistException
$e) {
435 if ($enableClickMenu && ($resource instanceof \TYPO3\CMS\Core\
Resource\File
)) {
436 $metaData = $resource->_getMetaData();
437 $iconImgTag = BackendUtility
::wrapClickMenuOnIcon($iconImgTag, 'sys_file_metadata', $metaData['uid']);
440 return '<span class="typo3-moduleHeader">' . $iconImgTag . $tWrap[0] . htmlspecialchars(GeneralUtility
::fixed_lgd_cs($resource->getName(), 45)) . $tWrap[1] . '</span>';
444 * Returns a linked shortcut-icon which will call the shortcut frame and set a shortcut there back to the calling page/module
446 * @param string $gvList Is the list of GET variables to store (if any)
447 * @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
448 * @param string $modName Module name string
449 * @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.
450 * @param string $classes
451 * @return string HTML content
453 public function makeShortcutIcon($gvList, $setList, $modName, $motherModName = '', $classes = '')
455 $gvList = 'route,' . $gvList;
456 $storeUrl = $this->makeShortcutUrl($gvList, $setList);
457 $pathInfo = parse_url(GeneralUtility
::getIndpEnv('REQUEST_URI'));
458 // Fallback for alt_mod. We still pass in the old xMOD... stuff, but TBE_MODULES only knows about "record_edit".
459 // We still need to pass the xMOD name to createShortcut below, since this is used for icons.
460 $moduleName = $modName === 'xMOD_alt_doc.php' ?
'record_edit' : $modName;
461 // Add the module identifier automatically if typo3/index.php is used:
462 if (GeneralUtility
::_GET('M') !== null) {
463 $storeUrl = '&M=' . $moduleName . $storeUrl;
465 if ((int)$motherModName === 1) {
466 $motherModule = 'top.currentModuleLoaded';
467 } elseif ($motherModName) {
468 $motherModule = GeneralUtility
::quoteJSvalue($motherModName);
470 $motherModule = '\'\'';
472 $confirmationText = GeneralUtility
::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.makeBookmark'));
474 $shortcutUrl = $pathInfo['path'] . '?' . $storeUrl;
475 $shortcutExist = BackendUtility
::shortcutExists($shortcutUrl);
477 if ($shortcutExist) {
478 return '<a class="active ' . htmlspecialchars($classes) . '" title="">' .
479 $this->iconFactory
->getIcon('actions-system-shortcut-active', Icon
::SIZE_SMALL
)->render() . '</a>';
481 $url = GeneralUtility
::quoteJSvalue(rawurlencode($shortcutUrl));
482 $onClick = 'top.TYPO3.ShortcutMenu.createShortcut(' . GeneralUtility
::quoteJSvalue(rawurlencode($modName)) .
483 ', ' . $url . ', ' . $confirmationText . ', ' . $motherModule . ', this);return false;';
485 return '<a href="#" class="' . htmlspecialchars($classes) . '" onclick="' . htmlspecialchars($onClick) . '" title="' .
486 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.makeBookmark', true) . '">' .
487 $this->iconFactory
->getIcon('actions-system-shortcut-new', Icon
::SIZE_SMALL
)->render() . '</a>';
491 * MAKE url for storing
494 * @param string $gvList Is the list of GET variables to store (if any)
495 * @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
498 * @see makeShortcutIcon()
500 public function makeShortcutUrl($gvList, $setList)
502 $GET = GeneralUtility
::_GET();
503 $storeArray = array_merge(GeneralUtility
::compileSelectedGetVarsFromArray($gvList, $GET), array('SET' => GeneralUtility
::compileSelectedGetVarsFromArray($setList, (array)$GLOBALS['SOBE']->MOD_SETTINGS
)));
504 $storeUrl = GeneralUtility
::implodeArrayForUrl('', $storeArray);
509 * Returns <input> attributes to set the width of an text-type input field.
510 * For client browsers with no CSS support the cols/size attribute is returned.
511 * For CSS compliant browsers (recommended) a ' style="width: ...px;"' is returned.
513 * @param int $size A relative number which multiplied with approx. 10 will lead to the width in pixels
514 * @param bool $textarea A flag you can set for textareas - DEPRECATED as there is no difference any more between the two
515 * @param string $styleOverride A string which will be returned as attribute-value for style="" instead of the calculated width (if CSS is enabled)
516 * @return string Tag attributes for an <input> tag (regarding width)
518 public function formWidth($size = 48, $textarea = false, $styleOverride = '')
520 return ' style="' . ($styleOverride ?
: 'width:' . ceil($size * 9.58) . 'px;') . '"';
524 * Returns JavaScript variables setting the returnUrl and thisScript location for use by JavaScript on the page.
525 * Used in fx. db_list.php (Web>List)
527 * @param string $thisLocation URL to "this location" / current script
528 * @return string Urls are returned as JavaScript variables T3_RETURN_URL and T3_THIS_LOCATION
529 * @see typo3/db_list.php
531 public function redirectUrls($thisLocation = '')
533 $thisLocation = $thisLocation ?
$thisLocation : GeneralUtility
::linkThisScript(array(
540 var T3_RETURN_URL = ' . GeneralUtility
::quoteJSvalue(str_replace('%20', '', rawurlencode(GeneralUtility
::sanitizeLocalUrl(GeneralUtility
::_GP('returnUrl'))))) . ';
541 var T3_THIS_LOCATION = ' . GeneralUtility
::quoteJSvalue(str_replace('%20', '', rawurlencode($thisLocation))) . '
547 * Defines whether to use the X-UA-Compatible meta tag.
549 * @param bool $useCompatibilityTag Whether to use the tag
552 public function useCompatibilityTag($useCompatibilityTag = true)
554 $this->useCompatibilityTag
= (bool)$useCompatibilityTag;
557 /*****************************************
559 * PAGE BUILDING FUNCTIONS.
560 * Use this to build the HTML of your backend modules
562 *****************************************/
565 * This includes the proper header with charset, title, meta tag and beginning body-tag.
567 * @param string $title HTML Page title for the header
568 * @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)
571 public function startPage($title)
573 // hook pre start page
574 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'])) {
575 $preStartPageHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'];
576 if (is_array($preStartPageHook)) {
577 $hookParameters = array(
580 foreach ($preStartPageHook as $hookFunction) {
581 GeneralUtility
::callUserFunction($hookFunction, $hookParameters, $this);
585 // alternative template for Header and Footer
586 if ($this->pageHeaderFooterTemplateFile
) {
587 $file = GeneralUtility
::getFileAbsFileName($this->pageHeaderFooterTemplateFile
, true);
589 $this->pageRenderer
->setTemplateFile($file);
593 // Disable rendering of XHTML tags
594 $this->pageRenderer
->setRenderXhtml(false);
596 $languageCode = $this->pageRenderer
->getLanguage() === 'default' ?
'en' : $this->pageRenderer
->getLanguage();
597 $this->pageRenderer
->setHtmlTag('<html lang="' . $languageCode . '">');
599 $headerStart = '<!DOCTYPE html>';
600 $this->pageRenderer
->setXmlPrologAndDocType($headerStart);
601 $this->pageRenderer
->setHeadTag('<head>' . LF
. '<!-- TYPO3 Script ID: ' . htmlspecialchars($this->scriptID
) . ' -->');
602 header('Content-Type:text/html;charset=utf-8');
603 $this->pageRenderer
->setCharSet('utf-8');
604 $this->pageRenderer
->addMetaTag($this->generator());
605 $this->pageRenderer
->addMetaTag('<meta name="robots" content="noindex,follow">');
606 $this->pageRenderer
->addMetaTag('<meta charset="utf-8">');
607 $this->pageRenderer
->addMetaTag('<meta name="viewport" content="width=device-width, initial-scale=1">');
608 $this->pageRenderer
->setFavIcon($this->getBackendFavicon());
609 if ($this->useCompatibilityTag
) {
610 $this->pageRenderer
->addMetaTag($this->xUaCompatible($this->xUaCompatibilityVersion
));
612 $this->pageRenderer
->setTitle($title);
615 if ($this->extDirectStateProvider
) {
616 $this->pageRenderer
->addJsFile('sysext/backend/Resources/Public/JavaScript/ExtDirect.StateProvider.js');
618 $this->pageRenderer
->addHeaderData($this->JScode
);
619 foreach ($this->JScodeArray
as $name => $code) {
620 $this->pageRenderer
->addJsInlineCode($name, $code, false);
622 if (!empty($this->JScodeLibArray
)) {
623 GeneralUtility
::deprecationLog('DocumentTemplate->JScodeLibArray is deprecated since TYPO3 CMS 7. Use the functionality within pageRenderer directly');
624 foreach ($this->JScodeLibArray
as $library) {
625 $this->pageRenderer
->addHeaderData($library);
628 if ($this->extJScode
) {
629 $this->pageRenderer
->addExtOnReadyCode($this->extJScode
);
632 // Load jquery and twbs JS libraries on every backend request
633 $this->pageRenderer
->loadJquery();
634 // Note: please do not reference "bootstrap" outside of the TYPO3 Core (not in your own extensions)
635 // as this is preliminary as long as Twitter bootstrap does not support AMD modules
636 // this logic will be changed once Twitter bootstrap 4 is included
637 $this->pageRenderer
->addJsFile('sysext/core/Resources/Public/JavaScript/Contrib/bootstrap/bootstrap.js');
639 // hook for additional headerData
640 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'])) {
641 $preHeaderRenderHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'];
642 if (is_array($preHeaderRenderHook)) {
643 $hookParameters = array(
644 'pageRenderer' => &$this->pageRenderer
646 foreach ($preHeaderRenderHook as $hookFunction) {
647 GeneralUtility
::callUserFunction($hookFunction, $hookParameters, $this);
651 // Construct page header.
652 $str = $this->pageRenderer
->render(PageRenderer
::PART_HEADER
);
653 $this->JScode
= ($this->extJScode
= '');
654 $this->JScodeArray
= array();
655 $this->endOfPageJsBlock
= $this->pageRenderer
->render(PageRenderer
::PART_FOOTER
);
656 $str .= $this->docBodyTagBegin() . ($this->divClass ?
'
658 <!-- Wrapping DIV-section for whole page BEGIN -->
659 <div class="' . $this->divClass
. '">
660 ' : '') . trim($this->form
);
665 * Returns page end; This includes finishing form, div, body and html tags.
667 * @return string The HTML end of a page
670 public function endPage()
672 $str = $this->sectionEnd() . $this->postCode
. $this->wrapScriptTags(BackendUtility
::getUpdateSignalCode()) . ($this->form ?
'
674 // If something is in buffer like debug, put it to end of page
675 if (ob_get_contents()) {
676 $str .= ob_get_clean();
677 if (!headers_sent()) {
678 header('Content-Encoding: None');
681 $str .= ($this->divClass ?
'
683 <!-- Wrapping DIV-section for whole page END -->
684 </div>' : '') . $this->endOfPageJsBlock
;
686 // Logging: Can't find better place to put it:
688 GeneralUtility
::devLog('END of BACKEND session', \TYPO3\CMS\Backend\Template\DocumentTemplate
::class, 0, array('_FLUSH' => true));
694 * Shortcut for render the complete page of a module
696 * @param string $title page title
697 * @param string $content page content
698 * @return string complete page
700 public function render($title, $content)
702 $pageContent = $this->startPage($title);
703 $pageContent .= $content;
704 $pageContent .= $this->endPage();
705 return $this->insertStylesAndJS($pageContent);
709 * Returns the header-bar in the top of most backend modules
710 * Closes section if open.
712 * @param string $text The text string for the header
713 * @return string HTML content
715 public function header($text)
719 <!-- MAIN Header in page top -->
720 <h1 class="t3js-title-inlineedit">' . htmlspecialchars($text) . '</h1>
722 return $this->sectionEnd() . $str;
726 * Begins an output section and sets header and content
728 * @param string $label The header
729 * @param string $text The HTML-content
730 * @param bool $nostrtoupper A flag that will prevent the header from being converted to uppercase
731 * @param bool $sH Defines the type of header (if set, "<h3>" rather than the default "h4")
732 * @param int $type The number of an icon to show with the header (see the icon-function). -1,1,2,3
733 * @param bool $allowHTMLinHeader If set, HTML tags are allowed in $label (otherwise this value is by default htmlspecialchars()'ed)
734 * @return string HTML content
735 * @see icons(), sectionHeader()
737 public function section($label, $text, $nostrtoupper = false, $sH = false, $type = 0, $allowHTMLinHeader = false)
742 if (!$allowHTMLinHeader) {
743 $label = htmlspecialchars($label);
745 $str .= $this->sectionHeader($this->icons($type) . $label, $sH, $nostrtoupper ?
'' : ' class="uppercase"');
750 <!-- Section content -->
752 return $this->sectionBegin() . $str;
756 * Inserts a divider image
757 * Ends a section (if open) before inserting the image
759 * @param int $dist The margin-top/-bottom of the <hr> ruler.
760 * @return string HTML content
762 public function divider($dist)
768 <hr style="margin-top: ' . $dist . 'px; margin-bottom: ' . $dist . 'px;" />
770 return $this->sectionEnd() . $str;
774 * Make a section header.
775 * Begins a section if not already open.
777 * @param string $label The label between the <h3> or <h4> tags. (Allows HTML)
778 * @param bool $sH If set, <h3> is used, otherwise <h4>
779 * @param string $addAttrib Additional attributes to h-tag, eg. ' class=""'
780 * @return string HTML content
782 public function sectionHeader($label, $sH = false, $addAttrib = '')
784 $tag = $sH ?
'h2' : 'h3';
785 if ($addAttrib && $addAttrib[0] !== ' ') {
786 $addAttrib = ' ' . $addAttrib;
790 <!-- Section header -->
791 <' . $tag . $addAttrib . '>' . $label . '</' . $tag . '>
793 return $this->sectionBegin() . $str;
797 * Begins an output section.
798 * Returns the <div>-begin tag AND sets the ->sectionFlag TRUE (if the ->sectionFlag is not already set!)
799 * 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!
801 * @return string HTML content
803 public function sectionBegin()
805 if (!$this->sectionFlag
) {
806 $this->sectionFlag
= 1;
809 <!-- ***********************
810 Begin output section.
811 *********************** -->
821 * Ends and output section
822 * Returns the </div>-end tag AND clears the ->sectionFlag (but does so only IF the sectionFlag is set - that is a section is 'open')
823 * See sectionBegin() also.
825 * @return string HTML content
827 public function sectionEnd()
829 if ($this->sectionFlag
) {
830 $this->sectionFlag
= 0;
833 <!-- *********************
835 ********************* -->
843 * Creates the bodyTag.
844 * You can add to the bodyTag by $this->bodyTagAdditions
846 * @return string HTML body tag
848 public function docBodyTagBegin()
850 return '<body ' . trim($this->bodyTagAdditions
. ($this->bodyTagId ?
' id="' . $this->bodyTagId
. '"' : '')) . '>';
854 * Outputting document style
856 * @return string HTML style section/link tags
858 public function docStyle()
861 $inDocStyles = implode(LF
, $this->inDocStylesArray
);
863 // Reset styles so they won't be added again in insertStylesAndJS()
864 $this->inDocStylesArray
= array();
866 if ($this->styleSheetFile
) {
867 $this->pageRenderer
->addCssFile($this->styleSheetFile
);
869 if ($this->styleSheetFile2
) {
870 $this->pageRenderer
->addCssFile($this->styleSheetFile2
);
873 if ($inDocStyles !== '') {
874 $this->pageRenderer
->addCssInlineBlock('inDocStyles', $inDocStyles . LF
. '/*###POSTCSSMARKER###*/');
877 if ($this->styleSheetFile_post
) {
878 $this->pageRenderer
->addCssFile($this->styleSheetFile_post
);
883 * Insert additional style sheet link
885 * @param string $key some key identifying the style sheet
886 * @param string $href uri to the style sheet file
887 * @param string $title value for the title attribute of the link element
888 * @param string $relation value for the rel attribute of the link element
891 public function addStyleSheet($key, $href, $title = '', $relation = 'stylesheet')
893 $this->pageRenderer
->addCssFile($href, $relation, 'screen', $title);
897 * Add all *.css files of the directory $path to the stylesheets
899 * @param string $path directory to add
902 public function addStyleSheetDirectory($path)
904 // Calculation needed, when TYPO3 source is used via a symlink
905 // absolute path to the stylesheets
906 $filePath = GeneralUtility
::getFileAbsFileName($path, false, true);
908 $resolvedPath = GeneralUtility
::resolveBackPath($filePath);
909 // Read all files in directory and sort them alphabetically
910 $files = GeneralUtility
::getFilesInDir($resolvedPath, 'css', false, 1);
911 foreach ($files as $file) {
912 $this->pageRenderer
->addCssFile($path . $file, 'stylesheet', 'all');
917 * Insert post rendering document style into already rendered content
918 * This is needed for extobjbase
920 * @param string $content style-content to insert.
921 * @return string content with inserted styles
923 public function insertStylesAndJS($content)
925 $styles = LF
. implode(LF
, $this->inDocStylesArray
);
926 $content = str_replace('/*###POSTCSSMARKER###*/', $styles, $content);
928 // Insert accumulated JS
929 $jscode = $this->JScode
. LF
. $this->wrapScriptTags(implode(LF
, $this->JScodeArray
));
930 $content = str_replace('<!--###POSTJSMARKER###-->', $jscode, $content);
935 * Returns an array of all stylesheet directories belonging to core and skins
937 * @return array Stylesheet directories
939 public function getSkinStylesheetDirectories()
941 $stylesheetDirectories = array();
942 // Stylesheets from skins
943 // merge default css directories ($this->stylesheetsSkin) with additional ones and include them
944 if (is_array($GLOBALS['TBE_STYLES']['skins'])) {
945 // loop over all registered skins
946 foreach ($GLOBALS['TBE_STYLES']['skins'] as $skinExtKey => $skin) {
947 $skinStylesheetDirs = $this->stylesheetsSkins
;
948 // Skins can add custom stylesheetDirectories using
949 // $GLOBALS['TBE_STYLES']['skins'][$_EXTKEY]['stylesheetDirectories']
950 if (is_array($skin['stylesheetDirectories'])) {
951 $skinStylesheetDirs = array_merge($skinStylesheetDirs, $skin['stylesheetDirectories']);
953 // Add all registered directories
954 foreach ($skinStylesheetDirs as $stylesheetDir) {
955 // for EXT:myskin/stylesheets/ syntax
956 if (substr($stylesheetDir, 0, 4) === 'EXT:') {
957 list($extKey, $path) = explode('/', substr($stylesheetDir, 4), 2);
958 if (!empty($extKey) && ExtensionManagementUtility
::isLoaded($extKey) && !empty($path)) {
959 $stylesheetDirectories[] = ExtensionManagementUtility
::extRelPath($extKey) . $path;
962 // For relative paths
963 $stylesheetDirectories[] = ExtensionManagementUtility
::extRelPath($skinExtKey) . $stylesheetDir;
968 return $stylesheetDirectories;
972 * Returns generator meta tag
974 * @return string <meta> tag with name "generator
976 public function generator()
978 $str = 'TYPO3 CMS, ' . TYPO3_URL_GENERAL
. ', © Kasper Skårhøj ' . TYPO3_copyright_year
. ', extensions are copyright of their respective owners.';
979 return '<meta name="generator" content="' . $str . '" />';
983 * Returns X-UA-Compatible meta tag
985 * @param string $content Content of the compatible tag (default: IE-8)
986 * @return string <meta http-equiv="X-UA-Compatible" content="???" />
988 public function xUaCompatible($content = 'IE=8')
990 return '<meta http-equiv="X-UA-Compatible" content="' . $content . '" />';
993 /*****************************************
996 * Tables, buttons, formatting dimmed/red strings
998 ******************************************/
1000 * Returns an image-tag with an 18x16 icon of the following types:
1003 * -1: OK icon (Check-mark)
1004 * 1: Notice (Speach-bubble)
1005 * 2: Warning (Yellow triangle)
1006 * 3: Fatal error (Red stop sign)
1008 * @param int $type See description
1009 * @param string $styleAttribValue Value for style attribute
1010 * @return string HTML image tag (if applicable)
1012 public function icons($type, $styleAttribValue = '')
1015 case self
::STATUS_ICON_ERROR
:
1016 $icon = 'status-dialog-error';
1018 case self
::STATUS_ICON_WARNING
:
1019 $icon = 'status-dialog-warning';
1021 case self
::STATUS_ICON_NOTIFICATION
:
1022 $icon = 'status-dialog-notification';
1024 case self
::STATUS_ICON_OK
:
1025 $icon = 'status-dialog-ok';
1031 return $this->iconFactory
->getIcon($icon, Icon
::SIZE_SMALL
)->render();
1036 * Returns an <input> button with the $onClick action and $label
1038 * @param string $onClick The value of the onclick attribute of the input tag (submit type)
1039 * @param string $label The label for the button (which will be htmlspecialchar'ed)
1040 * @return string A <input> tag of the type "submit
1042 public function t3Button($onClick, $label)
1044 $button = '<input class="btn btn-default" type="submit" onclick="' . htmlspecialchars($onClick) . '; return false;" value="' . htmlspecialchars($label) . '" />';
1049 * Returns string wrapped in CDATA "tags" for XML / XHTML (wrap content of <script> and <style> sections in those!)
1051 * @param string $string Input string
1052 * @return string Output string
1054 public function wrapInCData($string)
1056 $string = '/*<![CDATA[*/' . $string . '/*]]>*/';
1061 * Wraps the input string in script tags.
1062 * Automatic re-identing of the JS code is done by using the first line as ident reference.
1063 * This is nice for identing JS code with PHP code on the same level.
1065 * @param string $string Input string
1066 * @param bool $linebreak Wrap script element in linebreaks? Default is TRUE.
1067 * @return string Output string
1069 public function wrapScriptTags($string, $linebreak = true)
1071 if (trim($string)) {
1072 // <script wrapped in nl?
1073 $cr = $linebreak ? LF
: '';
1074 // Remove nl from the beginning
1075 $string = ltrim($string, LF
);
1076 // Re-ident to one tab using the first line as reference
1077 if ($string[0] === TAB
) {
1078 $string = TAB
. ltrim($string, TAB
);
1080 $string = $cr . '<script type="text/javascript">
1086 return trim($string);
1089 // These vars defines the layout for the table produced by the table() function.
1090 // You can override these values from outside if you like.
1091 public $tableLayout = array(
1093 'defCol' => array('<td valign="top">', '</td>')
1097 public $table_TR = '<tr>';
1099 public $table_TABLE = '<table border="0" cellspacing="0" cellpadding="0" class="typo3-dblist" id="typo3-tmpltable">';
1102 * Returns a one-row/two-celled table with $content and $menu side by side.
1103 * The table is a 100% width table and each cell is aligned left / right
1105 * @param string $content Content cell content (left)
1106 * @param string $menu Menu cell content (right)
1107 * @return string HTML output
1109 public function funcMenu($content, $menu)
1112 <table border="0" cellpadding="0" cellspacing="0" width="100%" id="typo3-funcmenu">
1114 <td valign="top" nowrap="nowrap">' . $content . '</td>
1115 <td valign="top" align="right" nowrap="nowrap">' . $menu . '</td>
1121 * Includes a javascript library that exists in the core /typo3/ directory
1123 * @param string $lib: Library name. Call it with the full path like "sysext/core/Resources/Public/JavaScript/QueryGenerator.js" to load it
1126 public function loadJavascriptLib($lib)
1128 // @todo: maybe we can remove this one as well
1129 $this->pageRenderer
->addJsFile($lib);
1133 * Includes the necessary Javascript function for the clickmenu (context sensitive menus) in the document
1137 public function getContextMenuCode()
1139 $this->pageRenderer
->loadJquery();
1140 $this->pageRenderer
->loadRequireJsModule('TYPO3/CMS/Backend/ClickMenu');
1144 * Includes the necessary javascript file for use on pages which have the
1145 * drag and drop functionality (legacy folder tree)
1147 * @param string $table indicator of which table the drag and drop function should work on (pages or folders)
1148 * @param string $additionalJavaScriptCode adds more code to the additional javascript code
1151 public function getDragDropCode($table, $additionalJavaScriptCode = '')
1153 $this->pageRenderer
->loadRequireJsModule('TYPO3/CMS/Backend/LegacyTree', 'function() {
1154 DragDrop.table = "' . $table . '";
1155 ' . $additionalJavaScriptCode . '
1160 * Creates a tab menu from an array definition
1162 * Returns a tab menu for a module
1163 * Requires the JS function jumpToUrl() to be available
1165 * @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=...
1166 * @param string $elementName it the form elements name, probably something like "SET[...]
1167 * @param string $currentValue is the value to be selected currently.
1168 * @param array $menuItems is an array with the menu items for the selector box
1169 * @param string $script is the script to send the &id to, if empty it's automatically found
1170 * @param string $addparams is additional parameters to pass to the script.
1171 * @return string HTML code for tab menu
1173 public function getTabMenu($mainParams, $elementName, $currentValue, $menuItems, $script = '', $addparams = '')
1176 if (is_array($menuItems)) {
1177 if (!is_array($mainParams)) {
1178 $mainParams = array('id' => $mainParams);
1180 $mainParams = GeneralUtility
::implodeArrayForUrl('', $mainParams);
1182 $script = basename(PATH_thisScript
);
1185 foreach ($menuItems as $value => $label) {
1186 $menuDef[$value]['isActive'] = (string)$currentValue === (string)$value;
1187 $menuDef[$value]['label'] = htmlspecialchars($label, ENT_COMPAT
, 'UTF-8', false);
1188 $menuDef[$value]['url'] = $script . '?' . $mainParams . $addparams . '&' . $elementName . '=' . $value;
1190 $content = $this->getTabMenuRaw($menuDef);
1196 * Creates the HTML content for the tab menu
1198 * @param array $menuItems Menu items for tabs
1199 * @return string Table HTML
1202 public function getTabMenuRaw($menuItems)
1204 if (!is_array($menuItems)) {
1209 foreach ($menuItems as $id => $def) {
1210 $class = $def['isActive'] ?
'active' : '';
1211 $label = $def['label'];
1212 $url = htmlspecialchars($def['url']);
1213 $params = $def['addParams'];
1215 $options .= '<li class="' . $class . '">' .
1216 '<a href="' . $url . '" ' . $params . '>' . $label . '</a>' .
1220 return '<ul class="nav nav-tabs" role="tablist">' .
1226 * Creates the version selector for the page id inputted.
1227 * Requires the core version management extension, "version" to be loaded.
1229 * @param int $id Page id to create selector for.
1230 * @param bool $noAction If set, there will be no button for swapping page.
1233 public function getVersionSelector($id, $noAction = false)
1236 ExtensionManagementUtility
::isLoaded('version') &&
1237 !ExtensionManagementUtility
::isLoaded('workspaces')
1239 $versionGuiObj = GeneralUtility
::makeInstance(\TYPO3\CMS\Version\View\VersionView
::class);
1240 return $versionGuiObj->getVersionSelector($id, $noAction);
1245 * Function to load a HTML template file with markers.
1246 * When calling from own extension, use syntax getHtmlTemplate('EXT:extkey/template.html')
1248 * @param string $filename tmpl name, usually in the typo3/template/ directory
1249 * @return string HTML of template
1251 public function getHtmlTemplate($filename)
1253 // setting the name of the original HTML template
1254 $this->moduleTemplateFilename
= $filename;
1255 if ($GLOBALS['TBE_STYLES']['htmlTemplates'][$filename]) {
1256 $filename = $GLOBALS['TBE_STYLES']['htmlTemplates'][$filename];
1258 if (GeneralUtility
::isFirstPartOfStr($filename, 'EXT:')) {
1259 $filename = GeneralUtility
::getFileAbsFileName($filename, true, true);
1260 } elseif (!GeneralUtility
::isAbsPath($filename)) {
1261 $filename = GeneralUtility
::resolveBackPath($filename);
1262 } elseif (!GeneralUtility
::isAllowedAbsPath($filename)) {
1266 if ($filename !== '') {
1267 $htmlTemplate = GeneralUtility
::getUrl($filename);
1269 return $htmlTemplate;
1273 * Define the template for the module
1275 * @param string $filename filename
1278 public function setModuleTemplate($filename)
1280 $this->moduleTemplate
= $this->getHtmlTemplate($filename);
1284 * Put together the various elements for the module <body> using a static HTML
1287 * @param array $pageRecord Record of the current page, used for page path and info
1288 * @param array $buttons HTML for all buttons
1289 * @param array $markerArray HTML for all other markers
1290 * @param array $subpartArray HTML for the subparts
1291 * @return string Composite HTML
1293 public function moduleBody($pageRecord = array(), $buttons = array(), $markerArray = array(), $subpartArray = array())
1295 // Get the HTML template for the module
1296 $moduleBody = $this->templateService
->getSubpart($this->moduleTemplate
, '###FULLDOC###');
1298 $this->inDocStylesArray
[] = 'html { overflow: hidden; }';
1299 // Get the page path for the docheader
1300 $markerArray['PAGEPATH'] = $this->getPagePath($pageRecord);
1301 // Get the page info for the docheader
1302 $markerArray['PAGEINFO'] = $this->getPageInfo($pageRecord);
1303 // Get all the buttons for the docheader
1304 $docHeaderButtons = $this->getDocHeaderButtons($buttons);
1305 // Merge docheader buttons with the marker array
1306 $markerArray = array_merge($markerArray, $docHeaderButtons);
1307 // replacing subparts
1308 foreach ($subpartArray as $marker => $content) {
1309 $moduleBody = $this->templateService
->substituteSubpart($moduleBody, $marker, $content);
1311 // adding flash messages
1312 if ($this->showFlashMessages
) {
1313 $flashMessages = $this->getFlashMessages();
1314 if (!empty($flashMessages)) {
1315 $markerArray['FLASHMESSAGES'] = $flashMessages;
1316 // If there is no dedicated marker for the messages present
1317 // then force them to appear before the content
1318 if (strpos($moduleBody, '###FLASHMESSAGES###') === false) {
1319 $moduleBody = str_replace('###CONTENT###', '###FLASHMESSAGES######CONTENT###', $moduleBody);
1323 // Hook for adding more markers/content to the page, like the version selector
1324 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['moduleBodyPostProcess'])) {
1326 'moduleTemplateFilename' => &$this->moduleTemplateFilename
,
1327 'moduleTemplate' => &$this->moduleTemplate
,
1328 'moduleBody' => &$moduleBody,
1329 'markers' => &$markerArray,
1330 'parentObject' => &$this
1332 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['moduleBodyPostProcess'] as $funcRef) {
1333 GeneralUtility
::callUserFunction($funcRef, $params, $this);
1336 // Replacing all markers with the finished markers and return the HTML content
1337 return $this->templateService
->substituteMarkerArray($moduleBody, $markerArray, '###|###');
1341 * Get the default rendered FlashMessages from queue
1345 public function getFlashMessages()
1347 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
1348 $flashMessageService = GeneralUtility
::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService
::class);
1349 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
1350 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
1351 return $defaultFlashMessageQueue->renderFlashMessages();
1355 * Renders the FlashMessages from queue and returns them as AJAX.
1357 * @param ServerRequestInterface $request
1358 * @param ResponseInterface $response
1359 * @return ResponseInterface
1361 public function renderQueuedFlashMessages(ServerRequestInterface
$request, ResponseInterface
$response)
1363 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
1364 $flashMessageService = GeneralUtility
::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService
::class);
1365 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
1366 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
1367 $flashMessages = $defaultFlashMessageQueue->getAllMessagesAndFlush();
1370 foreach ($flashMessages as $flashMessage) {
1372 'title' => $flashMessage->getTitle(),
1373 'message' => $flashMessage->getMessage(),
1374 'severity' => $flashMessage->getSeverity()
1378 $response->getBody()->write(json_encode($messages));
1383 * Fill the button lists with the defined HTML
1385 * @param array $buttons HTML for all buttons
1386 * @return array Containing HTML for both buttonlists
1388 protected function getDocHeaderButtons($buttons)
1391 // Fill buttons for left and right float
1392 $floats = array('left', 'right');
1393 foreach ($floats as $key) {
1394 // Get the template for each float
1395 $buttonTemplate = $this->templateService
->getSubpart($this->moduleTemplate
, '###BUTTON_GROUPS_' . strtoupper($key) . '###');
1396 // Fill the button markers in this float
1397 $buttonTemplate = $this->templateService
->substituteMarkerArray($buttonTemplate, $buttons, '###|###', true);
1398 // getting the wrap for each group
1399 $buttonWrap = $this->templateService
->getSubpart($this->moduleTemplate
, '###BUTTON_GROUP_WRAP###');
1400 // looping through the groups (max 6) and remove the empty groups
1401 for ($groupNumber = 1; $groupNumber < 6; $groupNumber++
) {
1402 $buttonMarker = '###BUTTON_GROUP' . $groupNumber . '###';
1403 $buttonGroup = $this->templateService
->getSubpart($buttonTemplate, $buttonMarker);
1404 if (trim($buttonGroup)) {
1406 $buttonGroup = $this->templateService
->substituteMarker($buttonWrap, '###BUTTONS###', $buttonGroup);
1408 $buttonTemplate = $this->templateService
->substituteSubpart($buttonTemplate, $buttonMarker, trim($buttonGroup));
1411 // Replace the marker with the template and remove all line breaks (for IE compat)
1412 $markers['BUTTONLIST_' . strtoupper($key)] = str_replace(LF
, '', $buttonTemplate);
1414 // Hook for manipulating docHeaderButtons
1415 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['docHeaderButtonsHook'])) {
1417 'buttons' => $buttons,
1418 'markers' => &$markers,
1421 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['docHeaderButtonsHook'] as $funcRef) {
1422 GeneralUtility
::callUserFunction($funcRef, $params, $this);
1429 * Generate the page path for docheader
1431 * @param array $pageRecord Current page
1432 * @return string Page path
1434 protected function getPagePath($pageRecord)
1436 // Is this a real page
1437 if (is_array($pageRecord) && $pageRecord['uid']) {
1438 $title = substr($pageRecord['_thePathFull'], 0, -1);
1439 // Remove current page title
1440 $pos = strrpos($title, $pageRecord['title']);
1441 if ($pos !== false) {
1442 $title = substr($title, 0, $pos);
1447 // Setting the path of the page
1448 $pagePath = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.path', true) . ': <span class="typo3-docheader-pagePath">';
1449 // crop the title to title limit (or 50, if not defined)
1450 $cropLength = empty($GLOBALS['BE_USER']->uc
['titleLen']) ?
50 : $GLOBALS['BE_USER']->uc
['titleLen'];
1451 $croppedTitle = GeneralUtility
::fixed_lgd_cs($title, -$cropLength);
1452 if ($croppedTitle !== $title) {
1453 $pagePath .= '<abbr title="' . htmlspecialchars($title) . '">' . htmlspecialchars($croppedTitle) . '</abbr>';
1455 $pagePath .= htmlspecialchars($title);
1457 $pagePath .= '</span>';
1462 * Setting page icon with clickmenu + uid for docheader
1464 * @param array $pageRecord Current page
1465 * @return string Page info
1467 protected function getPageInfo($pageRecord)
1469 // Add icon with clickmenu, etc:
1470 // If there IS a real page
1471 if (is_array($pageRecord) && $pageRecord['uid']) {
1472 $alttext = BackendUtility
::getRecordIconAltText($pageRecord, 'pages');
1473 $iconImg = '<span title="' . htmlspecialchars($alttext) . '">' . $this->iconFactory
->getIconForRecord('pages', $pageRecord, Icon
::SIZE_SMALL
)->render() . '</span>';
1475 $theIcon = BackendUtility
::wrapClickMenuOnIcon($iconImg, 'pages', $pageRecord['uid']);
1476 $uid = $pageRecord['uid'];
1477 $title = BackendUtility
::getRecordTitle('pages', $pageRecord);
1479 // On root-level of page tree
1481 $iconImg = '<span title="' . htmlspecialchars($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']) . '">' . $this->iconFactory
->getIcon('apps-pagetree-root', Icon
::SIZE_SMALL
)->render() . '</span>';
1482 if ($GLOBALS['BE_USER']->user
['admin']) {
1483 $theIcon = BackendUtility
::wrapClickMenuOnIcon($iconImg, 'pages', 0);
1485 $theIcon = $iconImg;
1488 $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
1490 // Setting icon with clickmenu + uid
1491 $pageInfo = $theIcon . '<strong>' . htmlspecialchars($title) . ' [' . $uid . ']</strong>';
1496 * Retrieves configured favicon for backend (with fallback)
1500 protected function getBackendFavicon()
1502 return $GLOBALS['TBE_STYLES']['favicon'] ?
: 'sysext/backend/Resources/Public/Icons/favicon.ico';