From 694dbadccc4b44794c05825fe1ed8f947f9c4c1e Mon Sep 17 00:00:00 2001
From: Michael Oehlhof <typo3@oehlhof.de>
Date: Sun, 13 Mar 2016 08:07:11 +0100
Subject: [PATCH] [TASK] Fluidification of TypoScriptTemplateModuleController

Moved all HTML code from the PHP code to an own Fluid template.

Resolves: #75028
Releases: master
Change-Id: I8efc78b60b6967922fc883354ce8df51b1094d0c
Reviewed-on: https://review.typo3.org/47226
Tested-by: Bamboo TYPO3com <info@typo3.com>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Andreas Fernandez <typo3@scripting-base.de>
Tested-by: Andreas Fernandez <typo3@scripting-base.de>
---
 .../TypoScriptTemplateModuleController.php    | 261 ++++++++++--------
 .../Private/Partials/NoTemplate.html          |  30 ++
 .../Resources/Private/Templates/InfoBox.html  |   3 -
 .../Resources/Private/Templates/Main.html     |   5 +
 .../Resources/Private/Templates/PageZero.html |  36 +++
 5 files changed, 222 insertions(+), 113 deletions(-)
 create mode 100644 typo3/sysext/tstemplate/Resources/Private/Partials/NoTemplate.html
 delete mode 100644 typo3/sysext/tstemplate/Resources/Private/Templates/InfoBox.html
 create mode 100644 typo3/sysext/tstemplate/Resources/Private/Templates/Main.html
 create mode 100644 typo3/sysext/tstemplate/Resources/Private/Templates/PageZero.html

diff --git a/typo3/sysext/tstemplate/Classes/Controller/TypoScriptTemplateModuleController.php b/typo3/sysext/tstemplate/Classes/Controller/TypoScriptTemplateModuleController.php
index 40e47f02e4a9..2f09db3850d2 100644
--- a/typo3/sysext/tstemplate/Classes/Controller/TypoScriptTemplateModuleController.php
+++ b/typo3/sysext/tstemplate/Classes/Controller/TypoScriptTemplateModuleController.php
@@ -159,19 +159,11 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
      */
     public function main()
     {
-        // Template markers
-        $markers = array(
-            'CSH' => '',
-            'FUNC_MENU' => '',
-            'CONTENT' => ''
-        );
-
         // Access check...
         // The page will show only if there is a valid page and if this page may be viewed by the user
         $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
         $this->access = is_array($this->pageinfo);
-
-        $lang = $this->getLanguageService();
+        $view = $this->getFluidTemplateObject('tstemplate');
 
         if ($this->id && $this->access) {
             $urlParameters = array(
@@ -182,35 +174,37 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
 
             // JavaScript
             $this->moduleTemplate->addJavaScriptCode(
-                'TSTemplateInlineJS', '
-                function uFormUrl(aname) {
-                    document.forms[0].action = ' . GeneralUtility::quoteJSvalue(($aHref . '#')) . '+aname;
+                'TSTemplateInlineJS',
+                'function uFormUrl(aname) {
+                    document.forms[0].action = ' . GeneralUtility::quoteJSvalue($aHref . '#') . '+aname;
                 }
                 function brPoint(lnumber,t) {
-                    window.location.href = ' . GeneralUtility::quoteJSvalue(($aHref . '&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TypoScriptTemplateObjectBrowserModuleFunctionController&SET[ts_browser_type]=')) . '+(t?"setup":"const")+"&breakPointLN="+lnumber;
+                    window.location.href = '
+                . GeneralUtility::quoteJSvalue(
+                    $aHref . '&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\'
+                    . 'TypoScriptTemplateObjectBrowserModuleFunctionController&SET[ts_browser_type]='
+                ) . '+(t?"setup":"const")+"&breakPointLN="+lnumber;
                     return false;
                 }
-                if (top.fsMod) top.fsMod.recentIds["web"] = ' . $this->id . ';
-            ');
+                if (top.fsMod) top.fsMod.recentIds["web"] = ' . $this->id . ';'
+            );
             $this->moduleTemplate->getPageRenderer()->addCssInlineBlock(
-                'TSTemplateInlineStyle', '
-                TABLE#typo3-objectBrowser { width: 100%; margin-bottom: 24px; }
+                'TSTemplateInlineStyle',
+                'TABLE#typo3-objectBrowser { width: 100%; margin-bottom: 24px; }
                 TABLE#typo3-objectBrowser A { text-decoration: none; }
                 TABLE#typo3-objectBrowser .comment { color: maroon; font-weight: bold; }
                 .ts-typoscript { width: 100%; }
                 .tsob-search-submit {margin-left: 3px; margin-right: 3px;}
-                .tst-analyzer-options { margin:5px 0; }
-            ');
+                .tst-analyzer-options { margin:5px 0; }'
+            );
             // Setting up the context sensitive menu:
             $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ClickMenu');
             // Build the module content
-            $this->content = '<form action="' . htmlspecialchars($aHref) . '" method="post" enctype="multipart/form-data" id="TypoScriptTemplateModuleController" name="editForm" class="form">';
-            $this->content .= $this->moduleTemplate->header($lang->getLL('moduleTitle'));
-            $this->extObjContent();
+            $view->assign('actionName', $aHref);
+            $view->assign('typoscriptTemplateModuleContent', $this->getExtObjContent());
             // Setting up the buttons and markers for docheader
             $this->getButtons();
             $this->generateMenu();
-            $this->content .= '</form>';
         } else {
             $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
             $queryBuilder->getRestrictions()
@@ -237,25 +231,14 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
                 $this->setInPageArray($pArray, BackendUtility::BEgetRootLine($record['uid'], 'AND 1=1'), $record);
             }
 
-            $table = '<div class="table-fit"><table class="table table-striped table-hover" id="ts-overview">' .
-                    '<thead>' .
-                    '<tr>' .
-                    '<th>' . $lang->getLL('pageName') . '</th>' .
-                    '<th>' . $lang->getLL('templates') . '</th>' .
-                    '<th>' . $lang->getLL('isRoot') . '</th>' .
-                    '<th>' . $lang->getLL('isExt') . '</th>' .
-                    '</tr>' .
-                    '</thead>' .
-                    '<tbody>' . implode('', $this->renderList($pArray)) . '</tbody>' .
-                    '</table></div>';
-
-            $this->content = $this->moduleTemplate->header($lang->getLL('moduleTitle'));
-            $this->content .= '<p class="lead">' . $lang->getLL('overview') . '</p>' . $table;
+            $view->getRenderingContext()->setControllerAction('PageZero');
+            $view->assign('templateList', $this->renderList($pArray));
 
             // RENDER LIST of pages with templates, END
             // Setting up the buttons and markers for docheader
             $this->getButtons();
         }
+        $this->content = $view->render();
     }
 
     /**
@@ -329,7 +312,11 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
             // View page
             $viewButton = $buttonBar->makeLinkButton()
                 ->setHref('#')
-                ->setOnClick(BackendUtility::viewOnClick($this->pageinfo['uid'], '', BackendUtility::BEgetRootLine($this->pageinfo['uid'])))
+                ->setOnClick(BackendUtility::viewOnClick(
+                    $this->pageinfo['uid'],
+                    '',
+                    BackendUtility::BEgetRootLine($this->pageinfo['uid'])
+                ))
                 ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage'))
                 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-view', Icon::SIZE_SMALL));
             $buttonBar->addButton($viewButton, ButtonBar::BUTTON_POSITION_LEFT, 99);
@@ -346,7 +333,10 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
                         ->setName('_savedok')
                         ->setValue('1')
                         ->setForm('TypoScriptTemplateModuleController')
-                        ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save', Icon::SIZE_SMALL))
+                        ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
+                            'actions-document-save',
+                            Icon::SIZE_SMALL
+                        ))
                         ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc'));
 
                     $saveAndCloseButton = $buttonBar->makeInputButton()
@@ -354,7 +344,10 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
                         ->setValue('1')
                         ->setForm('TypoScriptTemplateModuleController')
                         ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveCloseDoc'))
-                        ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save-close', Icon::SIZE_SMALL));
+                        ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
+                            'actions-document-save-close',
+                            Icon::SIZE_SMALL
+                        ));
 
                     $splitButtonElement = $buttonBar->makeSplitButton()
                         ->addItem($saveButton)
@@ -366,23 +359,33 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
                     $closeButton = $buttonBar->makeLinkButton()
                         ->setHref(BackendUtility::getModuleUrl('web_ts', array('id' => $this->id)))
                         ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.closeDoc'))
-                        ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-close', Icon::SIZE_SMALL));
+                        ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
+                            'actions-document-close',
+                            Icon::SIZE_SMALL
+                        ));
                     $buttonBar->addButton($closeButton);
                 } else {
                     $newButton = $buttonBar->makeLinkButton()
                         ->setHref(BackendUtility::getModuleUrl('web_ts', $urlParameters))
                         ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:db_new.php.pagetitle'))
-                        ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-new', Icon::SIZE_SMALL));
+                        ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
+                            'actions-document-new',
+                            Icon::SIZE_SMALL
+                        ));
                     $buttonBar->addButton($newButton);
                 }
-            } elseif ($this->extClassConf['name'] === TypoScriptTemplateConstantEditorModuleFunctionController::class && !empty($this->MOD_MENU['constant_editor_cat'])) {
+            } elseif ($this->extClassConf['name'] === TypoScriptTemplateConstantEditorModuleFunctionController::class
+                && !empty($this->MOD_MENU['constant_editor_cat'])) {
                 // SAVE button
                 $saveButton = $buttonBar->makeInputButton()
                     ->setName('_savedok')
                     ->setValue('1')
                     ->setForm('TypoScriptTemplateModuleController')
                     ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc'))
-                    ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save', Icon::SIZE_SMALL))
+                    ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
+                        'actions-document-save',
+                        Icon::SIZE_SMALL
+                    ))
                     ->setShowLabelText(true);
                 $buttonBar->addButton($saveButton);
             } elseif ($this->extClassConf['name'] === TypoScriptTemplateObjectBrowserModuleFunctionController::class) {
@@ -395,7 +398,10 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
                         ->setHref(BackendUtility::getModuleUrl('web_ts', $urlParameters))
                         ->setClasses('typo3-goBack')
                         ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.goBack'))
-                        ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL));
+                        ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
+                            'actions-view-go-back',
+                            Icon::SIZE_SMALL
+                        ));
                     $buttonBar->addButton($backButton);
                 }
             }
@@ -443,64 +449,44 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
         $GLOBALS['tmpl'] = $tmpl;
         $tmpl->init();
 
-        $lang = $this->getLanguageService();
-
-        $title = $lang->getLL('noTemplate');
-        $message = '<p>' . $lang->getLL('noTemplateDescription') . '<br />' . $lang->getLL('createTemplateToEditConfiguration') . '</p>';
-
-        $view = GeneralUtility::makeInstance(StandaloneView::class);
-        $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:tstemplate/Resources/Private/Templates/InfoBox.html'));
-        $view->assignMultiple(array(
-            'title' => $title,
-            'message' => $message,
-            'state' => InfoboxViewHelper::STATE_INFO
-        ));
-        $theOutput = $view->render();
+        $moduleContent['state'] = InfoboxViewHelper::STATE_INFO;
 
         // New standard?
         if ($newStandardTemplate) {
+            $selector = '';
+            $staticsText = '';
             // Hook to change output, implemented for statictemplates
-            if (isset(
-                $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateView']
-            )) {
-                $selector = '';
-                $staticsText = '';
+            $hookObject = $this->getHookObjectForAction('newStandardTemplateView');
+            if (!empty($hookObject)) {
                 $reference = array(
                     'selectorHtml' => &$selector,
                     'staticsText' => &$staticsText
                 );
                 GeneralUtility::callUserFunction(
-                    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateView'],
+                    $hookObject,
                     $reference,
                     $this
                 );
                 $selector = $reference['selectorHtml'];
                 $staticsText = $reference['staticsText'];
-            } else {
-                $selector = '<input type="hidden" name="createStandard" value="" />';
-                $staticsText = '';
             }
             // Extension?
-            $theOutput .= '<h2>' . htmlspecialchars($lang->getLL('newWebsite')) . $staticsText . '</h2>';
-            $theOutput .= '<div><p>' . $lang->getLL('newWebsiteDescription') . '</p>' . $selector
-                . '<input class="btn btn-primary" type="submit" form="TypoScriptTemplateModuleController" name="newWebsite" value="'
-                . $lang->getLL('newWebsiteAction') . '" /></div>';
+            $moduleContent['staticsText'] = $staticsText;
+            $moduleContent['selector'] = $selector;
         }
-        // Extension?
-        $theOutput .= '<h2>' . $lang->getLL('extTemplate') . '</h2>';
-        $theOutput .= '<div><p>' . $lang->getLL('extTemplateDescription') . '</p>' . '<input class="btn btn-default" type="submit" form="TypoScriptTemplateModuleController" name="createExtension" value="' . $lang->getLL('extTemplateAction') . '" /></div>';
-
-        // Go to first appearing...
-        $first = $tmpl->ext_prevPageWithTemplate($this->id, $this->perms_clause);
-        if ($first) {
-            $urlParameters = array(
-                'id' => $first['uid']
-            );
-            $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
-            $theOutput .= '<h3>' . $lang->getLL('goToClosest') . '</h3>';
-            $theOutput .= '<div>' . sprintf('<p>' . $lang->getLL('goToClosestDescription') . '</p>%s' . $lang->getLL('goToClosestAction') . '%s', htmlspecialchars($first['title']), $first['uid'], '<a class="btn btn-default" href="' . htmlspecialchars($aHref) . '">', '</a>') . '</div>';
+        // Go to previous Page with Template...
+        $previousPage = $tmpl->ext_prevPageWithTemplate($this->id, $this->perms_clause);
+        if ($previousPage) {
+            $urlParameters = [
+                'id' => $previousPage['uid']
+            ];
+            $previousPage['aHref'] = BackendUtility::getModuleUrl('web_ts', $urlParameters);
+            $moduleContent['previousPage'] = $previousPage;
         }
-        return $theOutput;
+        $view = $this->getFluidTemplateObject('tstemplate', 'NoTemplate');
+        $view->assign('partialName', 'NoTemplate');
+        $view->assign('content', $moduleContent);
+        return $view->render();
     }
 
     /**
@@ -522,8 +508,20 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
                 $this->MOD_MENU['templatesOnPage'][$d['uid']] = $d['title'];
             }
         }
-        $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), $this->MCONF['name'], $this->modMenu_type, $this->modMenu_dontValidateList, $this->modMenu_setDefaultList);
-        return BackendUtility::getFuncMenu($this->id, 'SET[templatesOnPage]', $this->MOD_SETTINGS['templatesOnPage'], $this->MOD_MENU['templatesOnPage']);
+        $this->MOD_SETTINGS = BackendUtility::getModuleData(
+            $this->MOD_MENU,
+            GeneralUtility::_GP('SET'),
+            $this->MCONF['name'],
+            $this->modMenu_type,
+            $this->modMenu_dontValidateList,
+            $this->modMenu_setDefaultList
+        );
+        return BackendUtility::getFuncMenu(
+            $this->id,
+            'SET[templatesOnPage]',
+            $this->MOD_SETTINGS['templatesOnPage'],
+            $this->MOD_MENU['templatesOnPage']
+        );
     }
 
     /**
@@ -548,15 +546,14 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
             $tce->process_datamap();
         } elseif (GeneralUtility::_GP('newWebsite')) {
             // Hook to handle row data, implemented for statictemplates
-            if (isset(
-                $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateHandler']
-            )) {
+            $hookObject = $this->getHookObjectForAction('newStandardTemplateHandler');
+            if (!empty($hookObject)) {
                 $reference = array(
                     'recData' => &$recData,
                     'id' => $id,
                 );
                 GeneralUtility::callUserFunction(
-                    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateHandler'],
+                    $hookObject,
                     $reference,
                     $this
                 );
@@ -603,17 +600,19 @@ page.10.value = HELLO WORLD!
         $pArray[$cEl['uid']] = htmlspecialchars($cEl['title']);
         array_shift($rlArr);
         if (!empty($rlArr)) {
-            if (!isset($pArray[$cEl['uid'] . '.'])) {
-                $pArray[$cEl['uid'] . '.'] = array();
+            $key = $cEl['uid'] . '.';
+            if (empty($pArray[$key])) {
+                $pArray[$key] = array();
             }
-            $this->setInPageArray($pArray[$cEl['uid'] . '.'], $rlArr, $row);
+            $this->setInPageArray($pArray[$key], $rlArr, $row);
         } else {
-            $pArray[$cEl['uid'] . '_'] = $row;
+            $key = $cEl['uid'] . '_';
+            $pArray[$key] = $row;
         }
     }
 
     /**
-     * Render the list
+     * Get the list
      *
      * @param array $pArray
      * @param array $lines
@@ -626,27 +625,69 @@ page.10.value = HELLO WORLD!
             return $lines;
         }
 
-        $statusCheckedIcon = $this->moduleTemplate->getIconFactory()->getIcon('status-status-checked', Icon::SIZE_SMALL)->render();
+        $statusCheckedIcon = $this->moduleTemplate->getIconFactory()
+            ->getIcon('status-status-checked', Icon::SIZE_SMALL)->render();
+        $i = 0;
         foreach ($pArray as $k => $v) {
             if (MathUtility::canBeInterpretedAsInteger($k)) {
-                if (isset($pArray[$k . '_'])) {
-                    $lines[] = '<tr>
-						<td nowrap><span style="width: 1px; height: 1px; display:inline-block; margin-left: ' . $c * 20 . 'px"></span>' . '<a href="' . htmlspecialchars(GeneralUtility::linkThisScript(array('id' => $k))) . '" title="' . htmlspecialchars('ID: ' . $k) . '">' . $this->moduleTemplate->getIconFactory()->getIconForRecord('pages', BackendUtility::getRecordWSOL('pages', $k), Icon::SIZE_SMALL)->render() . ' ' . GeneralUtility::fixed_lgd_cs($pArray[$k], 30) . '</a></td>
-						<td>' . $pArray[$k . '_']['count'] . '</td>
-						<td>' . ($pArray[$k . '_']['root_max_val'] > 0 ? $statusCheckedIcon : '') . '</td>
-						<td>' . ($pArray[$k . '_']['root_min_val'] == 0 ? $statusCheckedIcon : '') . '</td>
-						</tr>';
+                $line = array();
+                $key = $k . '_';
+                $line['marginLeft'] = $c * 20;
+                $line['class'] = ($i++ % 2 === 0 ? 'bgColor4' : 'bgColor6');
+                $line['pageTitle'] = GeneralUtility::fixed_lgd_cs($pArray[$k], 30);
+                $line['icon'] = $this->moduleTemplate->getIconFactory()
+                    ->getIconForRecord(
+                        'pages',
+                        BackendUtility::getRecordWSOL('pages', $k),
+                        Icon::SIZE_SMALL
+                    )->render();
+                if (!empty($pArray[$key])) {
+                    $line['href'] = GeneralUtility::linkThisScript(array('id' => (int)$k));
+                    $line['title'] = 'ID: ' . (int)$k;
+                    $line['count'] = $pArray[$k . '_']['count'];
+                    $line['root_max_val'] = ($pArray[$key]['root_max_val'] > 0 ? $statusCheckedIcon : '&nbsp;');
+                    $line['root_min_val'] = ($pArray[$key]['root_min_val'] === 0 ? $statusCheckedIcon : '&nbsp;');
                 } else {
-                    $lines[] = '<tr>
-						<td nowrap><span style="width: 1px; height: 1px; display:inline-block; margin-left: ' . $c * 20 . 'px"></span>' . $this->moduleTemplate->getIconFactory()->getIconForRecord('pages', BackendUtility::getRecordWSOL('pages', $k), Icon::SIZE_SMALL)->render() . GeneralUtility::fixed_lgd_cs($pArray[$k], 30) . '</td>
-						<td></td>
-						<td></td>
-						<td></td>
-						</tr>';
+                    $line['href'] = '';
+                    $line['title'] = '';
+                    $line['count'] = '';
+                    $line['root_max_val'] = '';
+                    $line['root_min_val'] = '';
                 }
+                $lines[] = $line;
                 $lines = $this->renderList($pArray[$k . '.'], $lines, $c + 1);
             }
         }
         return $lines;
     }
+
+    /**
+     * Returns a new standalone view, shorthand function
+     *
+     * @param string $extensionName
+     * @param string $templateName
+     * @return StandaloneView
+     */
+    protected function getFluidTemplateObject($extensionName, $templateName = 'Main')
+    {
+        /** @var StandaloneView $view */
+        $view = GeneralUtility::makeInstance(StandaloneView::class);
+        $view->getRenderingContext()->getTemplatePaths()->fillDefaultsByPackageName($extensionName);
+        $view->getRenderingContext()->setControllerAction($templateName);
+        // @TODO: not sure this should stay; this value should in any case be a *proper* extension name!
+        $view->getRequest()->setControllerExtensionName('web_ts');
+        return $view;
+    }
+
+    /**
+     * @param string $action
+     * @return string
+     */
+    protected function getHookObjectForAction($action)
+    {
+        if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class][$action])) {
+            return $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class][$action];
+        }
+        return null;
+    }
 }
diff --git a/typo3/sysext/tstemplate/Resources/Private/Partials/NoTemplate.html b/typo3/sysext/tstemplate/Resources/Private/Partials/NoTemplate.html
new file mode 100644
index 000000000000..8176dadad135
--- /dev/null
+++ b/typo3/sysext/tstemplate/Resources/Private/Partials/NoTemplate.html
@@ -0,0 +1,30 @@
+<form action="{content.actionName}" method="post" enctype="multipart/form-data" id="TypoScriptTemplateModuleController" name="editForm" class="form">
+    <f:be.infobox title="{f:translate(key: 'noTemplate', extensionName:'tstemplate')}" state="{content.state}">
+        <p>
+            <f:translate key="noTemplateDescription" />
+            <br />
+            <f:translate key="createTemplateToEditConfiguration" />
+        </p>
+    </f:be.infobox>
+
+    <h2><f:translate key="newWebsite" />{staticsText}</h2>
+    <div>
+        <p><f:translate key="newWebsiteDescription" /></p>
+        {content.selector -> f:format.raw() -> f:or(alternative: '<input type="hidden" name="createStandard" value="" />')}
+        <input class="btn btn-primary" type="submit" form="TypoScriptTemplateModuleController" name="newWebsite" value="{f:translate(key: 'newWebsiteAction', extensionName:'tstemplate')}" />
+    </div>
+
+    <h2><f:translate key="extTemplate" /></h2>
+    <div>
+        <p><f:translate key="extTemplateDescription" /></p>
+        <input class="btn btn-default" type="submit" form="TypoScriptTemplateModuleController" name="createExtension" value="{f:translate(key: 'extTemplateAction', extensionName:'tstemplate')}" />
+    </div>
+
+    <f:if condition="{content.previousPage}">
+        <h3><f:translate key="goToClosest" /></h3>
+        <div>
+            <p><f:translate key="goToClosestDescription"  arguments="{0: content.previousPage.title, 1: content.previousPage.uid}" /></p>
+            <a class="btn btn-default" href="{content.previousPage.aHref}"><f:translate key="goToClosestAction" /></a>
+        </div>
+    </f:if>
+</form>
\ No newline at end of file
diff --git a/typo3/sysext/tstemplate/Resources/Private/Templates/InfoBox.html b/typo3/sysext/tstemplate/Resources/Private/Templates/InfoBox.html
deleted file mode 100644
index 870c90946284..000000000000
--- a/typo3/sysext/tstemplate/Resources/Private/Templates/InfoBox.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<f:be.infobox title="{title}" state="{state}">
-	<f:format.raw>{message}</f:format.raw>
-</f:be.infobox>
diff --git a/typo3/sysext/tstemplate/Resources/Private/Templates/Main.html b/typo3/sysext/tstemplate/Resources/Private/Templates/Main.html
new file mode 100644
index 000000000000..2bbb2c485243
--- /dev/null
+++ b/typo3/sysext/tstemplate/Resources/Private/Templates/Main.html
@@ -0,0 +1,5 @@
+<form action="{actionName}" method="post" enctype="multipart/form-data" id="TypoScriptTemplateModuleController" name="editForm" class="form">
+    <h1><f:translate key="moduleTitle" /></h1>
+    <f:render partial="{partialName}" arguments="{content: content}" optional="1" />
+    <f:format.raw>{typoscriptTemplateModuleContent}</f:format.raw>
+</form>
\ No newline at end of file
diff --git a/typo3/sysext/tstemplate/Resources/Private/Templates/PageZero.html b/typo3/sysext/tstemplate/Resources/Private/Templates/PageZero.html
new file mode 100644
index 000000000000..2f3f4d78eaa0
--- /dev/null
+++ b/typo3/sysext/tstemplate/Resources/Private/Templates/PageZero.html
@@ -0,0 +1,36 @@
+<h1><f:translate key="moduleTitle" /></h1>
+<div>
+    <p class="lead"><f:translate key="overview" /></p>
+    <div class="table-fit">
+        <table class="table table-striped table-hover" id="ts-overview">
+        <thead>
+            <tr>
+                <th><f:translate key="pageName" /></th>
+                <th><f:translate key="templates" /></th>
+                <th><f:translate key="isRoot" /></th>
+                <th><f:translate key="isExt" /></th>
+            </tr>
+        </thead>
+        <tbody>
+            <f:for each="{templateList}" as="line">
+                <f:render section="PageZeroTableRow" arguments="{line: line}" />
+            </f:for>
+        </tbody>
+        </table>
+    </div>
+</div>
+
+<f:section name="PageZeroTableRow">
+    <tr class="{line.class}">
+        <td nowrap>
+            <span style="width: 1px; height: 1px; display:inline-block; margin-left: {line.marginLeft}px"></span>
+            <a href="{line.href}" title="{line.title}">
+                <f:format.raw>{line.icon}</f:format.raw>
+                {line.pageTitle}
+            </a>
+        </td>
+        <td>{line.count}</td>
+        <td><f:format.raw>{line.root_max_val}</f:format.raw></td>
+        <td><f:format.raw>{line.root_min_val}</f:format.raw></td>
+    </tr>
+</f:section>
\ No newline at end of file
-- 
GitLab