[BUGFIX] FormEngine: Inline getDynamicTabMenu 69/44269/6
authorChristian Kuhn <lolli@schwarzbu.ch>
Sun, 25 Oct 2015 19:45:41 +0000 (20:45 +0100)
committerChristian Kuhn <lolli@schwarzbu.ch>
Wed, 28 Oct 2015 15:01:26 +0000 (16:01 +0100)
getDynamicTabMenu() from DocumentTemplate is one of the last pieces
where FormEngine indirectly calls PageRenderer to load JS stuff
instead of returning those via the return structure of FormEngine.
This leads to missing JS if tabs are added via ajax dom modification
and parent has none yet.
The patch copies parts of the code to the FormEngine, re-uses the
template, but strips the method down to FormEngines need. As a result
getTabMenuId() can be deprecated in DocumentTemplate and removed in
ModuleTemplate. The patch then re-routes other usages of
getDynamicTabMenu from DocumentTemplate to ModuleTemplate, removes
another obsolete parameter in there and deprecates the method in
DocumentTemplate.

Resolves: #69729
Releases: master
Change-Id: Ibb94f036d052d5bb9eb4b85efb434b8a05c7755e
Reviewed-on: https://review.typo3.org/44269
Reviewed-by: Jan Helke <typo3@helke.de>
Tested-by: Jan Helke <typo3@helke.de>
Reviewed-by: Morton Jonuschat <m.jonuschat@mojocode.de>
Tested-by: Morton Jonuschat <m.jonuschat@mojocode.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
12 files changed:
typo3/sysext/backend/Classes/Form/Container/AbstractContainer.php
typo3/sysext/backend/Classes/Form/Container/FlexFormTabsContainer.php
typo3/sysext/backend/Classes/Form/Container/TabsContainer.php
typo3/sysext/backend/Classes/Form/FormResultCompiler.php
typo3/sysext/backend/Classes/Template/DocumentTemplate.php
typo3/sysext/backend/Classes/Template/ModuleTemplate.php
typo3/sysext/compatibility6/Classes/Form/Container/FlexFormTabsContainer.php
typo3/sysext/core/Documentation/Changelog/7.2/Deprecation-65111-getDynTabMenu.rst
typo3/sysext/core/Documentation/Changelog/7.5/Breaking-69795-UnusedDTMTabmenuCodeRemoved.rst
typo3/sysext/core/Documentation/Changelog/master/Deprecation-60712-GetDynamicTabMenu.rst [new file with mode: 0644]
typo3/sysext/linkvalidator/Classes/Report/LinkValidatorReport.php
typo3/sysext/setup/Classes/Controller/SetupModuleController.php

index 77ef3a0..ed09e28 100644 (file)
@@ -21,6 +21,7 @@ use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Backend\Form\AbstractNode;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Fluid\View\StandaloneView;
 
 /**
  * Abstract container has various methods used by the container classes
@@ -71,6 +72,29 @@ abstract class AbstractContainer extends AbstractNode
     }
 
     /**
+     * Render tabs with label and content. Used by TabsContainer and FlexFormTabsContainer.
+     * Re-uses the template Tabs.html which is also used by ModuleTemplate.php.
+     *
+     * @param array $menuItems Tab elements, each element is an array with "label" and "content"
+     * @param string $domId DOM id attribute, will be appended with an iteration number per tab.
+     * @return string
+     */
+    protected function renderTabMenu(array $menuItems, $domId, $defaultTabIndex = 1)
+    {
+        $templatePathAndFileName = 'EXT:backend/Resources/Private/Templates/DocumentTemplate/Tabs.html';
+        $view = GeneralUtility::makeInstance(StandaloneView::class);
+        $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templatePathAndFileName));
+        $view->assignMultiple(array(
+            'id' => $domId,
+            'items' => $menuItems,
+            'defaultTabIndex' => $defaultTabIndex,
+            'wrapContent' => false,
+            'storeLastActiveTab' => true,
+        ));
+        return $view->render();
+    }
+
+    /**
      * Rendering preview output of a field value which is not shown as a form field but just outputted.
      *
      * @param string $value The value to output
index 861de84..42ab85b 100644 (file)
@@ -14,7 +14,6 @@ namespace TYPO3\CMS\Backend\Form\Container;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Backend\Template\DocumentTemplate;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Lang\LanguageService;
 
@@ -34,7 +33,6 @@ class FlexFormTabsContainer extends AbstractContainer
     public function render()
     {
         $languageService = $this->getLanguageService();
-        $docTemplate = $this->getDocumentTemplate();
 
         $table = $this->data['tableName'];
         $row = $this->data['databaseRow'];
@@ -43,12 +41,12 @@ class FlexFormTabsContainer extends AbstractContainer
         $flexFormDataStructureArray = $this->data['flexFormDataStructureArray'];
         $flexFormRowData = $this->data['flexFormRowData'];
 
-        $tabId = 'TCEFORMS:flexform:' . $this->data['parameterArray']['itemFormElName'] . 'lDEF';
-        $tabIdString = $docTemplate->getDynTabMenuId($tabId);
-        $tabCounter = 0;
-
         $resultArray = $this->initializeResultArray();
-        $tabsContent = array();
+        $resultArray['requireJsModules'][] = 'TYPO3/CMS/Backend/Tabs';
+
+        $domIdPrefix = 'DTM-' . GeneralUtility::shortMD5($this->data['parameterArray']['itemFormElName']);
+        $tabCounter = 0;
+        $tabElements = array();
         foreach ($flexFormDataStructureArray['sheets'] as $sheetName => $sheetDataStructure) {
             $flexFormRowSheetDataSubPart = $flexFormRowData['data'][$sheetName]['lDEF'] ?: [];
 
@@ -78,12 +76,12 @@ class FlexFormTabsContainer extends AbstractContainer
             // palette and single field container to render this group
             $options['tabAndInlineStack'][] = array(
                 'tab',
-                $tabIdString . '-' . $tabCounter,
+                $domIdPrefix . '-' . $tabCounter,
             );
             $options['renderType'] = 'flexFormElementContainer';
             $childReturn = $this->nodeFactory->create($options)->render();
 
-            $tabsContent[] = array(
+            $tabElements[] = array(
                 'label' => !empty($sheetDataStructure['ROOT']['sheetTitle']) ? $languageService->sL($sheetDataStructure['ROOT']['sheetTitle']) : $sheetName,
                 'content' => $childReturn['html'],
                 'description' => $sheetDataStructure['ROOT']['sheetDescription'] ? $languageService->sL($sheetDataStructure['ROOT']['sheetDescription']) : '',
@@ -94,25 +92,11 @@ class FlexFormTabsContainer extends AbstractContainer
             $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $childReturn);
         }
 
-        // Feed everything to document template for tab rendering
-        $resultArray['html'] = $docTemplate->getDynamicTabMenu($tabsContent, $tabId, 1, false, false);
+        $resultArray['html'] = $this->renderTabMenu($tabElements, $domIdPrefix);
         return $resultArray;
     }
 
     /**
-     * @throws \RuntimeException
-     * @return DocumentTemplate
-     */
-    protected function getDocumentTemplate()
-    {
-        $docTemplate = $GLOBALS['TBE_TEMPLATE'];
-        if (!is_object($docTemplate)) {
-            throw new \RuntimeException('No instance of DocumentTemplate found', 1427143328);
-        }
-        return $docTemplate;
-    }
-
-    /**
      * @return LanguageService
      */
     protected function getLanguageService()
index 9a78c50..e4061a5 100644 (file)
@@ -14,8 +14,8 @@ namespace TYPO3\CMS\Backend\Form\Container;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Lang\LanguageService;
-use TYPO3\CMS\Backend\Template\DocumentTemplate;
 
 /**
  * Render all tabs of a record that has tabs.
@@ -34,7 +34,6 @@ class TabsContainer extends AbstractContainer
     public function render()
     {
         $languageService = $this->getLanguageService();
-        $docTemplate = $this->getDocumentTemplate();
 
         // All the fields to handle in a flat list
         $fieldsArray = $this->data['fieldsArray'];
@@ -62,15 +61,12 @@ class TabsContainer extends AbstractContainer
             }
         }
 
-        // Iterate over the tabs and compile content in $tabsContent array together with label
-        $tabsContent = array();
         $resultArray = $this->initializeResultArray();
+        $resultArray['requireJsModules'][] = 'TYPO3/CMS/Backend/Tabs';
 
-        $tabId = 'TCEforms:' . $this->data['tableName'] . ':' . $this->data['databaseRow']['uid'];
-        // @todo: This duplicates parts of the docTemplate code
-        $tabIdString = $docTemplate->getDynTabMenuId($tabId);
-
+        $domIdPrefix = 'DTM-' . GeneralUtility::shortMD5($this->data['tableName'] . $this->data['databaseRow']['uid']);
         $tabCounter = 0;
+        $tabElements = array();
         foreach ($tabsArray as $tabWithLabelAndElements) {
             $tabCounter ++;
             $elements = $tabWithLabelAndElements['elements'];
@@ -80,7 +76,7 @@ class TabsContainer extends AbstractContainer
             $options = $this->data;
             $options['tabAndInlineStack'][] = array(
                 'tab',
-                $tabIdString . '-' . $tabCounter,
+                $domIdPrefix . '-' . $tabCounter,
             );
             $options['fieldsArray'] = array();
             foreach ($elements as $element) {
@@ -89,7 +85,7 @@ class TabsContainer extends AbstractContainer
             $options['renderType'] = 'paletteAndSingleContainer';
             $childArray = $this->nodeFactory->create($options)->render();
 
-            $tabsContent[] = array(
+            $tabElements[] = array(
                 'label' => $tabWithLabelAndElements['label'],
                 'content' => $childArray['html'],
             );
@@ -97,8 +93,7 @@ class TabsContainer extends AbstractContainer
             $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $childArray);
         }
 
-        // Feed everything to document template for tab rendering
-        $resultArray['html'] = $docTemplate->getDynamicTabMenu($tabsContent, $tabId, 1, false, false);
+        $resultArray['html'] = $this->renderTabMenu($tabElements, $domIdPrefix);
         return $resultArray;
     }
 
@@ -110,16 +105,4 @@ class TabsContainer extends AbstractContainer
         return $GLOBALS['LANG'];
     }
 
-    /**
-     * @throws \RuntimeException
-     * @return DocumentTemplate
-     */
-    protected function getDocumentTemplate()
-    {
-        $docTemplate = $GLOBALS['TBE_TEMPLATE'];
-        if (!is_object($docTemplate)) {
-            throw new \RuntimeException('No instance of DocumentTemplate found', 1426459735);
-        }
-        return $docTemplate;
-    }
 }
index 6cdf5d2..4d09585 100644 (file)
@@ -306,7 +306,6 @@ class FormResultCompiler
     /**
      * Includes a javascript library that exists in the core /typo3/ directory. The
      * backpath is automatically applied.
-     * This method acts as wrapper for $GLOBALS['SOBE']->doc->loadJavascriptLib($lib).
      *
      * @param string $lib Library name. Call it with the full path like "sysext/core/Resources/Public/JavaScript/QueryGenerator.js" to load it
      * @return void
index 91c551a..ec9192f 100644 (file)
@@ -1613,15 +1613,17 @@ function jumpToUrl(URL) {
      * @param bool $wrapContent If set, the content is wrapped in div structure which provides a padding and border style. Set this FALSE to get unstyled content pane with fullsize content area.
      * @param bool $storeLastActiveTab If set, the last open tab is stored in local storage and will be re-open again. If you don't need this feature, e.g. for wizards like import/export you can disable this behaviour.
      * @return string
+     * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use getDynamicTabMenu() from ModuleTemplate instead.
      */
     public function getDynamicTabMenu(array $menuItems, $identString, $defaultTabIndex = 1, $collapseable = false, $wrapContent = true, $storeLastActiveTab = true)
     {
+        GeneralUtility::logDeprecatedFunction();
         $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Tabs');
         $templatePathAndFileName = 'EXT:backend/Resources/Private/Templates/DocumentTemplate/' . ($collapseable ? 'Collapse.html' : 'Tabs.html');
         $view = GeneralUtility::makeInstance(StandaloneView::class);
         $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templatePathAndFileName));
         $view->assignMultiple(array(
-            'id' => $this->getDynTabMenuId($identString),
+            'id' => 'DTM-' . GeneralUtility::shortMD5($identString),
             'items' => $menuItems,
             'defaultTabIndex' => $defaultTabIndex,
             'wrapContent' => $wrapContent,
@@ -1657,9 +1659,11 @@ function jumpToUrl(URL) {
      *
      * @param string $identString Identification string. This should be unique for every instance of a dynamic menu!
      * @return string The id with a short MD5 of $identString and prefixed "DTM-", like "DTM-2e8791854a
+     * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
      */
     public function getDynTabMenuId($identString)
     {
+        GeneralUtility::logDeprecatedFunction();
         $id = 'DTM-' . GeneralUtility::shortMD5($identString);
         return $id;
     }
index 7ff335f..8b27080 100644 (file)
@@ -397,15 +397,10 @@ class ModuleTemplate
     }
 
     /**
-     * Creates a DYNAMIC tab-menu where the tabs or collapsible are rendered with bootstrap markup
-     *
-     * @param array $menuItems Numeric array where each entry is an array in itself with associative keys: "label"
-     *                         contains the label for the TAB, "content" contains the HTML content that goes into the
-     *                         div-layer of the tabs content. "description" contains description text to be shown in the
-     *                         layer. "linkTitle" is short text for the title attribute of the tab-menu link (mouse-over
-     *                         text of tab). "stateIcon" indicates a standard status icon (see ->icon(),
-     *                         values: -1, 1, 2, 3). "icon" is an image tag placed before the text.
-     * @param string $identString Identification string. This should be unique for every instance of a dynamic menu!
+     * Creates a tab menu where the tabs or collapsible are rendered with bootstrap markup
+     *
+     * @param array $menuItems Tab elements, each element is an array with "label" and "content"
+     * @param string $domId DOM id attribute, will be appended with an iteration number per tab.
      * @param int $defaultTabIndex Default tab to open (for toggle <=0). Value corresponds to integer-array index + 1
      *                             (index zero is "1", index "1" is 2 etc.). A value of zero (or something non-existing
      *                             will result in no default tab open.
@@ -418,37 +413,22 @@ class ModuleTemplate
      *                                 disable this behaviour.
      * @return string
      */
-    public function getDynamicTabMenu(array $menuItems, $identString, $defaultTabIndex = 1, $collapsible = false, $wrapContent = true, $storeLastActiveTab = true)
+    public function getDynamicTabMenu(array $menuItems, $domId, $defaultTabIndex = 1, $collapsible = false, $wrapContent = true, $storeLastActiveTab = true)
     {
         $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Tabs');
         $templatePathAndFileName = 'EXT:backend/Resources/Private/Templates/DocumentTemplate/' . ($collapsible ? 'Collapse.html' : 'Tabs.html');
         $view = GeneralUtility::makeInstance(StandaloneView::class);
         $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templatePathAndFileName));
         $view->assignMultiple(array(
-            'id' => $this->getDynTabMenuId($identString),
+            'id' => 'DTM-' . GeneralUtility::shortMD5($domId),
             'items' => $menuItems,
             'defaultTabIndex' => $defaultTabIndex,
             'wrapContent' => $wrapContent,
             'storeLastActiveTab' => $storeLastActiveTab,
-            'BACK_PATH' => $GLOBALS['BACK_PATH']
         ));
         return $view->render();
     }
 
-    /**
-     * Creates the id for dynTabMenus.
-     *
-     * @param string $identString Identification string. This should be unique for every instance of a dynamic menu!
-     * @return string The id with a short MD5 of $identString and prefixed "DTM-", like "DTM-2e8791854a
-     */
-    public function getDynTabMenuId($identString)
-    {
-        $id = 'DTM-' . GeneralUtility::shortMD5($identString);
-        return $id;
-    }
-
-
-
     /*******************************************
      * THE FOLLOWING METHODS ARE SUBJECT TO BE DEPRECATED / DROPPED!
      *
index cabea31..b7d342b 100644 (file)
@@ -35,7 +35,6 @@ class FlexFormTabsContainer extends AbstractContainer
     public function render()
     {
         $languageService = $this->getLanguageService();
-        $docTemplate = $this->getDocumentTemplate();
 
         $table = $this->data['tableName'];
         $row = $this->data['databaseRow'];
@@ -45,12 +44,12 @@ class FlexFormTabsContainer extends AbstractContainer
         $flexFormCurrentLanguage = $this->data['flexFormCurrentLanguage'];
         $flexFormRowData = $this->data['flexFormRowData'];
 
-        $tabId = 'TCEFORMS:flexform:' . $this->data['parameterArray']['itemFormElName'] . $flexFormCurrentLanguage;
-        $tabIdString = $docTemplate->getDynTabMenuId($tabId);
-        $tabCounter = 0;
-
         $resultArray = $this->initializeResultArray();
-        $tabsContent = array();
+        $resultArray['requireJsModules'][] = 'TYPO3/CMS/Backend/Tabs';
+
+        $domIdPrefix = 'DTM-' . GeneralUtility::shortMD5($this->data['parameterArray']['itemFormElName'] . $flexFormCurrentLanguage);
+        $tabCounter = 0;
+        $tabElements = array();
         foreach ($flexFormDataStructureArray['sheets'] as $sheetName => $sheetDataStructure) {
             $flexFormRowSheetDataSubPart = $flexFormRowData['data'][$sheetName][$flexFormCurrentLanguage];
 
@@ -80,12 +79,12 @@ class FlexFormTabsContainer extends AbstractContainer
             // palette and single field container to render this group
             $options['tabAndInlineStack'][] = array(
                 'tab',
-                $tabIdString . '-' . $tabCounter,
+                $domIdPrefix . '-' . $tabCounter,
             );
             $options['renderType'] = 'flexFormElementContainer';
             $childReturn = $this->nodeFactory->create($options)->render();
 
-            $tabsContent[] = array(
+            $tabElements[] = array(
                 'label' => !empty($sheetDataStructure['ROOT']['sheetTitle']) ? $languageService->sL($sheetDataStructure['ROOT']['sheetTitle']) : $sheetName,
                 'content' => $childReturn['html'],
                 'description' => $sheetDataStructure['ROOT']['sheetDescription'] ? $languageService->sL($sheetDataStructure['ROOT']['sheetDescription']) : '',
@@ -97,24 +96,11 @@ class FlexFormTabsContainer extends AbstractContainer
         }
 
         // Feed everything to document template for tab rendering
-        $resultArray['html'] = $docTemplate->getDynamicTabMenu($tabsContent, $tabId, 1, false, false);
+        $resultArray['html'] = $this->renderTabMenu($tabElements, $domIdPrefix);
         return $resultArray;
     }
 
     /**
-     * @throws \RuntimeException
-     * @return DocumentTemplate
-     */
-    protected function getDocumentTemplate()
-    {
-        $docTemplate = $GLOBALS['TBE_TEMPLATE'];
-        if (!is_object($docTemplate)) {
-            throw new \RuntimeException('No instance of DocumentTemplate found', 1427143328);
-        }
-        return $docTemplate;
-    }
-
-    /**
      * @return LanguageService
      */
     protected function getLanguageService()
index 23ee1c0..2a29e3b 100644 (file)
@@ -24,4 +24,4 @@ All installations which make use of ``DocumentTemplate::getDynTabMenu()``
 Migration
 =========
 
-Use ``DocumentTemplate::getDynamicTabMenu()`` instead of ``DocumentTemplate::getDynTabMenu()``
+Use ``ModuleTemplate::getDynamicTabMenu()`` instead of ``DocumentTemplate::getDynTabMenu()``
index c12b5dc..6641fce 100644 (file)
@@ -26,5 +26,5 @@ TYPO3 Installations with custom extensions that use the logic mentioned above.
 Migration
 =========
 
-Use DocumentTemplate::getDynamicTabMenu() directly to use the Bootstrap-based API
+Use ModuleTemplate::getDynamicTabMenu() directly to use the Bootstrap-based API
 shipped with the TYPO3 Core.
\ No newline at end of file
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-60712-GetDynamicTabMenu.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-60712-GetDynamicTabMenu.rst
new file mode 100644 (file)
index 0000000..2c862d8
--- /dev/null
@@ -0,0 +1,21 @@
+=============================================================
+Deprecation: #70494 - DocumentTemplate->wrapClickMenuOnIcon()
+=============================================================
+
+Description
+===========
+
+Methods ``TYPO3\CMS\Backend\Template\DocumentTemplate::getDynamicTabMenu()`` and
+``TYPO3\CMS\Backend\Template\DocumentTemplate::getDynTabMenuId()`` have been deprecated.
+
+
+Affected Installations
+======================
+
+Instances with custom backend modules that use these methods.
+
+
+Migration
+=========
+
+Use ``TYPO3\CMS\Backend\Utility\ModuleTemplate::getDynamicTabMenu()`` instead.
index 3932b5b..f3d07bf 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\Linkvalidator\Report;
  */
 
 use TYPO3\CMS\Backend\Template\DocumentTemplate;
+use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
@@ -224,7 +225,10 @@ class LinkValidatorReport extends \TYPO3\CMS\Backend\Module\AbstractFunctionModu
             );
         }
 
-        return $this->doc->getDynamicTabMenu($menuItems, 'report-linkvalidator');
+        // @todo: Use $this-moduleTemplate as soon as this class extends from AbstractModule
+        /** @var ModuleTemplate $moduleTemplate */
+        $moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
+        return $moduleTemplate->getDynamicTabMenu($menuItems, 'report-linkvalidator');
     }
 
     /**
index 811241c..4be8f3e 100644 (file)
@@ -452,7 +452,7 @@ class SetupModuleController extends AbstractModule
 
         // Render the menu items
         $menuItems = $this->renderUserSetup();
-        $this->content .= $this->doc->getDynamicTabMenu($menuItems, 'user-setup', 1, false, false);
+        $this->content .= $this->moduleTemplate->getDynamicTabMenu($menuItems, 'user-setup', 1, false, false);
         $formToken = $this->formProtection->generateToken('BE user setup', 'edit');
         $this->content .= $this->doc->section('', '<input type="hidden" name="simUser" value="' . $this->simUser . '" />
             <input type="hidden" name="formToken" value="' . $formToken . '" />