[TASK] Use ModuleTemplate API for EXT:tstemplate 28/43828/11
authorMathias Schreiber <mathias.schreiber@wmdb.de>
Mon, 5 Oct 2015 19:32:46 +0000 (21:32 +0200)
committerAndreas Fernandez <typo3@scripting-base.de>
Fri, 9 Oct 2015 12:01:41 +0000 (14:01 +0200)
Releases: master
Resolves: #69888
Change-Id: I9c8bf6a3aa52c2f5d6abcb8744f9c21e0a274719
Reviewed-on: http://review.typo3.org/43828
Tested-by: Markus Klein <markus.klein@typo3.org>
Reviewed-by: Frank Nägler <frank.naegler@typo3.org>
Tested-by: Frank Nägler <frank.naegler@typo3.org>
Tested-by: Daniel Goerz <ervaude@gmail.com>
Reviewed-by: Markus Sommer <markussom@posteo.de>
Tested-by: Markus Sommer <markussom@posteo.de>
Reviewed-by: Andreas Fernandez <typo3@scripting-base.de>
Tested-by: Andreas Fernandez <typo3@scripting-base.de>
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine.js
typo3/sysext/t3editor/Classes/Hook/TypoScriptTemplateInfoHook.php
typo3/sysext/t3editor/Resources/Public/JavaScript/T3editor.js
typo3/sysext/tstemplate/Classes/Controller/TypoScriptTemplateModuleController.php
typo3/sysext/tstemplate/Resources/Private/Templates/tstemplate.html [deleted file]

index a29d850..43bf38a 100644 (file)
@@ -648,8 +648,11 @@ define('TYPO3/CMS/Backend/FormEngine', ['jquery'], function ($) {
 
                // remember the clicked submit button. we need to know that in TBE_EDITOR.submitForm();
                $(document).on('click', '.t3js-editform-submitButton', function(event) {
-                       var $elem = $('<input />').attr('type', 'hidden').attr('name', this.name).attr('value', '1');
-                       $(this).parents('form').append($elem);
+                       var $me = $(this),
+                               name = $me.data('name') || this.name,
+                               $elem = $('<input />').attr('type', 'hidden').attr('name', name).attr('value', '1');
+
+                       $me.parents('form').append($elem);
                });
        };
 
index 9989122..a5a86cc 100644 (file)
@@ -68,6 +68,7 @@ class TypoScriptTemplateInfoHook
     public function postOutputProcessingHook($parameters, $pObj)
     {
         $t3editor = $this->getT3editor();
+        $t3editor->getJavascriptCode();
         foreach (array('constants', 'config') as $type) {
             if ($parameters['e'][$type]) {
                 $attributes = 'rows="' . $parameters['numberOfRows'] . '" ' . 'wrap="off" ' . $pObj->pObj->doc->formWidth(48, true, 'width:98%;height:60%');
index f18b645..fa3e123 100644 (file)
@@ -11,7 +11,7 @@
  * The TYPO3 project - inspiring people to share!
  */
 
-define('TYPO3/CMS/T3editor/T3editor', ['jquery'], function ($) {
+define('TYPO3/CMS/T3editor/T3editor', ['jquery', 'TYPO3/CMS/Backend/SplitButtons'], function ($, SplitButtons) {
 
        var T3editor = {
                instances: {}
@@ -67,7 +67,7 @@ define('TYPO3/CMS/T3editor/T3editor', ['jquery'], function ($) {
         * Initializes editor events
         */
        T3editor.initializeEditorEvents = function(codemirror) {
-               $('button[name^="_save"]').on('click', function(e) {
+               SplitButtons.addPreSubmitCallback(function() {
                        codemirror.options.originalTextarea.val(codemirror.editor.getCode());
                });
 
index cda971f..71b2f74 100755 (executable)
@@ -17,11 +17,14 @@ namespace TYPO3\CMS\Tstemplate\Controller;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Module\BaseScriptClass;
+use TYPO3\CMS\Backend\Template\Components\ButtonBar;
 use TYPO3\CMS\Backend\Template\DocumentTemplate;
+use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
@@ -98,11 +101,19 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
     protected $iconFactory;
 
     /**
+     * ModuleTemplate Container
+     *
+     * @var ModuleTemplate
+     */
+    protected $moduleTemplate;
+
+    /**
      * Constructor
      */
     public function __construct()
     {
         $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
+        $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
         $this->getLanguageService()->includeLLFile('EXT:tstemplate/Resources/Private/Language/locallang.xlf');
 
         $this->MCONF = array(
@@ -162,8 +173,7 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
 
         /** @var DocumentTemplate doc */
         $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
-        $this->doc->setModuleTemplate('EXT:tstemplate/Resources/Private/Templates/tstemplate.html');
-        $this->doc->addStyleSheet('module', 'sysext/tstemplate/Resources/Public/Css/styles.css');
+        $this->moduleTemplate->getPageRenderer()->addCssFile(ExtensionManagementUtility::extRelPath('tstemplate') . 'Resources/Public/Css/styles.css');
 
         $lang = $this->getLanguageService();
 
@@ -173,42 +183,37 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
                 'template' => 'all'
             );
             $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
-            $this->doc->form = '<form action="' . htmlspecialchars($aHref) . '" method="post" enctype="multipart/form-data" name="editForm" class="form">';
+            $this->moduleTemplate->setForm('<form action="' . htmlspecialchars($aHref) . '" method="post" enctype="multipart/form-data" name="editForm" class="form">');
 
             // JavaScript
-            $this->doc->JScode = '
-               <script language="javascript" type="text/javascript">
-                       function uFormUrl(aname) {
-                               document.forms[0].action = ' . GeneralUtility::quoteJSvalue(($aHref . '#'), true) . '+aname;
-                       }
-                       function brPoint(lnumber,t) {
-                               window.location.href = ' . GeneralUtility::quoteJSvalue(($aHref . '&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TypoScriptTemplateObjectBrowserModuleFunctionController&SET[ts_browser_type]='), true) . '+(t?"setup":"const")+"&breakPointLN="+lnumber;
-                               return false;
-                       }
-               </script>
-               ';
-            $this->doc->postCode = '
-               <script language="javascript" type="text/javascript">
-                       if (top.fsMod) top.fsMod.recentIds["web"] = ' . $this->id . ';
-               </script>
-               ';
-            $this->doc->inDocStylesArray[] = '
-                               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; }
-                       ';
+            $this->moduleTemplate->addJavaScriptCode(
+                '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;
+                    return false;
+                }
+                if (top.fsMod) top.fsMod.recentIds["web"] = ' . $this->id . ';
+            ');
+            $this->moduleTemplate->getPageRenderer()->addCssInlineBlock(
+                '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; }
+            ');
             // Setting up the context sensitive menu:
-            $this->doc->getContextMenuCode();
-            // Build the modulle content
+            $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ClickMenu');
+            // Build the module content
             $this->content = $this->doc->header($lang->getLL('moduleTitle'));
             $this->extObjContent();
             // Setting up the buttons and markers for docheader
-            $docHeaderButtons = $this->getButtons();
-            $markers['FUNC_MENU'] = BackendUtility::getFuncMenu($this->id, 'SET[function]', $this->MOD_SETTINGS['function'], $this->MOD_MENU['function']);
-            $markers['CONTENT'] = $this->content;
+            $this->getButtons();
+            $this->generateMenu();
         } else {
             // Template pages:
             $records = $this->getDatabaseConnection()->exec_SELECTgetRows(
@@ -240,20 +245,46 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
                     '</table></div>';
 
             $this->content = $this->doc->header($lang->getLL('moduleTitle'));
-            $this->content .= $this->doc->section('', '<p class="lead">' . $lang->getLL('overview') . '</p>' . $table);
+            $this->content .= $this->moduleTemplate->section('', '<p class="lead">' . $lang->getLL('overview') . '</p>' . $table);
 
             // RENDER LIST of pages with templates, END
             // Setting up the buttons and markers for docheader
-            $docHeaderButtons = $this->getButtons();
-            $markers['CONTENT'] = $this->content;
+            $this->getButtons();
         }
-
-        // Build the <body> for the module
-        $this->content = $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
-        // Renders the module page
-        $this->content = $this->doc->render('Template Tools', $this->content);
     }
 
+    /**
+     * Generates the menu based on $this->MOD_MENU
+     *
+     * @return void
+     * @throws \InvalidArgumentException
+     */
+    protected function generateMenu()
+    {
+        $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
+        $menu->setIdentifier('WebFuncJumpMenu');
+        foreach ($this->MOD_MENU['function'] as $controller => $title) {
+            $item = $menu
+                ->makeMenuItem()
+                ->setHref(
+                    BackendUtility::getModuleUrl(
+                        $this->moduleName,
+                        [
+                            'id' => $this->id,
+                            'SET' => [
+                                'function' => $controller
+                            ]
+                        ]
+                    )
+                )
+                ->setTitle($title);
+            if ($controller === $this->MOD_SETTINGS['function']) {
+                $item->setActive(true);
+            }
+            $menu->addMenuItem($item);
+        }
+        $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
+    }
 
     /**
      * Injects the request object for the current request or subrequest
@@ -274,8 +305,8 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
         $this->clearCache();
         $this->main();
 
-        $this->content = $this->doc->insertStylesAndJS($this->content);
-        $response->getBody()->write($this->content);
+        $this->moduleTemplate->setContent($this->content);
+        $response->getBody()->write($this->moduleTemplate->renderContent());
         return $response;
     }
 
@@ -298,70 +329,87 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
      */
     protected function getButtons()
     {
-        $buttons = array(
-            'back' => '',
-            'close' => '',
-            'new' => '',
-            'save' => '',
-            'save_close' => '',
-            'view' => '',
-            'shortcut' => ''
-        );
-
+        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
         $lang = $this->getLanguageService();
 
         if ($this->id && $this->access) {
             // View page
-            $buttons['view'] = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick($this->pageinfo['uid'], '', BackendUtility::BEgetRootLine($this->pageinfo['uid']))) . '" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', true) . '">' . $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)->render() . '</a>';
-            if ($this->extClassConf['name'] == TypoScriptTemplateInformationModuleFunctionController::class) {
+            $viewButton = $buttonBar->makeLinkButton()
+                ->setHref('#')
+                ->setOnClick(BackendUtility::viewOnClick($this->pageinfo['uid'], '', BackendUtility::BEgetRootLine($this->pageinfo['uid'])))
+                ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', true))
+                ->setIcon($this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL));
+            $buttonBar->addButton($viewButton, ButtonBar::BUTTON_POSITION_LEFT, 99);
+            if ($this->extClassConf['name'] === TypoScriptTemplateInformationModuleFunctionController::class) {
                 // NEW button
                 $urlParameters = array(
                     'id' => $this->id,
                     'template' => 'all',
                     'createExtension' => 'new'
                 );
-                $buttons['new'] = '<a href="' . htmlspecialchars(BackendUtility::getModuleUrl('web_ts', $urlParameters)) . '" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:db_new.php.pagetitle', true) . '">' . $this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)->render() . '</a>';
+
                 if (!empty($this->e) && !GeneralUtility::_POST('_saveandclosedok')) {
-                    // no NEW-button while edit
-                    $buttons['new'] = '';
-                    // SAVE button
-                    $buttons['save'] = '<button type="submit" class="c-inputButton" name="_savedok" value="1" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc', true) . '">'
-                        . $this->iconFactory->getIcon('actions-document-save', Icon::SIZE_SMALL)->render()
-                        . '</button>';
-                    // SAVE AND CLOSE button
-                    $buttons['save_close'] = '<button type="submit" class="c-inputButton" name="_saveandclosedok" value="1" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveCloseDoc', true) . '">'
-                        . $this->iconFactory->getIcon('actions-document-save-close', Icon::SIZE_SMALL)->render()
-                        . '</button>';
+                    $saveButton = $buttonBar->makeInputButton()
+                        ->setName('_savedok')
+                        ->setValue('1')
+                        ->setIcon($this->iconFactory->getIcon('actions-document-save', Icon::SIZE_SMALL))
+                        ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc', true));
+
+                    $saveAndCloseButton = $buttonBar->makeInputButton()
+                        ->setName('_saveandclosedok')
+                        ->setValue('1')
+                        ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveCloseDoc', true))
+                        ->setIcon($this->iconFactory->getIcon('actions-document-save-close', Icon::SIZE_SMALL));
+
+                    $splitButtonElement = $buttonBar->makeSplitButton()
+                        ->addItem($saveButton)
+                        ->addItem($saveAndCloseButton);
+
+                    $buttonBar->addButton($splitButtonElement, ButtonBar::BUTTON_POSITION_LEFT, 3);
+
                     // CLOSE button
-                    $url = BackendUtility::getModuleUrl('web_ts', array('id' => $this->id));
-                    $buttons['close'] = '<a href="' . htmlspecialchars($url) . '" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.closeDoc', true) . '">' .  $this->iconFactory->getIcon('actions-document-close', Icon::SIZE_SMALL)->render() . '</a>';
+                    $closeButton = $buttonBar->makeLinkButton()
+                        ->setHref(BackendUtility::getModuleUrl('web_ts', array('id' => $this->id)))
+                        ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.closeDoc', true))
+                        ->setIcon($this->iconFactory->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', true))
+                        ->setIcon($this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL));
+                    $buttonBar->addButton($newButton);
                 }
             } elseif ($this->extClassConf['name'] === TypoScriptTemplateConstantEditorModuleFunctionController::class && !empty($this->MOD_MENU['constant_editor_cat'])) {
                 // SAVE button
-                $buttons['save'] = '<button class="c-inputButton" name="_savedok" value="1" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc', true) . '">'
-                    . $this->iconFactory->getIcon('actions-document-save', Icon::SIZE_SMALL)->render()
-                    . '</button>';
+                $saveButton = $buttonBar->makeInputButton()
+                    ->setName('_savedok')
+                    ->setValue('1')
+                    ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc', true))
+                    ->setIcon($this->iconFactory->getIcon('actions-document-save', Icon::SIZE_SMALL))
+                    ->setShowLabelText(true);
+                $buttonBar->addButton($saveButton);
             } elseif ($this->extClassConf['name'] === TypoScriptTemplateObjectBrowserModuleFunctionController::class) {
                 if (!empty($this->sObj)) {
                     // BACK
                     $urlParameters = array(
                         'id' => $this->id
                     );
-                    $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
-                    $buttons['back'] = '<a href="' . htmlspecialchars($aHref) . '" class="typo3-goBack" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.goBack', true) . '">' . $this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL)->render() . '</a>';
+                    $backButton = $buttonBar->makeLinkButton()
+                        ->setHref(BackendUtility::getModuleUrl('web_ts', $urlParameters))
+                        ->setClasses('typo3-goBack')
+                        ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.goBack', true))
+                        ->setIcon($this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL));
+                    $buttonBar->addButton($backButton);
                 }
             }
-            // Shortcut
-            if ($this->getBackendUser()->mayMakeShortcut()) {
-                $buttons['shortcut'] = $this->doc->makeShortcutIcon('id, edit_record, pointer, new_unique_uid, search_field, search_levels, showLimit', implode(',', array_keys($this->MOD_MENU)), $this->MCONF['name']);
-            }
-        } else {
-            // Shortcut
-            if ($this->getBackendUser()->mayMakeShortcut()) {
-                $buttons['shortcut'] = $this->doc->makeShortcutIcon('id', '', $this->MCONF['name']);
-            }
         }
-        return $buttons;
+        // Shortcut
+        if ($this->getBackendUser()->mayMakeShortcut()) {
+            $shortcutButton = $buttonBar->makeFullyRenderedButton()
+                ->setHtmlSource($this->moduleTemplate->makeShortcutIcon('id', '', $this->MCONF['name']));
+            $buttonBar->addButton($shortcutButton, ButtonBar::BUTTON_POSITION_RIGHT, 99);
+        }
     }
 
     // OTHER FUNCTIONS:
@@ -441,13 +489,13 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
                 $staticsText = '';
             }
             // Extension?
-            $theOutput .= $this->doc->section(
+            $theOutput .= $this->moduleTemplate->section(
                 $lang->getLL('newWebsite') . $staticsText,
                 '<p>' . $lang->getLL('newWebsiteDescription') . '</p>' . $selector . '<input class="btn btn-primary" type="submit" name="newWebsite" value="' . $lang->getLL('newWebsiteAction') . '" />',
                 0, 1);
         }
         // Extension?
-        $theOutput .= $this->doc->section(
+        $theOutput .= $this->moduleTemplate->section(
             $lang->getLL('extTemplate'),
             '<p>' . $lang->getLL('extTemplateDescription') . '</p>' . '<input class="btn btn-default" type="submit" name="createExtension" value="' . $lang->getLL('extTemplateAction') . '" />',
             0, 1);
@@ -458,7 +506,7 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
                 'id' => $first['uid']
             );
             $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
-            $theOutput .= $this->doc->section(
+            $theOutput .= $this->moduleTemplate->section(
                 $lang->getLL('goToClosest'),
                 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>'),
                 0, 1);
diff --git a/typo3/sysext/tstemplate/Resources/Private/Templates/tstemplate.html b/typo3/sysext/tstemplate/Resources/Private/Templates/tstemplate.html
deleted file mode 100644 (file)
index fc7a6c7..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-<!-- ###FULLDOC### begin -->
-<div class="typo3-fullDoc">
-       <div id="typo3-docheader">
-               <div class="typo3-docheader-functions">
-                       <div class="left">###CSH### ###FUNC_MENU###</div>
-                       <div class="right">###PAGEPATH######PAGEINFO###</div>
-               </div>
-               <div class="typo3-docheader-buttons">
-                       <div class="left">###BUTTONLIST_LEFT###</div>
-                       <div class="right">###BUTTONLIST_RIGHT###</div>
-               </div>
-       </div>
-
-       <div id="typo3-docbody">
-               <div id="typo3-inner-docbody">
-                       ###CONTENT###
-               </div>
-       </div>
-</div>
-<!-- ###FULLDOC### end -->
-
-<!-- Grouping the icons on top -->
-
-<!-- ###BUTTON_GROUP_WRAP### -->
-<div class="buttongroup">###BUTTONS###</div>
-<!-- ###BUTTON_GROUP_WRAP### -->
-
-<!-- ###BUTTON_GROUPS_LEFT### -->
-<!-- ###BUTTON_GROUP1### -->###BACK######NEW###<!-- ###BUTTON_GROUP1### -->
-<!-- ###BUTTON_GROUP2### -->###CLOSE###<!-- ###BUTTON_GROUP2### -->
-<!-- ###BUTTON_GROUP3### -->###SAVE######SAVE_CLOSE###<!-- ###BUTTON_GROUP3### -->
-<!-- ###BUTTON_GROUP4### -->###VIEW###<!-- ###BUTTON_GROUP4### -->
-<!-- ###BUTTON_GROUPS_LEFT### -->
-
-<!-- ###BUTTON_GROUPS_RIGHT### -->
-<!-- ###BUTTON_GROUP1### -->###SHORTCUT###<!-- ###BUTTON_GROUP1### -->
-<!-- ###BUTTON_GROUPS_RIGHT### -->