diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-76085-AddFluidDebugInformationToAdminPanel.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-76085-AddFluidDebugInformationToAdminPanel.rst new file mode 100644 index 0000000000000000000000000000000000000000..5d51c002c900224f34e66390edf4598a0f650ed0 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-76085-AddFluidDebugInformationToAdminPanel.rst @@ -0,0 +1,22 @@ +.. include:: ../../Includes.txt + +============================================================ +Feature: #76085 - Add fluid debug information to admin panel +============================================================ + +See :issue:`76085` + +Description +=========== + +A new setting in the admin panel (Preview > Show fluid debug output) enable fluid debug output. +If the checkbox is enabled, the path to the template file of a partial and the name of a section will be shown in the +frontend directly above the markup. +With this feature an integrator can easily find the correct template and section. + +Impact +====== + +Activating this option can break the output in frontend or result in unexpected behavior. + +.. index:: Frontend \ No newline at end of file diff --git a/typo3/sysext/fluid/Classes/Core/ViewHelper/ViewHelperResolver.php b/typo3/sysext/fluid/Classes/Core/ViewHelper/ViewHelperResolver.php index b2b854e0180cf360b0da68a548ed19268d50fc24..cf9206a9df846a8f053d7f11ab7df124a2f64491 100644 --- a/typo3/sysext/fluid/Classes/Core/ViewHelper/ViewHelperResolver.php +++ b/typo3/sysext/fluid/Classes/Core/ViewHelper/ViewHelperResolver.php @@ -14,6 +14,7 @@ namespace TYPO3\CMS\Fluid\Core\ViewHelper; * The TYPO3 project - inspiring people to share! */ +use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; @@ -52,6 +53,23 @@ class ViewHelperResolver extends \TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperRes ] ]; + /** + * ViewHelperResolver constructor + * + * Responsible for adding a third namespace in case this is requested from + * the admin panel - causes overlaying of `f:` with `f:debug`. + */ + public function __construct() + { + $configuration = $this->getBackendUser()->uc['TSFE_adminConfig']; + if (TYPO3_MODE === 'FE' + && isset($configuration['preview_showFluidDebug']) + && $configuration['preview_showFluidDebug'] + ) { + $this->namespaces['f'][] = 'TYPO3\\CMS\\Fluid\\ViewHelpers\\Debug'; + } + } + /** * @param string $viewHelperClassName * @return \TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperInterface @@ -68,4 +86,12 @@ class ViewHelperResolver extends \TYPO3Fluid\Fluid\Core\ViewHelper\ViewHelperRes { return GeneralUtility::makeInstance(ObjectManager::class); } + + /** + * @return BackendUserAuthentication + */ + protected function getBackendUser() + { + return $GLOBALS['BE_USER']; + } } diff --git a/typo3/sysext/fluid/Classes/View/TemplatePaths.php b/typo3/sysext/fluid/Classes/View/TemplatePaths.php index ee0fa28b20e56d56e0049ed346d0d7c8b4abfc8b..f4b2efb7a8841cc29938a7f1f22abe88624be340 100644 --- a/typo3/sysext/fluid/Classes/View/TemplatePaths.php +++ b/typo3/sysext/fluid/Classes/View/TemplatePaths.php @@ -208,4 +208,16 @@ class TemplatePaths extends \TYPO3Fluid\Fluid\View\TemplatePaths ArrayUtility::sortArrayWithIntegerKeys($partialRootPaths) ); } + + /** + * Public API for currently protected method. Can be dropped when switching to + * Fluid 1.1.0 or above. + * + * @param string $partialName + * @return string + */ + public function getPartialPathAndFilename($partialName) + { + return parent::getPartialPathAndFilename($partialName); + } } diff --git a/typo3/sysext/fluid/Classes/ViewHelpers/Debug/RenderViewHelper.php b/typo3/sysext/fluid/Classes/ViewHelpers/Debug/RenderViewHelper.php new file mode 100644 index 0000000000000000000000000000000000000000..035f37ef9bf40ac0ed3382a270a6666805dbc838 --- /dev/null +++ b/typo3/sysext/fluid/Classes/ViewHelpers/Debug/RenderViewHelper.php @@ -0,0 +1,124 @@ +<?php +namespace TYPO3\CMS\Fluid\ViewHelpers\Debug; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use TYPO3\CMS\Core\Utility\PathUtility; +use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper; + +/** + * Debuggable version of f:render - performs the same + * rendering operation but wraps the output with HTML + * that can be inspected with the admin panel in FE. + * + * Replaces `f:render` when the admin panel decides + * (see ViewHelperResolver class). Also possible to use + * explicitly by using `f:debug.render` instead of the + * normal `f:render` statement. + * + * @api + */ +class RenderViewHelper extends AbstractViewHelper +{ + + /** + * @var bool + */ + protected $escapeOutput = false; + + /** + * @return void + */ + public function initializeArguments() + { + parent::initializeArguments(); + $this->registerArgument('section', 'string', 'Section to render - combine with partial to render section in partial', false, null); + $this->registerArgument('partial', 'string', 'Partial to render, with or without section', false, null); + $this->registerArgument('arguments', 'array', 'Array of variables to be transferred. Use {_all} for all variables', false, []); + $this->registerArgument('optional', 'boolean', 'If TRUE, considers the *section* optional. Partial never is.', false, false); + $this->registerArgument('default', 'mixed', 'Value (usually string) to be displayed if the section or partial does not exist', false, null); + $this->registerArgument('contentAs', 'string', 'If used, renders the child content and adds it as a template variable with this name for use in the partial/section', false, null); + } + + /** + * Renders the content. + * + * @return string + * @api + */ + public function render() + { + $section = $this->arguments['section']; + $partial = $this->arguments['partial']; + $arguments = (array) $this->arguments['arguments']; + $optional = (boolean) $this->arguments['optional']; + $contentAs = $this->arguments['contentAs']; + $tagContent = $this->renderChildren(); + + if ($contentAs !== null) { + $arguments[$contentAs] = $tagContent; + } + + $content = ''; + if ($partial !== null) { + $content = $this->viewHelperVariableContainer->getView()->renderPartial($partial, $section, $arguments, $optional); + } elseif ($section !== null) { + $content = $this->viewHelperVariableContainer->getView()->renderSection($section, $arguments, $optional); + } + // Replace empty content with default value. If default is + // not set, NULL is returned and cast to a new, empty string + // outside of this ViewHelper. + if ($content === '') { + $content = isset($this->arguments['default']) ? $this->arguments['default'] : $tagContent; + } + + $cssRules = []; + $cssRules[] = 'display: block'; + $cssRules[] = 'background-color: #fff'; + $cssRules[] = 'padding: 5px'; + $cssRules[] = 'border: 1px solid #f00'; + $cssRules[] = 'color: #000'; + $cssRules[] = 'overflow: hidden'; + $cssWrapper = implode(';', $cssRules); + $cssRules[] = 'font-size: 11px'; + $cssRules[] = 'font-family: Monospace'; + $cssTitle = implode(';', $cssRules); + + $debugInfo = []; + if (isset($this->arguments['partial'])) { + $path = $this->renderingContext->getTemplatePaths()->getPartialPathAndFilename($partial); + $path = PathUtility::stripPathSitePrefix($path); + $path = str_replace('typo3conf/ext/', 'EXT:', $path); + $path = str_replace('typo3/sysext/', 'EXT:', $path); + $debugInfo['Partial'] = 'Partial: ' . $path; + } + if (isset($this->arguments['section'])) { + $debugInfo['Section'] = 'Section: ' . htmlspecialchars($section); + } + + $debugContent = sprintf( + '<strong>%s</strong>', + implode('<br />', $debugInfo) + ); + + return sprintf( + '<div class="t3js-debug-template" title="%s" style="%s"><span style="%s">%s</span>%s</div>', + htmlspecialchars(implode('/', array_keys($debugInfo))), + $cssTitle, + $cssWrapper, + $debugContent, + $content + ); + } +} diff --git a/typo3/sysext/frontend/Classes/View/AdminPanelView.php b/typo3/sysext/frontend/Classes/View/AdminPanelView.php index d1cdf9c2ec6806e76ea754a422320e9bf8702698..b7aa91590c50e3cb447190e11cccdb46a746cf7c 100644 --- a/typo3/sysext/frontend/Classes/View/AdminPanelView.php +++ b/typo3/sysext/frontend/Classes/View/AdminPanelView.php @@ -15,6 +15,7 @@ namespace TYPO3\CMS\Frontend\View; */ use TYPO3\CMS\Backend\Utility\BackendUtility; +use TYPO3\CMS\Core\Cache\CacheManager; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction; use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer; @@ -156,13 +157,17 @@ class AdminPanelView $beUser->uc['TSFE_adminConfig'] = array_merge(!is_array($beUser->uc['TSFE_adminConfig']) ? [] : $beUser->uc['TSFE_adminConfig'], $input); unset($beUser->uc['TSFE_adminConfig']['action']); // Actions: - if ($input['action']['clearCache'] && $this->isAdminModuleEnabled('cache')) { + if (($input['action']['clearCache'] && $this->isAdminModuleEnabled('cache')) || isset($input['preview_showFluidDebug'])) { $beUser->extPageInTreeInfo = []; $theStartId = (int)$input['cache_clearCacheId']; $this->getTypoScriptFrontendController()->clearPageCacheContent_pidList($beUser->extGetTreeList($theStartId, $this->extGetFeAdminValue('cache', 'clearCacheLevels'), 0, $beUser->getPagePermsClause(1)) . $theStartId); } // Saving $beUser->writeUC(); + // Flush fluid template cache + $cacheManager = new CacheManager(); + $cacheManager->setCacheConfigurations($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']); + $cacheManager->getCache('fluid_template')->flush(); } $this->getTimeTracker()->LR = $this->extGetFeAdminValue('tsdebug', 'LR'); if ($this->extGetFeAdminValue('cache', 'noCache')) { @@ -383,6 +388,8 @@ class AdminPanelView $this->extNeedUpdate = true; $out .= $this->extGetItem('preview_showHiddenPages', '', '<input type="hidden" name="TSFE_ADMIN_PANEL[preview_showHiddenPages]" value="0" /><input type="checkbox" id="preview_showHiddenPages" name="TSFE_ADMIN_PANEL[preview_showHiddenPages]" value="1"' . ($this->getBackendUser()->uc['TSFE_adminConfig']['preview_showHiddenPages'] ? ' checked="checked"' : '') . ' />'); $out .= $this->extGetItem('preview_showHiddenRecords', '', '<input type="hidden" name="TSFE_ADMIN_PANEL[preview_showHiddenRecords]" value="0" /><input type="checkbox" id="preview_showHiddenRecords" name="TSFE_ADMIN_PANEL[preview_showHiddenRecords]" value="1"' . ($this->getBackendUser()->uc['TSFE_adminConfig']['preview_showHiddenRecords'] ? ' checked="checked"' : '') . ' />'); + $out .= $this->extGetItem('preview_showFluidDebug', '', '<input type="hidden" name="TSFE_ADMIN_PANEL[preview_showFluidDebug]" value="0" /><input type="checkbox" id="preview_showFluidDebug" name="TSFE_ADMIN_PANEL[preview_showFluidDebug]" value="1"' . (!empty($this->getBackendUser()->uc['TSFE_adminConfig']['preview_showFluidDebug']) ? ' checked="checked"' : '') . ' />'); + // Simulate date $out .= $this->extGetItem('preview_simulateDate', '<input type="text" id="preview_simulateDate" name="TSFE_ADMIN_PANEL[preview_simulateDate]_hr" onchange="TSFEtypo3FormFieldGet(\'TSFE_ADMIN_PANEL[preview_simulateDate]\', \'datetime\', \'\', 1,0);" /><input type="hidden" name="TSFE_ADMIN_PANEL[preview_simulateDate]" value="' . $this->getBackendUser()->uc['TSFE_adminConfig']['preview_simulateDate'] . '" />'); $this->extJSCODE .= 'TSFEtypo3FormFieldSet("TSFE_ADMIN_PANEL[preview_simulateDate]", "datetime", "", 0, 0);'; diff --git a/typo3/sysext/lang/locallang_tsfe.xlf b/typo3/sysext/lang/locallang_tsfe.xlf index 498ba9051b3325c0e598c35bb8507f37e209db86..6f53f2377e7ae040d11bfded55fc6e9475caca60 100644 --- a/typo3/sysext/lang/locallang_tsfe.xlf +++ b/typo3/sysext/lang/locallang_tsfe.xlf @@ -18,6 +18,9 @@ <trans-unit id="preview_showHiddenRecords"> <source>Show hidden records</source> </trans-unit> + <trans-unit id="preview_showFluidDebug"> + <source>Show fluid debug output</source> + </trans-unit> <trans-unit id="preview_simulateDate"> <source>Simulate time</source> </trans-unit>