TYPO3 CMS  TYPO3_8-7
DocumentTemplate.php
Go to the documentation of this file.
1 <?php
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 
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 
65  public $extJScode = '';
66 
72  public $JScodeArray = ['jumpToUrl' => '
73 function jumpToUrl(URL) {
74  window.location.href = URL;
75  return false;
76 }
77  '];
78 
84  public $postCode = '';
85 
91  public $moduleTemplate = '';
92 
98  protected $moduleTemplateFilename = '';
99 
105  public $scriptID = '';
106 
112  public $bodyTagId = '';
113 
119  public $bodyTagAdditions = '';
120 
127  public $inDocStylesArray = [];
128 
134  public $form_largeComp = 1.33;
135 
141  public $styleSheetFile = '';
142 
148  public $styleSheetFile2 = '';
149 
155  public $styleSheetFile_post = '';
156 
162  protected $useCompatibilityTag = true;
163 
169  protected $xUaCompatibilityVersion = 'IE=edge';
170 
171  // Skinning
177  protected $stylesheetsSkins = [
178  'structure' => 'Resources/Public/Css/structure/',
179  'visual' => 'Resources/Public/Css/visual/'
180  ];
181 
187  protected $jsFiles = [];
188 
194  protected $jsFilesNoConcatenation = [];
195 
202  public $sectionFlag = 0;
203 
209  public $divClass = '';
210 
214  public $pageHeaderBlock = '';
215 
219  public $endOfPageJsBlock = '';
220 
224  public $hasDocheader = true;
225 
229  protected $pageRenderer = null;
230 
237 
243  public $showFlashMessages = true;
244 
248  protected $iconFactory;
249 
253  protected $templateService;
254 
255  const STATUS_ICON_ERROR = 3;
258  const STATUS_ICON_OK = -1;
259 
263  public function __construct()
264  {
265  // Initializes the page rendering object:
266  $this->initPageRenderer();
267 
268  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
269 
270  // initialize Marker Support
271  $this->templateService = GeneralUtility::makeInstance(MarkerBasedTemplateService::class);
272 
273  // Setting default scriptID, trim forward slash from route
274  $this->scriptID = GeneralUtility::_GET('M') !== null ? GeneralUtility::_GET('M') : ltrim(GeneralUtility::_GET('route'), '/');
275  $this->bodyTagId = preg_replace('/[^A-Za-z0-9-]/', '-', $this->scriptID);
276  // Individual configuration per script? If so, make a recursive merge of the arrays:
277  if (is_array($GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID])) {
278  // Make copy
279  $ovr = $GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID];
280  // merge styles.
282  // Have to unset - otherwise the second instantiation will do it again!
283  unset($GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID]);
284  }
285  // Main Stylesheets:
286  if ($GLOBALS['TBE_STYLES']['stylesheet']) {
287  $this->styleSheetFile = $GLOBALS['TBE_STYLES']['stylesheet'];
288  }
289  if ($GLOBALS['TBE_STYLES']['stylesheet2']) {
290  $this->styleSheetFile2 = $GLOBALS['TBE_STYLES']['stylesheet2'];
291  }
292  if ($GLOBALS['TBE_STYLES']['styleSheetFile_post']) {
293  $this->styleSheetFile_post = $GLOBALS['TBE_STYLES']['styleSheetFile_post'];
294  }
295  if ($GLOBALS['TBE_STYLES']['inDocStyles_TBEstyle']) {
296  $this->inDocStylesArray['TBEstyle'] = $GLOBALS['TBE_STYLES']['inDocStyles_TBEstyle'];
297  }
298  // include all stylesheets
299  foreach ($this->getSkinStylesheetDirectories() as $stylesheetDirectory) {
300  $this->addStyleSheetDirectory($stylesheetDirectory);
301  }
302  }
303 
307  protected function initPageRenderer()
308  {
309  if ($this->pageRenderer !== null) {
310  return;
311  }
312  $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
313  $this->pageRenderer->setLanguage($GLOBALS['LANG']->lang);
314  $this->pageRenderer->enableConcatenateFiles();
315  $this->pageRenderer->enableCompressCss();
316  $this->pageRenderer->enableCompressJavascript();
317  // Add all JavaScript files defined in $this->jsFiles to the PageRenderer
318  foreach ($this->jsFilesNoConcatenation as $file) {
319  $this->pageRenderer->addJsFile(
320  $file,
321  'text/javascript',
322  true,
323  false,
324  '',
325  true
326  );
327  }
328  // Add all JavaScript files defined in $this->jsFiles to the PageRenderer
329  foreach ($this->jsFiles as $file) {
330  $this->pageRenderer->addJsFile($file);
331  }
332  if ((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['debug'] === 1) {
333  $this->pageRenderer->enableDebugMode();
334  }
335  }
336 
337  /*****************************************
338  *
339  * EVALUATION FUNCTIONS
340  * Various centralized processing
341  *
342  *****************************************/
343 
354  public function viewPageIcon($id)
355  {
357  // If access to Web>List for user, then link to that module.
358  $str = '<a href="' . htmlspecialchars(BackendUtility::getModuleUrl('web_list', [
359  'id' => $id,
360  'returnUrl' > GeneralUtility::getIndpEnv('REQUEST_URI')
361  ])) . '" 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>';
362 
363  // Make link to view page
364  $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>';
365  return $str;
366  }
367 
383  public function getHeader($table, $row, $path, $noViewPageIcon = false, $tWrap = ['', ''], $enableClickMenu = true)
384  {
386  $viewPage = '';
387  if (is_array($row) && $row['uid']) {
388  $iconImgTag = '<span title="' . htmlspecialchars($path) . '">' . $this->iconFactory->getIconForRecord($table, $row, Icon::SIZE_SMALL)->render() . '</span>';
389  $title = strip_tags(BackendUtility::getRecordTitle($table, $row));
390  $viewPage = $noViewPageIcon ? '' : $this->viewPageIcon($row['uid']);
391  } else {
392  $iconImgTag = '<span title="' . htmlspecialchars($path) . '">' . $this->iconFactory->getIcon('apps-pagetree-page-domain', Icon::SIZE_SMALL)->render() . '</span>';
393  $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
394  }
395 
396  if ($enableClickMenu) {
397  $iconImgTag = BackendUtility::wrapClickMenuOnIcon($iconImgTag, $table, $row['uid']);
398  }
399 
400  return '<span class="typo3-moduleHeader">' . $iconImgTag . $viewPage . $tWrap[0] . htmlspecialchars(GeneralUtility::fixed_lgd_cs($title, 45)) . $tWrap[1] . '</span>';
401  }
402 
413  public function getResourceHeader(\TYPO3\CMS\Core\Resource\ResourceInterface $resource, $tWrap = ['', ''], $enableClickMenu = true)
414  {
416  try {
417  $path = $resource->getStorage()->getName() . $resource->getParentFolder()->getIdentifier();
418  $iconImgTag = '<span title="' . htmlspecialchars($path) . '">' . $this->iconFactory->getIconForResource($resource, Icon::SIZE_SMALL)->render() . '</span>';
419  } catch (\TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException $e) {
420  $iconImgTag = '';
421  }
422 
423  if ($enableClickMenu && ($resource instanceof \TYPO3\CMS\Core\Resource\File)) {
424  $metaData = $resource->_getMetaData();
425  $iconImgTag = BackendUtility::wrapClickMenuOnIcon($iconImgTag, 'sys_file_metadata', $metaData['uid']);
426  }
427 
428  return '<span class="typo3-moduleHeader">' . $iconImgTag . $tWrap[0] . htmlspecialchars(GeneralUtility::fixed_lgd_cs($resource->getName(), 45)) . $tWrap[1] . '</span>';
429  }
430 
441  public function makeShortcutIcon($gvList, $setList, $modName, $motherModName = '', $classes = '')
442  {
443  $gvList = 'route,' . $gvList;
444  $storeUrl = $this->makeShortcutUrl($gvList, $setList);
445  $pathInfo = parse_url(GeneralUtility::getIndpEnv('REQUEST_URI'));
446  // Fallback for alt_mod. We still pass in the old xMOD... stuff, but TBE_MODULES only knows about "record_edit".
447  // We still need to pass the xMOD name to createShortcut below, since this is used for icons.
448  $moduleName = $modName === 'xMOD_alt_doc.php' ? 'record_edit' : $modName;
449  // Add the module identifier automatically if typo3/index.php is used:
450  if (GeneralUtility::_GET('M') !== null) {
451  $storeUrl = '&M=' . $moduleName . $storeUrl;
452  }
453  if ((int)$motherModName === 1) {
454  $motherModule = 'top.currentModuleLoaded';
455  } elseif ($motherModName) {
456  $motherModule = GeneralUtility::quoteJSvalue($motherModName);
457  } else {
458  $motherModule = '\'\'';
459  }
460  $confirmationText = GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.makeBookmark'));
461 
462  $shortcutUrl = $pathInfo['path'] . '?' . $storeUrl;
463  $shortcutExist = BackendUtility::shortcutExists($shortcutUrl);
464 
465  if ($shortcutExist) {
466  return '<a class="active ' . htmlspecialchars($classes) . '" title="">' .
467  $this->iconFactory->getIcon('actions-system-shortcut-active', Icon::SIZE_SMALL)->render() . '</a>';
468  }
469  $url = GeneralUtility::quoteJSvalue(rawurlencode($shortcutUrl));
470  $onClick = 'top.TYPO3.ShortcutMenu.createShortcut(' . GeneralUtility::quoteJSvalue(rawurlencode($modName)) .
471  ', ' . $url . ', ' . $confirmationText . ', ' . $motherModule . ', this);return false;';
472 
473  return '<a href="#" class="' . htmlspecialchars($classes) . '" onclick="' . htmlspecialchars($onClick) . '" title="' .
474  htmlspecialchars($GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.makeBookmark')) . '">' .
475  $this->iconFactory->getIcon('actions-system-shortcut-new', Icon::SIZE_SMALL)->render() . '</a>';
476  }
477 
488  public function makeShortcutUrl($gvList, $setList)
489  {
490  $GET = GeneralUtility::_GET();
491  $storeArray = array_merge(GeneralUtility::compileSelectedGetVarsFromArray($gvList, $GET), ['SET' => GeneralUtility::compileSelectedGetVarsFromArray($setList, (array)$GLOBALS['SOBE']->MOD_SETTINGS)]);
492  $storeUrl = GeneralUtility::implodeArrayForUrl('', $storeArray);
493  return $storeUrl;
494  }
495 
506  public function formWidth($size = 48, $textarea = false, $styleOverride = '')
507  {
508  return ' style="' . ($styleOverride ?: 'width:' . ceil($size * 9.58) . 'px;') . '"';
509  }
510 
519  public function redirectUrls($thisLocation = '')
520  {
521  $thisLocation = $thisLocation ? $thisLocation : GeneralUtility::linkThisScript([
522  'CB' => '',
523  'SET' => '',
524  'cmd' => '',
525  'popViewId' => ''
526  ]);
527  $out = '
528  var T3_RETURN_URL = ' . GeneralUtility::quoteJSvalue(str_replace('%20', '', rawurlencode(GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'))))) . ';
529  var T3_THIS_LOCATION = ' . GeneralUtility::quoteJSvalue(str_replace('%20', '', rawurlencode($thisLocation))) . '
530  ';
531  return $out;
532  }
533 
540  {
542  }
543 
544  /*****************************************
545  *
546  * PAGE BUILDING FUNCTIONS.
547  * Use this to build the HTML of your backend modules
548  *
549  *****************************************/
558  public function startPage($title)
559  {
560  // hook pre start page
561  if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'])) {
562  $preStartPageHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'];
563  if (is_array($preStartPageHook)) {
564  $hookParameters = [
565  'title' => &$title
566  ];
567  foreach ($preStartPageHook as $hookFunction) {
568  GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
569  }
570  }
571  }
572  // alternative template for Header and Footer
573  if ($this->pageHeaderFooterTemplateFile) {
574  $file = GeneralUtility::getFileAbsFileName($this->pageHeaderFooterTemplateFile);
575  if ($file) {
576  $this->pageRenderer->setTemplateFile($file);
577  }
578  }
579 
580  // Disable rendering of XHTML tags
581  $this->pageRenderer->setRenderXhtml(false);
582 
583  $languageCode = $this->pageRenderer->getLanguage() === 'default' ? 'en' : $this->pageRenderer->getLanguage();
584  $this->pageRenderer->setHtmlTag('<html lang="' . $languageCode . '">');
585 
586  $headerStart = '<!DOCTYPE html>';
587  $this->pageRenderer->setXmlPrologAndDocType($headerStart);
588  $this->pageRenderer->setHeadTag('<head>' . LF . '<!-- TYPO3 Script ID: ' . htmlspecialchars($this->scriptID) . ' -->');
589  header('Content-Type:text/html;charset=utf-8');
590  $this->pageRenderer->setCharSet('utf-8');
591  $this->pageRenderer->addMetaTag($this->generator());
592  $this->pageRenderer->addMetaTag('<meta name="robots" content="noindex,follow">');
593  $this->pageRenderer->addMetaTag('<meta charset="utf-8">');
594  $this->pageRenderer->addMetaTag('<meta name="viewport" content="width=device-width, initial-scale=1">');
595  $this->pageRenderer->setFavIcon($this->getBackendFavicon());
596  if ($this->useCompatibilityTag) {
597  $this->pageRenderer->addMetaTag($this->xUaCompatible($this->xUaCompatibilityVersion));
598  }
599  $this->pageRenderer->setTitle($title);
600  // add docstyles
601  $this->docStyle();
602  $this->pageRenderer->addHeaderData($this->JScode);
603  foreach ($this->JScodeArray as $name => $code) {
604  $this->pageRenderer->addJsInlineCode($name, $code, false);
605  }
606 
607  if ($this->extJScode) {
608  GeneralUtility::deprecationLog('The property DocumentTemplate->extJScode to add ExtJS-based onReadyCode is deprecated since TYPO3 v8, and will be removed in TYPO3 v9. Use the page renderer directly instead to add JavaScript code.');
609  $this->pageRenderer->addExtOnReadyCode($this->extJScode);
610  }
611 
612  // Load jquery and twbs JS libraries on every backend request
613  $this->pageRenderer->loadJquery();
614  // Note: please do not reference "bootstrap" outside of the TYPO3 Core (not in your own extensions)
615  // as this is preliminary as long as Twitter bootstrap does not support AMD modules
616  // this logic will be changed once Twitter bootstrap 4 is included
617  $this->pageRenderer->addJsFile('EXT:core/Resources/Public/JavaScript/Contrib/bootstrap/bootstrap.js');
618 
619  // hook for additional headerData
620  if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'])) {
621  $preHeaderRenderHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'];
622  if (is_array($preHeaderRenderHook)) {
623  $hookParameters = [
624  'pageRenderer' => &$this->pageRenderer
625  ];
626  foreach ($preHeaderRenderHook as $hookFunction) {
627  GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
628  }
629  }
630  }
631  // Construct page header.
632  $str = $this->pageRenderer->render(PageRenderer::PART_HEADER);
633  $this->JScode = ($this->extJScode = '');
634  $this->JScodeArray = [];
635  $this->endOfPageJsBlock = $this->pageRenderer->render(PageRenderer::PART_FOOTER);
636  $str .= $this->docBodyTagBegin() . ($this->divClass ? '
637 
638 <!-- Wrapping DIV-section for whole page BEGIN -->
639 <div class="' . $this->divClass . '">
640 ' : '') . trim($this->form);
641  return $str;
642  }
643 
650  public function endPage()
651  {
652  $str = $this->postCode . GeneralUtility::wrapJS(BackendUtility::getUpdateSignalCode()) . ($this->form ? '
653 </form>' : '');
654  // If something is in buffer like debug, put it to end of page
655  if (ob_get_contents()) {
656  $str .= ob_get_clean();
657  if (!headers_sent()) {
658  header('Content-Encoding: None');
659  }
660  }
661  $str .= ($this->divClass ? '
662 
663 <!-- Wrapping DIV-section for whole page END -->
664 </div>' : '') . $this->endOfPageJsBlock;
665 
666  // Logging: Can't find better place to put it:
667  GeneralUtility::devLog('END of BACKEND session', \TYPO3\CMS\Backend\Template\DocumentTemplate::class, 0, ['_FLUSH' => true]);
668  return $str;
669  }
670 
678  public function render($title, $content)
679  {
680  $pageContent = $this->startPage($title);
681  $pageContent .= $content;
682  $pageContent .= $this->endPage();
683  return $this->insertStylesAndJS($pageContent);
684  }
685 
694  public function header($text)
695  {
697  $str = '
698 
699  <!-- MAIN Header in page top -->
700  <h1 class="t3js-title-inlineedit">' . htmlspecialchars($text) . '</h1>
701 ';
702  return $this->sectionEnd() . $str;
703  }
704 
718  public function section($label, $text, $nostrtoupper = false, $sH = false, $type = 0, $allowHTMLinHeader = false)
719  {
721  $str = '';
722  // Setting header
723  if ($label) {
724  if (!$allowHTMLinHeader) {
725  $label = htmlspecialchars($label);
726  }
727  $str .= $this->sectionHeader($this->icons($type) . $label, $sH, $nostrtoupper ? '' : ' class="uppercase"');
728  }
729  // Setting content
730  $str .= '
731 
732  <!-- Section content -->
733 ' . $text;
734  return $this->sectionBegin() . $str;
735  }
736 
745  public function divider($dist)
746  {
748  $dist = (int)$dist;
749  $str = '
750 
751  <!-- DIVIDER -->
752  <hr style="margin-top: ' . $dist . 'px; margin-bottom: ' . $dist . 'px;" />
753 ';
754  return $this->sectionEnd() . $str;
755  }
756 
767  public function sectionHeader($label, $sH = false, $addAttrib = '')
768  {
770  $tag = $sH ? 'h2' : 'h3';
771  if ($addAttrib && $addAttrib[0] !== ' ') {
772  $addAttrib = ' ' . $addAttrib;
773  }
774  $str = '
775 
776  <!-- Section header -->
777  <' . $tag . $addAttrib . '>' . $label . '</' . $tag . '>
778 ';
779  return $this->sectionBegin() . $str;
780  }
781 
790  public function sectionBegin()
791  {
793  if (!$this->sectionFlag) {
794  $this->sectionFlag = 1;
795  $str = '
796 
797  <!-- ***********************
798  Begin output section.
799  *********************** -->
800  <div>
801 ';
802  return $str;
803  }
804  return '';
805  }
806 
815  public function sectionEnd()
816  {
817  if ($this->sectionFlag) {
819  $this->sectionFlag = 0;
820  return '
821  </div>
822  <!-- *********************
823  End output section.
824  ********************* -->
825 ';
826  }
827  return '';
828  }
829 
836  public function docBodyTagBegin()
837  {
838  return '<body ' . trim($this->bodyTagAdditions . ($this->bodyTagId ? ' id="' . $this->bodyTagId . '"' : '')) . '>';
839  }
840 
846  public function docStyle()
847  {
848  // Implode it all:
849  $inDocStyles = implode(LF, $this->inDocStylesArray);
850 
851  // Reset styles so they won't be added again in insertStylesAndJS()
852  $this->inDocStylesArray = [];
853 
854  if ($this->styleSheetFile) {
855  $this->pageRenderer->addCssFile($this->styleSheetFile);
856  }
857  if ($this->styleSheetFile2) {
858  $this->pageRenderer->addCssFile($this->styleSheetFile2);
859  }
860 
861  if ($inDocStyles !== '') {
862  $this->pageRenderer->addCssInlineBlock('inDocStyles', $inDocStyles . LF . '/*###POSTCSSMARKER###*/');
863  }
864 
865  if ($this->styleSheetFile_post) {
866  $this->pageRenderer->addCssFile($this->styleSheetFile_post);
867  }
868  }
869 
878  public function addStyleSheet($key, $href, $title = '', $relation = 'stylesheet')
879  {
880  $this->pageRenderer->addCssFile($href, $relation, 'screen', $title);
881  }
882 
888  public function addStyleSheetDirectory($path)
889  {
890  $path = GeneralUtility::getFileAbsFileName($path);
891  // Read all files in directory and sort them alphabetically
892  $cssFiles = GeneralUtility::getFilesInDir($path, 'css');
893  foreach ($cssFiles as $cssFile) {
894  $this->pageRenderer->addCssFile(PathUtility::getRelativePathTo($path) . $cssFile);
895  }
896  }
897 
905  public function insertStylesAndJS($content)
906  {
907  $styles = LF . implode(LF, $this->inDocStylesArray);
908  $content = str_replace('/*###POSTCSSMARKER###*/', $styles, $content);
909 
910  // Insert accumulated JS
911  $jscode = $this->JScode . LF . GeneralUtility::wrapJS(implode(LF, $this->JScodeArray));
912  $content = str_replace('<!--###POSTJSMARKER###-->', $jscode, $content);
913  return $content;
914  }
915 
922  {
923  $stylesheetDirectories = [];
924  // Stylesheets from skins
925  // merge default css directories ($this->stylesheetsSkin) with additional ones and include them
926  if (is_array($GLOBALS['TBE_STYLES']['skins'])) {
927  // loop over all registered skins
928  foreach ($GLOBALS['TBE_STYLES']['skins'] as $skinExtKey => $skin) {
929  $skinStylesheetDirs = $this->stylesheetsSkins;
930  // Skins can add custom stylesheetDirectories using
931  // $GLOBALS['TBE_STYLES']['skins'][$_EXTKEY]['stylesheetDirectories']
932  if (is_array($skin['stylesheetDirectories'])) {
933  $skinStylesheetDirs = array_merge($skinStylesheetDirs, $skin['stylesheetDirectories']);
934  }
935  // Add all registered directories
936  foreach ($skinStylesheetDirs as $stylesheetDir) {
937  // for EXT:myskin/stylesheets/ syntax
938  if (strpos($stylesheetDir, 'EXT:') === 0) {
939  list($extKey, $path) = explode('/', substr($stylesheetDir, 4), 2);
940  if (!empty($extKey) && ExtensionManagementUtility::isLoaded($extKey) && !empty($path)) {
941  $stylesheetDirectories[] = ExtensionManagementUtility::extPath($extKey) . $path;
942  }
943  } else {
944  // For relative paths
945  $stylesheetDirectories[] = ExtensionManagementUtility::extPath($skinExtKey) . $stylesheetDir;
946  }
947  }
948  }
949  }
950  return $stylesheetDirectories;
951  }
952 
958  public function generator()
959  {
960  $str = 'TYPO3 CMS, ' . TYPO3_URL_GENERAL . ', &#169; Kasper Sk&#229;rh&#248;j ' . TYPO3_copyright_year . ', extensions are copyright of their respective owners.';
961  return '<meta name="generator" content="' . $str . '" />';
962  }
963 
970  public function xUaCompatible($content = 'IE=8')
971  {
972  return '<meta http-equiv="X-UA-Compatible" content="' . $content . '" />';
973  }
974 
975  /*****************************************
976  *
977  * OTHER ELEMENTS
978  * Tables, buttons, formatting dimmed/red strings
979  *
980  ******************************************/
995  public function icons($type, $styleAttribValue = '')
996  {
998  switch ($type) {
999  case self::STATUS_ICON_ERROR:
1000  $icon = 'status-dialog-error';
1001  break;
1002  case self::STATUS_ICON_WARNING:
1003  $icon = 'status-dialog-warning';
1004  break;
1005  case self::STATUS_ICON_NOTIFICATION:
1006  $icon = 'status-dialog-notification';
1007  break;
1008  case self::STATUS_ICON_OK:
1009  $icon = 'status-dialog-ok';
1010  break;
1011  default:
1012  // Do nothing
1013  }
1014  if ($icon) {
1015  return $this->iconFactory->getIcon($icon, Icon::SIZE_SMALL)->render();
1016  }
1017  }
1018 
1027  public function t3Button($onClick, $label)
1028  {
1030  $button = '<input class="btn btn-default" type="submit" onclick="' . htmlspecialchars($onClick) . '; return false;" value="' . htmlspecialchars($label) . '" />';
1031  return $button;
1032  }
1033 
1041  public function wrapInCData($string)
1042  {
1044  $string = '/*<![CDATA[*/' . $string . '/*]]>*/';
1045  return $string;
1046  }
1047 
1058  public function wrapScriptTags($string, $linebreak = true)
1059  {
1061  if (trim($string)) {
1062  // <script wrapped in nl?
1063  $cr = $linebreak ? LF : '';
1064  // Remove nl from the beginning
1065  $string = ltrim($string, LF);
1066  // Re-ident to one tab using the first line as reference
1067  if ($string[0] === TAB) {
1068  $string = TAB . ltrim($string, TAB);
1069  }
1070  $string = $cr . '<script type="text/javascript">
1071 /*<![CDATA[*/
1072 ' . $string . '
1073 /*]]>*/
1074 </script>' . $cr;
1075  }
1076  return trim($string);
1077  }
1078 
1088  public function funcMenu($content, $menu)
1089  {
1091  return '
1092  <table border="0" cellpadding="0" cellspacing="0" width="100%" id="typo3-funcmenu">
1093  <tr>
1094  <td valign="top" nowrap="nowrap">' . $content . '</td>
1095  <td valign="top" align="right" nowrap="nowrap">' . $menu . '</td>
1096  </tr>
1097  </table>';
1098  }
1099 
1106  public function loadJavascriptLib($lib)
1107  {
1109  $this->pageRenderer->addJsFile($lib);
1110  }
1111 
1117  public function getContextMenuCode()
1118  {
1120  $this->pageRenderer->loadJquery();
1121  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
1122  }
1123 
1132  public function getDragDropCode($table, $additionalJavaScriptCode = '')
1133  {
1135  $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LegacyTree', 'function() {
1136  DragDrop.table = "' . $table . '";
1137  ' . $additionalJavaScriptCode . '
1138  }');
1139  }
1140 
1156  public function getTabMenu($mainParams, $elementName, $currentValue, $menuItems, $script = '', $addparams = '')
1157  {
1159  $content = '';
1160  if (is_array($menuItems)) {
1161  if (!is_array($mainParams)) {
1162  $mainParams = ['id' => $mainParams];
1163  }
1164  $mainParams = GeneralUtility::implodeArrayForUrl('', $mainParams);
1165  if (!$script) {
1166  $script = basename(PATH_thisScript);
1167  }
1168  $menuDef = [];
1169  foreach ($menuItems as $value => $label) {
1170  $menuDef[$value]['isActive'] = (string)$currentValue === (string)$value;
1171  $menuDef[$value]['label'] = htmlspecialchars($label, ENT_COMPAT, 'UTF-8', false);
1172  $menuDef[$value]['url'] = $script . '?' . $mainParams . $addparams . '&' . $elementName . '=' . $value;
1173  }
1174  $content = $this->getTabMenuRaw($menuDef);
1175  }
1176  return $content;
1177  }
1178 
1186  public function getTabMenuRaw($menuItems)
1187  {
1188  if (!is_array($menuItems)) {
1189  return '';
1190  }
1191 
1192  $options = '';
1193  foreach ($menuItems as $id => $def) {
1194  $class = $def['isActive'] ? 'active' : '';
1195  $label = $def['label'];
1196  $url = htmlspecialchars($def['url']);
1197  $params = $def['addParams'];
1198 
1199  $options .= '<li class="' . $class . '">' .
1200  '<a href="' . $url . '" ' . $params . '>' . $label . '</a>' .
1201  '</li>';
1202  }
1203 
1204  return '<ul class="nav nav-tabs" role="tablist">' .
1205  $options .
1206  '</ul>';
1207  }
1208 
1218  public function getVersionSelector($id, $noAction = false)
1219  {
1221  if (
1223  ExtensionManagementUtility::isLoaded('compatibility7') &&
1225  ) {
1226  $versionGuiObj = GeneralUtility::makeInstance(\TYPO3\CMS\Compatibility7\View\VersionView::class);
1227  return $versionGuiObj->getVersionSelector($id, $noAction);
1228  }
1229  }
1230 
1238  public function getHtmlTemplate($filename)
1239  {
1240  // setting the name of the original HTML template
1241  $this->moduleTemplateFilename = $filename;
1242  if ($GLOBALS['TBE_STYLES']['htmlTemplates'][$filename]) {
1243  $filename = $GLOBALS['TBE_STYLES']['htmlTemplates'][$filename];
1244  }
1245  if (GeneralUtility::isFirstPartOfStr($filename, 'EXT:')) {
1246  $filename = GeneralUtility::getFileAbsFileName($filename);
1247  } elseif (!GeneralUtility::isAbsPath($filename)) {
1248  $filename = GeneralUtility::resolveBackPath($filename);
1249  } elseif (!GeneralUtility::isAllowedAbsPath($filename)) {
1250  $filename = '';
1251  }
1252  $htmlTemplate = '';
1253  if ($filename !== '') {
1254  $htmlTemplate = file_get_contents($filename);
1255  }
1256  return $htmlTemplate;
1257  }
1258 
1264  public function setModuleTemplate($filename)
1265  {
1266  $this->moduleTemplate = $this->getHtmlTemplate($filename);
1267  }
1268 
1279  public function moduleBody($pageRecord = [], $buttons = [], $markerArray = [], $subpartArray = [])
1280  {
1281  // Get the HTML template for the module
1282  $moduleBody = $this->templateService->getSubpart($this->moduleTemplate, '###FULLDOC###');
1283  // Add CSS
1284  $this->inDocStylesArray[] = 'html { overflow: hidden; }';
1285  // Get the page path for the docheader
1286  $markerArray['PAGEPATH'] = $this->getPagePath($pageRecord);
1287  // Get the page info for the docheader
1288  $markerArray['PAGEINFO'] = $this->getPageInfo($pageRecord);
1289  // Get all the buttons for the docheader
1290  $docHeaderButtons = $this->getDocHeaderButtons($buttons);
1291  // Merge docheader buttons with the marker array
1292  $markerArray = array_merge($markerArray, $docHeaderButtons);
1293  // replacing subparts
1294  foreach ($subpartArray as $marker => $content) {
1295  $moduleBody = $this->templateService->substituteSubpart($moduleBody, $marker, $content);
1296  }
1297  // adding flash messages
1298  if ($this->showFlashMessages) {
1299  $flashMessages = $this->getFlashMessages();
1300  if (!empty($flashMessages)) {
1301  $markerArray['FLASHMESSAGES'] = $flashMessages;
1302  // If there is no dedicated marker for the messages present
1303  // then force them to appear before the content
1304  if (strpos($moduleBody, '###FLASHMESSAGES###') === false) {
1305  $moduleBody = str_replace('###CONTENT###', '###FLASHMESSAGES######CONTENT###', $moduleBody);
1306  }
1307  }
1308  }
1309  // Hook for adding more markers/content to the page, like the version selector
1310  if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['moduleBodyPostProcess'])) {
1311  $params = [
1312  'moduleTemplateFilename' => &$this->moduleTemplateFilename,
1313  'moduleTemplate' => &$this->moduleTemplate,
1314  'moduleBody' => &$moduleBody,
1315  'markers' => &$markerArray,
1316  'parentObject' => &$this
1317  ];
1318  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['moduleBodyPostProcess'] as $funcRef) {
1319  GeneralUtility::callUserFunction($funcRef, $params, $this);
1320  }
1321  }
1322  // Replacing all markers with the finished markers and return the HTML content
1323  return $this->templateService->substituteMarkerArray($moduleBody, $markerArray, '###|###');
1324  }
1325 
1331  public function getFlashMessages()
1332  {
1334  $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
1336  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
1337  return $defaultFlashMessageQueue->renderFlashMessages();
1338  }
1339 
1347  public function renderQueuedFlashMessages(ServerRequestInterface $request, ResponseInterface $response)
1348  {
1350  $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
1352  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
1353  $flashMessages = $defaultFlashMessageQueue->getAllMessagesAndFlush();
1354 
1355  $messages = [];
1356  foreach ($flashMessages as $flashMessage) {
1357  $messages[] = [
1358  'title' => $flashMessage->getTitle(),
1359  'message' => $flashMessage->getMessage(),
1360  'severity' => $flashMessage->getSeverity()
1361  ];
1362  }
1363 
1364  $response->getBody()->write(json_encode($messages));
1365  return $response;
1366  }
1367 
1374  protected function getDocHeaderButtons($buttons)
1375  {
1376  $markers = [];
1377  // Fill buttons for left and right float
1378  $floats = ['left', 'right'];
1379  foreach ($floats as $key) {
1380  // Get the template for each float
1381  $buttonTemplate = $this->templateService->getSubpart($this->moduleTemplate, '###BUTTON_GROUPS_' . strtoupper($key) . '###');
1382  // Fill the button markers in this float
1383  $buttonTemplate = $this->templateService->substituteMarkerArray($buttonTemplate, $buttons, '###|###', true);
1384  // getting the wrap for each group
1385  $buttonWrap = $this->templateService->getSubpart($this->moduleTemplate, '###BUTTON_GROUP_WRAP###');
1386  // looping through the groups (max 6) and remove the empty groups
1387  for ($groupNumber = 1; $groupNumber < 6; $groupNumber++) {
1388  $buttonMarker = '###BUTTON_GROUP' . $groupNumber . '###';
1389  $buttonGroup = $this->templateService->getSubpart($buttonTemplate, $buttonMarker);
1390  if (trim($buttonGroup)) {
1391  if ($buttonWrap) {
1392  $buttonGroup = $this->templateService->substituteMarker($buttonWrap, '###BUTTONS###', $buttonGroup);
1393  }
1394  $buttonTemplate = $this->templateService->substituteSubpart($buttonTemplate, $buttonMarker, trim($buttonGroup));
1395  }
1396  }
1397  // Replace the marker with the template and remove all line breaks (for IE compat)
1398  $markers['BUTTONLIST_' . strtoupper($key)] = str_replace(LF, '', $buttonTemplate);
1399  }
1400  // Hook for manipulating docHeaderButtons
1401  if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['docHeaderButtonsHook'])) {
1402  $params = [
1403  'buttons' => $buttons,
1404  'markers' => &$markers,
1405  'pObj' => &$this
1406  ];
1407  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['docHeaderButtonsHook'] as $funcRef) {
1408  GeneralUtility::callUserFunction($funcRef, $params, $this);
1409  }
1410  }
1411  return $markers;
1412  }
1413 
1420  protected function getPagePath($pageRecord)
1421  {
1422  // Is this a real page
1423  if (is_array($pageRecord) && $pageRecord['uid']) {
1424  $title = substr($pageRecord['_thePathFull'], 0, -1);
1425  // Remove current page title
1426  $pos = strrpos($title, $pageRecord['title']);
1427  if ($pos !== false) {
1428  $title = substr($title, 0, $pos);
1429  }
1430  } else {
1431  $title = '';
1432  }
1433  // Setting the path of the page
1434  $pagePath = htmlspecialchars($GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.path')) . ': <span class="typo3-docheader-pagePath">';
1435  // crop the title to title limit (or 50, if not defined)
1436  $cropLength = empty($GLOBALS['BE_USER']->uc['titleLen']) ? 50 : $GLOBALS['BE_USER']->uc['titleLen'];
1437  $croppedTitle = GeneralUtility::fixed_lgd_cs($title, -$cropLength);
1438  if ($croppedTitle !== $title) {
1439  $pagePath .= '<abbr title="' . htmlspecialchars($title) . '">' . htmlspecialchars($croppedTitle) . '</abbr>';
1440  } else {
1441  $pagePath .= htmlspecialchars($title);
1442  }
1443  $pagePath .= '</span>';
1444  return $pagePath;
1445  }
1446 
1453  protected function getPageInfo($pageRecord)
1454  {
1455  // Add icon with context menu, etc:
1456  // If there IS a real page
1457  if (is_array($pageRecord) && $pageRecord['uid']) {
1458  $alttext = BackendUtility::getRecordIconAltText($pageRecord, 'pages');
1459  $iconImg = '<span title="' . htmlspecialchars($alttext) . '">' . $this->iconFactory->getIconForRecord('pages', $pageRecord, Icon::SIZE_SMALL)->render() . '</span>';
1460  // Make Icon:
1461  $theIcon = BackendUtility::wrapClickMenuOnIcon($iconImg, 'pages', $pageRecord['uid']);
1462  $uid = $pageRecord['uid'];
1463  $title = BackendUtility::getRecordTitle('pages', $pageRecord);
1464  } else {
1465  // On root-level of page tree
1466  // Make Icon
1467  $iconImg = '<span title="' . htmlspecialchars($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']) . '">' . $this->iconFactory->getIcon('apps-pagetree-root', Icon::SIZE_SMALL)->render() . '</span>';
1468  if ($GLOBALS['BE_USER']->user['admin']) {
1469  $theIcon = BackendUtility::wrapClickMenuOnIcon($iconImg, 'pages', 0);
1470  } else {
1471  $theIcon = $iconImg;
1472  }
1473  $uid = '0';
1474  $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
1475  }
1476  // Setting icon with context menu + uid
1477  $pageInfo = $theIcon . '<strong>' . htmlspecialchars($title) . '&nbsp;[' . $uid . ']</strong>';
1478  return $pageInfo;
1479  }
1480 
1486  protected function getBackendFavicon()
1487  {
1488  $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['backend'], ['allowed_classes' => false]);
1489 
1490  if (!empty($extConf['backendFavicon'])) {
1491  $path = $this->getUriForFileName($extConf['backendFavicon']);
1492  } else {
1493  $path = ExtensionManagementUtility::extPath('backend') . 'Resources/Public/Icons/favicon.ico';
1494  }
1495  return PathUtility::getAbsoluteWebPath($path);
1496  }
1497 
1506  protected function getUriForFileName($filename)
1507  {
1508  if (strpos($filename, '://')) {
1509  return $filename;
1510  }
1511  $urlPrefix = '';
1512  if (strpos($filename, 'EXT:') === 0) {
1513  $absoluteFilename = GeneralUtility::getFileAbsFileName($filename);
1514  $filename = '';
1515  if ($absoluteFilename !== '') {
1516  $filename = PathUtility::getAbsoluteWebPath($absoluteFilename);
1517  }
1518  } elseif (strpos($filename, '/') !== 0) {
1519  $urlPrefix = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH');
1520  }
1521  return $urlPrefix . $filename;
1522  }
1523 }
static devLog($msg, $extKey, $severity=0, $dataVar=false)
moduleBody($pageRecord=[], $buttons=[], $markerArray=[], $subpartArray=[])
static compileSelectedGetVarsFromArray($varList, array $getArray, $GPvarAlt=true)
getHeader($table, $row, $path, $noViewPageIcon=false, $tWrap=['', ''], $enableClickMenu=true)
static wrapClickMenuOnIcon( $content, $table, $uid=0, $context='', $_addParams='', $_enDisItems='', $returnTagParameters=false)
static getFilesInDir($path, $extensionList='', $prependPath=false, $order='', $excludePattern='')
static getRelativePathTo($targetPath)
Definition: PathUtility.php:29
addStyleSheet($key, $href, $title='', $relation='stylesheet')
static isFirstPartOfStr($str, $partStr)
static callUserFunction($funcName, &$params, &$ref, $_='', $errorMode=0)
makeShortcutIcon($gvList, $setList, $modName, $motherModName='', $classes='')
formWidth($size=48, $textarea=false, $styleOverride='')
static viewOnClick( $pageUid, $backPath='', $rootLine=null, $anchorSection='', $alternativeUrl='', $additionalGetVars='', $switchFocus=true)
static getAbsoluteWebPath($targetPath)
Definition: PathUtility.php:40
static BEgetRootLine($uid, $clause='', $workspaceOL=false)
static getFileAbsFileName($filename, $_=null, $_2=null)
section($label, $text, $nostrtoupper=false, $sH=false, $type=0, $allowHTMLinHeader=false)
static linkThisScript(array $getParams=[])
static makeInstance($className,... $constructorArguments)
getResourceHeader(\TYPO3\CMS\Core\Resource\ResourceInterface $resource, $tWrap=['', ''], $enableClickMenu=true)
getTabMenu($mainParams, $elementName, $currentValue, $menuItems, $script='', $addparams='')
static implodeArrayForUrl($name, array $theArray, $str='', $skipBlank=false, $rawurlencodeParamName=false)
$extConf
static getRecordTitle($table, $row, $prep=false, $forceResult=true)
getDragDropCode($table, $additionalJavaScriptCode='')
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
static getRecordIconAltText($row, $table='pages')
static fixed_lgd_cs($string, $chars, $appendString='...')
useCompatibilityTag($useCompatibilityTag=true)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
sectionHeader($label, $sH=false, $addAttrib='')