TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
DocumentTemplate.php
Go to the documentation of this file.
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 Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
27 
42 {
43  // Vars you typically might want to/should set from outside after making instance of this class:
50  public $form = '';
51 
57  public $JScode = '';
58 
64  public $extJScode = '';
65 
71  public $JScodeArray = ['jumpToUrl' => '
72 function jumpToUrl(URL) {
73  window.location.href = URL;
74  return false;
75 }
76  '];
77 
83  public $postCode = '';
84 
90  public $moduleTemplate = '';
91 
97  protected $moduleTemplateFilename = '';
98 
104  public $scriptID = '';
105 
111  public $bodyTagId = '';
112 
118  public $bodyTagAdditions = '';
119 
126  public $inDocStylesArray = [];
127 
133  public $form_largeComp = 1.33;
134 
140  public $styleSheetFile = '';
141 
147  public $styleSheetFile2 = '';
148 
154  public $styleSheetFile_post = '';
155 
161  protected $useCompatibilityTag = true;
162 
168  protected $xUaCompatibilityVersion = 'IE=edge';
169 
170  // Skinning
176  protected $stylesheetsSkins = [
177  'structure' => 'Resources/Public/Css/structure/',
178  'visual' => 'Resources/Public/Css/visual/'
179  ];
180 
186  protected $jsFiles = [];
187 
193  protected $jsFilesNoConcatenation = [];
194 
201  public $sectionFlag = 0;
202 
208  public $divClass = '';
209 
213  public $pageHeaderBlock = '';
214 
218  public $endOfPageJsBlock = '';
219 
223  public $hasDocheader = true;
224 
228  protected $pageRenderer = null;
229 
236 
240  protected $extDirectStateProvider = false;
241 
247  public $showFlashMessages = true;
248 
252  protected $iconFactory;
253 
257  protected $templateService;
258 
259  const STATUS_ICON_ERROR = 3;
262  const STATUS_ICON_OK = -1;
263 
267  public function __construct()
268  {
269  // Initializes the page rendering object:
270  $this->initPageRenderer();
271 
272  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
273 
274  // initialize Marker Support
275  $this->templateService = GeneralUtility::makeInstance(MarkerBasedTemplateService::class);
276 
277  // Setting default scriptID, trim forward slash from route
278  $this->scriptID = GeneralUtility::_GET('M') !== null ? GeneralUtility::_GET('M') : ltrim(GeneralUtility::_GET('route'), '/');
279  $this->bodyTagId = preg_replace('/[^A-Za-z0-9-]/', '-', $this->scriptID);
280  // Individual configuration per script? If so, make a recursive merge of the arrays:
281  if (is_array($GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID])) {
282  // Make copy
283  $ovr = $GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID];
284  // merge styles.
286  // Have to unset - otherwise the second instantiation will do it again!
287  unset($GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID]);
288  }
289  // Main Stylesheets:
290  if ($GLOBALS['TBE_STYLES']['stylesheet']) {
291  $this->styleSheetFile = $GLOBALS['TBE_STYLES']['stylesheet'];
292  }
293  if ($GLOBALS['TBE_STYLES']['stylesheet2']) {
294  $this->styleSheetFile2 = $GLOBALS['TBE_STYLES']['stylesheet2'];
295  }
296  if ($GLOBALS['TBE_STYLES']['styleSheetFile_post']) {
297  $this->styleSheetFile_post = $GLOBALS['TBE_STYLES']['styleSheetFile_post'];
298  }
299  if ($GLOBALS['TBE_STYLES']['inDocStyles_TBEstyle']) {
300  $this->inDocStylesArray['TBEstyle'] = $GLOBALS['TBE_STYLES']['inDocStyles_TBEstyle'];
301  }
302  // include all stylesheets
303  foreach ($this->getSkinStylesheetDirectories() as $stylesheetDirectory) {
304  $this->addStyleSheetDirectory($stylesheetDirectory);
305  }
306  }
307 
311  protected function initPageRenderer()
312  {
313  if ($this->pageRenderer !== null) {
314  return;
315  }
316  $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
317  $this->pageRenderer->setLanguage($GLOBALS['LANG']->lang);
318  $this->pageRenderer->enableConcatenateFiles();
319  $this->pageRenderer->enableCompressCss();
320  $this->pageRenderer->enableCompressJavascript();
321  // Add all JavaScript files defined in $this->jsFiles to the PageRenderer
322  foreach ($this->jsFilesNoConcatenation as $file) {
323  $this->pageRenderer->addJsFile(
324  $file,
325  'text/javascript',
326  true,
327  false,
328  '',
329  true
330  );
331  }
332  // Add all JavaScript files defined in $this->jsFiles to the PageRenderer
333  foreach ($this->jsFiles as $file) {
334  $this->pageRenderer->addJsFile($file);
335  }
336  if ((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['debug'] === 1) {
337  $this->pageRenderer->enableDebugMode();
338  }
339  }
340 
346  public function setExtDirectStateProvider()
347  {
348  $this->extDirectStateProvider = true;
349  }
350 
351  /*****************************************
352  *
353  * EVALUATION FUNCTIONS
354  * Various centralized processing
355  *
356  *****************************************/
357 
368  public function viewPageIcon($id)
369  {
371  // If access to Web>List for user, then link to that module.
372  $str = '<a href="' . htmlspecialchars(BackendUtility::getModuleUrl('web_list', [
373  'id' => $id,
374  'returnUrl' > GeneralUtility::getIndpEnv('REQUEST_URI')
375  ])) . '" title="' . htmlspecialchars($GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.showList')) . '">' . $this->iconFactory->getIcon('actions-system-list-open', Icon::SIZE_SMALL)->render() . '</a>';
376 
377  // Make link to view page
378  $str .= '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick($id, '', BackendUtility::BEgetRootLine($id))) . '" title="' . htmlspecialchars($GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.showPage')) . '">' . $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)->render() . '</a>';
379  return $str;
380  }
381 
397  public function getHeader($table, $row, $path, $noViewPageIcon = false, $tWrap = ['', ''], $enableClickMenu = true)
398  {
400  $viewPage = '';
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']);
405  } else {
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'];
408  }
409 
410  if ($enableClickMenu) {
411  $iconImgTag = BackendUtility::wrapClickMenuOnIcon($iconImgTag, $table, $row['uid']);
412  }
413 
414  return '<span class="typo3-moduleHeader">' . $iconImgTag . $viewPage . $tWrap[0] . htmlspecialchars(GeneralUtility::fixed_lgd_cs($title, 45)) . $tWrap[1] . '</span>';
415  }
416 
427  public function getResourceHeader(\TYPO3\CMS\Core\Resource\ResourceInterface $resource, $tWrap = ['', ''], $enableClickMenu = true)
428  {
430  try {
431  $path = $resource->getStorage()->getName() . $resource->getParentFolder()->getIdentifier();
432  $iconImgTag = '<span title="' . htmlspecialchars($path) . '">' . $this->iconFactory->getIconForResource($resource, Icon::SIZE_SMALL)->render() . '</span>';
433  } catch (\TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException $e) {
434  $iconImgTag = '';
435  }
436 
437  if ($enableClickMenu && ($resource instanceof \TYPO3\CMS\Core\Resource\File)) {
438  $metaData = $resource->_getMetaData();
439  $iconImgTag = BackendUtility::wrapClickMenuOnIcon($iconImgTag, 'sys_file_metadata', $metaData['uid']);
440  }
441 
442  return '<span class="typo3-moduleHeader">' . $iconImgTag . $tWrap[0] . htmlspecialchars(GeneralUtility::fixed_lgd_cs($resource->getName(), 45)) . $tWrap[1] . '</span>';
443  }
444 
455  public function makeShortcutIcon($gvList, $setList, $modName, $motherModName = '', $classes = '')
456  {
457  $gvList = 'route,' . $gvList;
458  $storeUrl = $this->makeShortcutUrl($gvList, $setList);
459  $pathInfo = parse_url(GeneralUtility::getIndpEnv('REQUEST_URI'));
460  // Fallback for alt_mod. We still pass in the old xMOD... stuff, but TBE_MODULES only knows about "record_edit".
461  // We still need to pass the xMOD name to createShortcut below, since this is used for icons.
462  $moduleName = $modName === 'xMOD_alt_doc.php' ? 'record_edit' : $modName;
463  // Add the module identifier automatically if typo3/index.php is used:
464  if (GeneralUtility::_GET('M') !== null) {
465  $storeUrl = '&M=' . $moduleName . $storeUrl;
466  }
467  if ((int)$motherModName === 1) {
468  $motherModule = 'top.currentModuleLoaded';
469  } elseif ($motherModName) {
470  $motherModule = GeneralUtility::quoteJSvalue($motherModName);
471  } else {
472  $motherModule = '\'\'';
473  }
474  $confirmationText = GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.makeBookmark'));
475 
476  $shortcutUrl = $pathInfo['path'] . '?' . $storeUrl;
477  $shortcutExist = BackendUtility::shortcutExists($shortcutUrl);
478 
479  if ($shortcutExist) {
480  return '<a class="active ' . htmlspecialchars($classes) . '" title="">' .
481  $this->iconFactory->getIcon('actions-system-shortcut-active', Icon::SIZE_SMALL)->render() . '</a>';
482  }
483  $url = GeneralUtility::quoteJSvalue(rawurlencode($shortcutUrl));
484  $onClick = 'top.TYPO3.ShortcutMenu.createShortcut(' . GeneralUtility::quoteJSvalue(rawurlencode($modName)) .
485  ', ' . $url . ', ' . $confirmationText . ', ' . $motherModule . ', this);return false;';
486 
487  return '<a href="#" class="' . htmlspecialchars($classes) . '" onclick="' . htmlspecialchars($onClick) . '" title="' .
488  htmlspecialchars($GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.makeBookmark')) . '">' .
489  $this->iconFactory->getIcon('actions-system-shortcut-new', Icon::SIZE_SMALL)->render() . '</a>';
490  }
491 
502  public function makeShortcutUrl($gvList, $setList)
503  {
504  $GET = GeneralUtility::_GET();
505  $storeArray = array_merge(GeneralUtility::compileSelectedGetVarsFromArray($gvList, $GET), ['SET' => GeneralUtility::compileSelectedGetVarsFromArray($setList, (array)$GLOBALS['SOBE']->MOD_SETTINGS)]);
506  $storeUrl = GeneralUtility::implodeArrayForUrl('', $storeArray);
507  return $storeUrl;
508  }
509 
520  public function formWidth($size = 48, $textarea = false, $styleOverride = '')
521  {
522  return ' style="' . ($styleOverride ?: 'width:' . ceil($size * 9.58) . 'px;') . '"';
523  }
524 
533  public function redirectUrls($thisLocation = '')
534  {
535  $thisLocation = $thisLocation ? $thisLocation : GeneralUtility::linkThisScript([
536  'CB' => '',
537  'SET' => '',
538  'cmd' => '',
539  'popViewId' => ''
540  ]);
541  $out = '
542  var T3_RETURN_URL = ' . GeneralUtility::quoteJSvalue(str_replace('%20', '', rawurlencode(GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'))))) . ';
543  var T3_THIS_LOCATION = ' . GeneralUtility::quoteJSvalue(str_replace('%20', '', rawurlencode($thisLocation))) . '
544  ';
545  return $out;
546  }
547 
555  {
557  }
558 
559  /*****************************************
560  *
561  * PAGE BUILDING FUNCTIONS.
562  * Use this to build the HTML of your backend modules
563  *
564  *****************************************/
573  public function startPage($title)
574  {
575  // hook pre start page
576  if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'])) {
577  $preStartPageHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'];
578  if (is_array($preStartPageHook)) {
579  $hookParameters = [
580  'title' => &$title
581  ];
582  foreach ($preStartPageHook as $hookFunction) {
583  GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
584  }
585  }
586  }
587  // alternative template for Header and Footer
588  if ($this->pageHeaderFooterTemplateFile) {
589  $file = GeneralUtility::getFileAbsFileName($this->pageHeaderFooterTemplateFile);
590  if ($file) {
591  $this->pageRenderer->setTemplateFile($file);
592  }
593  }
594 
595  // Disable rendering of XHTML tags
596  $this->pageRenderer->setRenderXhtml(false);
597 
598  $languageCode = $this->pageRenderer->getLanguage() === 'default' ? 'en' : $this->pageRenderer->getLanguage();
599  $this->pageRenderer->setHtmlTag('<html lang="' . $languageCode . '">');
600 
601  $headerStart = '<!DOCTYPE html>';
602  $this->pageRenderer->setXmlPrologAndDocType($headerStart);
603  $this->pageRenderer->setHeadTag('<head>' . LF . '<!-- TYPO3 Script ID: ' . htmlspecialchars($this->scriptID) . ' -->');
604  header('Content-Type:text/html;charset=utf-8');
605  $this->pageRenderer->setCharSet('utf-8');
606  $this->pageRenderer->addMetaTag($this->generator());
607  $this->pageRenderer->addMetaTag('<meta name="robots" content="noindex,follow">');
608  $this->pageRenderer->addMetaTag('<meta charset="utf-8">');
609  $this->pageRenderer->addMetaTag('<meta name="viewport" content="width=device-width, initial-scale=1">');
610  $this->pageRenderer->setFavIcon($this->getBackendFavicon());
611  if ($this->useCompatibilityTag) {
612  $this->pageRenderer->addMetaTag($this->xUaCompatible($this->xUaCompatibilityVersion));
613  }
614  $this->pageRenderer->setTitle($title);
615  // add docstyles
616  $this->docStyle();
617  if ($this->extDirectStateProvider) {
618  $this->pageRenderer->addJsFile('EXT:backend/Resources/Public/JavaScript/ExtDirect.StateProvider.js');
619  }
620  $this->pageRenderer->addHeaderData($this->JScode);
621  foreach ($this->JScodeArray as $name => $code) {
622  $this->pageRenderer->addJsInlineCode($name, $code, false);
623  }
624 
625  if ($this->extJScode) {
626  $this->pageRenderer->addExtOnReadyCode($this->extJScode);
627  }
628 
629  // Load jquery and twbs JS libraries on every backend request
630  $this->pageRenderer->loadJquery();
631  // Note: please do not reference "bootstrap" outside of the TYPO3 Core (not in your own extensions)
632  // as this is preliminary as long as Twitter bootstrap does not support AMD modules
633  // this logic will be changed once Twitter bootstrap 4 is included
634  $this->pageRenderer->addJsFile('EXT:core/Resources/Public/JavaScript/Contrib/bootstrap/bootstrap.js');
635 
636  // hook for additional headerData
637  if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'])) {
638  $preHeaderRenderHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'];
639  if (is_array($preHeaderRenderHook)) {
640  $hookParameters = [
641  'pageRenderer' => &$this->pageRenderer
642  ];
643  foreach ($preHeaderRenderHook as $hookFunction) {
644  GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
645  }
646  }
647  }
648  // Construct page header.
649  $str = $this->pageRenderer->render(PageRenderer::PART_HEADER);
650  $this->JScode = ($this->extJScode = '');
651  $this->JScodeArray = [];
652  $this->endOfPageJsBlock = $this->pageRenderer->render(PageRenderer::PART_FOOTER);
653  $str .= $this->docBodyTagBegin() . ($this->divClass ? '
654 
655 <!-- Wrapping DIV-section for whole page BEGIN -->
656 <div class="' . $this->divClass . '">
657 ' : '') . trim($this->form);
658  return $str;
659  }
660 
667  public function endPage()
668  {
669  $str = $this->postCode . GeneralUtility::wrapJS(BackendUtility::getUpdateSignalCode()) . ($this->form ? '
670 </form>' : '');
671  // If something is in buffer like debug, put it to end of page
672  if (ob_get_contents()) {
673  $str .= ob_get_clean();
674  if (!headers_sent()) {
675  header('Content-Encoding: None');
676  }
677  }
678  $str .= ($this->divClass ? '
679 
680 <!-- Wrapping DIV-section for whole page END -->
681 </div>' : '') . $this->endOfPageJsBlock;
682 
683  // Logging: Can't find better place to put it:
684  if (TYPO3_DLOG) {
685  GeneralUtility::devLog('END of BACKEND session', \TYPO3\CMS\Backend\Template\DocumentTemplate::class, 0, ['_FLUSH' => true]);
686  }
687  return $str;
688  }
689 
697  public function render($title, $content)
698  {
699  $pageContent = $this->startPage($title);
700  $pageContent .= $content;
701  $pageContent .= $this->endPage();
702  return $this->insertStylesAndJS($pageContent);
703  }
704 
713  public function header($text)
714  {
716  $str = '
717 
718  <!-- MAIN Header in page top -->
719  <h1 class="t3js-title-inlineedit">' . htmlspecialchars($text) . '</h1>
720 ';
721  return $this->sectionEnd() . $str;
722  }
723 
737  public function section($label, $text, $nostrtoupper = false, $sH = false, $type = 0, $allowHTMLinHeader = false)
738  {
740  $str = '';
741  // Setting header
742  if ($label) {
743  if (!$allowHTMLinHeader) {
744  $label = htmlspecialchars($label);
745  }
746  $str .= $this->sectionHeader($this->icons($type) . $label, $sH, $nostrtoupper ? '' : ' class="uppercase"');
747  }
748  // Setting content
749  $str .= '
750 
751  <!-- Section content -->
752 ' . $text;
753  return $this->sectionBegin() . $str;
754  }
755 
764  public function divider($dist)
765  {
767  $dist = (int)$dist;
768  $str = '
769 
770  <!-- DIVIDER -->
771  <hr style="margin-top: ' . $dist . 'px; margin-bottom: ' . $dist . 'px;" />
772 ';
773  return $this->sectionEnd() . $str;
774  }
775 
786  public function sectionHeader($label, $sH = false, $addAttrib = '')
787  {
789  $tag = $sH ? 'h2' : 'h3';
790  if ($addAttrib && $addAttrib[0] !== ' ') {
791  $addAttrib = ' ' . $addAttrib;
792  }
793  $str = '
794 
795  <!-- Section header -->
796  <' . $tag . $addAttrib . '>' . $label . '</' . $tag . '>
797 ';
798  return $this->sectionBegin() . $str;
799  }
800 
809  public function sectionBegin()
810  {
812  if (!$this->sectionFlag) {
813  $this->sectionFlag = 1;
814  $str = '
815 
816  <!-- ***********************
817  Begin output section.
818  *********************** -->
819  <div>
820 ';
821  return $str;
822  } else {
823  return '';
824  }
825  }
826 
835  public function sectionEnd()
836  {
837  if ($this->sectionFlag) {
839  $this->sectionFlag = 0;
840  return '
841  </div>
842  <!-- *********************
843  End output section.
844  ********************* -->
845 ';
846  } else {
847  return '';
848  }
849  }
850 
857  public function docBodyTagBegin()
858  {
859  return '<body ' . trim($this->bodyTagAdditions . ($this->bodyTagId ? ' id="' . $this->bodyTagId . '"' : '')) . '>';
860  }
861 
867  public function docStyle()
868  {
869  // Implode it all:
870  $inDocStyles = implode(LF, $this->inDocStylesArray);
871 
872  // Reset styles so they won't be added again in insertStylesAndJS()
873  $this->inDocStylesArray = [];
874 
875  if ($this->styleSheetFile) {
876  $this->pageRenderer->addCssFile($this->styleSheetFile);
877  }
878  if ($this->styleSheetFile2) {
879  $this->pageRenderer->addCssFile($this->styleSheetFile2);
880  }
881 
882  if ($inDocStyles !== '') {
883  $this->pageRenderer->addCssInlineBlock('inDocStyles', $inDocStyles . LF . '/*###POSTCSSMARKER###*/');
884  }
885 
886  if ($this->styleSheetFile_post) {
887  $this->pageRenderer->addCssFile($this->styleSheetFile_post);
888  }
889  }
890 
900  public function addStyleSheet($key, $href, $title = '', $relation = 'stylesheet')
901  {
902  $this->pageRenderer->addCssFile($href, $relation, 'screen', $title);
903  }
904 
911  public function addStyleSheetDirectory($path)
912  {
913  $path = GeneralUtility::getFileAbsFileName($path);
914  // Read all files in directory and sort them alphabetically
915  $cssFiles = GeneralUtility::getFilesInDir($path, 'css');
916  foreach ($cssFiles as $cssFile) {
917  $this->pageRenderer->addCssFile(PathUtility::getRelativePathTo($path) . $cssFile);
918  }
919  }
920 
928  public function insertStylesAndJS($content)
929  {
930  $styles = LF . implode(LF, $this->inDocStylesArray);
931  $content = str_replace('/*###POSTCSSMARKER###*/', $styles, $content);
932 
933  // Insert accumulated JS
934  $jscode = $this->JScode . LF . GeneralUtility::wrapJS(implode(LF, $this->JScodeArray));
935  $content = str_replace('<!--###POSTJSMARKER###-->', $jscode, $content);
936  return $content;
937  }
938 
945  {
946  $stylesheetDirectories = [];
947  // Stylesheets from skins
948  // merge default css directories ($this->stylesheetsSkin) with additional ones and include them
949  if (is_array($GLOBALS['TBE_STYLES']['skins'])) {
950  // loop over all registered skins
951  foreach ($GLOBALS['TBE_STYLES']['skins'] as $skinExtKey => $skin) {
952  $skinStylesheetDirs = $this->stylesheetsSkins;
953  // Skins can add custom stylesheetDirectories using
954  // $GLOBALS['TBE_STYLES']['skins'][$_EXTKEY]['stylesheetDirectories']
955  if (is_array($skin['stylesheetDirectories'])) {
956  $skinStylesheetDirs = array_merge($skinStylesheetDirs, $skin['stylesheetDirectories']);
957  }
958  // Add all registered directories
959  foreach ($skinStylesheetDirs as $stylesheetDir) {
960  // for EXT:myskin/stylesheets/ syntax
961  if (strpos($stylesheetDir, 'EXT:') === 0) {
962  list($extKey, $path) = explode('/', substr($stylesheetDir, 4), 2);
963  if (!empty($extKey) && ExtensionManagementUtility::isLoaded($extKey) && !empty($path)) {
964  $stylesheetDirectories[] = ExtensionManagementUtility::extPath($extKey) . $path;
965  }
966  } else {
967  // For relative paths
968  $stylesheetDirectories[] = ExtensionManagementUtility::extPath($skinExtKey) . $stylesheetDir;
969  }
970  }
971  }
972  }
973  return $stylesheetDirectories;
974  }
975 
981  public function generator()
982  {
983  $str = 'TYPO3 CMS, ' . TYPO3_URL_GENERAL . ', &#169; Kasper Sk&#229;rh&#248;j ' . TYPO3_copyright_year . ', extensions are copyright of their respective owners.';
984  return '<meta name="generator" content="' . $str . '" />';
985  }
986 
993  public function xUaCompatible($content = 'IE=8')
994  {
995  return '<meta http-equiv="X-UA-Compatible" content="' . $content . '" />';
996  }
997 
998  /*****************************************
999  *
1000  * OTHER ELEMENTS
1001  * Tables, buttons, formatting dimmed/red strings
1002  *
1003  ******************************************/
1018  public function icons($type, $styleAttribValue = '')
1019  {
1021  switch ($type) {
1022  case self::STATUS_ICON_ERROR:
1023  $icon = 'status-dialog-error';
1024  break;
1025  case self::STATUS_ICON_WARNING:
1026  $icon = 'status-dialog-warning';
1027  break;
1028  case self::STATUS_ICON_NOTIFICATION:
1029  $icon = 'status-dialog-notification';
1030  break;
1031  case self::STATUS_ICON_OK:
1032  $icon = 'status-dialog-ok';
1033  break;
1034  default:
1035  // Do nothing
1036  }
1037  if ($icon) {
1038  return $this->iconFactory->getIcon($icon, Icon::SIZE_SMALL)->render();
1039  }
1040  }
1041 
1050  public function t3Button($onClick, $label)
1051  {
1053  $button = '<input class="btn btn-default" type="submit" onclick="' . htmlspecialchars($onClick) . '; return false;" value="' . htmlspecialchars($label) . '" />';
1054  return $button;
1055  }
1056 
1064  public function wrapInCData($string)
1065  {
1067  $string = '/*<![CDATA[*/' . $string . '/*]]>*/';
1068  return $string;
1069  }
1070 
1081  public function wrapScriptTags($string, $linebreak = true)
1082  {
1084  if (trim($string)) {
1085  // <script wrapped in nl?
1086  $cr = $linebreak ? LF : '';
1087  // Remove nl from the beginning
1088  $string = ltrim($string, LF);
1089  // Re-ident to one tab using the first line as reference
1090  if ($string[0] === TAB) {
1091  $string = TAB . ltrim($string, TAB);
1092  }
1093  $string = $cr . '<script type="text/javascript">
1094 /*<![CDATA[*/
1095 ' . $string . '
1096 /*]]>*/
1097 </script>' . $cr;
1098  }
1099  return trim($string);
1100  }
1101 
1111  public function funcMenu($content, $menu)
1112  {
1114  return '
1115  <table border="0" cellpadding="0" cellspacing="0" width="100%" id="typo3-funcmenu">
1116  <tr>
1117  <td valign="top" nowrap="nowrap">' . $content . '</td>
1118  <td valign="top" align="right" nowrap="nowrap">' . $menu . '</td>
1119  </tr>
1120  </table>';
1121  }
1122 
1130  public function loadJavascriptLib($lib)
1131  {
1133  $this->pageRenderer->addJsFile($lib);
1134  }
1135 
1142  public function getContextMenuCode()
1143  {
1145  $this->pageRenderer->loadJquery();
1146  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ClickMenu');
1147  }
1148 
1158  public function getDragDropCode($table, $additionalJavaScriptCode = '')
1159  {
1161  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LegacyTree', 'function() {
1162  DragDrop.table = "' . $table . '";
1163  ' . $additionalJavaScriptCode . '
1164  }');
1165  }
1166 
1182  public function getTabMenu($mainParams, $elementName, $currentValue, $menuItems, $script = '', $addparams = '')
1183  {
1185  $content = '';
1186  if (is_array($menuItems)) {
1187  if (!is_array($mainParams)) {
1188  $mainParams = ['id' => $mainParams];
1189  }
1190  $mainParams = GeneralUtility::implodeArrayForUrl('', $mainParams);
1191  if (!$script) {
1192  $script = basename(PATH_thisScript);
1193  }
1194  $menuDef = [];
1195  foreach ($menuItems as $value => $label) {
1196  $menuDef[$value]['isActive'] = (string)$currentValue === (string)$value;
1197  $menuDef[$value]['label'] = htmlspecialchars($label, ENT_COMPAT, 'UTF-8', false);
1198  $menuDef[$value]['url'] = $script . '?' . $mainParams . $addparams . '&' . $elementName . '=' . $value;
1199  }
1200  $content = $this->getTabMenuRaw($menuDef);
1201  }
1202  return $content;
1203  }
1204 
1212  public function getTabMenuRaw($menuItems)
1213  {
1214  if (!is_array($menuItems)) {
1215  return '';
1216  }
1217 
1218  $options = '';
1219  foreach ($menuItems as $id => $def) {
1220  $class = $def['isActive'] ? 'active' : '';
1221  $label = $def['label'];
1222  $url = htmlspecialchars($def['url']);
1223  $params = $def['addParams'];
1224 
1225  $options .= '<li class="' . $class . '">' .
1226  '<a href="' . $url . '" ' . $params . '>' . $label . '</a>' .
1227  '</li>';
1228  }
1229 
1230  return '<ul class="nav nav-tabs" role="tablist">' .
1231  $options .
1232  '</ul>';
1233  }
1234 
1244  public function getVersionSelector($id, $noAction = false)
1245  {
1247  if (
1250  ) {
1251  $versionGuiObj = GeneralUtility::makeInstance(\TYPO3\CMS\Version\View\VersionView::class);
1252  return $versionGuiObj->getVersionSelector($id, $noAction);
1253  }
1254  }
1255 
1263  public function getHtmlTemplate($filename)
1264  {
1265  // setting the name of the original HTML template
1266  $this->moduleTemplateFilename = $filename;
1267  if ($GLOBALS['TBE_STYLES']['htmlTemplates'][$filename]) {
1268  $filename = $GLOBALS['TBE_STYLES']['htmlTemplates'][$filename];
1269  }
1270  if (GeneralUtility::isFirstPartOfStr($filename, 'EXT:')) {
1271  $filename = GeneralUtility::getFileAbsFileName($filename);
1272  } elseif (!GeneralUtility::isAbsPath($filename)) {
1273  $filename = GeneralUtility::resolveBackPath($filename);
1274  } elseif (!GeneralUtility::isAllowedAbsPath($filename)) {
1275  $filename = '';
1276  }
1277  $htmlTemplate = '';
1278  if ($filename !== '') {
1279  $htmlTemplate = file_get_contents($filename);
1280  }
1281  return $htmlTemplate;
1282  }
1283 
1290  public function setModuleTemplate($filename)
1291  {
1292  $this->moduleTemplate = $this->getHtmlTemplate($filename);
1293  }
1294 
1305  public function moduleBody($pageRecord = [], $buttons = [], $markerArray = [], $subpartArray = [])
1306  {
1307  // Get the HTML template for the module
1308  $moduleBody = $this->templateService->getSubpart($this->moduleTemplate, '###FULLDOC###');
1309  // Add CSS
1310  $this->inDocStylesArray[] = 'html { overflow: hidden; }';
1311  // Get the page path for the docheader
1312  $markerArray['PAGEPATH'] = $this->getPagePath($pageRecord);
1313  // Get the page info for the docheader
1314  $markerArray['PAGEINFO'] = $this->getPageInfo($pageRecord);
1315  // Get all the buttons for the docheader
1316  $docHeaderButtons = $this->getDocHeaderButtons($buttons);
1317  // Merge docheader buttons with the marker array
1318  $markerArray = array_merge($markerArray, $docHeaderButtons);
1319  // replacing subparts
1320  foreach ($subpartArray as $marker => $content) {
1321  $moduleBody = $this->templateService->substituteSubpart($moduleBody, $marker, $content);
1322  }
1323  // adding flash messages
1324  if ($this->showFlashMessages) {
1325  $flashMessages = $this->getFlashMessages();
1326  if (!empty($flashMessages)) {
1327  $markerArray['FLASHMESSAGES'] = $flashMessages;
1328  // If there is no dedicated marker for the messages present
1329  // then force them to appear before the content
1330  if (strpos($moduleBody, '###FLASHMESSAGES###') === false) {
1331  $moduleBody = str_replace('###CONTENT###', '###FLASHMESSAGES######CONTENT###', $moduleBody);
1332  }
1333  }
1334  }
1335  // Hook for adding more markers/content to the page, like the version selector
1336  if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['moduleBodyPostProcess'])) {
1337  $params = [
1338  'moduleTemplateFilename' => &$this->moduleTemplateFilename,
1339  'moduleTemplate' => &$this->moduleTemplate,
1340  'moduleBody' => &$moduleBody,
1341  'markers' => &$markerArray,
1342  'parentObject' => &$this
1343  ];
1344  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['moduleBodyPostProcess'] as $funcRef) {
1345  GeneralUtility::callUserFunction($funcRef, $params, $this);
1346  }
1347  }
1348  // Replacing all markers with the finished markers and return the HTML content
1349  return $this->templateService->substituteMarkerArray($moduleBody, $markerArray, '###|###');
1350  }
1351 
1357  public function getFlashMessages()
1358  {
1360  $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
1362  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
1363  return $defaultFlashMessageQueue->renderFlashMessages();
1364  }
1365 
1373  public function renderQueuedFlashMessages(ServerRequestInterface $request, ResponseInterface $response)
1374  {
1376  $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
1378  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
1379  $flashMessages = $defaultFlashMessageQueue->getAllMessagesAndFlush();
1380 
1381  $messages = [];
1382  foreach ($flashMessages as $flashMessage) {
1383  $messages[] = [
1384  'title' => $flashMessage->getTitle(),
1385  'message' => $flashMessage->getMessage(),
1386  'severity' => $flashMessage->getSeverity()
1387  ];
1388  }
1389 
1390  $response->getBody()->write(json_encode($messages));
1391  return $response;
1392  }
1393 
1400  protected function getDocHeaderButtons($buttons)
1401  {
1402  $markers = [];
1403  // Fill buttons for left and right float
1404  $floats = ['left', 'right'];
1405  foreach ($floats as $key) {
1406  // Get the template for each float
1407  $buttonTemplate = $this->templateService->getSubpart($this->moduleTemplate, '###BUTTON_GROUPS_' . strtoupper($key) . '###');
1408  // Fill the button markers in this float
1409  $buttonTemplate = $this->templateService->substituteMarkerArray($buttonTemplate, $buttons, '###|###', true);
1410  // getting the wrap for each group
1411  $buttonWrap = $this->templateService->getSubpart($this->moduleTemplate, '###BUTTON_GROUP_WRAP###');
1412  // looping through the groups (max 6) and remove the empty groups
1413  for ($groupNumber = 1; $groupNumber < 6; $groupNumber++) {
1414  $buttonMarker = '###BUTTON_GROUP' . $groupNumber . '###';
1415  $buttonGroup = $this->templateService->getSubpart($buttonTemplate, $buttonMarker);
1416  if (trim($buttonGroup)) {
1417  if ($buttonWrap) {
1418  $buttonGroup = $this->templateService->substituteMarker($buttonWrap, '###BUTTONS###', $buttonGroup);
1419  }
1420  $buttonTemplate = $this->templateService->substituteSubpart($buttonTemplate, $buttonMarker, trim($buttonGroup));
1421  }
1422  }
1423  // Replace the marker with the template and remove all line breaks (for IE compat)
1424  $markers['BUTTONLIST_' . strtoupper($key)] = str_replace(LF, '', $buttonTemplate);
1425  }
1426  // Hook for manipulating docHeaderButtons
1427  if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['docHeaderButtonsHook'])) {
1428  $params = [
1429  'buttons' => $buttons,
1430  'markers' => &$markers,
1431  'pObj' => &$this
1432  ];
1433  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['docHeaderButtonsHook'] as $funcRef) {
1434  GeneralUtility::callUserFunction($funcRef, $params, $this);
1435  }
1436  }
1437  return $markers;
1438  }
1439 
1446  protected function getPagePath($pageRecord)
1447  {
1448  // Is this a real page
1449  if (is_array($pageRecord) && $pageRecord['uid']) {
1450  $title = substr($pageRecord['_thePathFull'], 0, -1);
1451  // Remove current page title
1452  $pos = strrpos($title, $pageRecord['title']);
1453  if ($pos !== false) {
1454  $title = substr($title, 0, $pos);
1455  }
1456  } else {
1457  $title = '';
1458  }
1459  // Setting the path of the page
1460  $pagePath = htmlspecialchars($GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.path')) . ': <span class="typo3-docheader-pagePath">';
1461  // crop the title to title limit (or 50, if not defined)
1462  $cropLength = empty($GLOBALS['BE_USER']->uc['titleLen']) ? 50 : $GLOBALS['BE_USER']->uc['titleLen'];
1463  $croppedTitle = GeneralUtility::fixed_lgd_cs($title, -$cropLength);
1464  if ($croppedTitle !== $title) {
1465  $pagePath .= '<abbr title="' . htmlspecialchars($title) . '">' . htmlspecialchars($croppedTitle) . '</abbr>';
1466  } else {
1467  $pagePath .= htmlspecialchars($title);
1468  }
1469  $pagePath .= '</span>';
1470  return $pagePath;
1471  }
1472 
1479  protected function getPageInfo($pageRecord)
1480  {
1481  // Add icon with clickmenu, etc:
1482  // If there IS a real page
1483  if (is_array($pageRecord) && $pageRecord['uid']) {
1484  $alttext = BackendUtility::getRecordIconAltText($pageRecord, 'pages');
1485  $iconImg = '<span title="' . htmlspecialchars($alttext) . '">' . $this->iconFactory->getIconForRecord('pages', $pageRecord, Icon::SIZE_SMALL)->render() . '</span>';
1486  // Make Icon:
1487  $theIcon = BackendUtility::wrapClickMenuOnIcon($iconImg, 'pages', $pageRecord['uid']);
1488  $uid = $pageRecord['uid'];
1489  $title = BackendUtility::getRecordTitle('pages', $pageRecord);
1490  } else {
1491  // On root-level of page tree
1492  // Make Icon
1493  $iconImg = '<span title="' . htmlspecialchars($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']) . '">' . $this->iconFactory->getIcon('apps-pagetree-root', Icon::SIZE_SMALL)->render() . '</span>';
1494  if ($GLOBALS['BE_USER']->user['admin']) {
1495  $theIcon = BackendUtility::wrapClickMenuOnIcon($iconImg, 'pages', 0);
1496  } else {
1497  $theIcon = $iconImg;
1498  }
1499  $uid = '0';
1500  $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
1501  }
1502  // Setting icon with clickmenu + uid
1503  $pageInfo = $theIcon . '<strong>' . htmlspecialchars($title) . '&nbsp;[' . $uid . ']</strong>';
1504  return $pageInfo;
1505  }
1506 
1512  protected function getBackendFavicon()
1513  {
1514  $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['backend'], ['allowed_classes' => false]);
1515 
1516  if (!empty($extConf['backendFavicon'])) {
1517  $path = $this->getUriForFileName($extConf['backendFavicon']);
1518  } else {
1519  $path = ExtensionManagementUtility::extPath('backend') . 'Resources/Public/Icons/favicon.ico';
1520  }
1521  return PathUtility::getAbsoluteWebPath($path);
1522  }
1523 
1532  protected function getUriForFileName($filename)
1533  {
1534  if (strpos($filename, '://')) {
1535  return $filename;
1536  }
1537  $urlPrefix = '';
1538  if (strpos($filename, 'EXT:') === 0) {
1539  $absoluteFilename = GeneralUtility::getFileAbsFileName($filename);
1540  $filename = '';
1541  if ($absoluteFilename !== '') {
1542  $filename = PathUtility::getAbsoluteWebPath($absoluteFilename);
1543  }
1544  } elseif (strpos($filename, '/') !== 0) {
1545  $urlPrefix = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH');
1546  }
1547  return $urlPrefix . $filename;
1548  }
1549 }
getDragDropCode($table, $additionalJavaScriptCode= '')
static isFirstPartOfStr($str, $partStr)
makeShortcutIcon($gvList, $setList, $modName, $motherModName= '', $classes= '')
static getRelativePathTo($targetPath)
Definition: PathUtility.php:29
getResourceHeader(\TYPO3\CMS\Core\Resource\ResourceInterface $resource, $tWrap=['', ''], $enableClickMenu=true)
section($label, $text, $nostrtoupper=false, $sH=false, $type=0, $allowHTMLinHeader=false)
getHeader($table, $row, $path, $noViewPageIcon=false, $tWrap=['', ''], $enableClickMenu=true)
useCompatibilityTag($useCompatibilityTag=true)
getTabMenu($mainParams, $elementName, $currentValue, $menuItems, $script= '', $addparams= '')
addStyleSheet($key, $href, $title= '', $relation= 'stylesheet')
static implodeArrayForUrl($name, array $theArray, $str= '', $skipBlank=false, $rawurlencodeParamName=false)
static getRecordTitle($table, $row, $prep=false, $forceResult=true)
formWidth($size=48, $textarea=false, $styleOverride= '')
static viewOnClick($pageUid, $backPath= '', $rootLine=null, $anchorSection= '', $alternativeUrl= '', $additionalGetVars= '', $switchFocus=true)
static BEgetRootLine($uid, $clause= '', $workspaceOL=false)
static compileSelectedGetVarsFromArray($varList, array $getArray, $GPvarAlt=true)
static linkThisScript(array $getParams=[])
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
sectionHeader($label, $sH=false, $addAttrib= '')
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static makeInstance($className,...$constructorArguments)
static wrapClickMenuOnIcon($content, $table, $uid=0, $listFrame=true, $addParams= '', $enDisItems= '', $returnTagParameters=false)
static getFilesInDir($path, $extensionList= '', $prependPath=false, $order= '', $excludePattern= '')
static getFileAbsFileName($filename, $_=null, $_2=null)
static getAbsoluteWebPath($targetPath)
Definition: PathUtility.php:40
moduleBody($pageRecord=[], $buttons=[], $markerArray=[], $subpartArray=[])
static callUserFunction($funcName, &$params, &$ref, $_= '', $errorMode=0)
static devLog($msg, $extKey, $severity=0, $dataVar=false)